diff options
Diffstat (limited to 'core/src/main/java/org/bouncycastle/pqc')
125 files changed, 0 insertions, 35770 deletions
diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/GMSSPrivateKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/GMSSPrivateKey.java deleted file mode 100644 index 4e182c59..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/GMSSPrivateKey.java +++ /dev/null @@ -1,1312 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import java.math.BigInteger; -import java.util.Vector; - -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1Object; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.pqc.crypto.gmss.GMSSLeaf; -import org.bouncycastle.pqc.crypto.gmss.GMSSParameters; -import org.bouncycastle.pqc.crypto.gmss.GMSSRootCalc; -import org.bouncycastle.pqc.crypto.gmss.GMSSRootSig; -import org.bouncycastle.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/bouncycastle/pqc/asn1/GMSSPublicKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/GMSSPublicKey.java deleted file mode 100644 index fc5c4f2b..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/GMSSPublicKey.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1Object; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.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/bouncycastle/pqc/asn1/McElieceCCA2PrivateKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PrivateKey.java deleted file mode 100644 index 192484f8..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PrivateKey.java +++ /dev/null @@ -1,173 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import java.math.BigInteger; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1Object; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; - -import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.math.linearalgebra.Permutation; -import org.bouncycastle.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/bouncycastle/pqc/asn1/McElieceCCA2PublicKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PublicKey.java deleted file mode 100644 index adb5e46a..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PublicKey.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import java.math.BigInteger; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1Object; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.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/bouncycastle/pqc/asn1/McEliecePrivateKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/McEliecePrivateKey.java deleted file mode 100644 index 4bf2f822..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/McEliecePrivateKey.java +++ /dev/null @@ -1,197 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import java.math.BigInteger; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1Object; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.math.linearalgebra.Permutation; -import org.bouncycastle.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/bouncycastle/pqc/asn1/McEliecePublicKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/McEliecePublicKey.java deleted file mode 100644 index 6f1efc09..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/McEliecePublicKey.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import java.math.BigInteger; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1Object; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.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/bouncycastle/pqc/asn1/PQCObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/pqc/asn1/PQCObjectIdentifiers.java deleted file mode 100644 index d93d9952..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/PQCObjectIdentifiers.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import org.bouncycastle.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/bouncycastle/pqc/asn1/ParSet.java b/core/src/main/java/org/bouncycastle/pqc/asn1/ParSet.java deleted file mode 100644 index dee56a52..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/ParSet.java +++ /dev/null @@ -1,140 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import java.math.BigInteger; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1Object; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.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/bouncycastle/pqc/asn1/RainbowPrivateKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/RainbowPrivateKey.java deleted file mode 100644 index 7c21691d..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/RainbowPrivateKey.java +++ /dev/null @@ -1,349 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1Object; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.pqc.crypto.rainbow.Layer; -import org.bouncycastle.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/bouncycastle/pqc/asn1/RainbowPublicKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/RainbowPublicKey.java deleted file mode 100644 index febe5387..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/RainbowPublicKey.java +++ /dev/null @@ -1,174 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1Object; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.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); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/DigestingMessageSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/DigestingMessageSigner.java deleted file mode 100644 index 6b5b2515..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/DigestingMessageSigner.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.bouncycastle.pqc.crypto; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.Signer; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.params.ParametersWithRandom; - - -/** - * Implements the sign and verify functions for a Signature Scheme which can use a hash function. - */ -public class DigestingMessageSigner - implements Signer -{ - private final Digest messDigest; - private final MessageSigner messSigner; - private boolean forSigning; - - public DigestingMessageSigner(MessageSigner messSigner, Digest messDigest) - { - this.messSigner = messSigner; - this.messDigest = messDigest; - } - - public void init(boolean forSigning, - CipherParameters param) - { - - this.forSigning = forSigning; - AsymmetricKeyParameter k; - - if (param instanceof ParametersWithRandom) - { - k = (AsymmetricKeyParameter)((ParametersWithRandom)param).getParameters(); - } - else - { - k = (AsymmetricKeyParameter)param; - } - - if (forSigning && !k.isPrivate()) - { - throw new IllegalArgumentException("Signing Requires Private Key."); - } - - if (!forSigning && k.isPrivate()) - { - throw new IllegalArgumentException("Verification Requires Public Key."); - } - - reset(); - - messSigner.init(forSigning, param); - } - - - /** - * This function signs the message that has been updated, making use of the - * private key. - * - * @return the signature of the message. - */ - public byte[] generateSignature() - { - if (!forSigning) - { - throw new IllegalStateException("RainbowDigestSigner not initialised for signature generation."); - } - - byte[] hash = new byte[messDigest.getDigestSize()]; - messDigest.doFinal(hash, 0); - - return messSigner.generateSignature(hash); - } - - /** - * This function verifies the signature of the message that has been - * updated, with the aid of the public key. - * - * @param signature the signature of the message is given as a byte array. - * @return true if the signature has been verified, false otherwise. - */ - public boolean verify(byte[] signature) - { - if (forSigning) - { - throw new IllegalStateException("RainbowDigestSigner not initialised for verification"); - } - - byte[] hash = new byte[messDigest.getDigestSize()]; - messDigest.doFinal(hash, 0); - - return messSigner.verifySignature(hash, signature); - - } - - public void update(byte b) - { - messDigest.update(b); - } - - public void update(byte[] in, int off, int len) - { - messDigest.update(in, off, len); - } - - public void reset() - { - messDigest.reset(); - } - - public boolean verifySignature(byte[] signature) - { - return this.verify(signature); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/MessageEncryptor.java b/core/src/main/java/org/bouncycastle/pqc/crypto/MessageEncryptor.java deleted file mode 100644 index 8d67c5cd..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/MessageEncryptor.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.bouncycastle.pqc.crypto; - - -import org.bouncycastle.crypto.CipherParameters; - -public interface MessageEncryptor -{ - - /** - * - * @param forEncrypting true if we are encrypting a signature, false - * otherwise. - * @param param key parameters for encryption or decryption. - */ - public void init(boolean forEncrypting, CipherParameters param); - - /** - * - * @param message the message to be signed. - * @throws Exception - */ - public byte[] messageEncrypt(byte[] message) throws Exception; - - /** - * - * @param cipher the cipher text of the message - * @throws Exception - */ - public byte[] messageDecrypt(byte[] cipher) throws Exception; -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/MessageSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/MessageSigner.java deleted file mode 100644 index 50243f73..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/MessageSigner.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.bouncycastle.pqc.crypto; - -import org.bouncycastle.crypto.CipherParameters; - -public interface MessageSigner -{ - /** - * initialise the signer for signature generation or signature - * verification. - * - * @param forSigning true if we are generating a signature, false - * otherwise. - * @param param key parameters for signature generation. - */ - public void init(boolean forSigning, CipherParameters param); - - /** - * sign the passed in message (usually the output of a hash function). - * - * @param message the message to be signed. - * @return the signature of the message - */ - public byte[] generateSignature(byte[] message); - - /** - * verify the message message against the signature values r and s. - * - * @param message the message that was supposed to have been signed. - * @param signature the signature of the message - */ - public boolean verifySignature(byte[] message, byte[] signature); -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSDigestProvider.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSDigestProvider.java deleted file mode 100644 index 4af1a8b5..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSDigestProvider.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss; - -import org.bouncycastle.crypto.Digest; - -public interface GMSSDigestProvider -{ - Digest get(); -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSKeyGenerationParameters.java deleted file mode 100644 index eace4d03..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSKeyGenerationParameters.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.KeyGenerationParameters; - -public class GMSSKeyGenerationParameters - extends KeyGenerationParameters -{ - - private GMSSParameters params; - - public GMSSKeyGenerationParameters( - SecureRandom random, - GMSSParameters params) - { - // XXX key size? - super(random, 1); - this.params = params; - } - - public GMSSParameters getParameters() - { - return params; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSKeyPairGenerator.java deleted file mode 100644 index 013441ec..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSKeyPairGenerator.java +++ /dev/null @@ -1,476 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss; - -import java.security.SecureRandom; -import java.util.Vector; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.pqc.crypto.gmss.util.GMSSRandom; -import org.bouncycastle.pqc.crypto.gmss.util.WinternitzOTSVerify; -import org.bouncycastle.pqc.crypto.gmss.util.WinternitzOTSignature; - - -/** - * This class implements key pair generation of the generalized Merkle signature - * scheme (GMSS). - * - * @see GMSSSigner - */ -public class GMSSKeyPairGenerator - implements AsymmetricCipherKeyPairGenerator -{ - /** - * The source of randomness for OTS private key generation - */ - private GMSSRandom gmssRandom; - - /** - * The hash function used for the construction of the authentication trees - */ - private Digest messDigestTree; - - /** - * An array of the seeds for the PRGN (for main tree, and all current - * subtrees) - */ - private byte[][] currentSeeds; - - /** - * An array of seeds for the PRGN (for all subtrees after next) - */ - private byte[][] nextNextSeeds; - - /** - * An array of the RootSignatures - */ - private byte[][] currentRootSigs; - - /** - * Class of hash function to use - */ - private GMSSDigestProvider digestProvider; - - /** - * The length of the seed for the PRNG - */ - private int mdLength; - - /** - * the number of Layers - */ - private int numLayer; - - - /** - * Flag indicating if the class already has been initialized - */ - private boolean initialized = false; - - /** - * Instance of GMSSParameterset - */ - private GMSSParameters gmssPS; - - /** - * An array of the heights of the authentication trees of each layer - */ - private int[] heightOfTrees; - - /** - * An array of the Winternitz parameter 'w' of each layer - */ - private int[] otsIndex; - - /** - * The parameter K needed for the authentication path computation - */ - private int[] K; - - private GMSSKeyGenerationParameters gmssParams; - - /** - * The GMSS OID. - */ - public static final String OID = "1.3.6.1.4.1.8301.3.1.3.3"; - - /** - * The standard constructor tries to generate the GMSS algorithm identifier - * with the corresponding OID. - * - * @param digestProvider provider for digest implementations. - */ - public GMSSKeyPairGenerator(GMSSDigestProvider digestProvider) - { - this.digestProvider = digestProvider; - messDigestTree = digestProvider.get(); - - // set mdLength - this.mdLength = messDigestTree.getDigestSize(); - // construct randomizer - this.gmssRandom = new GMSSRandom(messDigestTree); - - } - - /** - * Generates the GMSS key pair. The public key is an instance of - * JDKGMSSPublicKey, the private key is an instance of JDKGMSSPrivateKey. - * - * @return Key pair containing a JDKGMSSPublicKey and a JDKGMSSPrivateKey - */ - private AsymmetricCipherKeyPair genKeyPair() - { - if (!initialized) - { - initializeDefault(); - } - - // initialize authenticationPaths and treehash instances - byte[][][] currentAuthPaths = new byte[numLayer][][]; - byte[][][] nextAuthPaths = new byte[numLayer - 1][][]; - Treehash[][] currentTreehash = new Treehash[numLayer][]; - Treehash[][] nextTreehash = new Treehash[numLayer - 1][]; - - Vector[] currentStack = new Vector[numLayer]; - Vector[] nextStack = new Vector[numLayer - 1]; - - Vector[][] currentRetain = new Vector[numLayer][]; - Vector[][] nextRetain = new Vector[numLayer - 1][]; - - for (int i = 0; i < numLayer; i++) - { - currentAuthPaths[i] = new byte[heightOfTrees[i]][mdLength]; - currentTreehash[i] = new Treehash[heightOfTrees[i] - K[i]]; - - if (i > 0) - { - nextAuthPaths[i - 1] = new byte[heightOfTrees[i]][mdLength]; - nextTreehash[i - 1] = new Treehash[heightOfTrees[i] - K[i]]; - } - - currentStack[i] = new Vector(); - if (i > 0) - { - nextStack[i - 1] = new Vector(); - } - } - - // initialize roots - byte[][] currentRoots = new byte[numLayer][mdLength]; - byte[][] nextRoots = new byte[numLayer - 1][mdLength]; - // initialize seeds - byte[][] seeds = new byte[numLayer][mdLength]; - // initialize seeds[] by copying starting-seeds of first trees of each - // layer - for (int i = 0; i < numLayer; i++) - { - System.arraycopy(currentSeeds[i], 0, seeds[i], 0, mdLength); - } - - // initialize rootSigs - currentRootSigs = new byte[numLayer - 1][mdLength]; - - // ------------------------- - // ------------------------- - // --- calculation of current authpaths and current rootsigs (AUTHPATHS, - // SIG)------ - // from bottom up to the root - for (int h = numLayer - 1; h >= 0; h--) - { - GMSSRootCalc tree = new GMSSRootCalc(this.heightOfTrees[h], this.K[h], digestProvider); - try - { - // on lowest layer no lower root is available, so just call - // the method with null as first parameter - if (h == numLayer - 1) - { - tree = this.generateCurrentAuthpathAndRoot(null, currentStack[h], seeds[h], h); - } - else - // otherwise call the method with the former computed root - // value - { - tree = this.generateCurrentAuthpathAndRoot(currentRoots[h + 1], currentStack[h], seeds[h], h); - } - - } - catch (Exception e1) - { - e1.printStackTrace(); - } - - // set initial values needed for the private key construction - for (int i = 0; i < heightOfTrees[h]; i++) - { - System.arraycopy(tree.getAuthPath()[i], 0, currentAuthPaths[h][i], 0, mdLength); - } - currentRetain[h] = tree.getRetain(); - currentTreehash[h] = tree.getTreehash(); - System.arraycopy(tree.getRoot(), 0, currentRoots[h], 0, mdLength); - } - - // --- calculation of next authpaths and next roots (AUTHPATHS+, ROOTS+) - // ------ - for (int h = numLayer - 2; h >= 0; h--) - { - GMSSRootCalc tree = this.generateNextAuthpathAndRoot(nextStack[h], seeds[h + 1], h + 1); - - // set initial values needed for the private key construction - for (int i = 0; i < heightOfTrees[h + 1]; i++) - { - System.arraycopy(tree.getAuthPath()[i], 0, nextAuthPaths[h][i], 0, mdLength); - } - nextRetain[h] = tree.getRetain(); - nextTreehash[h] = tree.getTreehash(); - System.arraycopy(tree.getRoot(), 0, nextRoots[h], 0, mdLength); - - // create seed for the Merkle tree after next (nextNextSeeds) - // SEEDs++ - System.arraycopy(seeds[h + 1], 0, this.nextNextSeeds[h], 0, mdLength); - } - // ------------ - - // generate JDKGMSSPublicKey - GMSSPublicKeyParameters publicKey = new GMSSPublicKeyParameters(currentRoots[0], gmssPS); - - // generate the JDKGMSSPrivateKey - GMSSPrivateKeyParameters privateKey = new GMSSPrivateKeyParameters(currentSeeds, nextNextSeeds, currentAuthPaths, - nextAuthPaths, currentTreehash, nextTreehash, currentStack, nextStack, currentRetain, nextRetain, nextRoots, currentRootSigs, gmssPS, digestProvider); - - // return the KeyPair - return (new AsymmetricCipherKeyPair(publicKey, privateKey)); - } - - /** - * calculates the authpath for tree in layer h which starts with seed[h] - * additionally computes the rootSignature of underlaying root - * - * @param currentStack stack used for the treehash instance created by this method - * @param lowerRoot stores the root of the lower tree - * @param seed starting seeds - * @param h actual layer - */ - private GMSSRootCalc generateCurrentAuthpathAndRoot(byte[] lowerRoot, Vector currentStack, byte[] seed, int h) - { - byte[] help = new byte[mdLength]; - - byte[] OTSseed = new byte[mdLength]; - OTSseed = gmssRandom.nextSeed(seed); - - WinternitzOTSignature ots; - - // data structure that constructs the whole tree and stores - // the initial values for treehash, Auth and retain - GMSSRootCalc treeToConstruct = new GMSSRootCalc(this.heightOfTrees[h], this.K[h], digestProvider); - - treeToConstruct.initialize(currentStack); - - // generate the first leaf - if (h == numLayer - 1) - { - ots = new WinternitzOTSignature(OTSseed, digestProvider.get(), otsIndex[h]); - help = ots.getPublicKey(); - } - else - { - // for all layers except the lowest, generate the signature of the - // underlying root - // and reuse this signature to compute the first leaf of acual layer - // more efficiently (by verifiing the signature) - ots = new WinternitzOTSignature(OTSseed, digestProvider.get(), otsIndex[h]); - currentRootSigs[h] = ots.getSignature(lowerRoot); - WinternitzOTSVerify otsver = new WinternitzOTSVerify(digestProvider.get(), otsIndex[h]); - help = otsver.Verify(lowerRoot, currentRootSigs[h]); - } - // update the tree with the first leaf - treeToConstruct.update(help); - - int seedForTreehashIndex = 3; - int count = 0; - - // update the tree 2^(H) - 1 times, from the second to the last leaf - for (int i = 1; i < (1 << this.heightOfTrees[h]); i++) - { - // initialize the seeds for the leaf generation with index 3 * 2^h - if (i == seedForTreehashIndex && count < this.heightOfTrees[h] - this.K[h]) - { - treeToConstruct.initializeTreehashSeed(seed, count); - seedForTreehashIndex *= 2; - count++; - } - - OTSseed = gmssRandom.nextSeed(seed); - ots = new WinternitzOTSignature(OTSseed, digestProvider.get(), otsIndex[h]); - treeToConstruct.update(ots.getPublicKey()); - } - - if (treeToConstruct.wasFinished()) - { - return treeToConstruct; - } - System.err.println("Baum noch nicht fertig konstruiert!!!"); - return null; - } - - /** - * calculates the authpath and root for tree in layer h which starts with - * seed[h] - * - * @param nextStack stack used for the treehash instance created by this method - * @param seed starting seeds - * @param h actual layer - */ - private GMSSRootCalc generateNextAuthpathAndRoot(Vector nextStack, byte[] seed, int h) - { - byte[] OTSseed = new byte[numLayer]; - WinternitzOTSignature ots; - - // data structure that constructs the whole tree and stores - // the initial values for treehash, Auth and retain - GMSSRootCalc treeToConstruct = new GMSSRootCalc(this.heightOfTrees[h], this.K[h], this.digestProvider); - treeToConstruct.initialize(nextStack); - - int seedForTreehashIndex = 3; - int count = 0; - - // update the tree 2^(H) times, from the first to the last leaf - for (int i = 0; i < (1 << this.heightOfTrees[h]); i++) - { - // initialize the seeds for the leaf generation with index 3 * 2^h - if (i == seedForTreehashIndex && count < this.heightOfTrees[h] - this.K[h]) - { - treeToConstruct.initializeTreehashSeed(seed, count); - seedForTreehashIndex *= 2; - count++; - } - - OTSseed = gmssRandom.nextSeed(seed); - ots = new WinternitzOTSignature(OTSseed, digestProvider.get(), otsIndex[h]); - treeToConstruct.update(ots.getPublicKey()); - } - - if (treeToConstruct.wasFinished()) - { - return treeToConstruct; - } - System.err.println("N�chster Baum noch nicht fertig konstruiert!!!"); - return null; - } - - /** - * This method initializes the GMSS KeyPairGenerator using an integer value - * <code>keySize</code> as input. It provides a simple use of the GMSS for - * testing demands. - * <p> - * A given <code>keysize</code> of less than 10 creates an amount 2^10 - * signatures. A keySize between 10 and 20 creates 2^20 signatures. Given an - * integer greater than 20 the key pair generator creates 2^40 signatures. - * - * @param keySize Assigns the parameters used for the GMSS signatures. There are - * 3 choices:<br> - * 1. keysize <= 10: creates 2^10 signatures using the - * parameterset<br> - * P = (2, (5, 5), (3, 3), (3, 3))<br> - * 2. keysize > 10 and <= 20: creates 2^20 signatures using the - * parameterset<br> - * P = (2, (10, 10), (5, 4), (2, 2))<br> - * 3. keysize > 20: creates 2^40 signatures using the - * parameterset<br> - * P = (2, (10, 10, 10, 10), (9, 9, 9, 3), (2, 2, 2, 2)) - * @param secureRandom not used by GMSS, the SHA1PRNG of the SUN Provider is always - * used - */ - public void initialize(int keySize, SecureRandom secureRandom) - { - - KeyGenerationParameters kgp; - if (keySize <= 10) - { // create 2^10 keys - int[] defh = {10}; - int[] defw = {3}; - int[] defk = {2}; - // XXX sec random neede? - kgp = new GMSSKeyGenerationParameters(secureRandom, new GMSSParameters(defh.length, defh, defw, defk)); - } - else if (keySize <= 20) - { // create 2^20 keys - int[] defh = {10, 10}; - int[] defw = {5, 4}; - int[] defk = {2, 2}; - kgp = new GMSSKeyGenerationParameters(secureRandom, new GMSSParameters(defh.length, defh, defw, defk)); - } - else - { // create 2^40 keys, keygen lasts around 80 seconds - int[] defh = {10, 10, 10, 10}; - int[] defw = {9, 9, 9, 3}; - int[] defk = {2, 2, 2, 2}; - kgp = new GMSSKeyGenerationParameters(secureRandom, new GMSSParameters(defh.length, defh, defw, defk)); - } - - // call the initializer with the chosen parameters - this.initialize(kgp); - - } - - - /** - * Initalizes the key pair generator using a parameter set as input - */ - public void initialize(KeyGenerationParameters param) - { - - this.gmssParams = (GMSSKeyGenerationParameters)param; - - // generate GMSSParameterset - this.gmssPS = new GMSSParameters(gmssParams.getParameters().getNumOfLayers(), gmssParams.getParameters().getHeightOfTrees(), - gmssParams.getParameters().getWinternitzParameter(), gmssParams.getParameters().getK()); - - this.numLayer = gmssPS.getNumOfLayers(); - this.heightOfTrees = gmssPS.getHeightOfTrees(); - this.otsIndex = gmssPS.getWinternitzParameter(); - this.K = gmssPS.getK(); - - // seeds - this.currentSeeds = new byte[numLayer][mdLength]; - this.nextNextSeeds = new byte[numLayer - 1][mdLength]; - - // construct SecureRandom for initial seed generation - SecureRandom secRan = new SecureRandom(); - - // generation of initial seeds - for (int i = 0; i < numLayer; i++) - { - secRan.nextBytes(currentSeeds[i]); - gmssRandom.nextSeed(currentSeeds[i]); - } - - this.initialized = true; - } - - /** - * This method is called by generateKeyPair() in case that no other - * initialization method has been called by the user - */ - private void initializeDefault() - { - int[] defh = {10, 10, 10, 10}; - int[] defw = {3, 3, 3, 3}; - int[] defk = {2, 2, 2, 2}; - - KeyGenerationParameters kgp = new GMSSKeyGenerationParameters(new SecureRandom(), new GMSSParameters(defh.length, defh, defw, defk)); - this.initialize(kgp); - - } - - public void init(KeyGenerationParameters param) - { - this.initialize(param); - - } - - public AsymmetricCipherKeyPair generateKeyPair() - { - return genKeyPair(); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSKeyParameters.java deleted file mode 100644 index 53f6e432..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSKeyParameters.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; - -public class GMSSKeyParameters - extends AsymmetricKeyParameter -{ - private GMSSParameters params; - - public GMSSKeyParameters( - boolean isPrivate, - GMSSParameters params) - { - super(isPrivate); - this.params = params; - } - - public GMSSParameters getParameters() - { - return params; - } -}
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSLeaf.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSLeaf.java deleted file mode 100644 index 6823ce3f..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSLeaf.java +++ /dev/null @@ -1,376 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.pqc.crypto.gmss.util.GMSSRandom; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.encoders.Hex; - - -/** - * This class implements the distributed computation of the public key of the - * Winternitz one-time signature scheme (OTSS). The class is used by the GMSS - * classes for calculation of upcoming leafs. - */ -public class GMSSLeaf -{ - - /** - * The hash function used by the OTS and the PRNG - */ - private Digest messDigestOTS; - - /** - * The length of the message digest and private key - */ - private int mdsize, keysize; - - /** - * The source of randomness for OTS private key generation - */ - private GMSSRandom gmssRandom; - - /** - * Byte array for distributed computation of the upcoming leaf - */ - private byte[] leaf; - - /** - * Byte array for storing the concatenated hashes of private key parts - */ - private byte[] concHashs; - - /** - * indices for distributed computation - */ - private int i, j; - - /** - * storing 2^w - */ - private int two_power_w; - - /** - * Winternitz parameter w - */ - private int w; - - /** - * the amount of distributed computation steps when updateLeaf is called - */ - private int steps; - - /** - * the internal seed - */ - private byte[] seed; - - /** - * the OTS privateKey parts - */ - byte[] privateKeyOTS; - - /** - * This constructor regenerates a prior GMSSLeaf object - * - * @param digest an array of strings, containing the name of the used hash - * function and PRNG and the name of the corresponding - * provider - * @param otsIndex status bytes - * @param numLeafs status ints - */ - public GMSSLeaf(Digest digest, byte[][] otsIndex, int[] numLeafs) - { - this.i = numLeafs[0]; - this.j = numLeafs[1]; - this.steps = numLeafs[2]; - this.w = numLeafs[3]; - - messDigestOTS = digest; - - gmssRandom = new GMSSRandom(messDigestOTS); - - // calulate keysize for private key and the help array - mdsize = messDigestOTS.getDigestSize(); - int mdsizeBit = mdsize << 3; - int messagesize = (int)Math.ceil((double)(mdsizeBit) / (double)w); - int checksumsize = getLog((messagesize << w) + 1); - this.keysize = messagesize - + (int)Math.ceil((double)checksumsize / (double)w); - this.two_power_w = 1 << w; - - // calculate steps - // ((2^w)-1)*keysize + keysize + 1 / (2^h -1) - - // initialize arrays - this.privateKeyOTS = otsIndex[0]; - this.seed = otsIndex[1]; - this.concHashs = otsIndex[2]; - this.leaf = otsIndex[3]; - } - - /** - * The constructor precomputes some needed variables for distributed leaf - * calculation - * - * @param digest an array of strings, containing the digest of the used hash - * function and PRNG and the digest of the corresponding - * provider - * @param w the winterniz parameter of that tree the leaf is computed - * for - * @param numLeafs the number of leafs of the tree from where the distributed - * computation is called - */ - GMSSLeaf(Digest digest, int w, int numLeafs) - { - this.w = w; - - messDigestOTS = digest; - - gmssRandom = new GMSSRandom(messDigestOTS); - - // calulate keysize for private key and the help array - mdsize = messDigestOTS.getDigestSize(); - int mdsizeBit = mdsize << 3; - int messagesize = (int)Math.ceil((double)(mdsizeBit) / (double)w); - int checksumsize = getLog((messagesize << w) + 1); - this.keysize = messagesize - + (int)Math.ceil((double)checksumsize / (double)w); - this.two_power_w = 1 << w; - - // calculate steps - // ((2^w)-1)*keysize + keysize + 1 / (2^h -1) - this.steps = (int)Math - .ceil((double)(((1 << w) - 1) * keysize + 1 + keysize) - / (double)(numLeafs)); - - // initialize arrays - this.seed = new byte[mdsize]; - this.leaf = new byte[mdsize]; - this.privateKeyOTS = new byte[mdsize]; - this.concHashs = new byte[mdsize * keysize]; - } - - public GMSSLeaf(Digest digest, int w, int numLeafs, byte[] seed0) - { - this.w = w; - - messDigestOTS = digest; - - gmssRandom = new GMSSRandom(messDigestOTS); - - // calulate keysize for private key and the help array - mdsize = messDigestOTS.getDigestSize(); - int mdsizeBit = mdsize << 3; - int messagesize = (int)Math.ceil((double)(mdsizeBit) / (double)w); - int checksumsize = getLog((messagesize << w) + 1); - this.keysize = messagesize - + (int)Math.ceil((double)checksumsize / (double)w); - this.two_power_w = 1 << w; - - // calculate steps - // ((2^w)-1)*keysize + keysize + 1 / (2^h -1) - this.steps = (int)Math - .ceil((double)(((1 << w) - 1) * keysize + 1 + keysize) - / (double)(numLeafs)); - - // initialize arrays - this.seed = new byte[mdsize]; - this.leaf = new byte[mdsize]; - this.privateKeyOTS = new byte[mdsize]; - this.concHashs = new byte[mdsize * keysize]; - - initLeafCalc(seed0); - } - - private GMSSLeaf(GMSSLeaf original) - { - this.messDigestOTS = original.messDigestOTS; - this.mdsize = original.mdsize; - this.keysize = original.keysize; - this.gmssRandom = original.gmssRandom; - this.leaf = Arrays.clone(original.leaf); - this.concHashs = Arrays.clone(original.concHashs); - this.i = original.i; - this.j = original.j; - this.two_power_w = original.two_power_w; - this.w = original.w; - this.steps = original.steps; - this.seed = Arrays.clone(original.seed); - this.privateKeyOTS = Arrays.clone(original.privateKeyOTS); - } - - /** - * initialize the distributed leaf calculation reset i,j and compute OTSseed - * with seed0 - * - * @param seed0 the starting seed - */ - // TODO: this really looks like it should be either always called from a constructor or nextLeaf. - void initLeafCalc(byte[] seed0) - { - this.i = 0; - this.j = 0; - byte[] dummy = new byte[mdsize]; - System.arraycopy(seed0, 0, dummy, 0, seed.length); - this.seed = gmssRandom.nextSeed(dummy); - } - - GMSSLeaf nextLeaf() - { - GMSSLeaf nextLeaf = new GMSSLeaf(this); - - nextLeaf.updateLeafCalc(); - - return nextLeaf; - } - - /** - * Processes <code>steps</code> steps of distributed leaf calculation - * - * @return true if leaf is completed, else false - */ - private void updateLeafCalc() - { - byte[] buf = new byte[messDigestOTS.getDigestSize()]; - - // steps times do - // TODO: this really needs to be looked at, the 10000 has been added as - // prior to this the leaf value always ended up as zeros. - for (int s = 0; s < steps + 10000; s++) - { - if (i == keysize && j == two_power_w - 1) - { // [3] at last hash the - // concatenation - messDigestOTS.update(concHashs, 0, concHashs.length); - leaf = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(leaf, 0); - return; - } - else if (i == 0 || j == two_power_w - 1) - { // [1] at the - // beginning and - // when [2] is - // finished: get the - // next private key - // part - i++; - j = 0; - // get next privKey part - this.privateKeyOTS = gmssRandom.nextSeed(seed); - } - else - { // [2] hash the privKey part - messDigestOTS.update(privateKeyOTS, 0, privateKeyOTS.length); - privateKeyOTS = buf; - messDigestOTS.doFinal(privateKeyOTS, 0); - j++; - if (j == two_power_w - 1) - { // after w hashes add to the - // concatenated array - System.arraycopy(privateKeyOTS, 0, concHashs, mdsize - * (i - 1), mdsize); - } - } - } - - throw new IllegalStateException("unable to updateLeaf in steps: " + steps + " " + i + " " + j); - } - - /** - * Returns the leaf value. - * - * @return the leaf value - */ - public byte[] getLeaf() - { - return Arrays.clone(leaf); - } - - /** - * This method returns the least integer that is greater or equal to the - * logarithm to the base 2 of an integer <code>intValue</code>. - * - * @param intValue an integer - * @return The least integer greater or equal to the logarithm to the base 2 - * of <code>intValue</code> - */ - private int getLog(int intValue) - { - int log = 1; - int i = 2; - while (i < intValue) - { - i <<= 1; - log++; - } - return log; - } - - /** - * Returns the status byte array used by the GMSSPrivateKeyASN.1 class - * - * @return The status bytes - */ - public byte[][] getStatByte() - { - - byte[][] statByte = new byte[4][]; - statByte[0] = new byte[mdsize]; - statByte[1] = new byte[mdsize]; - statByte[2] = new byte[mdsize * keysize]; - statByte[3] = new byte[mdsize]; - statByte[0] = privateKeyOTS; - statByte[1] = seed; - statByte[2] = concHashs; - statByte[3] = leaf; - - return statByte; - } - - /** - * Returns the status int array used by the GMSSPrivateKeyASN.1 class - * - * @return The status ints - */ - public int[] getStatInt() - { - - int[] statInt = new int[4]; - statInt[0] = i; - statInt[1] = j; - statInt[2] = steps; - statInt[3] = w; - return statInt; - } - - /** - * Returns a String representation of the main part of this element - * - * @return a String representation of the main part of this element - */ - public String toString() - { - String out = ""; - - for (int i = 0; i < 4; i++) - { - out = out + this.getStatInt()[i] + " "; - } - out = out + " " + this.mdsize + " " + this.keysize + " " - + this.two_power_w + " "; - - byte[][] temp = this.getStatByte(); - for (int i = 0; i < 4; i++) - { - if (temp[i] != null) - { - out = out + new String(Hex.encode(temp[i])) + " "; - } - else - { - out = out + "null "; - } - } - return out; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSParameters.java deleted file mode 100644 index aa89f76a..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSParameters.java +++ /dev/null @@ -1,155 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss; - -import org.bouncycastle.util.Arrays; - -/** - * This class provides a specification for the GMSS parameters that are used by - * the GMSSKeyPairGenerator and GMSSSignature classes. - * - * @see org.bouncycastle.pqc.crypto.gmss.GMSSKeyPairGenerator - */ -public class GMSSParameters -{ - /** - * The number of authentication tree layers. - */ - private int numOfLayers; - - /** - * The height of the authentication trees of each layer. - */ - private int[] heightOfTrees; - - /** - * The Winternitz Parameter 'w' of each layer. - */ - private int[] winternitzParameter; - - /** - * The parameter K needed for the authentication path computation - */ - private int[] K; - - /** - * The constructor for the parameters of the GMSSKeyPairGenerator. - * - * @param layers the number of authentication tree layers - * @param heightOfTrees the height of the authentication trees - * @param winternitzParameter the Winternitz Parameter 'w' of each layer - * @param K parameter for authpath computation - */ - public GMSSParameters(int layers, int[] heightOfTrees, int[] winternitzParameter, int[] K) - throws IllegalArgumentException - { - init(layers, heightOfTrees, winternitzParameter, K); - } - - private void init(int layers, int[] heightOfTrees, - int[] winternitzParameter, int[] K) - throws IllegalArgumentException - { - boolean valid = true; - String errMsg = ""; - this.numOfLayers = layers; - if ((numOfLayers != winternitzParameter.length) - || (numOfLayers != heightOfTrees.length) - || (numOfLayers != K.length)) - { - valid = false; - errMsg = "Unexpected parameterset format"; - } - for (int i = 0; i < numOfLayers; i++) - { - if ((K[i] < 2) || ((heightOfTrees[i] - K[i]) % 2 != 0)) - { - valid = false; - errMsg = "Wrong parameter K (K >= 2 and H-K even required)!"; - } - - if ((heightOfTrees[i] < 4) || (winternitzParameter[i] < 2)) - { - valid = false; - errMsg = "Wrong parameter H or w (H > 3 and w > 1 required)!"; - } - } - - if (valid) - { - this.heightOfTrees = Arrays.clone(heightOfTrees); - this.winternitzParameter = Arrays.clone(winternitzParameter); - this.K = Arrays.clone(K); - } - else - { - throw new IllegalArgumentException(errMsg); - } - } - - public GMSSParameters(int keySize) - throws IllegalArgumentException - { - if (keySize <= 10) - { // create 2^10 keys - int[] defh = {10}; - int[] defw = {3}; - int[] defk = {2}; - this.init(defh.length, defh, defw, defk); - } - else if (keySize <= 20) - { // create 2^20 keys - int[] defh = {10, 10}; - int[] defw = {5, 4}; - int[] defk = {2, 2}; - this.init(defh.length, defh, defw, defk); - } - else - { // create 2^40 keys, keygen lasts around 80 seconds - int[] defh = {10, 10, 10, 10}; - int[] defw = {9, 9, 9, 3}; - int[] defk = {2, 2, 2, 2}; - this.init(defh.length, defh, defw, defk); - } - } - - /** - * Returns the number of levels of the authentication trees. - * - * @return The number of levels of the authentication trees. - */ - public int getNumOfLayers() - { - return numOfLayers; - } - - /** - * Returns the array of height (for each layer) of the authentication trees - * - * @return The array of height (for each layer) of the authentication trees - */ - public int[] getHeightOfTrees() - { - return Arrays.clone(heightOfTrees); - } - - /** - * Returns the array of WinternitzParameter (for each layer) of the - * authentication trees - * - * @return The array of WinternitzParameter (for each layer) of the - * authentication trees - */ - public int[] getWinternitzParameter() - { - return Arrays.clone(winternitzParameter); - } - - /** - * Returns the parameter K needed for authentication path computation - * - * @return The parameter K needed for authentication path computation - */ - public int[] getK() - { - return Arrays.clone(K); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSPrivateKeyParameters.java deleted file mode 100644 index 83cf7972..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSPrivateKeyParameters.java +++ /dev/null @@ -1,1041 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss; - -import java.util.Vector; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.pqc.crypto.gmss.util.GMSSRandom; -import org.bouncycastle.pqc.crypto.gmss.util.WinternitzOTSignature; -import org.bouncycastle.util.Arrays; - - -/** - * This class provides a specification for a GMSS private key. - */ -public class GMSSPrivateKeyParameters - extends GMSSKeyParameters -{ - private int[] index; - - private byte[][] currentSeeds; - private byte[][] nextNextSeeds; - - private byte[][][] currentAuthPaths; - private byte[][][] nextAuthPaths; - - private Treehash[][] currentTreehash; - private Treehash[][] nextTreehash; - - private Vector[] currentStack; - private Vector[] nextStack; - - private Vector[][] currentRetain; - private Vector[][] nextRetain; - - private byte[][][] keep; - - private GMSSLeaf[] nextNextLeaf; - private GMSSLeaf[] upperLeaf; - private GMSSLeaf[] upperTreehashLeaf; - - private int[] minTreehash; - - private GMSSParameters gmssPS; - - private byte[][] nextRoot; - private GMSSRootCalc[] nextNextRoot; - - private byte[][] currentRootSig; - private GMSSRootSig[] nextRootSig; - - private GMSSDigestProvider digestProvider; - - private boolean used = false; - - /** - * An array of the heights of the authentication trees of each layer - */ - private int[] heightOfTrees; - - /** - * An array of the Winternitz parameter 'w' of each layer - */ - private int[] otsIndex; - - /** - * The parameter K needed for the authentication path computation - */ - private int[] K; - - /** - * the number of Layers - */ - private int numLayer; - - /** - * The hash function used to construct the authentication trees - */ - private Digest messDigestTrees; - - /** - * The message digest length - */ - private int mdLength; - - /** - * The PRNG used for private key generation - */ - private GMSSRandom gmssRandom; - - - /** - * The number of leafs of one tree of each layer - */ - private int[] numLeafs; - - - /** - * Generates a new GMSS private key - * - * @param currentSeed seed for the generation of private OTS keys for the - * current subtrees - * @param nextNextSeed seed for the generation of private OTS keys for the next - * subtrees - * @param currentAuthPath array of current authentication paths - * @param nextAuthPath array of next authentication paths - * @param currentTreehash array of current treehash instances - * @param nextTreehash array of next treehash instances - * @param currentStack array of current shared stacks - * @param nextStack array of next shared stacks - * @param currentRetain array of current retain stacks - * @param nextRetain array of next retain stacks - * @param nextRoot the roots of the next subtree - * @param currentRootSig array of signatures of the roots of the current subtrees - * @param gmssParameterset the GMSS Parameterset - * @see org.bouncycastle.pqc.crypto.gmss.GMSSKeyPairGenerator - */ - - public GMSSPrivateKeyParameters(byte[][] currentSeed, byte[][] nextNextSeed, - byte[][][] currentAuthPath, byte[][][] nextAuthPath, - Treehash[][] currentTreehash, Treehash[][] nextTreehash, - Vector[] currentStack, Vector[] nextStack, - Vector[][] currentRetain, Vector[][] nextRetain, byte[][] nextRoot, - byte[][] currentRootSig, GMSSParameters gmssParameterset, - GMSSDigestProvider digestProvider) - { - this(null, currentSeed, nextNextSeed, currentAuthPath, nextAuthPath, - null, currentTreehash, nextTreehash, currentStack, nextStack, - currentRetain, nextRetain, null, null, null, null, nextRoot, - null, currentRootSig, null, gmssParameterset, digestProvider); - } - - /** - * /** - * - * @param index tree indices - * @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 - */ - public GMSSPrivateKeyParameters(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, - GMSSDigestProvider digestProvider) - { - - super(true, gmssParameterset); - - // construct message digest - - this.messDigestTrees = digestProvider.get(); - this.mdLength = messDigestTrees.getDigestSize(); - - - // Parameter - this.gmssPS = gmssParameterset; - this.otsIndex = gmssParameterset.getWinternitzParameter(); - this.K = gmssParameterset.getK(); - this.heightOfTrees = gmssParameterset.getHeightOfTrees(); - // initialize numLayer - this.numLayer = gmssPS.getNumOfLayers(); - - // initialize index if null - if (index == null) - { - this.index = new int[numLayer]; - for (int i = 0; i < numLayer; i++) - { - this.index[i] = 0; - } - } - else - { - this.index = index; - } - - this.currentSeeds = currentSeeds; - this.nextNextSeeds = nextNextSeeds; - - this.currentAuthPaths = currentAuthPaths; - this.nextAuthPaths = nextAuthPaths; - - // initialize keep if null - if (keep == null) - { - this.keep = new byte[numLayer][][]; - for (int i = 0; i < numLayer; i++) - { - this.keep[i] = new byte[(int)Math.floor(heightOfTrees[i] / 2)][mdLength]; - } - } - else - { - this.keep = keep; - } - - // initialize stack if null - if (currentStack == null) - { - this.currentStack = new Vector[numLayer]; - for (int i = 0; i < numLayer; i++) - { - this.currentStack[i] = new Vector(); - } - } - else - { - this.currentStack = currentStack; - } - - // initialize nextStack if null - if (nextStack == null) - { - this.nextStack = new Vector[numLayer - 1]; - for (int i = 0; i < numLayer - 1; i++) - { - this.nextStack[i] = new Vector(); - } - } - else - { - this.nextStack = nextStack; - } - - this.currentTreehash = currentTreehash; - this.nextTreehash = nextTreehash; - - this.currentRetain = currentRetain; - this.nextRetain = nextRetain; - - this.nextRoot = nextRoot; - - this.digestProvider = digestProvider; - - if (nextNextRoot == null) - { - this.nextNextRoot = new GMSSRootCalc[numLayer - 1]; - for (int i = 0; i < numLayer - 1; i++) - { - this.nextNextRoot[i] = new GMSSRootCalc( - this.heightOfTrees[i + 1], this.K[i + 1], this.digestProvider); - } - } - else - { - this.nextNextRoot = nextNextRoot; - } - this.currentRootSig = currentRootSig; - - // calculate numLeafs - numLeafs = new int[numLayer]; - for (int i = 0; i < numLayer; i++) - { - numLeafs[i] = 1 << heightOfTrees[i]; - } - // construct PRNG - this.gmssRandom = new GMSSRandom(messDigestTrees); - - if (numLayer > 1) - { - // construct the nextNextLeaf (LEAFs++) array for upcoming leafs in - // tree after next (TREE++) - if (nextNextLeaf == null) - { - this.nextNextLeaf = new GMSSLeaf[numLayer - 2]; - for (int i = 0; i < numLayer - 2; i++) - { - this.nextNextLeaf[i] = new GMSSLeaf(digestProvider.get(), otsIndex[i + 1], numLeafs[i + 2], this.nextNextSeeds[i]); - } - } - else - { - this.nextNextLeaf = nextNextLeaf; - } - } - else - { - this.nextNextLeaf = new GMSSLeaf[0]; - } - - // construct the upperLeaf array for upcoming leafs in tree over the - // actual - if (upperLeaf == null) - { - this.upperLeaf = new GMSSLeaf[numLayer - 1]; - for (int i = 0; i < numLayer - 1; i++) - { - this.upperLeaf[i] = new GMSSLeaf(digestProvider.get(), otsIndex[i], - numLeafs[i + 1], this.currentSeeds[i]); - } - } - else - { - this.upperLeaf = upperLeaf; - } - - // construct the leafs for upcoming leafs in treehashs in tree over the - // actual - if (upperTreehashLeaf == null) - { - this.upperTreehashLeaf = new GMSSLeaf[numLayer - 1]; - for (int i = 0; i < numLayer - 1; i++) - { - this.upperTreehashLeaf[i] = new GMSSLeaf(digestProvider.get(), otsIndex[i], numLeafs[i + 1]); - } - } - else - { - this.upperTreehashLeaf = upperTreehashLeaf; - } - - if (minTreehash == null) - { - this.minTreehash = new int[numLayer - 1]; - for (int i = 0; i < numLayer - 1; i++) - { - this.minTreehash[i] = -1; - } - } - else - { - this.minTreehash = minTreehash; - } - - // construct the nextRootSig (RootSig++) - byte[] dummy = new byte[mdLength]; - byte[] OTSseed = new byte[mdLength]; - if (nextRootSig == null) - { - this.nextRootSig = new GMSSRootSig[numLayer - 1]; - for (int i = 0; i < numLayer - 1; i++) - { - System.arraycopy(currentSeeds[i], 0, dummy, 0, mdLength); - gmssRandom.nextSeed(dummy); - OTSseed = gmssRandom.nextSeed(dummy); - this.nextRootSig[i] = new GMSSRootSig(digestProvider.get(), otsIndex[i], - heightOfTrees[i + 1]); - this.nextRootSig[i].initSign(OTSseed, nextRoot[i]); - } - } - else - { - this.nextRootSig = nextRootSig; - } - } - - // we assume this only gets called from nextKey so used is never copied. - private GMSSPrivateKeyParameters(GMSSPrivateKeyParameters original) - { - super(true, original.getParameters()); - - this.index = Arrays.clone(original.index); - this.currentSeeds = Arrays.clone(original.currentSeeds); - this.nextNextSeeds = Arrays.clone(original.nextNextSeeds); - this.currentAuthPaths = Arrays.clone(original.currentAuthPaths); - this.nextAuthPaths = Arrays.clone(original.nextAuthPaths); - this.currentTreehash = original.currentTreehash; - this.nextTreehash = original.nextTreehash; - this.currentStack = original.currentStack; - this.nextStack = original.nextStack; - this.currentRetain = original.currentRetain; - this.nextRetain = original.nextRetain; - this.keep = Arrays.clone(original.keep); - this.nextNextLeaf = original.nextNextLeaf; - this.upperLeaf = original.upperLeaf; - this.upperTreehashLeaf = original.upperTreehashLeaf; - this.minTreehash = original.minTreehash; - this.gmssPS = original.gmssPS; - this.nextRoot = Arrays.clone(original.nextRoot); - this.nextNextRoot = original.nextNextRoot; - this.currentRootSig = original.currentRootSig; - this.nextRootSig = original.nextRootSig; - this.digestProvider = original.digestProvider; - this.heightOfTrees = original.heightOfTrees; - this.otsIndex = original.otsIndex; - this.K = original.K; - this.numLayer = original.numLayer; - this.messDigestTrees = original.messDigestTrees; - this.mdLength = original.mdLength; - this.gmssRandom = original.gmssRandom; - this.numLeafs = original.numLeafs; - } - - public boolean isUsed() - { - return this.used; - } - - public void markUsed() - { - this.used = true; - } - - public GMSSPrivateKeyParameters nextKey() - { - GMSSPrivateKeyParameters nKey = new GMSSPrivateKeyParameters(this); - - nKey.nextKey(gmssPS.getNumOfLayers() - 1); - - return nKey; - } - - /** - * This method updates the GMSS private key for the next signature - * - * @param layer the layer where the next key is processed - */ - private void nextKey(int layer) - { - // only for lowest layer ( other layers indices are raised in nextTree() - // method ) - if (layer == numLayer - 1) - { - index[layer]++; - } // else System.out.println(" --- nextKey on layer " + layer + " - // index is now : " + index[layer]); - - // if tree of this layer is depleted - if (index[layer] == numLeafs[layer]) - { - if (numLayer != 1) - { - nextTree(layer); - index[layer] = 0; - } - } - else - { - updateKey(layer); - } - } - - /** - * Switch to next subtree if the current one is depleted - * - * @param layer the layer where the next tree is processed - */ - private void nextTree(int layer) - { - // System.out.println("NextTree method called on layer " + layer); - // dont create next tree for the top layer - if (layer > 0) - { - // raise index for upper layer - index[layer - 1]++; - - // test if it is already the last tree - boolean lastTree = true; - int z = layer; - do - { - z--; - if (index[z] < numLeafs[z]) - { - lastTree = false; - } - } - while (lastTree && (z > 0)); - - // only construct next subtree if last one is not already in use - if (!lastTree) - { - gmssRandom.nextSeed(currentSeeds[layer]); - - // last step of distributed signature calculation - nextRootSig[layer - 1].updateSign(); - - // last step of distributed leaf calculation for nextNextLeaf - if (layer > 1) - { - nextNextLeaf[layer - 1 - 1] = nextNextLeaf[layer - 1 - 1].nextLeaf(); - } - - // last step of distributed leaf calculation for upper leaf - upperLeaf[layer - 1] = upperLeaf[layer - 1].nextLeaf(); - - // last step of distributed leaf calculation for all treehashs - - if (minTreehash[layer - 1] >= 0) - { - upperTreehashLeaf[layer - 1] = upperTreehashLeaf[layer - 1].nextLeaf(); - byte[] leaf = this.upperTreehashLeaf[layer - 1].getLeaf(); - // if update is required use the precomputed leaf to update - // treehash - try - { - currentTreehash[layer - 1][minTreehash[layer - 1]] - .update(this.gmssRandom, leaf); - // System.out.println("UUUpdated TH " + - // minTreehash[layer - 1]); - if (currentTreehash[layer - 1][minTreehash[layer - 1]] - .wasFinished()) - { - // System.out.println("FFFinished TH " + - // minTreehash[layer - 1]); - } - } - catch (Exception e) - { - System.out.println(e); - } - } - - // last step of nextNextAuthRoot calculation - this.updateNextNextAuthRoot(layer); - - // ******************************************************** / - - // NOW: advance to next tree on layer 'layer' - - // NextRootSig --> currentRootSigs - this.currentRootSig[layer - 1] = nextRootSig[layer - 1] - .getSig(); - - // ----------------------- - - // nextTreehash --> currentTreehash - // nextNextTreehash --> nextTreehash - for (int i = 0; i < heightOfTrees[layer] - K[layer]; i++) - { - this.currentTreehash[layer][i] = this.nextTreehash[layer - 1][i]; - this.nextTreehash[layer - 1][i] = this.nextNextRoot[layer - 1] - .getTreehash()[i]; - } - - // NextAuthPath --> currentAuthPath - // nextNextAuthPath --> nextAuthPath - for (int i = 0; i < heightOfTrees[layer]; i++) - { - System.arraycopy(nextAuthPaths[layer - 1][i], 0, - currentAuthPaths[layer][i], 0, mdLength); - System.arraycopy(nextNextRoot[layer - 1].getAuthPath()[i], - 0, nextAuthPaths[layer - 1][i], 0, mdLength); - } - - // nextRetain --> currentRetain - // nextNextRetain --> nextRetain - for (int i = 0; i < K[layer] - 1; i++) - { - this.currentRetain[layer][i] = this.nextRetain[layer - 1][i]; - this.nextRetain[layer - 1][i] = this.nextNextRoot[layer - 1] - .getRetain()[i]; - } - - // nextStack --> currentStack - this.currentStack[layer] = this.nextStack[layer - 1]; - // nextNextStack --> nextStack - this.nextStack[layer - 1] = this.nextNextRoot[layer - 1] - .getStack(); - - // nextNextRoot --> nextRoot - this.nextRoot[layer - 1] = this.nextNextRoot[layer - 1] - .getRoot(); - // ----------------------- - - // ----------------- - byte[] OTSseed = new byte[mdLength]; - byte[] dummy = new byte[mdLength]; - // gmssRandom.setSeed(currentSeeds[layer]); - System - .arraycopy(currentSeeds[layer - 1], 0, dummy, 0, - mdLength); - OTSseed = gmssRandom.nextSeed(dummy); // only need OTSSeed - OTSseed = gmssRandom.nextSeed(dummy); - OTSseed = gmssRandom.nextSeed(dummy); - // nextWinSig[layer-1]=new - // GMSSWinSig(OTSseed,algNames,otsIndex[layer-1],heightOfTrees[layer],nextRoot[layer-1]); - nextRootSig[layer - 1].initSign(OTSseed, nextRoot[layer - 1]); - - // nextKey for upper layer - nextKey(layer - 1); - } - } - } - - /** - * This method computes the authpath (AUTH) for the current tree, - * Additionally the root signature for the next tree (SIG+), the authpath - * (AUTH++) and root (ROOT++) for the tree after next in layer - * <code>layer</code>, and the LEAF++^1 for the next next tree in the - * layer above are updated This method is used by nextKey() - * - * @param layer - */ - private void updateKey(int layer) - { - // ----------current tree processing of actual layer--------- - // compute upcoming authpath for current Tree (AUTH) - computeAuthPaths(layer); - - // -----------distributed calculations part------------ - // not for highest tree layer - if (layer > 0) - { - - // compute (partial) next leaf on TREE++ (not on layer 1 and 0) - if (layer > 1) - { - nextNextLeaf[layer - 1 - 1] = nextNextLeaf[layer - 1 - 1].nextLeaf(); - } - - // compute (partial) next leaf on tree above (not on layer 0) - upperLeaf[layer - 1] = upperLeaf[layer - 1].nextLeaf(); - - // compute (partial) next leaf for all treehashs on tree above (not - // on layer 0) - - int t = (int)Math - .floor((double)(this.getNumLeafs(layer) * 2) - / (double)(this.heightOfTrees[layer - 1] - this.K[layer - 1])); - - if (index[layer] % t == 1) - { - // System.out.println(" layer: " + layer + " index: " + - // index[layer] + " t : " + t); - - // take precomputed node for treehash update - // ------------------------------------------------ - if (index[layer] > 1 && minTreehash[layer - 1] >= 0) - { - byte[] leaf = this.upperTreehashLeaf[layer - 1].getLeaf(); - // if update is required use the precomputed leaf to update - // treehash - try - { - currentTreehash[layer - 1][minTreehash[layer - 1]] - .update(this.gmssRandom, leaf); - // System.out.println("Updated TH " + minTreehash[layer - // - 1]); - if (currentTreehash[layer - 1][minTreehash[layer - 1]] - .wasFinished()) - { - // System.out.println("Finished TH " + - // minTreehash[layer - 1]); - } - } - catch (Exception e) - { - System.out.println(e); - } - // ------------------------------------------------ - } - - // initialize next leaf precomputation - // ------------------------------------------------ - - // get lowest index of treehashs - this.minTreehash[layer - 1] = getMinTreehashIndex(layer - 1); - - if (this.minTreehash[layer - 1] >= 0) - { - // initialize leaf - byte[] seed = this.currentTreehash[layer - 1][this.minTreehash[layer - 1]] - .getSeedActive(); - this.upperTreehashLeaf[layer - 1] = new GMSSLeaf( - this.digestProvider.get(), this.otsIndex[layer - 1], t, seed); - this.upperTreehashLeaf[layer - 1] = this.upperTreehashLeaf[layer - 1].nextLeaf(); - // System.out.println("restarted treehashleaf (" + (layer - - // 1) + "," + this.minTreehash[layer - 1] + ")"); - } - // ------------------------------------------------ - - } - else - { - // update the upper leaf for the treehash one step - if (this.minTreehash[layer - 1] >= 0) - { - this.upperTreehashLeaf[layer - 1] = this.upperTreehashLeaf[layer - 1].nextLeaf(); - // if (minTreehash[layer - 1] > 3) - // System.out.print("#"); - } - } - - // compute (partial) the signature of ROOT+ (RootSig+) (not on top - // layer) - nextRootSig[layer - 1].updateSign(); - - // compute (partial) AUTHPATH++ & ROOT++ (not on top layer) - if (index[layer] == 1) - { - // init root and authpath calculation for tree after next - // (AUTH++, ROOT++) - this.nextNextRoot[layer - 1].initialize(new Vector()); - } - - // update root and authpath calculation for tree after next (AUTH++, - // ROOT++) - this.updateNextNextAuthRoot(layer); - } - // ----------- end distributed calculations part----------------- - } - - /** - * This method returns the index of the next Treehash instance that should - * receive an update - * - * @param layer the layer of the GMSS tree - * @return index of the treehash instance that should get the update - */ - private int getMinTreehashIndex(int layer) - { - int minTreehash = -1; - for (int h = 0; h < heightOfTrees[layer] - K[layer]; h++) - { - if (currentTreehash[layer][h].wasInitialized() - && !currentTreehash[layer][h].wasFinished()) - { - if (minTreehash == -1) - { - minTreehash = h; - } - else if (currentTreehash[layer][h].getLowestNodeHeight() < currentTreehash[layer][minTreehash] - .getLowestNodeHeight()) - { - minTreehash = h; - } - } - } - return minTreehash; - } - - /** - * Computes the upcoming currentAuthpath of layer <code>layer</code> using - * the revisited authentication path computation of Dahmen/Schneider 2008 - * - * @param layer the actual layer - */ - private void computeAuthPaths(int layer) - { - - int Phi = index[layer]; - int H = heightOfTrees[layer]; - int K = this.K[layer]; - - // update all nextSeeds for seed scheduling - for (int i = 0; i < H - K; i++) - { - currentTreehash[layer][i].updateNextSeed(gmssRandom); - } - - // STEP 1 of Algorithm - int Tau = heightOfPhi(Phi); - - byte[] OTSseed = new byte[mdLength]; - OTSseed = gmssRandom.nextSeed(currentSeeds[layer]); - - // STEP 2 of Algorithm - // if phi's parent on height tau + 1 if left node, store auth_tau - // in keep_tau. - // TODO check it, formerly was - // int L = Phi / (int) Math.floor(Math.pow(2, Tau + 1)); - // L %= 2; - int L = (Phi >>> (Tau + 1)) & 1; - - byte[] tempKeep = new byte[mdLength]; - // store the keep node not in keep[layer][tau/2] because it might be in - // use - // wait until the space is freed in step 4a - if (Tau < H - 1 && L == 0) - { - System.arraycopy(currentAuthPaths[layer][Tau], 0, tempKeep, 0, - mdLength); - } - - byte[] help = new byte[mdLength]; - // STEP 3 of Algorithm - // if phi is left child, compute and store leaf for next currentAuthPath - // path, - // (obtained by veriying current signature) - if (Tau == 0) - { - // LEAFCALC !!! - if (layer == numLayer - 1) - { // lowest layer computes the - // necessary leaf completely at this - // time - WinternitzOTSignature ots = new WinternitzOTSignature(OTSseed, - digestProvider.get(), otsIndex[layer]); - help = ots.getPublicKey(); - } - else - { // other layers use the precomputed leafs in - // nextNextLeaf - byte[] dummy = new byte[mdLength]; - System.arraycopy(currentSeeds[layer], 0, dummy, 0, mdLength); - gmssRandom.nextSeed(dummy); - help = upperLeaf[layer].getLeaf(); - this.upperLeaf[layer].initLeafCalc(dummy); - - // WinternitzOTSVerify otsver = new - // WinternitzOTSVerify(algNames, otsIndex[layer]); - // byte[] help2 = otsver.Verify(currentRoot[layer], - // currentRootSig[layer]); - // System.out.println(" --- " + layer + " " + - // ByteUtils.toHexString(help) + " " + - // ByteUtils.toHexString(help2)); - } - System.arraycopy(help, 0, currentAuthPaths[layer][0], 0, mdLength); - } - else - { - // STEP 4a of Algorithm - // get new left currentAuthPath node on height tau - byte[] toBeHashed = new byte[mdLength << 1]; - System.arraycopy(currentAuthPaths[layer][Tau - 1], 0, toBeHashed, - 0, mdLength); - // free the shared keep[layer][tau/2] - System.arraycopy(keep[layer][(int)Math.floor((Tau - 1) / 2)], 0, - toBeHashed, mdLength, mdLength); - messDigestTrees.update(toBeHashed, 0, toBeHashed.length); - currentAuthPaths[layer][Tau] = new byte[messDigestTrees.getDigestSize()]; - messDigestTrees.doFinal(currentAuthPaths[layer][Tau], 0); - - // STEP 4b and 4c of Algorithm - // copy right nodes to currentAuthPath on height 0..Tau-1 - for (int i = 0; i < Tau; i++) - { - - // STEP 4b of Algorithm - // 1st: copy from treehashs - if (i < H - K) - { - if (currentTreehash[layer][i].wasFinished()) - { - System.arraycopy(currentTreehash[layer][i] - .getFirstNode(), 0, currentAuthPaths[layer][i], - 0, mdLength); - currentTreehash[layer][i].destroy(); - } - else - { - System.err - .println("Treehash (" - + layer - + "," - + i - + ") not finished when needed in AuthPathComputation"); - } - } - - // 2nd: copy precomputed values from Retain - if (i < H - 1 && i >= H - K) - { - if (currentRetain[layer][i - (H - K)].size() > 0) - { - // pop element from retain - System.arraycopy(currentRetain[layer][i - (H - K)] - .lastElement(), 0, currentAuthPaths[layer][i], - 0, mdLength); - currentRetain[layer][i - (H - K)] - .removeElementAt(currentRetain[layer][i - - (H - K)].size() - 1); - } - } - - // STEP 4c of Algorithm - // initialize new stack at heights 0..Tau-1 - if (i < H - K) - { - // create stacks anew - int startPoint = Phi + 3 * (1 << i); - if (startPoint < numLeafs[layer]) - { - // if (layer < 2) { - // System.out.println("initialized TH " + i + " on layer - // " + layer); - // } - currentTreehash[layer][i].initialize(); - } - } - } - } - - // now keep space is free to use - if (Tau < H - 1 && L == 0) - { - System.arraycopy(tempKeep, 0, - keep[layer][(int)Math.floor(Tau / 2)], 0, mdLength); - } - - // only update empty stack at height h if all other stacks have - // tailnodes with height >h - // finds active stack with lowest node height, choses lower index in - // case of tie - - // on the lowest layer leafs must be computed at once, no precomputation - // is possible. So all treehash updates are done at once here - if (layer == numLayer - 1) - { - for (int tmp = 1; tmp <= (H - K) / 2; tmp++) - { - // index of the treehash instance that receives the next update - int minTreehash = getMinTreehashIndex(layer); - - // if active treehash is found update with a leaf - if (minTreehash >= 0) - { - try - { - byte[] seed = new byte[mdLength]; - System.arraycopy( - this.currentTreehash[layer][minTreehash] - .getSeedActive(), 0, seed, 0, mdLength); - byte[] seed2 = gmssRandom.nextSeed(seed); - WinternitzOTSignature ots = new WinternitzOTSignature( - seed2, this.digestProvider.get(), this.otsIndex[layer]); - byte[] leaf = ots.getPublicKey(); - currentTreehash[layer][minTreehash].update( - this.gmssRandom, leaf); - } - catch (Exception e) - { - System.out.println(e); - } - } - } - } - else - { // on higher layers the updates are done later - this.minTreehash[layer] = getMinTreehashIndex(layer); - } - } - - /** - * Returns the largest h such that 2^h | Phi - * - * @param Phi the leaf index - * @return The largest <code>h</code> with <code>2^h | Phi</code> if - * <code>Phi!=0</code> else return <code>-1</code> - */ - private int heightOfPhi(int Phi) - { - if (Phi == 0) - { - return -1; - } - int Tau = 0; - int modul = 1; - while (Phi % modul == 0) - { - modul *= 2; - Tau += 1; - } - return Tau - 1; - } - - /** - * Updates the authentication path and root calculation for the tree after - * next (AUTH++, ROOT++) in layer <code>layer</code> - * - * @param layer - */ - private void updateNextNextAuthRoot(int layer) - { - - byte[] OTSseed = new byte[mdLength]; - OTSseed = gmssRandom.nextSeed(nextNextSeeds[layer - 1]); - - // get the necessary leaf - if (layer == numLayer - 1) - { // lowest layer computes the necessary - // leaf completely at this time - WinternitzOTSignature ots = new WinternitzOTSignature(OTSseed, - digestProvider.get(), otsIndex[layer]); - this.nextNextRoot[layer - 1].update(nextNextSeeds[layer - 1], ots - .getPublicKey()); - } - else - { // other layers use the precomputed leafs in nextNextLeaf - this.nextNextRoot[layer - 1].update(nextNextSeeds[layer - 1], nextNextLeaf[layer - 1].getLeaf()); - this.nextNextLeaf[layer - 1].initLeafCalc(nextNextSeeds[layer - 1]); - } - } - - public int[] getIndex() - { - return index; - } - - /** - * @return The current index of layer i - */ - public int getIndex(int i) - { - return index[i]; - } - - public byte[][] getCurrentSeeds() - { - return Arrays.clone(currentSeeds); - } - - public byte[][][] getCurrentAuthPaths() - { - return Arrays.clone(currentAuthPaths); - } - - /** - * @return The one-time signature of the root of the current subtree - */ - public byte[] getSubtreeRootSig(int i) - { - return currentRootSig[i]; - } - - - public GMSSDigestProvider getName() - { - return digestProvider; - } - - /** - * @return The number of leafs of each tree of layer i - */ - public int getNumLeafs(int i) - { - return numLeafs[i]; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSPublicKeyParameters.java deleted file mode 100644 index 492802d4..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSPublicKeyParameters.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss; - - -public class GMSSPublicKeyParameters - extends GMSSKeyParameters -{ - /** - * The GMSS public key - */ - private byte[] gmssPublicKey; - - /** - * The constructor. - * - * @param key a raw GMSS public key - * @param gmssParameterSet an instance of GMSSParameterset - */ - public GMSSPublicKeyParameters(byte[] key, GMSSParameters gmssParameterSet) - { - super(false, gmssParameterSet); - this.gmssPublicKey = key; - } - - /** - * Returns the GMSS public key - * - * @return The GMSS public key - */ - public byte[] getPublicKey() - { - return gmssPublicKey; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSRootCalc.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSRootCalc.java deleted file mode 100644 index 35ac2e32..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSRootCalc.java +++ /dev/null @@ -1,596 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss; - -import java.util.Enumeration; -import java.util.Vector; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Integers; -import org.bouncycastle.util.encoders.Hex; - - -/** - * This class computes a whole Merkle tree and saves the needed values for - * AuthPath computation. It is used for precomputation of the root of a - * following tree. After initialization, 2^H updates are required to complete - * the root. Every update requires one leaf value as parameter. While computing - * the root all initial values for the authentication path algorithm (treehash, - * auth, retain) are stored for later use. - */ -public class GMSSRootCalc -{ - - /** - * max height of the tree - */ - private int heightOfTree; - - /** - * length of the messageDigest - */ - private int mdLength; - - /** - * the treehash instances of the tree - */ - private Treehash[] treehash; - - /** - * stores the retain nodes for authPath computation - */ - private Vector[] retain; - - /** - * finally stores the root of the tree when finished - */ - private byte[] root; - - /** - * stores the authentication path y_1(i), i = 0..H-1 - */ - private byte[][] AuthPath; - - /** - * the value K for the authentication path computation - */ - private int K; - - /** - * Vector element that stores the nodes on the stack - */ - private Vector tailStack; - - /** - * stores the height of all nodes laying on the tailStack - */ - private Vector heightOfNodes; - /** - * The hash function used for the construction of the authentication trees - */ - private Digest messDigestTree; - - /** - * An array of strings containing the name of the hash function used to - * construct the authentication trees and used by the OTS. - */ - private GMSSDigestProvider digestProvider; - - /** - * stores the index of the current node on each height of the tree - */ - private int[] index; - - /** - * true if instance was already initialized, false otherwise - */ - private boolean isInitialized; - - /** - * true it instance was finished - */ - private boolean isFinished; - - /** - * Integer that stores the index of the next seed that has to be omitted to - * the treehashs - */ - private int indexForNextSeed; - - /** - * temporary integer that stores the height of the next treehash instance - * that gets initialized with a seed - */ - private int heightOfNextSeed; - - /** - * This constructor regenerates a prior treehash object - * - * @param digest an array of strings, containing the digest of the used hash - * function and PRNG and the digest of the corresponding - * provider - * @param statByte status bytes - * @param statInt status ints - */ - public GMSSRootCalc(Digest digest, byte[][] statByte, int[] statInt, - Treehash[] treeH, Vector[] ret) - { - this.messDigestTree = digestProvider.get(); - this.digestProvider = digestProvider; - // decode statInt - this.heightOfTree = statInt[0]; - this.mdLength = statInt[1]; - this.K = statInt[2]; - this.indexForNextSeed = statInt[3]; - this.heightOfNextSeed = statInt[4]; - if (statInt[5] == 1) - { - this.isFinished = true; - } - else - { - this.isFinished = false; - } - if (statInt[6] == 1) - { - this.isInitialized = true; - } - else - { - this.isInitialized = false; - } - - int tailLength = statInt[7]; - - this.index = new int[heightOfTree]; - for (int i = 0; i < heightOfTree; i++) - { - this.index[i] = statInt[8 + i]; - } - - this.heightOfNodes = new Vector(); - for (int i = 0; i < tailLength; i++) - { - this.heightOfNodes.addElement(Integers.valueOf(statInt[8 + heightOfTree - + i])); - } - - // decode statByte - this.root = statByte[0]; - - this.AuthPath = new byte[heightOfTree][mdLength]; - for (int i = 0; i < heightOfTree; i++) - { - this.AuthPath[i] = statByte[1 + i]; - } - - this.tailStack = new Vector(); - for (int i = 0; i < tailLength; i++) - { - this.tailStack.addElement(statByte[1 + heightOfTree + i]); - } - - // decode treeH - this.treehash = GMSSUtils.clone(treeH); - - // decode ret - this.retain = GMSSUtils.clone(ret); - } - - /** - * Constructor - * - * @param heightOfTree maximal height of the tree - * @param digestProvider an array of strings, containing the name of the used hash - * function and PRNG and the name of the corresponding - * provider - */ - public GMSSRootCalc(int heightOfTree, int K, GMSSDigestProvider digestProvider) - { - this.heightOfTree = heightOfTree; - this.digestProvider = digestProvider; - this.messDigestTree = digestProvider.get(); - this.mdLength = messDigestTree.getDigestSize(); - this.K = K; - this.index = new int[heightOfTree]; - this.AuthPath = new byte[heightOfTree][mdLength]; - this.root = new byte[mdLength]; - // this.treehash = new Treehash[this.heightOfTree - this.K]; - this.retain = new Vector[this.K - 1]; - for (int i = 0; i < K - 1; i++) - { - this.retain[i] = new Vector(); - } - - } - - /** - * Initializes the calculation of a new root - * - * @param sharedStack the stack shared by all treehash instances of this tree - */ - public void initialize(Vector sharedStack) - { - this.treehash = new Treehash[this.heightOfTree - this.K]; - for (int i = 0; i < this.heightOfTree - this.K; i++) - { - this.treehash[i] = new Treehash(sharedStack, i, this.digestProvider.get()); - } - - this.index = new int[heightOfTree]; - this.AuthPath = new byte[heightOfTree][mdLength]; - this.root = new byte[mdLength]; - - this.tailStack = new Vector(); - this.heightOfNodes = new Vector(); - this.isInitialized = true; - this.isFinished = false; - - for (int i = 0; i < heightOfTree; i++) - { - this.index[i] = -1; - } - - this.retain = new Vector[this.K - 1]; - for (int i = 0; i < K - 1; i++) - { - this.retain[i] = new Vector(); - } - - this.indexForNextSeed = 3; - this.heightOfNextSeed = 0; - } - - /** - * updates the root with one leaf and stores needed values in retain, - * treehash or authpath. Additionally counts the seeds used. This method is - * used when performing the updates for TREE++. - * - * @param seed the initial seed for treehash: seedNext - * @param leaf the height of the treehash - */ - public void update(byte[] seed, byte[] leaf) - { - if (this.heightOfNextSeed < (this.heightOfTree - this.K) - && this.indexForNextSeed - 2 == index[0]) - { - this.initializeTreehashSeed(seed, this.heightOfNextSeed); - this.heightOfNextSeed++; - this.indexForNextSeed *= 2; - } - // now call the simple update - this.update(leaf); - } - - /** - * Updates the root with one leaf and stores the needed values in retain, - * treehash or authpath - */ - public void update(byte[] leaf) - { - - if (isFinished) - { - System.out.print("Too much updates for Tree!!"); - return; - } - if (!isInitialized) - { - System.err.println("GMSSRootCalc not initialized!"); - return; - } - - // a new leaf was omitted, so raise index on lowest layer - index[0]++; - - // store the nodes on the lowest layer in treehash or authpath - if (index[0] == 1) - { - System.arraycopy(leaf, 0, AuthPath[0], 0, mdLength); - } - else if (index[0] == 3) - { - // store in treehash only if K < H - if (heightOfTree > K) - { - treehash[0].setFirstNode(leaf); - } - } - - if ((index[0] - 3) % 2 == 0 && index[0] >= 3) - { - // store in retain if K = H - if (heightOfTree == K) - // TODO: check it - { - retain[0].insertElementAt(leaf, 0); - } - } - - // if first update to this tree is made - if (index[0] == 0) - { - tailStack.addElement(leaf); - heightOfNodes.addElement(Integers.valueOf(0)); - } - else - { - - byte[] help = new byte[mdLength]; - byte[] toBeHashed = new byte[mdLength << 1]; - - // store the new leaf in help - System.arraycopy(leaf, 0, help, 0, mdLength); - int helpHeight = 0; - // while top to nodes have same height - while (tailStack.size() > 0 - && helpHeight == ((Integer)heightOfNodes.lastElement()) - .intValue()) - { - - // help <-- hash(stack top element || help) - System.arraycopy(tailStack.lastElement(), 0, toBeHashed, 0, - mdLength); - tailStack.removeElementAt(tailStack.size() - 1); - heightOfNodes.removeElementAt(heightOfNodes.size() - 1); - System.arraycopy(help, 0, toBeHashed, mdLength, mdLength); - - messDigestTree.update(toBeHashed, 0, toBeHashed.length); - help = new byte[messDigestTree.getDigestSize()]; - messDigestTree.doFinal(help, 0); - - // the new help node is one step higher - helpHeight++; - if (helpHeight < heightOfTree) - { - index[helpHeight]++; - - // add index 1 element to initial authpath - if (index[helpHeight] == 1) - { - System.arraycopy(help, 0, AuthPath[helpHeight], 0, - mdLength); - } - - if (helpHeight >= heightOfTree - K) - { - if (helpHeight == 0) - { - System.out.println("M���P"); - } - // add help element to retain stack if it is a right - // node - // and not stored in treehash - if ((index[helpHeight] - 3) % 2 == 0 - && index[helpHeight] >= 3) - // TODO: check it - { - retain[helpHeight - (heightOfTree - K)] - .insertElementAt(help, 0); - } - } - else - { - // if element is third in his line add it to treehash - if (index[helpHeight] == 3) - { - treehash[helpHeight].setFirstNode(help); - } - } - } - } - // push help element to the stack - tailStack.addElement(help); - heightOfNodes.addElement(Integers.valueOf(helpHeight)); - - // is the root calculation finished? - if (helpHeight == heightOfTree) - { - isFinished = true; - isInitialized = false; - root = (byte[])tailStack.lastElement(); - } - } - - } - - /** - * initializes the seeds for the treehashs of the tree precomputed by this - * class - * - * @param seed the initial seed for treehash: seedNext - * @param index the height of the treehash - */ - public void initializeTreehashSeed(byte[] seed, int index) - { - treehash[index].initializeSeed(seed); - } - - /** - * Method to check whether the instance has been initialized or not - * - * @return true if treehash was already initialized - */ - public boolean wasInitialized() - { - return isInitialized; - } - - /** - * Method to check whether the instance has been finished or not - * - * @return true if tree has reached its maximum height - */ - public boolean wasFinished() - { - return isFinished; - } - - /** - * returns the authentication path of the first leaf of the tree - * - * @return the authentication path of the first leaf of the tree - */ - public byte[][] getAuthPath() - { - return GMSSUtils.clone(AuthPath); - } - - /** - * returns the initial treehash instances, storing value y_3(i) - * - * @return the initial treehash instances, storing value y_3(i) - */ - public Treehash[] getTreehash() - { - return GMSSUtils.clone(treehash); - } - - /** - * returns the retain stacks storing all right nodes near to the root - * - * @return the retain stacks storing all right nodes near to the root - */ - public Vector[] getRetain() - { - return GMSSUtils.clone(retain); - } - - /** - * returns the finished root value - * - * @return the finished root value - */ - public byte[] getRoot() - { - return Arrays.clone(root); - } - - /** - * returns the shared stack - * - * @return the shared stack - */ - public Vector getStack() - { - Vector copy = new Vector(); - for (Enumeration en = tailStack.elements(); en.hasMoreElements();) - { - copy.addElement(en.nextElement()); - } - return copy; - } - - /** - * Returns the status byte array used by the GMSSPrivateKeyASN.1 class - * - * @return The status bytes - */ - public byte[][] getStatByte() - { - - int tailLength; - if (tailStack == null) - { - tailLength = 0; - } - else - { - tailLength = tailStack.size(); - } - byte[][] statByte = new byte[1 + heightOfTree + tailLength][64]; //FIXME: messDigestTree.getByteLength() - statByte[0] = root; - - for (int i = 0; i < heightOfTree; i++) - { - statByte[1 + i] = AuthPath[i]; - } - for (int i = 0; i < tailLength; i++) - { - statByte[1 + heightOfTree + i] = (byte[])tailStack.elementAt(i); - } - - return statByte; - } - - /** - * Returns the status int array used by the GMSSPrivateKeyASN.1 class - * - * @return The status ints - */ - public int[] getStatInt() - { - - int tailLength; - if (tailStack == null) - { - tailLength = 0; - } - else - { - tailLength = tailStack.size(); - } - int[] statInt = new int[8 + heightOfTree + tailLength]; - statInt[0] = heightOfTree; - statInt[1] = mdLength; - statInt[2] = K; - statInt[3] = indexForNextSeed; - statInt[4] = heightOfNextSeed; - if (isFinished) - { - statInt[5] = 1; - } - else - { - statInt[5] = 0; - } - if (isInitialized) - { - statInt[6] = 1; - } - else - { - statInt[6] = 0; - } - statInt[7] = tailLength; - - for (int i = 0; i < heightOfTree; i++) - { - statInt[8 + i] = index[i]; - } - for (int i = 0; i < tailLength; i++) - { - statInt[8 + heightOfTree + i] = ((Integer)heightOfNodes - .elementAt(i)).intValue(); - } - - return statInt; - } - - /** - * @return a human readable version of the structure - */ - public String toString() - { - String out = ""; - int tailLength; - if (tailStack == null) - { - tailLength = 0; - } - else - { - tailLength = tailStack.size(); - } - - for (int i = 0; i < 8 + heightOfTree + tailLength; i++) - { - out = out + getStatInt()[i] + " "; - } - for (int i = 0; i < 1 + heightOfTree + tailLength; i++) - { - out = out + new String(Hex.encode(getStatByte()[i])) + " "; - } - out = out + " " + digestProvider.get().getDigestSize(); - return out; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSRootSig.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSRootSig.java deleted file mode 100644 index 8a4796f0..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSRootSig.java +++ /dev/null @@ -1,666 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.pqc.crypto.gmss.util.GMSSRandom; -import org.bouncycastle.util.encoders.Hex; - - -/** - * This class implements the distributed signature generation of the Winternitz - * one-time signature scheme (OTSS), described in C.Dods, N.P. Smart, and M. - * Stam, "Hash Based Digital Signature Schemes", LNCS 3796, pages 96–115, - * 2005. The class is used by the GMSS classes. - */ -public class GMSSRootSig -{ - - /** - * The hash function used by the OTS - */ - private Digest messDigestOTS; - - /** - * The length of the message digest and private key - */ - private int mdsize, keysize; - - /** - * The private key - */ - private byte[] privateKeyOTS; - - /** - * The message bytes - */ - private byte[] hash; - - /** - * The signature bytes - */ - private byte[] sign; - - /** - * The Winternitz parameter - */ - private int w; - - /** - * The source of randomness for OTS private key generation - */ - private GMSSRandom gmssRandom; - - /** - * Sizes of the message - */ - private int messagesize; - - /** - * Some precalculated values - */ - private int k; - - /** - * Some variables for storing the actual status of distributed signing - */ - private int r, test, counter, ii; - - /** - * variables for storing big numbers for the actual status of distributed - * signing - */ - private long test8, big8; - - /** - * The necessary steps of each updateSign() call - */ - private int steps; - - /** - * The checksum part - */ - private int checksum; - - /** - * The height of the tree - */ - private int height; - - /** - * The current intern OTSseed - */ - private byte[] seed; - - /** - * This constructor regenerates a prior GMSSRootSig object used by the - * GMSSPrivateKeyASN.1 class - * - * @param digest an array of strings, containing the digest of the used hash - * function, the digest of the PRGN and the names of the - * corresponding providers - * @param statByte status byte array - * @param statInt status int array - */ - public GMSSRootSig(Digest digest, byte[][] statByte, int[] statInt) - { - messDigestOTS = digest; - gmssRandom = new GMSSRandom(messDigestOTS); - - this.counter = statInt[0]; - this.test = statInt[1]; - this.ii = statInt[2]; - this.r = statInt[3]; - this.steps = statInt[4]; - this.keysize = statInt[5]; - this.height = statInt[6]; - this.w = statInt[7]; - this.checksum = statInt[8]; - - this.mdsize = messDigestOTS.getDigestSize(); - - this.k = (1 << w) - 1; - - int mdsizeBit = mdsize << 3; - this.messagesize = (int)Math.ceil((double)(mdsizeBit) / (double)w); - - this.privateKeyOTS = statByte[0]; - this.seed = statByte[1]; - this.hash = statByte[2]; - - this.sign = statByte[3]; - - this.test8 = ((statByte[4][0] & 0xff)) - | ((long)(statByte[4][1] & 0xff) << 8) - | ((long)(statByte[4][2] & 0xff) << 16) - | ((long)(statByte[4][3] & 0xff)) << 24 - | ((long)(statByte[4][4] & 0xff)) << 32 - | ((long)(statByte[4][5] & 0xff)) << 40 - | ((long)(statByte[4][6] & 0xff)) << 48 - | ((long)(statByte[4][7] & 0xff)) << 56; - - this.big8 = ((statByte[4][8] & 0xff)) - | ((long)(statByte[4][9] & 0xff) << 8) - | ((long)(statByte[4][10] & 0xff) << 16) - | ((long)(statByte[4][11] & 0xff)) << 24 - | ((long)(statByte[4][12] & 0xff)) << 32 - | ((long)(statByte[4][13] & 0xff)) << 40 - | ((long)(statByte[4][14] & 0xff)) << 48 - | ((long)(statByte[4][15] & 0xff)) << 56; - } - - /** - * The constructor generates the PRNG and initializes some variables - * - * @param digest an array of strings, containing the digest of the used hash - * function, the digest of the PRGN and the names of the - * corresponding providers - * @param w the winternitz parameter - * @param height the heigth of the tree - */ - public GMSSRootSig(Digest digest, int w, int height) - { - messDigestOTS = digest; - gmssRandom = new GMSSRandom(messDigestOTS); - - this.mdsize = messDigestOTS.getDigestSize(); - this.w = w; - this.height = height; - - this.k = (1 << w) - 1; - - int mdsizeBit = mdsize << 3; - this.messagesize = (int)Math.ceil((double)(mdsizeBit) / (double)w); - } - - /** - * This method initializes the distributed sigature calculation. Variables - * are reseted and necessary steps are calculated - * - * @param seed0 the initial OTSseed - * @param message the massage which will be signed - */ - public void initSign(byte[] seed0, byte[] message) - { - - // create hash of message m - this.hash = new byte[mdsize]; - messDigestOTS.update(message, 0, message.length); - this.hash = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(this.hash, 0); - - // variables for calculation of steps - byte[] messPart = new byte[mdsize]; - System.arraycopy(hash, 0, messPart, 0, mdsize); - int checkPart = 0; - int sumH = 0; - int checksumsize = getLog((messagesize << w) + 1); - - // ------- calculation of necessary steps ------ - if (8 % w == 0) - { - int dt = 8 / w; - // message part - for (int a = 0; a < mdsize; a++) - { - // count necessary hashs in 'sumH' - for (int b = 0; b < dt; b++) - { - sumH += messPart[a] & k; - messPart[a] = (byte)(messPart[a] >>> w); - } - } - // checksum part - this.checksum = (messagesize << w) - sumH; - checkPart = checksum; - // count necessary hashs in 'sumH' - for (int b = 0; b < checksumsize; b += w) - { - sumH += checkPart & k; - checkPart >>>= w; - } - } // end if ( 8 % w == 0 ) - else if (w < 8) - { - long big8; - int ii = 0; - int dt = mdsize / w; - - // first d*w bytes of hash (main message part) - for (int i = 0; i < dt; i++) - { - big8 = 0; - for (int j = 0; j < w; j++) - { - big8 ^= (messPart[ii] & 0xff) << (j << 3); - ii++; - } - // count necessary hashs in 'sumH' - for (int j = 0; j < 8; j++) - { - sumH += (int)(big8 & k); - big8 >>>= w; - } - } - // rest of message part - dt = mdsize % w; - big8 = 0; - for (int j = 0; j < dt; j++) - { - big8 ^= (messPart[ii] & 0xff) << (j << 3); - ii++; - } - dt <<= 3; - // count necessary hashs in 'sumH' - for (int j = 0; j < dt; j += w) - { - sumH += (int)(big8 & k); - big8 >>>= w; - } - // checksum part - this.checksum = (messagesize << w) - sumH; - checkPart = checksum; - // count necessary hashs in 'sumH' - for (int i = 0; i < checksumsize; i += w) - { - sumH += checkPart & k; - checkPart >>>= w; - } - }// end if(w<8) - else if (w < 57) - { - long big8; - int r = 0; - int s, f, rest, ii; - - // first a*w bits of hash where a*w <= 8*mdsize < (a+1)*w (main - // message part) - while (r <= ((mdsize << 3) - w)) - { - s = r >>> 3; - rest = r % 8; - r += w; - f = (r + 7) >>> 3; - big8 = 0; - ii = 0; - for (int j = s; j < f; j++) - { - big8 ^= (messPart[j] & 0xff) << (ii << 3); - ii++; - } - big8 >>>= rest; - // count necessary hashs in 'sumH' - sumH += (big8 & k); - - } - // rest of message part - s = r >>> 3; - if (s < mdsize) - { - rest = r % 8; - big8 = 0; - ii = 0; - for (int j = s; j < mdsize; j++) - { - big8 ^= (messPart[j] & 0xff) << (ii << 3); - ii++; - } - - big8 >>>= rest; - // count necessary hashs in 'sumH' - sumH += (big8 & k); - } - // checksum part - this.checksum = (messagesize << w) - sumH; - checkPart = checksum; - // count necessary hashs in 'sumH' - for (int i = 0; i < checksumsize; i += w) - { - sumH += (checkPart & k); - checkPart >>>= w; - } - }// end if(w<57) - - // calculate keysize - this.keysize = messagesize - + (int)Math.ceil((double)checksumsize / (double)w); - - // calculate steps: 'keysize' times PRNG, 'sumH' times hashing, - // (1<<height)-1 updateSign() calls - this.steps = (int)Math.ceil((double)(keysize + sumH) - / (double)((1 << height))); - // ---------------------------- - - // reset variables - this.sign = new byte[keysize * mdsize]; - this.counter = 0; - this.test = 0; - this.ii = 0; - this.test8 = 0; - this.r = 0; - // define the private key messagesize - this.privateKeyOTS = new byte[mdsize]; - // copy the seed - this.seed = new byte[mdsize]; - System.arraycopy(seed0, 0, this.seed, 0, mdsize); - - } - - /** - * This Method performs <code>steps</code> steps of distributed signature - * calculaion - * - * @return true if signature is generated completly, else false - */ - public boolean updateSign() - { - // steps times do - - for (int s = 0; s < steps; s++) - { // do 'step' times - - if (counter < keysize) - { // generate the private key or perform - // the next hash - oneStep(); - } - if (counter == keysize) - {// finish - return true; - } - } - - return false; // leaf not finished yet - } - - /** - * @return The private OTS key - */ - public byte[] getSig() - { - - return sign; - } - - /** - * @return The one-time signature of the message, generated step by step - */ - private void oneStep() - { - // -------- if (8 % w == 0) ---------- - if (8 % w == 0) - { - if (test == 0) - { - // get current OTSprivateKey - this.privateKeyOTS = gmssRandom.nextSeed(seed); - // System.arraycopy(privateKeyOTS, 0, hlp, 0, mdsize); - - if (ii < mdsize) - { // for main message part - test = hash[ii] & k; - hash[ii] = (byte)(hash[ii] >>> w); - } - else - { // for checksum part - test = checksum & k; - checksum >>>= w; - } - } - else if (test > 0) - { // hash the private Key 'test' times (on - // time each step) - messDigestOTS.update(privateKeyOTS, 0, privateKeyOTS.length); - privateKeyOTS = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(privateKeyOTS, 0); - test--; - } - if (test == 0) - { // if all hashes done copy result to siganture - // array - System.arraycopy(privateKeyOTS, 0, sign, counter * mdsize, - mdsize); - counter++; - - if (counter % (8 / w) == 0) - { // raise array index for main - // massage part - ii++; - } - } - - }// ----- end if (8 % w == 0) ----- - // ---------- if ( w < 8 ) ---------------- - else if (w < 8) - { - - if (test == 0) - { - if (counter % 8 == 0 && ii < mdsize) - { // after every 8th "add - // to signature"-step - big8 = 0; - if (counter < ((mdsize / w) << 3)) - {// main massage - // (generate w*8 Bits - // every time) part - for (int j = 0; j < w; j++) - { - big8 ^= (hash[ii] & 0xff) << (j << 3); - ii++; - } - } - else - { // rest of massage part (once) - for (int j = 0; j < mdsize % w; j++) - { - big8 ^= (hash[ii] & 0xff) << (j << 3); - ii++; - } - } - } - if (counter == messagesize) - { // checksum part (once) - big8 = checksum; - } - - test = (int)(big8 & k); - // generate current OTSprivateKey - this.privateKeyOTS = gmssRandom.nextSeed(seed); - // System.arraycopy(privateKeyOTS, 0, hlp, 0, mdsize); - - } - else if (test > 0) - { // hash the private Key 'test' times (on - // time each step) - messDigestOTS.update(privateKeyOTS, 0, privateKeyOTS.length); - privateKeyOTS = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(privateKeyOTS, 0); - test--; - } - if (test == 0) - { // if all hashes done copy result to siganture - // array - System.arraycopy(privateKeyOTS, 0, sign, counter * mdsize, - mdsize); - big8 >>>= w; - counter++; - } - - }// ------- end if(w<8)-------------------------------- - // --------- if w < 57 ----------------------------- - else if (w < 57) - { - - if (test8 == 0) - { - int s, f, rest; - big8 = 0; - ii = 0; - rest = r % 8; - s = r >>> 3; - // --- message part--- - if (s < mdsize) - { - if (r <= ((mdsize << 3) - w)) - { // first message part - r += w; - f = (r + 7) >>> 3; - } - else - { // rest of message part (once) - f = mdsize; - r += w; - } - // generate long 'big8' with minimum w next bits of the - // message array - for (int i = s; i < f; i++) - { - big8 ^= (hash[i] & 0xff) << (ii << 3); - ii++; - } - // delete bits on the right side, which were used already by - // the last loop - big8 >>>= rest; - test8 = (big8 & k); - } - // --- checksum part - else - { - test8 = (checksum & k); - checksum >>>= w; - } - // generate current OTSprivateKey - this.privateKeyOTS = gmssRandom.nextSeed(seed); - // System.arraycopy(privateKeyOTS, 0, hlp, 0, mdsize); - - } - else if (test8 > 0) - { // hash the private Key 'test' times (on - // time each step) - messDigestOTS.update(privateKeyOTS, 0, privateKeyOTS.length); - privateKeyOTS = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(privateKeyOTS, 0); - test8--; - } - if (test8 == 0) - { // if all hashes done copy result to siganture - // array - System.arraycopy(privateKeyOTS, 0, sign, counter * mdsize, - mdsize); - counter++; - } - - } - } - - /** - * This method returns the least integer that is greater or equal to the - * logarithm to the base 2 of an integer <code>intValue</code>. - * - * @param intValue an integer - * @return The least integer greater or equal to the logarithm to the base 2 - * of <code>intValue</code> - */ - public int getLog(int intValue) - { - int log = 1; - int i = 2; - while (i < intValue) - { - i <<= 1; - log++; - } - return log; - } - - /** - * This method returns the status byte array - * - * @return statBytes - */ - public byte[][] getStatByte() - { - - byte[][] statByte = new byte[5][mdsize]; - statByte[0] = privateKeyOTS; - statByte[1] = seed; - statByte[2] = hash; - statByte[3] = sign; - statByte[4] = this.getStatLong(); - - return statByte; - } - - /** - * This method returns the status int array - * - * @return statInt - */ - public int[] getStatInt() - { - int[] statInt = new int[9]; - statInt[0] = counter; - statInt[1] = test; - statInt[2] = ii; - statInt[3] = r; - statInt[4] = steps; - statInt[5] = keysize; - statInt[6] = height; - statInt[7] = w; - statInt[8] = checksum; - return statInt; - } - - /** - * Converts the long parameters into byte arrays to store it in - * statByte-Array - */ - public byte[] getStatLong() - { - byte[] bytes = new byte[16]; - - bytes[0] = (byte)((test8) & 0xff); - bytes[1] = (byte)((test8 >> 8) & 0xff); - bytes[2] = (byte)((test8 >> 16) & 0xff); - bytes[3] = (byte)((test8 >> 24) & 0xff); - bytes[4] = (byte)((test8) >> 32 & 0xff); - bytes[5] = (byte)((test8 >> 40) & 0xff); - bytes[6] = (byte)((test8 >> 48) & 0xff); - bytes[7] = (byte)((test8 >> 56) & 0xff); - - bytes[8] = (byte)((big8) & 0xff); - bytes[9] = (byte)((big8 >> 8) & 0xff); - bytes[10] = (byte)((big8 >> 16) & 0xff); - bytes[11] = (byte)((big8 >> 24) & 0xff); - bytes[12] = (byte)((big8) >> 32 & 0xff); - bytes[13] = (byte)((big8 >> 40) & 0xff); - bytes[14] = (byte)((big8 >> 48) & 0xff); - bytes[15] = (byte)((big8 >> 56) & 0xff); - - return bytes; - } - - /** - * returns a string representation of the instance - * - * @return a string representation of the instance - */ - public String toString() - { - String out = "" + this.big8 + " "; - int[] statInt = new int[9]; - statInt = this.getStatInt(); - byte[][] statByte = new byte[5][mdsize]; - statByte = this.getStatByte(); - for (int i = 0; i < 9; i++) - { - out = out + statInt[i] + " "; - } - for (int i = 0; i < 5; i++) - { - out = out + new String(Hex.encode(statByte[i])) + " "; - } - - return out; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSSigner.java deleted file mode 100644 index 8832fb34..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSSigner.java +++ /dev/null @@ -1,403 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.MessageSigner; -import org.bouncycastle.pqc.crypto.gmss.util.GMSSRandom; -import org.bouncycastle.pqc.crypto.gmss.util.GMSSUtil; -import org.bouncycastle.pqc.crypto.gmss.util.WinternitzOTSVerify; -import org.bouncycastle.pqc.crypto.gmss.util.WinternitzOTSignature; -import org.bouncycastle.util.Arrays; - -/** - * This class implements the GMSS signature scheme. - */ -public class GMSSSigner - implements MessageSigner -{ - - /** - * Instance of GMSSParameterSpec - */ - //private GMSSParameterSpec gmssParameterSpec; - - /** - * Instance of GMSSUtilities - */ - private GMSSUtil gmssUtil = new GMSSUtil(); - - - /** - * The raw GMSS public key - */ - private byte[] pubKeyBytes; - - /** - * Hash function for the construction of the authentication trees - */ - private Digest messDigestTrees; - - /** - * The length of the hash function output - */ - private int mdLength; - - /** - * The number of tree layers - */ - private int numLayer; - - /** - * The hash function used by the OTS - */ - private Digest messDigestOTS; - - /** - * An instance of the Winternitz one-time signature - */ - private WinternitzOTSignature ots; - - /** - * Array of strings containing the name of the hash function used by the OTS - * and the corresponding provider name - */ - private GMSSDigestProvider digestProvider; - - /** - * The current main tree and subtree indices - */ - private int[] index; - - /** - * Array of the authentication paths for the current trees of all layers - */ - private byte[][][] currentAuthPaths; - - /** - * The one-time signature of the roots of the current subtrees - */ - private byte[][] subtreeRootSig; - - - /** - * The GMSSParameterset - */ - private GMSSParameters gmssPS; - - /** - * The PRNG - */ - private GMSSRandom gmssRandom; - - GMSSKeyParameters key; - - // XXX needed? Source of randomness - private SecureRandom random; - - - /** - * The standard constructor tries to generate the MerkleTree Algorithm - * identifier with the corresponding OID. - * - * @param digest the digest to use - */ - // TODO - public GMSSSigner(GMSSDigestProvider digest) - { - digestProvider = digest; - messDigestTrees = digest.get(); - messDigestOTS = messDigestTrees; - mdLength = messDigestTrees.getDigestSize(); - gmssRandom = new GMSSRandom(messDigestTrees); - } - - public void init(boolean forSigning, - CipherParameters param) - { - - if (forSigning) - { - if (param instanceof ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom)param; - - // XXX random needed? - this.random = rParam.getRandom(); - this.key = (GMSSPrivateKeyParameters)rParam.getParameters(); - initSign(); - - } - else - { - - this.random = new SecureRandom(); - this.key = (GMSSPrivateKeyParameters)param; - initSign(); - } - } - else - { - this.key = (GMSSPublicKeyParameters)param; - initVerify(); - - } - - } - - - /** - * Initializes the signature algorithm for signing a message. - */ - private void initSign() - { - messDigestTrees.reset(); - // set private key and take from it ots key, auth, tree and key - // counter, rootSign - GMSSPrivateKeyParameters gmssPrivateKey = (GMSSPrivateKeyParameters)key; - - if (gmssPrivateKey.isUsed()) - { - throw new IllegalStateException("Private key already used"); - } - - // check if last signature has been generated - if (gmssPrivateKey.getIndex(0) >= gmssPrivateKey.getNumLeafs(0)) - { - throw new IllegalStateException("No more signatures can be generated"); - } - - // get Parameterset - this.gmssPS = gmssPrivateKey.getParameters(); - // get numLayer - this.numLayer = gmssPS.getNumOfLayers(); - - // get OTS Instance of lowest layer - byte[] seed = gmssPrivateKey.getCurrentSeeds()[numLayer - 1]; - byte[] OTSSeed = new byte[mdLength]; - byte[] dummy = new byte[mdLength]; - System.arraycopy(seed, 0, dummy, 0, mdLength); - OTSSeed = gmssRandom.nextSeed(dummy); // secureRandom.nextBytes(currentSeeds[currentSeeds.length-1]);secureRandom.nextBytes(OTSseed); - this.ots = new WinternitzOTSignature(OTSSeed, digestProvider.get(), gmssPS.getWinternitzParameter()[numLayer - 1]); - - byte[][][] helpCurrentAuthPaths = gmssPrivateKey.getCurrentAuthPaths(); - currentAuthPaths = new byte[numLayer][][]; - - // copy the main tree authentication path - for (int j = 0; j < numLayer; j++) - { - currentAuthPaths[j] = new byte[helpCurrentAuthPaths[j].length][mdLength]; - for (int i = 0; i < helpCurrentAuthPaths[j].length; i++) - { - System.arraycopy(helpCurrentAuthPaths[j][i], 0, currentAuthPaths[j][i], 0, mdLength); - } - } - - // copy index - index = new int[numLayer]; - System.arraycopy(gmssPrivateKey.getIndex(), 0, index, 0, numLayer); - - // copy subtreeRootSig - byte[] helpSubtreeRootSig; - subtreeRootSig = new byte[numLayer - 1][]; - for (int i = 0; i < numLayer - 1; i++) - { - helpSubtreeRootSig = gmssPrivateKey.getSubtreeRootSig(i); - subtreeRootSig[i] = new byte[helpSubtreeRootSig.length]; - System.arraycopy(helpSubtreeRootSig, 0, subtreeRootSig[i], 0, helpSubtreeRootSig.length); - } - - gmssPrivateKey.markUsed(); - } - - /** - * Signs a message. - * - * @return the signature. - */ - public byte[] generateSignature(byte[] message) - { - - byte[] otsSig = new byte[mdLength]; - byte[] authPathBytes; - byte[] indexBytes; - - otsSig = ots.getSignature(message); - - // get concatenated lowest layer tree authentication path - authPathBytes = gmssUtil.concatenateArray(currentAuthPaths[numLayer - 1]); - - // put lowest layer index into a byte array - indexBytes = gmssUtil.intToBytesLittleEndian(index[numLayer - 1]); - - // create first part of GMSS signature - byte[] gmssSigFirstPart = new byte[indexBytes.length + otsSig.length + authPathBytes.length]; - System.arraycopy(indexBytes, 0, gmssSigFirstPart, 0, indexBytes.length); - System.arraycopy(otsSig, 0, gmssSigFirstPart, indexBytes.length, otsSig.length); - System.arraycopy(authPathBytes, 0, gmssSigFirstPart, (indexBytes.length + otsSig.length), authPathBytes.length); - // --- end first part - - // --- next parts of the signature - // create initial array with length 0 for iteration - byte[] gmssSigNextPart = new byte[0]; - - for (int i = numLayer - 1 - 1; i >= 0; i--) - { - - // get concatenated next tree authentication path - authPathBytes = gmssUtil.concatenateArray(currentAuthPaths[i]); - - // put next tree index into a byte array - indexBytes = gmssUtil.intToBytesLittleEndian(index[i]); - - // create next part of GMSS signature - - // create help array and copy actual gmssSig into it - byte[] helpGmssSig = new byte[gmssSigNextPart.length]; - System.arraycopy(gmssSigNextPart, 0, helpGmssSig, 0, gmssSigNextPart.length); - // adjust length of gmssSigNextPart for adding next part - gmssSigNextPart = new byte[helpGmssSig.length + indexBytes.length + subtreeRootSig[i].length + authPathBytes.length]; - - // copy old data (help array) and new data in gmssSigNextPart - System.arraycopy(helpGmssSig, 0, gmssSigNextPart, 0, helpGmssSig.length); - System.arraycopy(indexBytes, 0, gmssSigNextPart, helpGmssSig.length, indexBytes.length); - System.arraycopy(subtreeRootSig[i], 0, gmssSigNextPart, (helpGmssSig.length + indexBytes.length), subtreeRootSig[i].length); - System.arraycopy(authPathBytes, 0, gmssSigNextPart, (helpGmssSig.length + indexBytes.length + subtreeRootSig[i].length), authPathBytes.length); - - } - // --- end next parts - - // concatenate the two parts of the GMSS signature - byte[] gmssSig = new byte[gmssSigFirstPart.length + gmssSigNextPart.length]; - System.arraycopy(gmssSigFirstPart, 0, gmssSig, 0, gmssSigFirstPart.length); - System.arraycopy(gmssSigNextPart, 0, gmssSig, gmssSigFirstPart.length, gmssSigNextPart.length); - - // return the GMSS signature - return gmssSig; - } - - /** - * Initializes the signature algorithm for verifying a signature. - */ - private void initVerify() - { - messDigestTrees.reset(); - - GMSSPublicKeyParameters gmssPublicKey = (GMSSPublicKeyParameters)key; - pubKeyBytes = gmssPublicKey.getPublicKey(); - gmssPS = gmssPublicKey.getParameters(); - // get numLayer - this.numLayer = gmssPS.getNumOfLayers(); - - - } - - /** - * This function verifies the signature of the message that has been - * updated, with the aid of the public key. - * - * @param message the message - * @param signature the signature associated with the message - * @return true if the signature has been verified, false otherwise. - */ - public boolean verifySignature(byte[] message, byte[] signature) - { - - boolean success = false; - // int halfSigLength = signature.length >>> 1; - messDigestOTS.reset(); - WinternitzOTSVerify otsVerify; - int otsSigLength; - - byte[] help = message; - - byte[] otsSig; - byte[] otsPublicKey; - byte[][] authPath; - byte[] dest; - int nextEntry = 0; - int index; - // Verify signature - - // --- begin with message = 'message that was signed' - // and then in each step message = subtree root - for (int j = numLayer - 1; j >= 0; j--) - { - otsVerify = new WinternitzOTSVerify(digestProvider.get(), gmssPS.getWinternitzParameter()[j]); - otsSigLength = otsVerify.getSignatureLength(); - - message = help; - // get the subtree index - index = gmssUtil.bytesToIntLittleEndian(signature, nextEntry); - - // 4 is the number of bytes in integer - nextEntry += 4; - - // get one-time signature - otsSig = new byte[otsSigLength]; - System.arraycopy(signature, nextEntry, otsSig, 0, otsSigLength); - nextEntry += otsSigLength; - - // compute public OTS key from the one-time signature - otsPublicKey = otsVerify.Verify(message, otsSig); - - // test if OTSsignature is correct - if (otsPublicKey == null) - { - System.err.println("OTS Public Key is null in GMSSSignature.verify"); - return false; - } - - // get authentication path from the signature - authPath = new byte[gmssPS.getHeightOfTrees()[j]][mdLength]; - for (int i = 0; i < authPath.length; i++) - { - System.arraycopy(signature, nextEntry, authPath[i], 0, mdLength); - nextEntry = nextEntry + mdLength; - } - - // compute the root of the subtree from the authentication path - help = new byte[mdLength]; - - help = otsPublicKey; - - int count = 1 << authPath.length; - count = count + index; - - for (int i = 0; i < authPath.length; i++) - { - dest = new byte[mdLength << 1]; - - if ((count % 2) == 0) - { - System.arraycopy(help, 0, dest, 0, mdLength); - System.arraycopy(authPath[i], 0, dest, mdLength, mdLength); - count = count / 2; - } - else - { - System.arraycopy(authPath[i], 0, dest, 0, mdLength); - System.arraycopy(help, 0, dest, mdLength, help.length); - count = (count - 1) / 2; - } - messDigestTrees.update(dest, 0, dest.length); - help = new byte[messDigestTrees.getDigestSize()]; - messDigestTrees.doFinal(help, 0); - } - } - - // now help contains the root of the maintree - - // test if help is equal to the GMSS public key - if (Arrays.areEqual(pubKeyBytes, help)) - { - success = true; - } - - return success; - } - - -}
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSUtils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSUtils.java deleted file mode 100644 index 9d289513..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/GMSSUtils.java +++ /dev/null @@ -1,145 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss; - -import java.util.Enumeration; -import java.util.Vector; - -import org.bouncycastle.util.Arrays; - -class GMSSUtils -{ - static GMSSLeaf[] clone(GMSSLeaf[] data) - { - if (data == null) - { - return null; - } - GMSSLeaf[] copy = new GMSSLeaf[data.length]; - - System.arraycopy(data, 0, copy, 0, data.length); - - return copy; - } - - static GMSSRootCalc[] clone(GMSSRootCalc[] data) - { - if (data == null) - { - return null; - } - GMSSRootCalc[] copy = new GMSSRootCalc[data.length]; - - System.arraycopy(data, 0, copy, 0, data.length); - - return copy; - } - - static GMSSRootSig[] clone(GMSSRootSig[] data) - { - if (data == null) - { - return null; - } - GMSSRootSig[] copy = new GMSSRootSig[data.length]; - - System.arraycopy(data, 0, copy, 0, data.length); - - return copy; - } - - static byte[][] clone(byte[][] data) - { - if (data == null) - { - return null; - } - byte[][] copy = new byte[data.length][]; - - for (int i = 0; i != data.length; i++) - { - copy[i] = Arrays.clone(data[i]); - } - - return copy; - } - - static byte[][][] clone(byte[][][] data) - { - if (data == null) - { - return null; - } - byte[][][] copy = new byte[data.length][][]; - - for (int i = 0; i != data.length; i++) - { - copy[i] = clone(data[i]); - } - - return copy; - } - - static Treehash[] clone(Treehash[] data) - { - if (data == null) - { - return null; - } - Treehash[] copy = new Treehash[data.length]; - - System.arraycopy(data, 0, copy, 0, data.length); - - return copy; - } - - static Treehash[][] clone(Treehash[][] data) - { - if (data == null) - { - return null; - } - Treehash[][] copy = new Treehash[data.length][]; - - for (int i = 0; i != data.length; i++) - { - copy[i] = clone(data[i]); - } - - return copy; - } - - static Vector[] clone(Vector[] data) - { - if (data == null) - { - return null; - } - Vector[] copy = new Vector[data.length]; - - for (int i = 0; i != data.length; i++) - { - copy[i] = new Vector(); - for (Enumeration en = data[i].elements(); en.hasMoreElements();) - { - copy[i].addElement(en.nextElement()); - } - } - - return copy; - } - - static Vector[][] clone(Vector[][] data) - { - if (data == null) - { - return null; - } - Vector[][] copy = new Vector[data.length][]; - - for (int i = 0; i != data.length; i++) - { - copy[i] = clone(data[i]); - } - - return copy; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/Treehash.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/Treehash.java deleted file mode 100644 index 797355cb..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/Treehash.java +++ /dev/null @@ -1,525 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss; - -import java.util.Vector; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.pqc.crypto.gmss.util.GMSSRandom; -import org.bouncycastle.util.Integers; -import org.bouncycastle.util.encoders.Hex; - - -/** - * This class implements a treehash instance for the Merkle tree traversal - * algorithm. The first node of the stack is stored in this instance itself, - * additional tail nodes are stored on a tailstack. - */ -public class Treehash -{ - - /** - * max height of current treehash instance. - */ - private int maxHeight; - - /** - * Vector element that stores the nodes on the stack - */ - private Vector tailStack; - - /** - * Vector element that stores the height of the nodes on the stack - */ - private Vector heightOfNodes; - - /** - * the first node is stored in the treehash instance itself, not on stack - */ - private byte[] firstNode; - - /** - * seedActive needed for the actual node - */ - private byte[] seedActive; - - /** - * the seed needed for the next re-initialization of the treehash instance - */ - private byte[] seedNext; - - /** - * number of nodes stored on the stack and belonging to this treehash - * instance - */ - private int tailLength; - - /** - * the height in the tree of the first node stored in treehash - */ - private int firstNodeHeight; - - /** - * true if treehash instance was already initialized, false otherwise - */ - private boolean isInitialized; - - /** - * true if the first node's height equals the maxHeight of the treehash - */ - private boolean isFinished; - - /** - * true if the nextSeed has been initialized with index 3*2^h needed for the - * seed scheduling - */ - private boolean seedInitialized; - - /** - * denotes the Message Digest used by the tree to create nodes - */ - private Digest messDigestTree; - - /** - * This constructor regenerates a prior treehash object - * - * @param name an array of strings, containing the name of the used hash - * function and PRNG and the name of the corresponding provider - * @param statByte status bytes - * @param statInt status ints - */ - public Treehash(Digest name, byte[][] statByte, int[] statInt) - { - this.messDigestTree = name; - - // decode statInt - this.maxHeight = statInt[0]; - this.tailLength = statInt[1]; - this.firstNodeHeight = statInt[2]; - - if (statInt[3] == 1) - { - this.isFinished = true; - } - else - { - this.isFinished = false; - } - if (statInt[4] == 1) - { - this.isInitialized = true; - } - else - { - this.isInitialized = false; - } - if (statInt[5] == 1) - { - this.seedInitialized = true; - } - else - { - this.seedInitialized = false; - } - - this.heightOfNodes = new Vector(); - for (int i = 0; i < tailLength; i++) - { - this.heightOfNodes.addElement(Integers.valueOf(statInt[6 + i])); - } - - // decode statByte - this.firstNode = statByte[0]; - this.seedActive = statByte[1]; - this.seedNext = statByte[2]; - - this.tailStack = new Vector(); - for (int i = 0; i < tailLength; i++) - { - this.tailStack.addElement(statByte[3 + i]); - } - } - - /** - * Constructor - * - * @param tailStack a vector element where the stack nodes are stored - * @param maxHeight maximal height of the treehash instance - * @param digest an array of strings, containing the name of the used hash - * function and PRNG and the name of the corresponding provider - */ - public Treehash(Vector tailStack, int maxHeight, Digest digest) - { - this.tailStack = tailStack; - this.maxHeight = maxHeight; - this.firstNode = null; - this.isInitialized = false; - this.isFinished = false; - this.seedInitialized = false; - this.messDigestTree = digest; - - this.seedNext = new byte[messDigestTree.getDigestSize()]; - this.seedActive = new byte[messDigestTree.getDigestSize()]; - } - - /** - * Method to initialize the seeds needed for the precomputation of right - * nodes. Should be initialized with index 3*2^i for treehash_i - * - * @param seedIn - */ - public void initializeSeed(byte[] seedIn) - { - System.arraycopy(seedIn, 0, this.seedNext, 0, this.messDigestTree - .getDigestSize()); - this.seedInitialized = true; - } - - /** - * initializes the treehash instance. The seeds must already have been - * initialized to work correctly. - */ - public void initialize() - { - if (!this.seedInitialized) - { - System.err.println("Seed " + this.maxHeight + " not initialized"); - return; - } - - this.heightOfNodes = new Vector(); - this.tailLength = 0; - this.firstNode = null; - this.firstNodeHeight = -1; - this.isInitialized = true; - System.arraycopy(this.seedNext, 0, this.seedActive, 0, messDigestTree - .getDigestSize()); - } - - /** - * Calculates one update of the treehash instance, i.e. creates a new leaf - * and hashes if possible - * - * @param gmssRandom an instance of the PRNG - * @param leaf The byte value of the leaf needed for the update - */ - public void update(GMSSRandom gmssRandom, byte[] leaf) - { - - if (this.isFinished) - { - System.err - .println("No more update possible for treehash instance!"); - return; - } - if (!this.isInitialized) - { - System.err - .println("Treehash instance not initialized before update"); - return; - } - - byte[] help = new byte[this.messDigestTree.getDigestSize()]; - int helpHeight = -1; - - gmssRandom.nextSeed(this.seedActive); - - // if treehash gets first update - if (this.firstNode == null) - { - this.firstNode = leaf; - this.firstNodeHeight = 0; - } - else - { - // store the new node in help array, do not push it on the stack - help = leaf; - helpHeight = 0; - - // hash the nodes on the stack if possible - while (this.tailLength > 0 - && helpHeight == ((Integer)heightOfNodes.lastElement()) - .intValue()) - { - // put top element of the stack and help node in array - // 'tobehashed' - // and hash them together, put result again in help array - byte[] toBeHashed = new byte[this.messDigestTree - .getDigestSize() << 1]; - - // pop element from stack - System.arraycopy(this.tailStack.lastElement(), 0, toBeHashed, - 0, this.messDigestTree.getDigestSize()); - this.tailStack.removeElementAt(this.tailStack.size() - 1); - this.heightOfNodes - .removeElementAt(this.heightOfNodes.size() - 1); - - System.arraycopy(help, 0, toBeHashed, this.messDigestTree - .getDigestSize(), this.messDigestTree - .getDigestSize()); - messDigestTree.update(toBeHashed, 0, toBeHashed.length); - help = new byte[messDigestTree.getDigestSize()]; - messDigestTree.doFinal(help, 0); - - // increase help height, stack was reduced by one element - helpHeight++; - this.tailLength--; - } - - // push the new node on the stack - this.tailStack.addElement(help); - this.heightOfNodes.addElement(Integers.valueOf(helpHeight)); - this.tailLength++; - - // finally check whether the top node on stack and the first node - // in treehash have same height. If so hash them together - // and store them in treehash - if (((Integer)heightOfNodes.lastElement()).intValue() == this.firstNodeHeight) - { - byte[] toBeHashed = new byte[this.messDigestTree - .getDigestSize() << 1]; - System.arraycopy(this.firstNode, 0, toBeHashed, 0, - this.messDigestTree.getDigestSize()); - - // pop element from tailStack and copy it into help2 array - System.arraycopy(this.tailStack.lastElement(), 0, toBeHashed, - this.messDigestTree.getDigestSize(), - this.messDigestTree.getDigestSize()); - this.tailStack.removeElementAt(this.tailStack.size() - 1); - this.heightOfNodes - .removeElementAt(this.heightOfNodes.size() - 1); - - // store new element in firstNode, stack is then empty - messDigestTree.update(toBeHashed, 0, toBeHashed.length); - this.firstNode = new byte[messDigestTree.getDigestSize()]; - messDigestTree.doFinal(this.firstNode, 0); - this.firstNodeHeight++; - - // empty the stack - this.tailLength = 0; - } - } - - // check if treehash instance is completed - if (this.firstNodeHeight == this.maxHeight) - { - this.isFinished = true; - } - } - - /** - * Destroys a treehash instance after the top node was taken for - * authentication path. - */ - public void destroy() - { - this.isInitialized = false; - this.isFinished = false; - this.firstNode = null; - this.tailLength = 0; - this.firstNodeHeight = -1; - } - - /** - * Returns the height of the lowest node stored either in treehash or on the - * stack. It must not be set to infinity (as mentioned in the paper) because - * this cases are considered in the computeAuthPaths method of - * JDKGMSSPrivateKey - * - * @return Height of the lowest node - */ - public int getLowestNodeHeight() - { - if (this.firstNode == null) - { - return this.maxHeight; - } - else if (this.tailLength == 0) - { - return this.firstNodeHeight; - } - else - { - return Math.min(this.firstNodeHeight, ((Integer)heightOfNodes - .lastElement()).intValue()); - } - } - - /** - * Returns the top node height - * - * @return Height of the first node, the top node - */ - public int getFirstNodeHeight() - { - if (firstNode == null) - { - return maxHeight; - } - return firstNodeHeight; - } - - /** - * Method to check whether the instance has been initialized or not - * - * @return true if treehash was already initialized - */ - public boolean wasInitialized() - { - return this.isInitialized; - } - - /** - * Method to check whether the instance has been finished or not - * - * @return true if treehash has reached its maximum height - */ - public boolean wasFinished() - { - return this.isFinished; - } - - /** - * returns the first node stored in treehash instance itself - * - * @return the first node stored in treehash instance itself - */ - public byte[] getFirstNode() - { - return this.firstNode; - } - - /** - * returns the active seed - * - * @return the active seed - */ - public byte[] getSeedActive() - { - return this.seedActive; - } - - /** - * This method sets the first node stored in the treehash instance itself - * - * @param hash - */ - public void setFirstNode(byte[] hash) - { - if (!this.isInitialized) - { - this.initialize(); - } - this.firstNode = hash; - this.firstNodeHeight = this.maxHeight; - this.isFinished = true; - } - - /** - * updates the nextSeed of this treehash instance one step needed for the - * schedulng of the seeds - * - * @param gmssRandom the prng used for the seeds - */ - public void updateNextSeed(GMSSRandom gmssRandom) - { - gmssRandom.nextSeed(seedNext); - } - - /** - * Returns the tailstack - * - * @return the tailstack - */ - public Vector getTailStack() - { - return this.tailStack; - } - - /** - * Returns the status byte array used by the GMSSPrivateKeyASN.1 class - * - * @return The status bytes - */ - public byte[][] getStatByte() - { - - byte[][] statByte = new byte[3 + tailLength][this.messDigestTree - .getDigestSize()]; - statByte[0] = firstNode; - statByte[1] = seedActive; - statByte[2] = seedNext; - for (int i = 0; i < tailLength; i++) - { - statByte[3 + i] = (byte[])tailStack.elementAt(i); - } - return statByte; - } - - /** - * Returns the status int array used by the GMSSPrivateKeyASN.1 class - * - * @return The status ints - */ - public int[] getStatInt() - { - - int[] statInt = new int[6 + tailLength]; - statInt[0] = maxHeight; - statInt[1] = tailLength; - statInt[2] = firstNodeHeight; - if (this.isFinished) - { - statInt[3] = 1; - } - else - { - statInt[3] = 0; - } - if (this.isInitialized) - { - statInt[4] = 1; - } - else - { - statInt[4] = 0; - } - if (this.seedInitialized) - { - statInt[5] = 1; - } - else - { - statInt[5] = 0; - } - for (int i = 0; i < tailLength; i++) - { - statInt[6 + i] = ((Integer)heightOfNodes.elementAt(i)).intValue(); - } - return statInt; - } - - /** - * returns a String representation of the treehash instance - */ - public String toString() - { - String out = "Treehash : "; - for (int i = 0; i < 6 + tailLength; i++) - { - out = out + this.getStatInt()[i] + " "; - } - for (int i = 0; i < 3 + tailLength; i++) - { - if (this.getStatByte()[i] != null) - { - out = out + new String(Hex.encode((this.getStatByte()[i]))) + " "; - } - else - { - out = out + "null "; - } - } - out = out + " " + this.messDigestTree.getDigestSize(); - return out; - } - -}
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/util/GMSSRandom.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/util/GMSSRandom.java deleted file mode 100644 index c6d30227..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/util/GMSSRandom.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss.util; - -import org.bouncycastle.crypto.Digest; - -/** - * This class provides a PRNG for GMSS - */ -public class GMSSRandom -{ - /** - * Hash function for the construction of the authentication trees - */ - private Digest messDigestTree; - - /** - * Constructor - * - * @param messDigestTree2 - */ - public GMSSRandom(Digest messDigestTree2) - { - - this.messDigestTree = messDigestTree2; - } - - /** - * computes the next seed value, returns a random byte array and sets - * outseed to the next value - * - * @param outseed byte array in which ((1 + SEEDin +RAND) mod 2^n) will be - * stored - * @return byte array of H(SEEDin) - */ - public byte[] nextSeed(byte[] outseed) - { - // RAND <-- H(SEEDin) - byte[] rand = new byte[outseed.length]; - messDigestTree.update(outseed, 0, outseed.length); - rand = new byte[messDigestTree.getDigestSize()]; - messDigestTree.doFinal(rand, 0); - - // SEEDout <-- (1 + SEEDin +RAND) mod 2^n - addByteArrays(outseed, rand); - addOne(outseed); - - // System.arraycopy(outseed, 0, outseed, 0, outseed.length); - - return rand; - } - - private void addByteArrays(byte[] a, byte[] b) - { - - byte overflow = 0; - int temp; - - for (int i = 0; i < a.length; i++) - { - temp = (0xFF & a[i]) + (0xFF & b[i]) + overflow; - a[i] = (byte)temp; - overflow = (byte)(temp >> 8); - } - } - - private void addOne(byte[] a) - { - - byte overflow = 1; - int temp; - - for (int i = 0; i < a.length; i++) - { - temp = (0xFF & a[i]) + overflow; - a[i] = (byte)temp; - overflow = (byte)(temp >> 8); - } - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/util/GMSSUtil.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/util/GMSSUtil.java deleted file mode 100644 index 80f8828b..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/util/GMSSUtil.java +++ /dev/null @@ -1,151 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss.util; - -/** - * This class provides several methods that are required by the GMSS classes. - */ -public class GMSSUtil -{ - /** - * Converts a 32 bit integer into a byte array beginning at - * <code>offset</code> (little-endian representation) - * - * @param value the integer to convert - */ - public byte[] intToBytesLittleEndian(int value) - { - byte[] bytes = new byte[4]; - - bytes[0] = (byte)((value) & 0xff); - bytes[1] = (byte)((value >> 8) & 0xff); - bytes[2] = (byte)((value >> 16) & 0xff); - bytes[3] = (byte)((value >> 24) & 0xff); - return bytes; - } - - /** - * Converts a byte array beginning at <code>offset</code> into a 32 bit - * integer (little-endian representation) - * - * @param bytes the byte array - * @return The resulting integer - */ - public int bytesToIntLittleEndian(byte[] bytes) - { - - return ((bytes[0] & 0xff)) | ((bytes[1] & 0xff) << 8) - | ((bytes[2] & 0xff) << 16) | ((bytes[3] & 0xff)) << 24; - } - - /** - * Converts a byte array beginning at <code>offset</code> into a 32 bit - * integer (little-endian representation) - * - * @param bytes the byte array - * @param offset the integer offset into the byte array - * @return The resulting integer - */ - public int bytesToIntLittleEndian(byte[] bytes, int offset) - { - return ((bytes[offset++] & 0xff)) | ((bytes[offset++] & 0xff) << 8) - | ((bytes[offset++] & 0xff) << 16) - | ((bytes[offset] & 0xff)) << 24; - } - - /** - * This method concatenates a 2-dimensional byte array into a 1-dimensional - * byte array - * - * @param arraycp a 2-dimensional byte array. - * @return 1-dimensional byte array with concatenated input array - */ - public byte[] concatenateArray(byte[][] arraycp) - { - byte[] dest = new byte[arraycp.length * arraycp[0].length]; - int indx = 0; - for (int i = 0; i < arraycp.length; i++) - { - System.arraycopy(arraycp[i], 0, dest, indx, arraycp[i].length); - indx = indx + arraycp[i].length; - } - return dest; - } - - /** - * This method prints the values of a 2-dimensional byte array - * - * @param text a String - * @param array a 2-dimensional byte array - */ - public void printArray(String text, byte[][] array) - { - System.out.println(text); - int counter = 0; - for (int i = 0; i < array.length; i++) - { - for (int j = 0; j < array[0].length; j++) - { - System.out.println(counter + "; " + array[i][j]); - counter++; - } - } - } - - /** - * This method prints the values of a 1-dimensional byte array - * - * @param text a String - * @param array a 1-dimensional byte array. - */ - public void printArray(String text, byte[] array) - { - System.out.println(text); - int counter = 0; - for (int i = 0; i < array.length; i++) - { - System.out.println(counter + "; " + array[i]); - counter++; - } - } - - /** - * This method tests if an integer is a power of 2. - * - * @param testValue an integer - * @return <code>TRUE</code> if <code>testValue</code> is a power of 2, - * <code>FALSE</code> otherwise - */ - public boolean testPowerOfTwo(int testValue) - { - int a = 1; - while (a < testValue) - { - a <<= 1; - } - if (testValue == a) - { - return true; - } - - return false; - } - - /** - * This method returns the least integer that is greater or equal to the - * logarithm to the base 2 of an integer <code>intValue</code>. - * - * @param intValue an integer - * @return The least integer greater or equal to the logarithm to the base 2 - * of <code>intValue</code> - */ - public int getLog(int intValue) - { - int log = 1; - int i = 2; - while (i < intValue) - { - i <<= 1; - log++; - } - return log; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/util/WinternitzOTSVerify.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/util/WinternitzOTSVerify.java deleted file mode 100644 index d012ce7c..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/util/WinternitzOTSVerify.java +++ /dev/null @@ -1,344 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss.util; - -import org.bouncycastle.crypto.Digest; - -/** - * This class implements signature verification of the Winternitz one-time - * signature scheme (OTSS), described in C.Dods, N.P. Smart, and M. Stam, "Hash - * Based Digital Signature Schemes", LNCS 3796, pages 96–115, 2005. The - * class is used by the GMSS classes. - */ -public class WinternitzOTSVerify -{ - - private Digest messDigestOTS; - - /** - * The Winternitz parameter - */ - private int w; - - /** - * The constructor - * - * @param digest the name of the hash function used by the OTS and the provider - * name of the hash function - * @param w the Winternitz parameter - */ - public WinternitzOTSVerify(Digest digest, int w) - { - this.w = w; - - messDigestOTS = digest; - } - - /** - * @return The length of the one-time signature - */ - public int getSignatureLength() - { - int mdsize = messDigestOTS.getDigestSize(); - int size = ((mdsize << 3) + (w - 1)) / w; - int logs = getLog((size << w) + 1); - size += (logs + w - 1) / w; - - return mdsize * size; - } - - /** - * This method computes the public OTS key from the one-time signature of a - * message. This is *NOT* a complete OTS signature verification, but it - * suffices for usage with CMSS. - * - * @param message the message - * @param signature the one-time signature - * @return The public OTS key - */ - public byte[] Verify(byte[] message, byte[] signature) - { - - int mdsize = messDigestOTS.getDigestSize(); - byte[] hash = new byte[mdsize]; // hash of message m - - // create hash of message m - messDigestOTS.update(message, 0, message.length); - hash = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hash, 0); - - int size = ((mdsize << 3) + (w - 1)) / w; - int logs = getLog((size << w) + 1); - int keysize = size + (logs + w - 1) / w; - - int testKeySize = mdsize * keysize; - - if (testKeySize != signature.length) - { - return null; - } - - byte[] testKey = new byte[testKeySize]; - - int c = 0; - int counter = 0; - int test; - - if (8 % w == 0) - { - int d = 8 / w; - int k = (1 << w) - 1; - byte[] hlp = new byte[mdsize]; - - // verify signature - for (int i = 0; i < hash.length; i++) - { - for (int j = 0; j < d; j++) - { - test = hash[i] & k; - c += test; - - System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize); - - while (test < k) - { - messDigestOTS.update(hlp, 0, hlp.length); - hlp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hlp, 0); - test++; - } - - System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize); - hash[i] = (byte)(hash[i] >>> w); - counter++; - } - } - - c = (size << w) - c; - for (int i = 0; i < logs; i += w) - { - test = c & k; - - System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize); - - while (test < k) - { - messDigestOTS.update(hlp, 0, hlp.length); - hlp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hlp, 0); - test++; - } - System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize); - c >>>= w; - counter++; - } - } - else if (w < 8) - { - int d = mdsize / w; - int k = (1 << w) - 1; - byte[] hlp = new byte[mdsize]; - long big8; - int ii = 0; - // create signature - // first d*w bytes of hash - for (int i = 0; i < d; i++) - { - big8 = 0; - for (int j = 0; j < w; j++) - { - big8 ^= (hash[ii] & 0xff) << (j << 3); - ii++; - } - for (int j = 0; j < 8; j++) - { - test = (int)(big8 & k); - c += test; - - System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize); - - while (test < k) - { - messDigestOTS.update(hlp, 0, hlp.length); - hlp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hlp, 0); - test++; - } - - System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize); - big8 >>>= w; - counter++; - } - } - // rest of hash - d = mdsize % w; - big8 = 0; - for (int j = 0; j < d; j++) - { - big8 ^= (hash[ii] & 0xff) << (j << 3); - ii++; - } - d <<= 3; - for (int j = 0; j < d; j += w) - { - test = (int)(big8 & k); - c += test; - - System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize); - - while (test < k) - { - messDigestOTS.update(hlp, 0, hlp.length); - hlp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hlp, 0); - test++; - } - - System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize); - big8 >>>= w; - counter++; - } - - // check bytes - c = (size << w) - c; - for (int i = 0; i < logs; i += w) - { - test = c & k; - - System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize); - - while (test < k) - { - messDigestOTS.update(hlp, 0, hlp.length); - hlp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hlp, 0); - test++; - } - - System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize); - c >>>= w; - counter++; - } - }// end if(w<8) - else if (w < 57) - { - int d = (mdsize << 3) - w; - int k = (1 << w) - 1; - byte[] hlp = new byte[mdsize]; - long big8, test8; - int r = 0; - int s, f, rest, ii; - // create signature - // first a*w bits of hash where a*w <= 8*mdsize < (a+1)*w - while (r <= d) - { - s = r >>> 3; - rest = r % 8; - r += w; - f = (r + 7) >>> 3; - big8 = 0; - ii = 0; - for (int j = s; j < f; j++) - { - big8 ^= (hash[j] & 0xff) << (ii << 3); - ii++; - } - - big8 >>>= rest; - test8 = (big8 & k); - c += test8; - - System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize); - - while (test8 < k) - { - messDigestOTS.update(hlp, 0, hlp.length); - hlp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hlp, 0); - test8++; - } - - System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize); - counter++; - - } - // rest of hash - s = r >>> 3; - if (s < mdsize) - { - rest = r % 8; - big8 = 0; - ii = 0; - for (int j = s; j < mdsize; j++) - { - big8 ^= (hash[j] & 0xff) << (ii << 3); - ii++; - } - - big8 >>>= rest; - test8 = (big8 & k); - c += test8; - - System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize); - - while (test8 < k) - { - messDigestOTS.update(hlp, 0, hlp.length); - hlp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hlp, 0); - test8++; - } - - System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize); - counter++; - } - // check bytes - c = (size << w) - c; - for (int i = 0; i < logs; i += w) - { - test8 = (c & k); - - System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize); - - while (test8 < k) - { - messDigestOTS.update(hlp, 0, hlp.length); - hlp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hlp, 0); - test8++; - } - - System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize); - c >>>= w; - counter++; - } - }// end if(w<57) - - byte[] TKey = new byte[mdsize]; - messDigestOTS.update(testKey, 0, testKey.length); - TKey = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(TKey, 0); - - return TKey; - - } - - /** - * This method returns the least integer that is greater or equal to the - * logarithm to the base 2 of an integer <code>intValue</code>. - * - * @param intValue an integer - * @return The least integer greater or equal to the logarithm to the base - * 256 of <code>intValue</code> - */ - public int getLog(int intValue) - { - int log = 1; - int i = 2; - while (i < intValue) - { - i <<= 1; - log++; - } - return log; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/util/WinternitzOTSignature.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/util/WinternitzOTSignature.java deleted file mode 100644 index 23bf3fab..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gmss/util/WinternitzOTSignature.java +++ /dev/null @@ -1,404 +0,0 @@ -package org.bouncycastle.pqc.crypto.gmss.util; - -import org.bouncycastle.crypto.Digest; - -/** - * This class implements key pair generation and signature generation of the - * Winternitz one-time signature scheme (OTSS), described in C.Dods, N.P. Smart, - * and M. Stam, "Hash Based Digital Signature Schemes", LNCS 3796, pages - * 96–115, 2005. The class is used by the GMSS classes. - */ - -public class WinternitzOTSignature -{ - - /** - * The hash function used by the OTS - */ - private Digest messDigestOTS; - - /** - * The length of the message digest and private key - */ - private int mdsize, keysize; - - /** - * An array of strings, containing the name of the used hash function, the - * name of the PRGN and the names of the corresponding providers - */ - // private String[] name = new String[2]; - /** - * The private key - */ - private byte[][] privateKeyOTS; - - /** - * The Winternitz parameter - */ - private int w; - - /** - * The source of randomness for OTS private key generation - */ - private GMSSRandom gmssRandom; - - /** - * Sizes of the message and the checksum, both - */ - private int messagesize, checksumsize; - - /** - * The constructor generates an OTS key pair, using <code>seed0</code> and - * the PRNG - * - * @param seed0 the seed for the PRGN - * @param digest an array of strings, containing the name of the used hash - * function, the name of the PRGN and the names of the - * corresponding providers - * @param w the Winternitz parameter - */ - public WinternitzOTSignature(byte[] seed0, Digest digest, int w) - { - // this.name = name; - this.w = w; - - messDigestOTS = digest; - - gmssRandom = new GMSSRandom(messDigestOTS); - - // calulate keysize for private and public key and also the help - // array - - mdsize = messDigestOTS.getDigestSize(); - int mdsizeBit = mdsize << 3; - messagesize = (int)Math.ceil((double)(mdsizeBit) / (double)w); - - checksumsize = getLog((messagesize << w) + 1); - - keysize = messagesize - + (int)Math.ceil((double)checksumsize / (double)w); - - /* - * mdsize = messDigestOTS.getDigestLength(); messagesize = - * ((mdsize<<3)+(w-1))/w; - * - * checksumsize = getlog((messagesize<<w)+1); - * - * keysize = messagesize + (checksumsize+w-1)/w; - */ - // define the private key messagesize - privateKeyOTS = new byte[keysize][mdsize]; - - // gmssRandom.setSeed(seed0); - byte[] dummy = new byte[mdsize]; - System.arraycopy(seed0, 0, dummy, 0, dummy.length); - - // generate random bytes and - // assign them to the private key - for (int i = 0; i < keysize; i++) - { - privateKeyOTS[i] = gmssRandom.nextSeed(dummy); - } - } - - /** - * @return The private OTS key - */ - public byte[][] getPrivateKey() - { - return privateKeyOTS; - } - - /** - * @return The public OTS key - */ - public byte[] getPublicKey() - { - byte[] helppubKey = new byte[keysize * mdsize]; - - byte[] help = new byte[mdsize]; - int two_power_t = 1 << w; - - for (int i = 0; i < keysize; i++) - { - // hash w-1 time the private key and assign it to the public key - messDigestOTS.update(privateKeyOTS[i], 0, privateKeyOTS[i].length); - help = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(help, 0); - for (int j = 2; j < two_power_t; j++) - { - messDigestOTS.update(help, 0, help.length); - help = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(help, 0); - } - System.arraycopy(help, 0, helppubKey, mdsize * i, mdsize); - } - - messDigestOTS.update(helppubKey, 0, helppubKey.length); - byte[] tmp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(tmp, 0); - return tmp; - } - - /** - * @return The one-time signature of the message, generated with the private - * key - */ - public byte[] getSignature(byte[] message) - { - byte[] sign = new byte[keysize * mdsize]; - // byte [] message; // message m as input - byte[] hash = new byte[mdsize]; // hash of message m - int counter = 0; - int c = 0; - int test = 0; - // create hash of message m - messDigestOTS.update(message, 0, message.length); - hash = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hash, 0); - - if (8 % w == 0) - { - int d = 8 / w; - int k = (1 << w) - 1; - byte[] hlp = new byte[mdsize]; - - // create signature - for (int i = 0; i < hash.length; i++) - { - for (int j = 0; j < d; j++) - { - test = hash[i] & k; - c += test; - - System.arraycopy(privateKeyOTS[counter], 0, hlp, 0, mdsize); - - while (test > 0) - { - messDigestOTS.update(hlp, 0, hlp.length); - hlp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hlp, 0); - test--; - } - System.arraycopy(hlp, 0, sign, counter * mdsize, mdsize); - hash[i] = (byte)(hash[i] >>> w); - counter++; - } - } - - c = (messagesize << w) - c; - for (int i = 0; i < checksumsize; i += w) - { - test = c & k; - - System.arraycopy(privateKeyOTS[counter], 0, hlp, 0, mdsize); - - while (test > 0) - { - messDigestOTS.update(hlp, 0, hlp.length); - hlp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hlp, 0); - test--; - } - System.arraycopy(hlp, 0, sign, counter * mdsize, mdsize); - c >>>= w; - counter++; - } - } - else if (w < 8) - { - int d = mdsize / w; - int k = (1 << w) - 1; - byte[] hlp = new byte[mdsize]; - long big8; - int ii = 0; - // create signature - // first d*w bytes of hash - for (int i = 0; i < d; i++) - { - big8 = 0; - for (int j = 0; j < w; j++) - { - big8 ^= (hash[ii] & 0xff) << (j << 3); - ii++; - } - for (int j = 0; j < 8; j++) - { - test = (int)(big8 & k); - c += test; - - System.arraycopy(privateKeyOTS[counter], 0, hlp, 0, mdsize); - - while (test > 0) - { - messDigestOTS.update(hlp, 0, hlp.length); - hlp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hlp, 0); - test--; - } - System.arraycopy(hlp, 0, sign, counter * mdsize, mdsize); - big8 >>>= w; - counter++; - } - } - // rest of hash - d = mdsize % w; - big8 = 0; - for (int j = 0; j < d; j++) - { - big8 ^= (hash[ii] & 0xff) << (j << 3); - ii++; - } - d <<= 3; - for (int j = 0; j < d; j += w) - { - test = (int)(big8 & k); - c += test; - - System.arraycopy(privateKeyOTS[counter], 0, hlp, 0, mdsize); - - while (test > 0) - { - messDigestOTS.update(hlp, 0, hlp.length); - hlp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hlp, 0); - test--; - } - System.arraycopy(hlp, 0, sign, counter * mdsize, mdsize); - big8 >>>= w; - counter++; - } - - // check bytes - c = (messagesize << w) - c; - for (int i = 0; i < checksumsize; i += w) - { - test = c & k; - - System.arraycopy(privateKeyOTS[counter], 0, hlp, 0, mdsize); - - while (test > 0) - { - messDigestOTS.update(hlp, 0, hlp.length); - hlp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hlp, 0); - test--; - } - System.arraycopy(hlp, 0, sign, counter * mdsize, mdsize); - c >>>= w; - counter++; - } - }// end if(w<8) - else if (w < 57) - { - int d = (mdsize << 3) - w; - int k = (1 << w) - 1; - byte[] hlp = new byte[mdsize]; - long big8, test8; - int r = 0; - int s, f, rest, ii; - // create signature - // first a*w bits of hash where a*w <= 8*mdsize < (a+1)*w - while (r <= d) - { - s = r >>> 3; - rest = r % 8; - r += w; - f = (r + 7) >>> 3; - big8 = 0; - ii = 0; - for (int j = s; j < f; j++) - { - big8 ^= (hash[j] & 0xff) << (ii << 3); - ii++; - } - - big8 >>>= rest; - test8 = (big8 & k); - c += test8; - - System.arraycopy(privateKeyOTS[counter], 0, hlp, 0, mdsize); - while (test8 > 0) - { - messDigestOTS.update(hlp, 0, hlp.length); - hlp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hlp, 0); - test8--; - } - System.arraycopy(hlp, 0, sign, counter * mdsize, mdsize); - counter++; - - } - // rest of hash - s = r >>> 3; - if (s < mdsize) - { - rest = r % 8; - big8 = 0; - ii = 0; - for (int j = s; j < mdsize; j++) - { - big8 ^= (hash[j] & 0xff) << (ii << 3); - ii++; - } - - big8 >>>= rest; - test8 = (big8 & k); - c += test8; - - System.arraycopy(privateKeyOTS[counter], 0, hlp, 0, mdsize); - while (test8 > 0) - { - messDigestOTS.update(hlp, 0, hlp.length); - hlp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hlp, 0); - test8--; - } - System.arraycopy(hlp, 0, sign, counter * mdsize, mdsize); - counter++; - } - // check bytes - c = (messagesize << w) - c; - for (int i = 0; i < checksumsize; i += w) - { - test8 = (c & k); - - System.arraycopy(privateKeyOTS[counter], 0, hlp, 0, mdsize); - - while (test8 > 0) - { - messDigestOTS.update(hlp, 0, hlp.length); - hlp = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(hlp, 0); - test8--; - } - System.arraycopy(hlp, 0, sign, counter * mdsize, mdsize); - c >>>= w; - counter++; - } - }// end if(w<57) - - return sign; - } - - /** - * This method returns the least integer that is greater or equal to the - * logarithm to the base 2 of an integer <code>intValue</code>. - * - * @param intValue an integer - * @return The least integer greater or equal to the logarithm to the base 2 - * of <code>intValue</code> - */ - public int getLog(int intValue) - { - int log = 1; - int i = 2; - while (i < intValue) - { - i <<= 1; - log++; - } - return log; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/Conversions.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/Conversions.java deleted file mode 100644 index 752d51cc..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/Conversions.java +++ /dev/null @@ -1,236 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - -import java.math.BigInteger; - -import org.bouncycastle.pqc.math.linearalgebra.BigIntUtils; -import org.bouncycastle.pqc.math.linearalgebra.GF2Vector; -import org.bouncycastle.pqc.math.linearalgebra.IntegerFunctions; - - -/** - * Provides methods for CCA2-Secure Conversions of McEliece PKCS - */ -final class Conversions -{ - private static final BigInteger ZERO = BigInteger.valueOf(0); - private static final BigInteger ONE = BigInteger.valueOf(1); - - /** - * Default constructor (private). - */ - private Conversions() - { - } - - /** - * Encode a number between 0 and (n|t) (binomial coefficient) into a binary - * vector of length n with weight t. The number is given as a byte array. - * Only the first s bits are used, where s = floor[log(n|t)]. - * - * @param n integer - * @param t integer - * @param m the message as a byte array - * @return the encoded message as {@link GF2Vector} - */ - public static GF2Vector encode(final int n, final int t, final byte[] m) - { - if (n < t) - { - throw new IllegalArgumentException("n < t"); - } - - // compute the binomial c = (n|t) - BigInteger c = IntegerFunctions.binomial(n, t); - // get the number encoded in m - BigInteger i = new BigInteger(1, m); - // compare - if (i.compareTo(c) >= 0) - { - throw new IllegalArgumentException("Encoded number too large."); - } - - GF2Vector result = new GF2Vector(n); - - int nn = n; - int tt = t; - for (int j = 0; j < n; j++) - { - c = c.multiply(BigInteger.valueOf(nn - tt)).divide( - BigInteger.valueOf(nn)); - nn--; - if (c.compareTo(i) <= 0) - { - result.setBit(j); - i = i.subtract(c); - tt--; - if (nn == tt) - { - c = ONE; - } - else - { - c = (c.multiply(BigInteger.valueOf(tt + 1))) - .divide(BigInteger.valueOf(nn - tt)); - } - } - } - - return result; - } - - /** - * Decode a binary vector of length n and weight t into a number between 0 - * and (n|t) (binomial coefficient). The result is given as a byte array of - * length floor[(s+7)/8], where s = floor[log(n|t)]. - * - * @param n integer - * @param t integer - * @param vec the binary vector - * @return the decoded vector as a byte array - */ - public static byte[] decode(int n, int t, GF2Vector vec) - { - if ((vec.getLength() != n) || (vec.getHammingWeight() != t)) - { - throw new IllegalArgumentException( - "vector has wrong length or hamming weight"); - } - int[] vecArray = vec.getVecArray(); - - BigInteger bc = IntegerFunctions.binomial(n, t); - BigInteger d = ZERO; - int nn = n; - int tt = t; - for (int i = 0; i < n; i++) - { - bc = bc.multiply(BigInteger.valueOf(nn - tt)).divide( - BigInteger.valueOf(nn)); - nn--; - - int q = i >> 5; - int e = vecArray[q] & (1 << (i & 0x1f)); - if (e != 0) - { - d = d.add(bc); - tt--; - if (nn == tt) - { - bc = ONE; - } - else - { - bc = bc.multiply(BigInteger.valueOf(tt + 1)).divide( - BigInteger.valueOf(nn - tt)); - } - - } - } - - return BigIntUtils.toMinimalByteArray(d); - } - - /** - * Compute a message representative of a message given as a vector of length - * <tt>n</tt> bit and of hamming weight <tt>t</tt>. The result is a - * byte array of length <tt>(s+7)/8</tt>, where - * <tt>s = floor[log(n|t)]</tt>. - * - * @param n integer - * @param t integer - * @param m the message vector as a byte array - * @return a message representative for <tt>m</tt> - */ - public static byte[] signConversion(int n, int t, byte[] m) - { - if (n < t) - { - throw new IllegalArgumentException("n < t"); - } - - BigInteger bc = IntegerFunctions.binomial(n, t); - // finds s = floor[log(binomial(n,t))] - int s = bc.bitLength() - 1; - // s = sq*8 + sr; - int sq = s >> 3; - int sr = s & 7; - if (sr == 0) - { - sq--; - sr = 8; - } - - // n = nq*8+nr; - int nq = n >> 3; - int nr = n & 7; - if (nr == 0) - { - nq--; - nr = 8; - } - // take s bit from m - byte[] data = new byte[nq + 1]; - if (m.length < data.length) - { - System.arraycopy(m, 0, data, 0, m.length); - for (int i = m.length; i < data.length; i++) - { - data[i] = 0; - } - } - else - { - System.arraycopy(m, 0, data, 0, nq); - int h = (1 << nr) - 1; - data[nq] = (byte)(h & m[nq]); - } - - BigInteger d = ZERO; - int nn = n; - int tt = t; - for (int i = 0; i < n; i++) - { - bc = (bc.multiply(new BigInteger(Integer.toString(nn - tt)))) - .divide(new BigInteger(Integer.toString(nn))); - nn--; - - int q = i >>> 3; - int r = i & 7; - r = 1 << r; - byte e = (byte)(r & data[q]); - if (e != 0) - { - d = d.add(bc); - tt--; - if (nn == tt) - { - bc = ONE; - } - else - { - bc = (bc - .multiply(new BigInteger(Integer.toString(tt + 1)))) - .divide(new BigInteger(Integer.toString(nn - tt))); - } - } - } - - byte[] result = new byte[sq + 1]; - byte[] help = d.toByteArray(); - if (help.length < result.length) - { - System.arraycopy(help, 0, result, 0, help.length); - for (int i = help.length; i < result.length; i++) - { - result[i] = 0; - } - } - else - { - System.arraycopy(help, 0, result, 0, sq); - result[sq] = (byte)(((1 << sr) - 1) & help[sq]); - } - - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyGenerationParameters.java deleted file mode 100644 index dbd5a82a..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyGenerationParameters.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.KeyGenerationParameters; - -public class McElieceCCA2KeyGenerationParameters - extends KeyGenerationParameters -{ - private McElieceCCA2Parameters params; - - public McElieceCCA2KeyGenerationParameters( - SecureRandom random, - McElieceCCA2Parameters params) - { - // XXX key size? - super(random, 128); - this.params = params; - } - - public McElieceCCA2Parameters getParameters() - { - return params; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyPairGenerator.java deleted file mode 100644 index 198e5d29..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyPairGenerator.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.math.linearalgebra.GoppaCode; -import org.bouncycastle.pqc.math.linearalgebra.GoppaCode.MaMaPe; -import org.bouncycastle.pqc.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM; -import org.bouncycastle.pqc.math.linearalgebra.PolynomialRingGF2m; - - -/** - * This class implements key pair generation of the McEliece Public Key - * Cryptosystem (McEliecePKC). - */ -public class McElieceCCA2KeyPairGenerator - implements AsymmetricCipherKeyPairGenerator -{ - - - /** - * The OID of the algorithm. - */ - public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2"; - - private McElieceCCA2KeyGenerationParameters mcElieceCCA2Params; - - // the extension degree of the finite field GF(2^m) - private int m; - - // the length of the code - private int n; - - // the error correction capability - private int t; - - // the field polynomial - private int fieldPoly; - - // the source of randomness - private SecureRandom random; - - // flag indicating whether the key pair generator has been initialized - private boolean initialized = false; - - /** - * Default initialization of the key pair generator. - */ - private void initializeDefault() - { - McElieceCCA2KeyGenerationParameters mcCCA2Params = new McElieceCCA2KeyGenerationParameters(new SecureRandom(), new McElieceCCA2Parameters()); - init(mcCCA2Params); - } - - // TODO - public void init( - KeyGenerationParameters param) - { - this.mcElieceCCA2Params = (McElieceCCA2KeyGenerationParameters)param; - - // set source of randomness - this.random = new SecureRandom(); - - this.m = this.mcElieceCCA2Params.getParameters().getM(); - this.n = this.mcElieceCCA2Params.getParameters().getN(); - this.t = this.mcElieceCCA2Params.getParameters().getT(); - this.fieldPoly = this.mcElieceCCA2Params.getParameters().getFieldPoly(); - this.initialized = true; - } - - - public AsymmetricCipherKeyPair generateKeyPair() - { - - if (!initialized) - { - initializeDefault(); - } - - // finite field GF(2^m) - GF2mField field = new GF2mField(m, fieldPoly); - - // irreducible Goppa polynomial - PolynomialGF2mSmallM gp = new PolynomialGF2mSmallM(field, t, - PolynomialGF2mSmallM.RANDOM_IRREDUCIBLE_POLYNOMIAL, random); - PolynomialRingGF2m ring = new PolynomialRingGF2m(field, gp); - - // matrix for computing square roots in (GF(2^m))^t - PolynomialGF2mSmallM[] qInv = ring.getSquareRootMatrix(); - - // generate canonical check matrix - GF2Matrix h = GoppaCode.createCanonicalCheckMatrix(field, gp); - - // compute short systematic form of check matrix - MaMaPe mmp = GoppaCode.computeSystematicForm(h, random); - GF2Matrix shortH = mmp.getSecondMatrix(); - Permutation p = mmp.getPermutation(); - - // compute short systematic form of generator matrix - GF2Matrix shortG = (GF2Matrix)shortH.computeTranspose(); - - // obtain number of rows of G (= dimension of the code) - int k = shortG.getNumRows(); - - // generate keys - McElieceCCA2PublicKeyParameters pubKey = new McElieceCCA2PublicKeyParameters(OID, n, t, shortG, mcElieceCCA2Params.getParameters()); - McElieceCCA2PrivateKeyParameters privKey = new McElieceCCA2PrivateKeyParameters(OID, n, k, - field, gp, p, h, qInv, mcElieceCCA2Params.getParameters()); - - // return key pair - return new AsymmetricCipherKeyPair(pubKey, privKey); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyParameters.java deleted file mode 100644 index 80114767..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2KeyParameters.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; - - -public class McElieceCCA2KeyParameters - extends AsymmetricKeyParameter -{ - private McElieceCCA2Parameters params; - - public McElieceCCA2KeyParameters( - boolean isPrivate, - McElieceCCA2Parameters params) - { - super(isPrivate); - this.params = params; - } - - - public McElieceCCA2Parameters getParameters() - { - return params; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2Parameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2Parameters.java deleted file mode 100644 index 7f800106..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2Parameters.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; - -/** - * This class provides a specification for the parameters of the CCA2-secure - * variants of the McEliece PKCS that are used with - * {@link McElieceFujisakiCipher}, {@link McElieceKobaraImaiCipher}, and - * {@link McEliecePointchevalCipher}. - * - * @see McElieceFujisakiCipher - * @see McElieceKobaraImaiCipher - * @see McEliecePointchevalCipher - */ -public class McElieceCCA2Parameters - extends McElieceParameters -{ - - - public Digest digest; - - - /** - * Construct the default parameters. - * The default message digest is SHA256. - */ - public McElieceCCA2Parameters() - { - this.digest = new SHA256Digest(); - } - - public McElieceCCA2Parameters(int m, int t) - { - super(m, t); - this.digest = new SHA256Digest(); - } - - public McElieceCCA2Parameters(Digest digest) - { - this.digest = digest; - } - - public Digest getDigest() - { - return this.digest; - } - - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2Primitives.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2Primitives.java deleted file mode 100644 index 726add15..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2Primitives.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - -import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.math.linearalgebra.GF2Vector; -import org.bouncycastle.pqc.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.math.linearalgebra.GoppaCode; -import org.bouncycastle.pqc.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM; -import org.bouncycastle.pqc.math.linearalgebra.Vector; - -/** - * Core operations for the CCA-secure variants of McEliece. - */ -public final class McElieceCCA2Primitives -{ - - /** - * Default constructor (private). - */ - private McElieceCCA2Primitives() - { - } - - /** - * The McEliece encryption primitive. - * - * @param pubKey the public key - * @param m the message vector - * @param z the error vector - * @return <tt>m*G + z</tt> - */ - - - public static GF2Vector encryptionPrimitive(McElieceCCA2PublicKeyParameters pubKey, - GF2Vector m, GF2Vector z) - { - - GF2Matrix matrixG = pubKey.getMatrixG(); - Vector mG = matrixG.leftMultiplyLeftCompactForm(m); - return (GF2Vector)mG.add(z); - } - - /** - * The McEliece decryption primitive. - * - * @param privKey the private key - * @param c the ciphertext vector <tt>c = m*G + z</tt> - * @return the message vector <tt>m</tt> and the error vector <tt>z</tt> - */ - public static GF2Vector[] decryptionPrimitive( - McElieceCCA2PrivateKeyParameters privKey, GF2Vector c) - { - - // obtain values from private key - int k = privKey.getK(); - Permutation p = privKey.getP(); - GF2mField field = privKey.getField(); - PolynomialGF2mSmallM gp = privKey.getGoppaPoly(); - GF2Matrix h = privKey.getH(); - PolynomialGF2mSmallM[] q = privKey.getQInv(); - - // compute inverse permutation P^-1 - Permutation pInv = p.computeInverse(); - - // multiply c with permutation P^-1 - GF2Vector cPInv = (GF2Vector)c.multiply(pInv); - - // compute syndrome of cP^-1 - GF2Vector syndVec = (GF2Vector)h.rightMultiply(cPInv); - - // decode syndrome - GF2Vector errors = GoppaCode.syndromeDecode(syndVec, field, gp, q); - GF2Vector mG = (GF2Vector)cPInv.add(errors); - - // multiply codeword and error vector with P - mG = (GF2Vector)mG.multiply(p); - errors = (GF2Vector)errors.multiply(p); - - // extract plaintext vector (last k columns of mG) - GF2Vector m = mG.extractRightVector(k); - - // return vectors - return new GF2Vector[]{m, errors}; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2PrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2PrivateKeyParameters.java deleted file mode 100644 index 980ecdc9..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2PrivateKeyParameters.java +++ /dev/null @@ -1,172 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - - -import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM; - -/** - * - * - * - */ -public class McElieceCCA2PrivateKeyParameters - extends McElieceCCA2KeyParameters -{ - - // the OID of the algorithm - private String oid; - - // the length of the code - private int n; - - // the dimension of the code - private int k; - - // the finte field GF(2^m) - private GF2mField field; - - // the irreducible Goppa polynomial - private PolynomialGF2mSmallM goppaPoly; - - // the permutation - private Permutation p; - - // the canonical check matrix - private GF2Matrix h; - - // the matrix used to compute square roots in (GF(2^m))^t - private PolynomialGF2mSmallM[] qInv; - - /** - * Constructor. - * - * @param n the length of the code - * @param k the dimension of the code - * @param field the finite field <tt>GF(2<sup>m</sup>)</tt> - * @param gp the irreducible Goppa polynomial - * @param p the permutation - * @param h the canonical check matrix - * @param qInv the matrix used to compute square roots in - * <tt>(GF(2^m))^t</tt> - * @param params McElieceCCA2Parameters - */ - public McElieceCCA2PrivateKeyParameters(String oid, int n, int k, GF2mField field, - PolynomialGF2mSmallM gp, Permutation p, GF2Matrix h, - PolynomialGF2mSmallM[] qInv, McElieceCCA2Parameters params) - { - super(true, params); - this.oid = oid; - this.n = n; - this.k = k; - this.field = field; - this.goppaPoly = gp; - this.p = p; - this.h = h; - this.qInv = qInv; - } - - /** - * Constructor used by the {@link McElieceKeyFactory}. - * - * @param n the length of the code - * @param k the dimension of the code - * @param encFieldPoly the encoded field polynomial defining the finite field - * <tt>GF(2<sup>m</sup>)</tt> - * @param encGoppaPoly the encoded irreducible Goppa polynomial - * @param encP the encoded permutation - * @param encH the encoded canonical check matrix - * @param encQInv the encoded matrix used to compute square roots in - * <tt>(GF(2^m))^t</tt> - * @param params McElieceCCA2Parameters - */ - public McElieceCCA2PrivateKeyParameters(String oid, int n, int k, byte[] encFieldPoly, - byte[] encGoppaPoly, byte[] encP, byte[] encH, byte[][] encQInv, McElieceCCA2Parameters params) - { - super(true, params); - this.oid = oid; - this.n = n; - this.k = k; - field = new GF2mField(encFieldPoly); - goppaPoly = new PolynomialGF2mSmallM(field, encGoppaPoly); - p = new Permutation(encP); - h = new GF2Matrix(encH); - qInv = new PolynomialGF2mSmallM[encQInv.length]; - for (int i = 0; i < encQInv.length; i++) - { - qInv[i] = new PolynomialGF2mSmallM(field, encQInv[i]); - } - } - - /** - * @return the length of the code - */ - public int getN() - { - return n; - } - - /** - * @return the dimension of the code - */ - public int getK() - { - return k; - } - - /** - * @return the degree of the Goppa polynomial (error correcting capability) - */ - public int getT() - { - return goppaPoly.getDegree(); - } - - /** - * @return the finite field - */ - public GF2mField getField() - { - return field; - } - - /** - * @return the irreducible Goppa polynomial - */ - public PolynomialGF2mSmallM getGoppaPoly() - { - return goppaPoly; - } - - /** - * @return the permutation P - */ - public Permutation getP() - { - return p; - } - - /** - * @return the canonical check matrix H - */ - public GF2Matrix getH() - { - return h; - } - - /** - * @return the matrix used to compute square roots in <tt>(GF(2^m))^t</tt> - */ - public PolynomialGF2mSmallM[] getQInv() - { - return qInv; - } - - public String getOIDString() - { - return oid; - - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2PublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2PublicKeyParameters.java deleted file mode 100644 index e63377c3..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceCCA2PublicKeyParameters.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - -import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix; - -/** - * - * - * - */ -public class McElieceCCA2PublicKeyParameters - extends McElieceCCA2KeyParameters -{ - - // the OID of the algorithm - private String oid; - - // the length of the code - private int n; - - // the error correction capability of the code - private int t; - - // the generator matrix - private GF2Matrix matrixG; - - /** - * Constructor. - * - * @param n length of the code - * @param t error correction capability - * @param matrix generator matrix - * @param params McElieceCCA2Parameters - */ - public McElieceCCA2PublicKeyParameters(String oid, int n, int t, GF2Matrix matrix, McElieceCCA2Parameters params) - { - super(false, params); - this.oid = oid; - this.n = n; - this.t = t; - this.matrixG = new GF2Matrix(matrix); - } - - /** - * Constructor (used by {@link McElieceKeyFactory}). - * - * @param n length of the code - * @param t error correction capability of the code - * @param encMatrix encoded generator matrix - * @param params McElieceCCA2Parameters - */ - public McElieceCCA2PublicKeyParameters(String oid, int n, int t, byte[] encMatrix, McElieceCCA2Parameters params) - { - super(false, params); - this.oid = oid; - this.n = n; - this.t = t; - this.matrixG = new GF2Matrix(encMatrix); - } - - /** - * @return the length of the code - */ - public int getN() - { - return n; - } - - /** - * @return the error correction capability of the code - */ - public int getT() - { - return t; - } - - /** - * @return the generator matrix - */ - public GF2Matrix getMatrixG() - { - return matrixG; - } - - /** - * @return the dimension of the code - */ - public int getK() - { - return matrixG.getNumRows(); - } - - public String getOIDString() - { - return oid; - - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceFujisakiCipher.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceFujisakiCipher.java deleted file mode 100644 index c414540f..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceFujisakiCipher.java +++ /dev/null @@ -1,218 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.crypto.prng.DigestRandomGenerator; -import org.bouncycastle.pqc.crypto.MessageEncryptor; -import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; -import org.bouncycastle.pqc.math.linearalgebra.GF2Vector; - -/** - * This class implements the Fujisaki/Okamoto conversion of the McEliecePKCS. - * Fujisaki and Okamoto propose hybrid encryption that merges a symmetric - * encryption scheme which is secure in the find-guess model with an asymmetric - * one-way encryption scheme which is sufficiently probabilistic to obtain a - * public key cryptosystem which is CCA2-secure. For details, see D. Engelbert, - * R. Overbeck, A. Schmidt, "A summary of the development of the McEliece - * Cryptosystem", technical report. - */ -public class McElieceFujisakiCipher - implements MessageEncryptor -{ - - - /** - * The OID of the algorithm. - */ - public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2.1"; - - private static final String DEFAULT_PRNG_NAME = "SHA1PRNG"; - - private Digest messDigest; - - private SecureRandom sr; - - /** - * The McEliece main parameters - */ - private int n, k, t; - - McElieceCCA2KeyParameters key; - - - public void init(boolean forSigning, - CipherParameters param) - { - - if (forSigning) - { - if (param instanceof ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom)param; - - this.sr = rParam.getRandom(); - this.key = (McElieceCCA2PublicKeyParameters)rParam.getParameters(); - this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key); - - } - else - { - this.sr = new SecureRandom(); - this.key = (McElieceCCA2PublicKeyParameters)param; - this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key); - } - } - else - { - this.key = (McElieceCCA2PrivateKeyParameters)param; - this.initCipherDecrypt((McElieceCCA2PrivateKeyParameters)key); - } - - } - - - public int getKeySize(McElieceCCA2KeyParameters key) - throws IllegalArgumentException - { - - if (key instanceof McElieceCCA2PublicKeyParameters) - { - return ((McElieceCCA2PublicKeyParameters)key).getN(); - - } - if (key instanceof McElieceCCA2PrivateKeyParameters) - { - return ((McElieceCCA2PrivateKeyParameters)key).getN(); - } - throw new IllegalArgumentException("unsupported type"); - - } - - - private void initCipherEncrypt(McElieceCCA2PublicKeyParameters pubKey) - { - this.sr = sr != null ? sr : new SecureRandom(); - this.messDigest = pubKey.getParameters().getDigest(); - n = pubKey.getN(); - k = pubKey.getK(); - t = pubKey.getT(); - } - - - public void initCipherDecrypt(McElieceCCA2PrivateKeyParameters privKey) - { - this.messDigest = privKey.getParameters().getDigest(); - n = privKey.getN(); - t = privKey.getT(); - } - - - public byte[] messageEncrypt(byte[] input) - throws Exception - { - - // generate random vector r of length k bits - GF2Vector r = new GF2Vector(k, sr); - - // convert r to byte array - byte[] rBytes = r.getEncoded(); - - // compute (r||input) - byte[] rm = ByteUtils.concatenate(rBytes, input); - - // compute H(r||input) - messDigest.update(rm, 0, rm.length); - byte[] hrm = new byte[messDigest.getDigestSize()]; - messDigest.doFinal(hrm, 0); - - // convert H(r||input) to error vector z - GF2Vector z = Conversions.encode(n, t, hrm); - - // compute c1 = E(r, z) - byte[] c1 = McElieceCCA2Primitives.encryptionPrimitive((McElieceCCA2PublicKeyParameters)key, r, z) - .getEncoded(); - - // get PRNG object - DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest()); - - // seed PRNG with r' - sr0.addSeedMaterial(rBytes); - - // generate random c2 - byte[] c2 = new byte[input.length]; - sr0.nextBytes(c2); - - // XOR with input - for (int i = 0; i < input.length; i++) - { - c2[i] ^= input[i]; - } - - // return (c1||c2) - return ByteUtils.concatenate(c1, c2); - } - - public byte[] messageDecrypt(byte[] input) - throws Exception - { - - int c1Len = (n + 7) >> 3; - int c2Len = input.length - c1Len; - - // split ciphertext (c1||c2) - byte[][] c1c2 = ByteUtils.split(input, c1Len); - byte[] c1 = c1c2[0]; - byte[] c2 = c1c2[1]; - - // decrypt c1 ... - GF2Vector hrmVec = GF2Vector.OS2VP(n, c1); - GF2Vector[] decC1 = McElieceCCA2Primitives.decryptionPrimitive((McElieceCCA2PrivateKeyParameters)key, - hrmVec); - byte[] rBytes = decC1[0].getEncoded(); - // ... and obtain error vector z - GF2Vector z = decC1[1]; - - // get PRNG object - DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest()); - - // seed PRNG with r' - sr0.addSeedMaterial(rBytes); - - // generate random sequence - byte[] mBytes = new byte[c2Len]; - sr0.nextBytes(mBytes); - - // XOR with c2 to obtain m - for (int i = 0; i < c2Len; i++) - { - mBytes[i] ^= c2[i]; - } - - // compute H(r||m) - byte[] rmBytes = ByteUtils.concatenate(rBytes, mBytes); - byte[] hrm = new byte[messDigest.getDigestSize()]; - messDigest.update(rmBytes, 0, rmBytes.length); - messDigest.doFinal(hrm, 0); - - - // compute Conv(H(r||m)) - hrmVec = Conversions.encode(n, t, hrm); - - // check that Conv(H(m||r)) = z - if (!hrmVec.equals(z)) - { - - throw new Exception("Bad Padding: invalid ciphertext"); - - } - - // return plaintext m - return mBytes; - } - - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceFujisakiDigestCipher.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceFujisakiDigestCipher.java deleted file mode 100644 index 423e6ff8..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceFujisakiDigestCipher.java +++ /dev/null @@ -1,128 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.MessageEncryptor; - -// TODO should implement some interface? -public class McElieceFujisakiDigestCipher -{ - - private final Digest messDigest; - - private final MessageEncryptor mcElieceCCA2Cipher; - - private boolean forEncrypting; - - - public McElieceFujisakiDigestCipher(MessageEncryptor mcElieceCCA2Cipher, Digest messDigest) - { - this.mcElieceCCA2Cipher = mcElieceCCA2Cipher; - this.messDigest = messDigest; - } - - - public void init(boolean forEncrypting, - CipherParameters param) - { - - this.forEncrypting = forEncrypting; - AsymmetricKeyParameter k; - - if (param instanceof ParametersWithRandom) - { - k = (AsymmetricKeyParameter)((ParametersWithRandom)param).getParameters(); - } - else - { - k = (AsymmetricKeyParameter)param; - } - - if (forEncrypting && k.isPrivate()) - { - throw new IllegalArgumentException("Encrypting Requires Public Key."); - } - - if (!forEncrypting && !k.isPrivate()) - { - throw new IllegalArgumentException("Decrypting Requires Private Key."); - } - - reset(); - - mcElieceCCA2Cipher.init(forEncrypting, param); - } - - - public byte[] messageEncrypt() - { - if (!forEncrypting) - { - throw new IllegalStateException("McElieceFujisakiDigestCipher not initialised for encrypting."); - } - - byte[] hash = new byte[messDigest.getDigestSize()]; - messDigest.doFinal(hash, 0); - byte[] enc = null; - - try - { - enc = mcElieceCCA2Cipher.messageEncrypt(hash); - } - catch (Exception e) - { - e.printStackTrace(); - } - - - return enc; - } - - - public byte[] messageDecrypt(byte[] ciphertext) - { - byte[] output = null; - if (forEncrypting) - { - throw new IllegalStateException("McElieceFujisakiDigestCipher not initialised for decrypting."); - } - - - try - { - output = mcElieceCCA2Cipher.messageDecrypt(ciphertext); - } - catch (Exception e) - { - e.printStackTrace(); - } - - - return output; - } - - - public void update(byte b) - { - messDigest.update(b); - - } - - public void update(byte[] in, int off, int len) - { - messDigest.update(in, off, len); - - } - - - public void reset() - { - messDigest.reset(); - - } - - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyGenerationParameters.java deleted file mode 100644 index 1b1fa658..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyGenerationParameters.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.KeyGenerationParameters; - -public class McElieceKeyGenerationParameters - extends KeyGenerationParameters -{ - private McElieceParameters params; - - public McElieceKeyGenerationParameters( - SecureRandom random, - McElieceParameters params) - { - // XXX key size? - super(random, 256); - this.params = params; - } - - public McElieceParameters getParameters() - { - return params; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyPairGenerator.java deleted file mode 100644 index 6ad7fc2f..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyPairGenerator.java +++ /dev/null @@ -1,151 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.math.linearalgebra.GoppaCode; -import org.bouncycastle.pqc.math.linearalgebra.GoppaCode.MaMaPe; -import org.bouncycastle.pqc.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM; -import org.bouncycastle.pqc.math.linearalgebra.PolynomialRingGF2m; - - -/** - * This class implements key pair generation of the McEliece Public Key - * Cryptosystem (McEliecePKC). - */ -public class McElieceKeyPairGenerator - implements AsymmetricCipherKeyPairGenerator -{ - - - public McElieceKeyPairGenerator() - { - - } - - - /** - * The OID of the algorithm. - */ - private static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.1"; - - private McElieceKeyGenerationParameters mcElieceParams; - - // the extension degree of the finite field GF(2^m) - private int m; - - // the length of the code - private int n; - - // the error correction capability - private int t; - - // the field polynomial - private int fieldPoly; - - // the source of randomness - private SecureRandom random; - - // flag indicating whether the key pair generator has been initialized - private boolean initialized = false; - - - /** - * Default initialization of the key pair generator. - */ - private void initializeDefault() - { - McElieceKeyGenerationParameters mcParams = new McElieceKeyGenerationParameters(new SecureRandom(), new McElieceParameters()); - initialize(mcParams); - } - - private void initialize( - KeyGenerationParameters param) - { - this.mcElieceParams = (McElieceKeyGenerationParameters)param; - - // set source of randomness - this.random = new SecureRandom(); - - this.m = this.mcElieceParams.getParameters().getM(); - this.n = this.mcElieceParams.getParameters().getN(); - this.t = this.mcElieceParams.getParameters().getT(); - this.fieldPoly = this.mcElieceParams.getParameters().getFieldPoly(); - this.initialized = true; - } - - - private AsymmetricCipherKeyPair genKeyPair() - { - - if (!initialized) - { - initializeDefault(); - } - - // finite field GF(2^m) - GF2mField field = new GF2mField(m, fieldPoly); - - // irreducible Goppa polynomial - PolynomialGF2mSmallM gp = new PolynomialGF2mSmallM(field, t, - PolynomialGF2mSmallM.RANDOM_IRREDUCIBLE_POLYNOMIAL, random); - PolynomialRingGF2m ring = new PolynomialRingGF2m(field, gp); - - // matrix used to compute square roots in (GF(2^m))^t - PolynomialGF2mSmallM[] sqRootMatrix = ring.getSquareRootMatrix(); - - // generate canonical check matrix - GF2Matrix h = GoppaCode.createCanonicalCheckMatrix(field, gp); - - // compute short systematic form of check matrix - MaMaPe mmp = GoppaCode.computeSystematicForm(h, random); - GF2Matrix shortH = mmp.getSecondMatrix(); - Permutation p1 = mmp.getPermutation(); - - // compute short systematic form of generator matrix - GF2Matrix shortG = (GF2Matrix)shortH.computeTranspose(); - - // extend to full systematic form - GF2Matrix gPrime = shortG.extendLeftCompactForm(); - - // obtain number of rows of G (= dimension of the code) - int k = shortG.getNumRows(); - - // generate random invertible (k x k)-matrix S and its inverse S^-1 - GF2Matrix[] matrixSandInverse = GF2Matrix - .createRandomRegularMatrixAndItsInverse(k, random); - - // generate random permutation P2 - Permutation p2 = new Permutation(n, random); - - // compute public matrix G=S*G'*P2 - GF2Matrix g = (GF2Matrix)matrixSandInverse[0].rightMultiply(gPrime); - g = (GF2Matrix)g.rightMultiply(p2); - - - // generate keys - McEliecePublicKeyParameters pubKey = new McEliecePublicKeyParameters(OID, n, t, g, mcElieceParams.getParameters()); - McEliecePrivateKeyParameters privKey = new McEliecePrivateKeyParameters(OID, n, k, - field, gp, matrixSandInverse[1], p1, p2, h, sqRootMatrix, mcElieceParams.getParameters()); - - // return key pair - return new AsymmetricCipherKeyPair(pubKey, privKey); - } - - public void init(KeyGenerationParameters param) - { - this.initialize(param); - - } - - public AsymmetricCipherKeyPair generateKeyPair() - { - return genKeyPair(); - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyParameters.java deleted file mode 100644 index 007e743e..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyParameters.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; - - -public class McElieceKeyParameters - extends AsymmetricKeyParameter -{ - private McElieceParameters params; - - public McElieceKeyParameters( - boolean isPrivate, - McElieceParameters params) - { - super(isPrivate); - this.params = params; - } - - - public McElieceParameters getParameters() - { - return params; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKobaraImaiCipher.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKobaraImaiCipher.java deleted file mode 100644 index fe3ebf94..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKobaraImaiCipher.java +++ /dev/null @@ -1,319 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.crypto.prng.DigestRandomGenerator; -import org.bouncycastle.pqc.crypto.MessageEncryptor; -import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; -import org.bouncycastle.pqc.math.linearalgebra.GF2Vector; -import org.bouncycastle.pqc.math.linearalgebra.IntegerFunctions; - -/** - * This class implements the Kobara/Imai conversion of the McEliecePKCS. This is - * a conversion of the McEliecePKCS which is CCA2-secure. For details, see D. - * Engelbert, R. Overbeck, A. Schmidt, "A summary of the development of the - * McEliece Cryptosystem", technical report. - */ -public class McElieceKobaraImaiCipher - implements MessageEncryptor -{ - - /** - * The OID of the algorithm. - */ - public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2.3"; - - private static final String DEFAULT_PRNG_NAME = "SHA1PRNG"; - - /** - * A predetermined public constant. - */ - public static final byte[] PUBLIC_CONSTANT = "a predetermined public constant" - .getBytes(); - - - private Digest messDigest; - - private SecureRandom sr; - - McElieceCCA2KeyParameters key; - - /** - * The McEliece main parameters - */ - private int n, k, t; - - - public void init(boolean forSigning, - CipherParameters param) - { - - if (forSigning) - { - if (param instanceof ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom)param; - - this.sr = rParam.getRandom(); - this.key = (McElieceCCA2PublicKeyParameters)rParam.getParameters(); - this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key); - - } - else - { - this.sr = new SecureRandom(); - this.key = (McElieceCCA2PublicKeyParameters)param; - this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key); - } - } - else - { - this.key = (McElieceCCA2PrivateKeyParameters)param; - this.initCipherDecrypt((McElieceCCA2PrivateKeyParameters)key); - } - - } - - /** - * Return the key size of the given key object. - * - * @param key the McElieceCCA2KeyParameters object - * @return the key size of the given key object - */ - public int getKeySize(McElieceCCA2KeyParameters key) - { - if (key instanceof McElieceCCA2PublicKeyParameters) - { - return ((McElieceCCA2PublicKeyParameters)key).getN(); - - } - if (key instanceof McElieceCCA2PrivateKeyParameters) - { - return ((McElieceCCA2PrivateKeyParameters)key).getN(); - } - throw new IllegalArgumentException("unsupported type"); - } - - private void initCipherEncrypt(McElieceCCA2PublicKeyParameters pubKey) - { - this.messDigest = pubKey.getParameters().getDigest(); - n = pubKey.getN(); - k = pubKey.getK(); - t = pubKey.getT(); - - } - - public void initCipherDecrypt(McElieceCCA2PrivateKeyParameters privKey) - { - this.messDigest = privKey.getParameters().getDigest(); - n = privKey.getN(); - k = privKey.getK(); - t = privKey.getT(); - } - - public byte[] messageEncrypt(byte[] input) - throws Exception - { - - int c2Len = messDigest.getDigestSize(); - int c4Len = k >> 3; - int c5Len = (IntegerFunctions.binomial(n, t).bitLength() - 1) >> 3; - - - int mLen = c4Len + c5Len - c2Len - PUBLIC_CONSTANT.length; - if (input.length > mLen) - { - mLen = input.length; - } - - int c1Len = mLen + PUBLIC_CONSTANT.length; - int c6Len = c1Len + c2Len - c4Len - c5Len; - - // compute (m||const) - byte[] mConst = new byte[c1Len]; - System.arraycopy(input, 0, mConst, 0, input.length); - System.arraycopy(PUBLIC_CONSTANT, 0, mConst, mLen, - PUBLIC_CONSTANT.length); - - // generate random r of length c2Len bytes - byte[] r = new byte[c2Len]; - sr.nextBytes(r); - - // get PRNG object - // get PRNG object - DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest()); - - // seed PRNG with r' - sr0.addSeedMaterial(r); - - // generate random sequence ... - byte[] c1 = new byte[c1Len]; - sr0.nextBytes(c1); - - // ... and XOR with (m||const) to obtain c1 - for (int i = c1Len - 1; i >= 0; i--) - { - c1[i] ^= mConst[i]; - } - - // compute H(c1) ... - byte[] c2 = new byte[messDigest.getDigestSize()]; - messDigest.update(c1, 0, c1.length); - messDigest.doFinal(c2, 0); - - // ... and XOR with r - for (int i = c2Len - 1; i >= 0; i--) - { - c2[i] ^= r[i]; - } - - // compute (c2||c1) - byte[] c2c1 = ByteUtils.concatenate(c2, c1); - - // split (c2||c1) into (c6||c5||c4), where c4Len is k/8 bytes, c5Len is - // floor[log(n|t)]/8 bytes, and c6Len is c1Len+c2Len-c4Len-c5Len (may be - // 0). - byte[] c6 = new byte[0]; - if (c6Len > 0) - { - c6 = new byte[c6Len]; - System.arraycopy(c2c1, 0, c6, 0, c6Len); - } - - byte[] c5 = new byte[c5Len]; - System.arraycopy(c2c1, c6Len, c5, 0, c5Len); - - byte[] c4 = new byte[c4Len]; - System.arraycopy(c2c1, c6Len + c5Len, c4, 0, c4Len); - - // convert c4 to vector over GF(2) - GF2Vector c4Vec = GF2Vector.OS2VP(k, c4); - - // convert c5 to error vector z - GF2Vector z = Conversions.encode(n, t, c5); - - // compute encC4 = E(c4, z) - byte[] encC4 = McElieceCCA2Primitives.encryptionPrimitive((McElieceCCA2PublicKeyParameters)key, - c4Vec, z).getEncoded(); - - // if c6Len > 0 - if (c6Len > 0) - { - // return (c6||encC4) - return ByteUtils.concatenate(c6, encC4); - } - // else, return encC4 - return encC4; - } - - - public byte[] messageDecrypt(byte[] input) - throws Exception - { - - int nDiv8 = n >> 3; - - if (input.length < nDiv8) - { - throw new Exception("Bad Padding: Ciphertext too short."); - } - - int c2Len = messDigest.getDigestSize(); - int c4Len = k >> 3; - int c6Len = input.length - nDiv8; - - // split cipher text (c6||encC4), where c6 may be empty - byte[] c6, encC4; - if (c6Len > 0) - { - byte[][] c6EncC4 = ByteUtils.split(input, c6Len); - c6 = c6EncC4[0]; - encC4 = c6EncC4[1]; - } - else - { - c6 = new byte[0]; - encC4 = input; - } - - // convert encC4 into vector over GF(2) - GF2Vector encC4Vec = GF2Vector.OS2VP(n, encC4); - - // decrypt encC4Vec to obtain c4 and error vector z - GF2Vector[] c4z = McElieceCCA2Primitives.decryptionPrimitive((McElieceCCA2PrivateKeyParameters)key, - encC4Vec); - byte[] c4 = c4z[0].getEncoded(); - GF2Vector z = c4z[1]; - - // if length of c4 is greater than c4Len (because of padding) ... - if (c4.length > c4Len) - { - // ... truncate the padding bytes - c4 = ByteUtils.subArray(c4, 0, c4Len); - } - - // compute c5 = Conv^-1(z) - byte[] c5 = Conversions.decode(n, t, z); - - // compute (c6||c5||c4) - byte[] c6c5c4 = ByteUtils.concatenate(c6, c5); - c6c5c4 = ByteUtils.concatenate(c6c5c4, c4); - - // split (c6||c5||c4) into (c2||c1), where c2Len = mdLen and c1Len = - // input.length-c2Len bytes. - int c1Len = c6c5c4.length - c2Len; - byte[][] c2c1 = ByteUtils.split(c6c5c4, c2Len); - byte[] c2 = c2c1[0]; - byte[] c1 = c2c1[1]; - - // compute H(c1) ... - byte[] rPrime = new byte[messDigest.getDigestSize()]; - messDigest.update(c1, 0, c1.length); - messDigest.doFinal(rPrime, 0); - - // ... and XOR with c2 to obtain r' - for (int i = c2Len - 1; i >= 0; i--) - { - rPrime[i] ^= c2[i]; - } - - // get PRNG object - DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest()); - - // seed PRNG with r' - sr0.addSeedMaterial(rPrime); - - // generate random sequence R(r') ... - byte[] mConstPrime = new byte[c1Len]; - sr0.nextBytes(mConstPrime); - - // ... and XOR with c1 to obtain (m||const') - for (int i = c1Len - 1; i >= 0; i--) - { - mConstPrime[i] ^= c1[i]; - } - - if (mConstPrime.length < c1Len) - { - throw new Exception("Bad Padding: invalid ciphertext"); - } - - byte[][] temp = ByteUtils.split(mConstPrime, c1Len - - PUBLIC_CONSTANT.length); - byte[] mr = temp[0]; - byte[] constPrime = temp[1]; - - if (!ByteUtils.equals(constPrime, PUBLIC_CONSTANT)) - { - throw new Exception("Bad Padding: invalid ciphertext"); - } - - return mr; - } - - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKobaraImaiDigestCipher.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKobaraImaiDigestCipher.java deleted file mode 100644 index 365f387c..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceKobaraImaiDigestCipher.java +++ /dev/null @@ -1,128 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.MessageEncryptor; - -// TODO should implement some interface? -public class McElieceKobaraImaiDigestCipher -{ - - private final Digest messDigest; - - private final MessageEncryptor mcElieceCCA2Cipher; - - private boolean forEncrypting; - - - public McElieceKobaraImaiDigestCipher(MessageEncryptor mcElieceCCA2Cipher, Digest messDigest) - { - this.mcElieceCCA2Cipher = mcElieceCCA2Cipher; - this.messDigest = messDigest; - } - - - public void init(boolean forEncrypting, - CipherParameters param) - { - - this.forEncrypting = forEncrypting; - AsymmetricKeyParameter k; - - if (param instanceof ParametersWithRandom) - { - k = (AsymmetricKeyParameter)((ParametersWithRandom)param).getParameters(); - } - else - { - k = (AsymmetricKeyParameter)param; - } - - if (forEncrypting && k.isPrivate()) - { - throw new IllegalArgumentException("Encrypting Requires Public Key."); - } - - if (!forEncrypting && !k.isPrivate()) - { - throw new IllegalArgumentException("Decrypting Requires Private Key."); - } - - reset(); - - mcElieceCCA2Cipher.init(forEncrypting, param); - } - - - public byte[] messageEncrypt() - { - if (!forEncrypting) - { - throw new IllegalStateException("McElieceKobaraImaiDigestCipher not initialised for encrypting."); - } - - byte[] hash = new byte[messDigest.getDigestSize()]; - messDigest.doFinal(hash, 0); - byte[] enc = null; - - try - { - enc = mcElieceCCA2Cipher.messageEncrypt(hash); - } - catch (Exception e) - { - e.printStackTrace(); - } - - - return enc; - } - - - public byte[] messageDecrypt(byte[] ciphertext) - { - byte[] output = null; - if (forEncrypting) - { - throw new IllegalStateException("McElieceKobaraImaiDigestCipher not initialised for decrypting."); - } - - - try - { - output = mcElieceCCA2Cipher.messageDecrypt(ciphertext); - } - catch (Exception e) - { - e.printStackTrace(); - } - - - return output; - } - - - public void update(byte b) - { - messDigest.update(b); - - } - - public void update(byte[] in, int off, int len) - { - messDigest.update(in, off, len); - - } - - - public void reset() - { - messDigest.reset(); - - } - - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePKCSCipher.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePKCSCipher.java deleted file mode 100644 index 7a6be1be..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePKCSCipher.java +++ /dev/null @@ -1,224 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.MessageEncryptor; -import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.math.linearalgebra.GF2Vector; -import org.bouncycastle.pqc.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.math.linearalgebra.GoppaCode; -import org.bouncycastle.pqc.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM; -import org.bouncycastle.pqc.math.linearalgebra.Vector; - -/** - * This class implements the McEliece Public Key cryptosystem (McEliecePKCS). It - * was first described in R.J. McEliece, "A public key cryptosystem based on - * algebraic coding theory", DSN progress report, 42-44:114-116, 1978. The - * McEliecePKCS is the first cryptosystem which is based on error correcting - * codes. The trapdoor for the McEliece cryptosystem using Goppa codes is the - * knowledge of the Goppa polynomial used to generate the code. - */ -public class McEliecePKCSCipher - implements MessageEncryptor -{ - - /** - * The OID of the algorithm. - */ - public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.1"; - - - // the source of randomness - private SecureRandom sr; - - // the McEliece main parameters - private int n, k, t; - - // The maximum number of bytes the cipher can decrypt - public int maxPlainTextSize; - - // The maximum number of bytes the cipher can encrypt - public int cipherTextSize; - - McElieceKeyParameters key; - - - public void init(boolean forSigning, - CipherParameters param) - { - - if (forSigning) - { - if (param instanceof ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom)param; - - this.sr = rParam.getRandom(); - this.key = (McEliecePublicKeyParameters)rParam.getParameters(); - this.initCipherEncrypt((McEliecePublicKeyParameters)key); - - } - else - { - this.sr = new SecureRandom(); - this.key = (McEliecePublicKeyParameters)param; - this.initCipherEncrypt((McEliecePublicKeyParameters)key); - } - } - else - { - this.key = (McEliecePrivateKeyParameters)param; - this.initCipherDecrypt((McEliecePrivateKeyParameters)key); - } - - } - - - /** - * Return the key size of the given key object. - * - * @param key the McElieceKeyParameters object - * @return the keysize of the given key object - */ - - public int getKeySize(McElieceKeyParameters key) - { - - if (key instanceof McEliecePublicKeyParameters) - { - return ((McEliecePublicKeyParameters)key).getN(); - - } - if (key instanceof McEliecePrivateKeyParameters) - { - return ((McEliecePrivateKeyParameters)key).getN(); - } - throw new IllegalArgumentException("unsupported type"); - - } - - - public void initCipherEncrypt(McEliecePublicKeyParameters pubKey) - { - this.sr = sr != null ? sr : new SecureRandom(); - n = pubKey.getN(); - k = pubKey.getK(); - t = pubKey.getT(); - cipherTextSize = n >> 3; - maxPlainTextSize = (k >> 3); - } - - - public void initCipherDecrypt(McEliecePrivateKeyParameters privKey) - { - n = privKey.getN(); - k = privKey.getK(); - - maxPlainTextSize = (k >> 3); - cipherTextSize = n >> 3; - } - - /** - * Encrypt a plain text. - * - * @param input the plain text - * @return the cipher text - */ - public byte[] messageEncrypt(byte[] input) - { - GF2Vector m = computeMessageRepresentative(input); - GF2Vector z = new GF2Vector(n, t, sr); - - GF2Matrix g = ((McEliecePublicKeyParameters)key).getG(); - Vector mG = g.leftMultiply(m); - GF2Vector mGZ = (GF2Vector)mG.add(z); - - return mGZ.getEncoded(); - } - - private GF2Vector computeMessageRepresentative(byte[] input) - { - byte[] data = new byte[maxPlainTextSize + ((k & 0x07) != 0 ? 1 : 0)]; - System.arraycopy(input, 0, data, 0, input.length); - data[input.length] = 0x01; - return GF2Vector.OS2VP(k, data); - } - - /** - * Decrypt a cipher text. - * - * @param input the cipher text - * @return the plain text - * @throws Exception if the cipher text is invalid. - */ - public byte[] messageDecrypt(byte[] input) - throws Exception - { - GF2Vector vec = GF2Vector.OS2VP(n, input); - McEliecePrivateKeyParameters privKey = (McEliecePrivateKeyParameters)key; - GF2mField field = privKey.getField(); - PolynomialGF2mSmallM gp = privKey.getGoppaPoly(); - GF2Matrix sInv = privKey.getSInv(); - Permutation p1 = privKey.getP1(); - Permutation p2 = privKey.getP2(); - GF2Matrix h = privKey.getH(); - PolynomialGF2mSmallM[] qInv = privKey.getQInv(); - - // compute permutation P = P1 * P2 - Permutation p = p1.rightMultiply(p2); - - // compute P^-1 - Permutation pInv = p.computeInverse(); - - // compute c P^-1 - GF2Vector cPInv = (GF2Vector)vec.multiply(pInv); - - // compute syndrome of c P^-1 - GF2Vector syndrome = (GF2Vector)h.rightMultiply(cPInv); - - // decode syndrome - GF2Vector z = GoppaCode.syndromeDecode(syndrome, field, gp, qInv); - GF2Vector mSG = (GF2Vector)cPInv.add(z); - - // multiply codeword with P1 and error vector with P - mSG = (GF2Vector)mSG.multiply(p1); - z = (GF2Vector)z.multiply(p); - - // extract mS (last k columns of mSG) - GF2Vector mS = mSG.extractRightVector(k); - - // compute plaintext vector - GF2Vector mVec = (GF2Vector)sInv.leftMultiply(mS); - - // compute and return plaintext - return computeMessage(mVec); - } - - private byte[] computeMessage(GF2Vector mr) - throws Exception - { - byte[] mrBytes = mr.getEncoded(); - // find first non-zero byte - int index; - for (index = mrBytes.length - 1; index >= 0 && mrBytes[index] == 0; index--) - { - ; - } - - // check if padding byte is valid - if (mrBytes[index] != 0x01) - { - throw new Exception("Bad Padding: invalid ciphertext"); - } - - // extract and return message - byte[] mBytes = new byte[index]; - System.arraycopy(mrBytes, 0, mBytes, 0, index); - return mBytes; - } - - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePKCSDigestCipher.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePKCSDigestCipher.java deleted file mode 100644 index d8e6ba25..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePKCSDigestCipher.java +++ /dev/null @@ -1,128 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.MessageEncryptor; - -// TODO should implement some interface? -public class McEliecePKCSDigestCipher -{ - - private final Digest messDigest; - - private final MessageEncryptor mcElieceCipher; - - private boolean forEncrypting; - - - public McEliecePKCSDigestCipher(MessageEncryptor mcElieceCipher, Digest messDigest) - { - this.mcElieceCipher = mcElieceCipher; - this.messDigest = messDigest; - } - - - public void init(boolean forEncrypting, - CipherParameters param) - { - - this.forEncrypting = forEncrypting; - AsymmetricKeyParameter k; - - if (param instanceof ParametersWithRandom) - { - k = (AsymmetricKeyParameter)((ParametersWithRandom)param).getParameters(); - } - else - { - k = (AsymmetricKeyParameter)param; - } - - if (forEncrypting && k.isPrivate()) - { - throw new IllegalArgumentException("Encrypting Requires Public Key."); - } - - if (!forEncrypting && !k.isPrivate()) - { - throw new IllegalArgumentException("Decrypting Requires Private Key."); - } - - reset(); - - mcElieceCipher.init(forEncrypting, param); - } - - - public byte[] messageEncrypt() - { - if (!forEncrypting) - { - throw new IllegalStateException("McEliecePKCSDigestCipher not initialised for encrypting."); - } - - byte[] hash = new byte[messDigest.getDigestSize()]; - messDigest.doFinal(hash, 0); - byte[] enc = null; - - try - { - enc = mcElieceCipher.messageEncrypt(hash); - } - catch (Exception e) - { - e.printStackTrace(); - } - - - return enc; - } - - - public byte[] messageDecrypt(byte[] ciphertext) - { - byte[] output = null; - if (forEncrypting) - { - throw new IllegalStateException("McEliecePKCSDigestCipher not initialised for decrypting."); - } - - - try - { - output = mcElieceCipher.messageDecrypt(ciphertext); - } - catch (Exception e) - { - e.printStackTrace(); - } - - - return output; - } - - - public void update(byte b) - { - messDigest.update(b); - - } - - public void update(byte[] in, int off, int len) - { - messDigest.update(in, off, len); - - } - - - public void reset() - { - messDigest.reset(); - - } - - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceParameters.java deleted file mode 100644 index e90c7846..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McElieceParameters.java +++ /dev/null @@ -1,181 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.pqc.math.linearalgebra.PolynomialRingGF2; - -public class McElieceParameters - implements CipherParameters -{ - - /** - * The default extension degree - */ - public static final int DEFAULT_M = 11; - - /** - * The default error correcting capability. - */ - public static final int DEFAULT_T = 50; - - /** - * extension degree of the finite field GF(2^m) - */ - private int m; - - /** - * error correction capability of the code - */ - private int t; - - /** - * length of the code - */ - private int n; - - /** - * the field polynomial - */ - private int fieldPoly; - - /** - * Constructor. Set the default parameters: extension degree. - */ - public McElieceParameters() - { - this(DEFAULT_M, DEFAULT_T); - } - - /** - * Constructor. - * - * @param keysize the length of a Goppa code - * @throws IllegalArgumentException if <tt>keysize < 1</tt>. - */ - public McElieceParameters(int keysize) - throws IllegalArgumentException - { - if (keysize < 1) - { - throw new IllegalArgumentException("key size must be positive"); - } - m = 0; - n = 1; - while (n < keysize) - { - n <<= 1; - m++; - } - t = n >>> 1; - t /= m; - fieldPoly = PolynomialRingGF2.getIrreduciblePolynomial(m); - } - - /** - * Constructor. - * - * @param m degree of the finite field GF(2^m) - * @param t error correction capability of the code - * @throws IllegalArgumentException if <tt>m < 1</tt> or <tt>m > 32</tt> or - * <tt>t < 0</tt> or <tt>t > n</tt>. - */ - public McElieceParameters(int m, int t) - throws IllegalArgumentException - { - if (m < 1) - { - throw new IllegalArgumentException("m must be positive"); - } - if (m > 32) - { - throw new IllegalArgumentException("m is too large"); - } - this.m = m; - n = 1 << m; - if (t < 0) - { - throw new IllegalArgumentException("t must be positive"); - } - if (t > n) - { - throw new IllegalArgumentException("t must be less than n = 2^m"); - } - this.t = t; - fieldPoly = PolynomialRingGF2.getIrreduciblePolynomial(m); - } - - /** - * Constructor. - * - * @param m degree of the finite field GF(2^m) - * @param t error correction capability of the code - * @param poly the field polynomial - * @throws IllegalArgumentException if <tt>m < 1</tt> or <tt>m > 32</tt> or - * <tt>t < 0</tt> or <tt>t > n</tt> or - * <tt>poly</tt> is not an irreducible field polynomial. - */ - public McElieceParameters(int m, int t, int poly) - throws IllegalArgumentException - { - this.m = m; - if (m < 1) - { - throw new IllegalArgumentException("m must be positive"); - } - if (m > 32) - { - throw new IllegalArgumentException(" m is too large"); - } - this.n = 1 << m; - this.t = t; - if (t < 0) - { - throw new IllegalArgumentException("t must be positive"); - } - if (t > n) - { - throw new IllegalArgumentException("t must be less than n = 2^m"); - } - if ((PolynomialRingGF2.degree(poly) == m) - && (PolynomialRingGF2.isIrreducible(poly))) - { - this.fieldPoly = poly; - } - else - { - throw new IllegalArgumentException( - "polynomial is not a field polynomial for GF(2^m)"); - } - } - - /** - * @return the extension degree of the finite field GF(2^m) - */ - public int getM() - { - return m; - } - - /** - * @return the length of the code - */ - public int getN() - { - return n; - } - - /** - * @return the error correction capability of the code - */ - public int getT() - { - return t; - } - - /** - * @return the field polynomial - */ - public int getFieldPoly() - { - return fieldPoly; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePointchevalCipher.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePointchevalCipher.java deleted file mode 100644 index 854d79e0..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePointchevalCipher.java +++ /dev/null @@ -1,241 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.crypto.prng.DigestRandomGenerator; -import org.bouncycastle.pqc.crypto.MessageEncryptor; -import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; -import org.bouncycastle.pqc.math.linearalgebra.GF2Vector; - -/** - * This class implements the Pointcheval conversion of the McEliecePKCS. - * Pointcheval presents a generic technique to make a CCA2-secure cryptosystem - * from any partially trapdoor one-way function in the random oracle model. For - * details, see D. Engelbert, R. Overbeck, A. Schmidt, "A summary of the - * development of the McEliece Cryptosystem", technical report. - */ -public class McEliecePointchevalCipher - implements MessageEncryptor -{ - - - /** - * The OID of the algorithm. - */ - public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2.2"; - - private Digest messDigest; - - private SecureRandom sr; - - /** - * The McEliece main parameters - */ - private int n, k, t; - - McElieceCCA2KeyParameters key; - - public void init(boolean forSigning, - CipherParameters param) - { - - if (forSigning) - { - if (param instanceof ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom)param; - - this.sr = rParam.getRandom(); - this.key = (McElieceCCA2PublicKeyParameters)rParam.getParameters(); - this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key); - - } - else - { - this.sr = new SecureRandom(); - this.key = (McElieceCCA2PublicKeyParameters)param; - this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key); - } - } - else - { - this.key = (McElieceCCA2PrivateKeyParameters)param; - this.initCipherDecrypt((McElieceCCA2PrivateKeyParameters)key); - } - - } - - /** - * Return the key size of the given key object. - * - * @param key the McElieceCCA2KeyParameters object - * @return the key size of the given key object - * @throws IllegalArgumentException if the key is invalid - */ - public int getKeySize(McElieceCCA2KeyParameters key) - throws IllegalArgumentException - { - - if (key instanceof McElieceCCA2PublicKeyParameters) - { - return ((McElieceCCA2PublicKeyParameters)key).getN(); - - } - if (key instanceof McElieceCCA2PrivateKeyParameters) - { - return ((McElieceCCA2PrivateKeyParameters)key).getN(); - } - throw new IllegalArgumentException("unsupported type"); - - } - - - protected int decryptOutputSize(int inLen) - { - return 0; - } - - protected int encryptOutputSize(int inLen) - { - return 0; - } - - - public void initCipherEncrypt(McElieceCCA2PublicKeyParameters pubKey) - { - this.sr = sr != null ? sr : new SecureRandom(); - this.messDigest = pubKey.getParameters().getDigest(); - n = pubKey.getN(); - k = pubKey.getK(); - t = pubKey.getT(); - } - - public void initCipherDecrypt(McElieceCCA2PrivateKeyParameters privKey) - { - this.messDigest = privKey.getParameters().getDigest(); - n = privKey.getN(); - k = privKey.getK(); - t = privKey.getT(); - } - - public byte[] messageEncrypt(byte[] input) - throws Exception - { - - int kDiv8 = k >> 3; - - // generate random r of length k div 8 bytes - byte[] r = new byte[kDiv8]; - sr.nextBytes(r); - - // generate random vector r' of length k bits - GF2Vector rPrime = new GF2Vector(k, sr); - - // convert r' to byte array - byte[] rPrimeBytes = rPrime.getEncoded(); - - // compute (input||r) - byte[] mr = ByteUtils.concatenate(input, r); - - // compute H(input||r) - messDigest.update(mr, 0, mr.length); - byte[] hmr = new byte[messDigest.getDigestSize()]; - messDigest.doFinal(hmr, 0); - - - // convert H(input||r) to error vector z - GF2Vector z = Conversions.encode(n, t, hmr); - - // compute c1 = E(rPrime, z) - byte[] c1 = McElieceCCA2Primitives.encryptionPrimitive((McElieceCCA2PublicKeyParameters)key, rPrime, - z).getEncoded(); - - // get PRNG object - DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest()); - - // seed PRNG with r' - sr0.addSeedMaterial(rPrimeBytes); - - // generate random c2 - byte[] c2 = new byte[input.length + kDiv8]; - sr0.nextBytes(c2); - - // XOR with input - for (int i = 0; i < input.length; i++) - { - c2[i] ^= input[i]; - } - // XOR with r - for (int i = 0; i < kDiv8; i++) - { - c2[input.length + i] ^= r[i]; - } - - // return (c1||c2) - return ByteUtils.concatenate(c1, c2); - } - - public byte[] messageDecrypt(byte[] input) - throws Exception - { - - int c1Len = (n + 7) >> 3; - int c2Len = input.length - c1Len; - - // split cipher text (c1||c2) - byte[][] c1c2 = ByteUtils.split(input, c1Len); - byte[] c1 = c1c2[0]; - byte[] c2 = c1c2[1]; - - // decrypt c1 ... - GF2Vector c1Vec = GF2Vector.OS2VP(n, c1); - GF2Vector[] c1Dec = McElieceCCA2Primitives.decryptionPrimitive((McElieceCCA2PrivateKeyParameters)key, - c1Vec); - byte[] rPrimeBytes = c1Dec[0].getEncoded(); - // ... and obtain error vector z - GF2Vector z = c1Dec[1]; - - // get PRNG object - DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest()); - - // seed PRNG with r' - sr0.addSeedMaterial(rPrimeBytes); - - // generate random sequence - byte[] mrBytes = new byte[c2Len]; - sr0.nextBytes(mrBytes); - - // XOR with c2 to obtain (m||r) - for (int i = 0; i < c2Len; i++) - { - mrBytes[i] ^= c2[i]; - } - - // compute H(m||r) - messDigest.update(mrBytes, 0, mrBytes.length); - byte[] hmr = new byte[messDigest.getDigestSize()]; - messDigest.doFinal(hmr, 0); - - // compute Conv(H(m||r)) - c1Vec = Conversions.encode(n, t, hmr); - - // check that Conv(H(m||r)) = z - if (!c1Vec.equals(z)) - { - throw new Exception("Bad Padding: Invalid ciphertext."); - } - - // split (m||r) to obtain m - int kDiv8 = k >> 3; - byte[][] mr = ByteUtils.split(mrBytes, c2Len - kDiv8); - - // return plain text m - return mr[0]; - } - - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePointchevalDigestCipher.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePointchevalDigestCipher.java deleted file mode 100644 index 8a1ed62a..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePointchevalDigestCipher.java +++ /dev/null @@ -1,128 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.MessageEncryptor; - -// TODO should implement some interface? -public class McEliecePointchevalDigestCipher -{ - - private final Digest messDigest; - - private final MessageEncryptor mcElieceCCA2Cipher; - - private boolean forEncrypting; - - - public McEliecePointchevalDigestCipher(MessageEncryptor mcElieceCCA2Cipher, Digest messDigest) - { - this.mcElieceCCA2Cipher = mcElieceCCA2Cipher; - this.messDigest = messDigest; - } - - - public void init(boolean forEncrypting, - CipherParameters param) - { - - this.forEncrypting = forEncrypting; - AsymmetricKeyParameter k; - - if (param instanceof ParametersWithRandom) - { - k = (AsymmetricKeyParameter)((ParametersWithRandom)param).getParameters(); - } - else - { - k = (AsymmetricKeyParameter)param; - } - - if (forEncrypting && k.isPrivate()) - { - throw new IllegalArgumentException("Encrypting Requires Public Key."); - } - - if (!forEncrypting && !k.isPrivate()) - { - throw new IllegalArgumentException("Decrypting Requires Private Key."); - } - - reset(); - - mcElieceCCA2Cipher.init(forEncrypting, param); - } - - - public byte[] messageEncrypt() - { - if (!forEncrypting) - { - throw new IllegalStateException("McEliecePointchevalDigestCipher not initialised for encrypting."); - } - - byte[] hash = new byte[messDigest.getDigestSize()]; - messDigest.doFinal(hash, 0); - byte[] enc = null; - - try - { - enc = mcElieceCCA2Cipher.messageEncrypt(hash); - } - catch (Exception e) - { - e.printStackTrace(); - } - - - return enc; - } - - - public byte[] messageDecrypt(byte[] ciphertext) - { - byte[] output = null; - if (forEncrypting) - { - throw new IllegalStateException("McEliecePointchevalDigestCipher not initialised for decrypting."); - } - - - try - { - output = mcElieceCCA2Cipher.messageDecrypt(ciphertext); - } - catch (Exception e) - { - e.printStackTrace(); - } - - - return output; - } - - - public void update(byte b) - { - messDigest.update(b); - - } - - public void update(byte[] in, int off, int len) - { - messDigest.update(in, off, len); - - } - - - public void reset() - { - messDigest.reset(); - - } - - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePrivateKeyParameters.java deleted file mode 100644 index 762c2a25..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePrivateKeyParameters.java +++ /dev/null @@ -1,197 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - -import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM; - - -public class McEliecePrivateKeyParameters - extends McElieceKeyParameters -{ - - // the OID of the algorithm - private String oid; - - // the length of the code - private int n; - - // the dimension of the code, where <tt>k >= n - mt</tt> - private int k; - - // the underlying finite field - private GF2mField field; - - // the irreducible Goppa polynomial - private PolynomialGF2mSmallM goppaPoly; - - // a k x k random binary non-singular matrix - private GF2Matrix sInv; - - // the permutation used to generate the systematic check matrix - private Permutation p1; - - // the permutation used to compute the public generator matrix - private Permutation p2; - - // the canonical check matrix of the code - private GF2Matrix h; - - // the matrix used to compute square roots in <tt>(GF(2^m))^t</tt> - private PolynomialGF2mSmallM[] qInv; - - /** - * Constructor. - * - * @param oid - * @param n the length of the code - * @param k the dimension of the code - * @param field the field polynomial defining the finite field - * <tt>GF(2<sup>m</sup>)</tt> - * @param goppaPoly the irreducible Goppa polynomial - * @param sInv the matrix <tt>S<sup>-1</sup></tt> - * @param p1 the permutation used to generate the systematic check - * matrix - * @param p2 the permutation used to compute the public generator - * matrix - * @param h the canonical check matrix - * @param qInv the matrix used to compute square roots in - * <tt>(GF(2<sup>m</sup>))<sup>t</sup></tt> - * @param params McElieceParameters - */ - public McEliecePrivateKeyParameters(String oid, int n, int k, GF2mField field, - PolynomialGF2mSmallM goppaPoly, GF2Matrix sInv, Permutation p1, - Permutation p2, GF2Matrix h, PolynomialGF2mSmallM[] qInv, McElieceParameters params) - { - super(true, params); - this.oid = oid; - this.k = k; - this.n = n; - this.field = field; - this.goppaPoly = goppaPoly; - this.sInv = sInv; - this.p1 = p1; - this.p2 = p2; - this.h = h; - this.qInv = qInv; - } - - /** - * Constructor (used by the {@link McElieceKeyFactory}). - * - * @param oid - * @param n the length of the code - * @param k the dimension of the code - * @param encField the encoded field polynomial defining the finite field - * <tt>GF(2<sup>m</sup>)</tt> - * @param encGoppaPoly the encoded irreducible Goppa polynomial - * @param encSInv the encoded matrix <tt>S<sup>-1</sup></tt> - * @param encP1 the encoded permutation used to generate the systematic - * check matrix - * @param encP2 the encoded permutation used to compute the public - * generator matrix - * @param encH the encoded canonical check matrix - * @param encQInv the encoded matrix used to compute square roots in - * <tt>(GF(2<sup>m</sup>))<sup>t</sup></tt> - * @param params McElieceParameters - */ - public McEliecePrivateKeyParameters(String oid, int n, int k, byte[] encField, - byte[] encGoppaPoly, byte[] encSInv, byte[] encP1, byte[] encP2, - byte[] encH, byte[][] encQInv, McElieceParameters params) - { - super(true, params); - this.oid = oid; - this.n = n; - this.k = k; - field = new GF2mField(encField); - goppaPoly = new PolynomialGF2mSmallM(field, encGoppaPoly); - sInv = new GF2Matrix(encSInv); - p1 = new Permutation(encP1); - p2 = new Permutation(encP2); - h = new GF2Matrix(encH); - qInv = new PolynomialGF2mSmallM[encQInv.length]; - for (int i = 0; i < encQInv.length; i++) - { - qInv[i] = new PolynomialGF2mSmallM(field, encQInv[i]); - } - } - - /** - * @return the length of the code - */ - public int getN() - { - return n; - } - - /** - * @return the dimension of the code - */ - public int getK() - { - return k; - } - - /** - * @return the finite field <tt>GF(2<sup>m</sup>)</tt> - */ - public GF2mField getField() - { - return field; - } - - /** - * @return the irreducible Goppa polynomial - */ - public PolynomialGF2mSmallM getGoppaPoly() - { - return goppaPoly; - } - - /** - * @return the k x k random binary non-singular matrix S^-1 - */ - public GF2Matrix getSInv() - { - return sInv; - } - - /** - * @return the permutation used to generate the systematic check matrix - */ - public Permutation getP1() - { - return p1; - } - - /** - * @return the permutation used to compute the public generator matrix - */ - public Permutation getP2() - { - return p2; - } - - /** - * @return the canonical check matrix H - */ - public GF2Matrix getH() - { - return h; - } - - /** - * @return the matrix used to compute square roots in - * <tt>(GF(2<sup>m</sup>))<sup>t</sup></tt> - */ - public PolynomialGF2mSmallM[] getQInv() - { - return qInv; - } - - public String getOIDString() - { - return oid; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePublicKeyParameters.java deleted file mode 100644 index 6059e2e8..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mceliece/McEliecePublicKeyParameters.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.bouncycastle.pqc.crypto.mceliece; - -import org.bouncycastle.pqc.math.linearalgebra.GF2Matrix; - - -public class McEliecePublicKeyParameters - extends McElieceKeyParameters -{ - - // the OID of the algorithm - private String oid; - - // the length of the code - private int n; - - // the error correction capability of the code - private int t; - - // the generator matrix - private GF2Matrix g; - - /** - * Constructor (used by {@link McElieceKeyFactory}). - * - * @param oid - * @param n the length of the code - * @param t the error correction capability of the code - * @param g the generator matrix - * @param params McElieceParameters - */ - public McEliecePublicKeyParameters(String oid, int n, int t, GF2Matrix g, McElieceParameters params) - { - super(false, params); - this.oid = oid; - this.n = n; - this.t = t; - this.g = new GF2Matrix(g); - } - - /** - * Constructor (used by {@link McElieceKeyFactory}). - * - * @param oid - * @param n the length of the code - * @param t the error correction capability of the code - * @param encG the encoded generator matrix - * @param params McElieceParameters - */ - public McEliecePublicKeyParameters(String oid, int t, int n, byte[] encG, McElieceParameters params) - { - super(false, params); - this.oid = oid; - this.n = n; - this.t = t; - this.g = new GF2Matrix(encG); - } - - /** - * @return the length of the code - */ - public int getN() - { - return n; - } - - /** - * @return the error correction capability of the code - */ - public int getT() - { - return t; - } - - /** - * @return the generator matrix - */ - public GF2Matrix getG() - { - return g; - } - - public String getOIDString() - { - return oid; - - } - - /** - * @return the dimension of the code - */ - public int getK() - { - return g.getNumRows(); - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/IndexGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/IndexGenerator.java deleted file mode 100644 index 82974b30..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/IndexGenerator.java +++ /dev/null @@ -1,239 +0,0 @@ -package org.bouncycastle.pqc.crypto.ntru; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.util.Arrays; - -/** - * An implementation of the Index Generation Function in IEEE P1363.1. - */ -public class IndexGenerator -{ - private byte[] seed; - private int N; - private int c; - private int minCallsR; - private int totLen; - private int remLen; - private BitString buf; - private int counter; - private boolean initialized; - private Digest hashAlg; - private int hLen; - - /** - * Constructs a new index generator. - * - * @param seed a seed of arbitrary length to initialize the index generator with - * @param params NtruEncrypt parameters - */ - IndexGenerator(byte[] seed, NTRUEncryptionParameters params) - { - this.seed = seed; - N = params.N; - c = params.c; - minCallsR = params.minCallsR; - - totLen = 0; - remLen = 0; - counter = 0; - hashAlg = params.hashAlg; - - hLen = hashAlg.getDigestSize(); // hash length - initialized = false; - } - - /** - * Returns a number <code>i</code> such that <code>0 <= i < N</code>. - * - * @return - */ - int nextIndex() - { - if (!initialized) - { - buf = new BitString(); - byte[] hash = new byte[hashAlg.getDigestSize()]; - while (counter < minCallsR) - { - appendHash(buf, hash); - counter++; - } - totLen = minCallsR * 8 * hLen; - remLen = totLen; - initialized = true; - } - - while (true) - { - totLen += c; - BitString M = buf.getTrailing(remLen); - if (remLen < c) - { - int tmpLen = c - remLen; - int cThreshold = counter + (tmpLen + hLen - 1) / hLen; - byte[] hash = new byte[hashAlg.getDigestSize()]; - while (counter < cThreshold) - { - appendHash(M, hash); - counter++; - if (tmpLen > 8 * hLen) - { - tmpLen -= 8 * hLen; - } - } - remLen = 8 * hLen - tmpLen; - buf = new BitString(); - buf.appendBits(hash); - } - else - { - remLen -= c; - } - - int i = M.getLeadingAsInt(c); // assume c<32 - if (i < (1 << c) - ((1 << c) % N)) - { - return i % N; - } - } - } - - private void appendHash(BitString m, byte[] hash) - { - hashAlg.update(seed, 0, seed.length); - - putInt(hashAlg, counter); - - hashAlg.doFinal(hash, 0); - - m.appendBits(hash); - } - - private void putInt(Digest hashAlg, int counter) - { - hashAlg.update((byte)(counter >> 24)); - hashAlg.update((byte)(counter >> 16)); - hashAlg.update((byte)(counter >> 8)); - hashAlg.update((byte)counter); - } - - /** - * Represents a string of bits and supports appending, reading the head, and reading the tail. - */ - public static class BitString - { - byte[] bytes = new byte[4]; - int numBytes; // includes the last byte even if only some of its bits are used - int lastByteBits; // lastByteBits <= 8 - - /** - * Appends all bits in a byte array to the end of the bit string. - * - * @param bytes a byte array - */ - void appendBits(byte[] bytes) - { - for (int i = 0; i != bytes.length; i++) - { - appendBits(bytes[i]); - } - } - - /** - * Appends all bits in a byte to the end of the bit string. - * - * @param b a byte - */ - public void appendBits(byte b) - { - if (numBytes == bytes.length) - { - bytes = copyOf(bytes, 2 * bytes.length); - } - - if (numBytes == 0) - { - numBytes = 1; - bytes[0] = b; - lastByteBits = 8; - } - else if (lastByteBits == 8) - { - bytes[numBytes++] = b; - } - else - { - int s = 8 - lastByteBits; - bytes[numBytes - 1] |= (b & 0xFF) << lastByteBits; - bytes[numBytes++] = (byte)((b & 0xFF) >> s); - } - } - - /** - * Returns the last <code>numBits</code> bits from the end of the bit string. - * - * @param numBits number of bits - * @return a new <code>BitString</code> of length <code>numBits</code> - */ - public BitString getTrailing(int numBits) - { - BitString newStr = new BitString(); - newStr.numBytes = (numBits + 7) / 8; - newStr.bytes = new byte[newStr.numBytes]; - for (int i = 0; i < newStr.numBytes; i++) - { - newStr.bytes[i] = bytes[i]; - } - - newStr.lastByteBits = numBits % 8; - if (newStr.lastByteBits == 0) - { - newStr.lastByteBits = 8; - } - else - { - int s = 32 - newStr.lastByteBits; - newStr.bytes[newStr.numBytes - 1] = (byte)(newStr.bytes[newStr.numBytes - 1] << s >>> s); - } - - return newStr; - } - - /** - * Returns up to 32 bits from the beginning of the bit string. - * - * @param numBits number of bits - * @return an <code>int</code> whose lower <code>numBits</code> bits are the beginning of the bit string - */ - public int getLeadingAsInt(int numBits) - { - int startBit = (numBytes - 1) * 8 + lastByteBits - numBits; - int startByte = startBit / 8; - - int startBitInStartByte = startBit % 8; - int sum = (bytes[startByte] & 0xFF) >>> startBitInStartByte; - int shift = 8 - startBitInStartByte; - for (int i = startByte + 1; i < numBytes; i++) - { - sum |= (bytes[i] & 0xFF) << shift; - shift += 8; - } - - return sum; - } - - public byte[] getBytes() - { - return Arrays.clone(bytes); - } - } - - private static byte[] copyOf(byte[] src, int len) - { - byte[] tmp = new byte[len]; - - System.arraycopy(src, 0, tmp, 0, len < src.length ? len : src.length); - - return tmp; - } -}
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionKeyGenerationParameters.java deleted file mode 100644 index 8d64ae29..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionKeyGenerationParameters.java +++ /dev/null @@ -1,463 +0,0 @@ -package org.bouncycastle.pqc.crypto.ntru; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.SecureRandom; -import java.util.Arrays; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; - -/** - * A set of parameters for NtruEncrypt. Several predefined parameter sets are available and new ones can be created as well. - */ -public class NTRUEncryptionKeyGenerationParameters - extends KeyGenerationParameters - implements Cloneable -{ - /** - * A conservative (in terms of security) parameter set that gives 256 bits of security and is optimized for key size. - */ - public static final NTRUEncryptionKeyGenerationParameters EES1087EP2 = new NTRUEncryptionKeyGenerationParameters(1087, 2048, 120, 120, 256, 13, 25, 14, true, new byte[]{0, 6, 3}, true, false, new SHA512Digest()); - - /** - * A conservative (in terms of security) parameter set that gives 256 bits of security and is a tradeoff between key size and encryption/decryption speed. - */ - public static final NTRUEncryptionKeyGenerationParameters EES1171EP1 = new NTRUEncryptionKeyGenerationParameters(1171, 2048, 106, 106, 256, 13, 20, 15, true, new byte[]{0, 6, 4}, true, false, new SHA512Digest()); - - /** - * A conservative (in terms of security) parameter set that gives 256 bits of security and is optimized for encryption/decryption speed. - */ - public static final NTRUEncryptionKeyGenerationParameters EES1499EP1 = new NTRUEncryptionKeyGenerationParameters(1499, 2048, 79, 79, 256, 13, 17, 19, true, new byte[]{0, 6, 5}, true, false, new SHA512Digest()); - - /** - * A parameter set that gives 128 bits of security and uses simple ternary polynomials. - */ - public static final NTRUEncryptionKeyGenerationParameters APR2011_439 = new NTRUEncryptionKeyGenerationParameters(439, 2048, 146, 130, 128, 9, 32, 9, true, new byte[]{0, 7, 101}, true, false, new SHA256Digest()); - - /** - * Like <code>APR2011_439</code>, this parameter set gives 128 bits of security but uses product-form polynomials and <code>f=1+pF</code>. - */ - public static final NTRUEncryptionKeyGenerationParameters APR2011_439_FAST = new NTRUEncryptionKeyGenerationParameters(439, 2048, 9, 8, 5, 130, 128, 9, 32, 9, true, new byte[]{0, 7, 101}, true, true, new SHA256Digest()); - - /** - * A parameter set that gives 256 bits of security and uses simple ternary polynomials. - */ - public static final NTRUEncryptionKeyGenerationParameters APR2011_743 = new NTRUEncryptionKeyGenerationParameters(743, 2048, 248, 220, 256, 10, 27, 14, true, new byte[]{0, 7, 105}, false, false, new SHA512Digest()); - - /** - * Like <code>APR2011_743</code>, this parameter set gives 256 bits of security but uses product-form polynomials and <code>f=1+pF</code>. - */ - public static final NTRUEncryptionKeyGenerationParameters APR2011_743_FAST = new NTRUEncryptionKeyGenerationParameters(743, 2048, 11, 11, 15, 220, 256, 10, 27, 14, true, new byte[]{0, 7, 105}, false, true, new SHA512Digest()); - - public int N, q, df, df1, df2, df3; - public int dr; - public int dr1; - public int dr2; - public int dr3; - public int dg; - int llen; - public int maxMsgLenBytes; - public int db; - public int bufferLenBits; - int bufferLenTrits; - public int dm0; - public int pkLen; - public int c; - public int minCallsR; - public int minCallsMask; - public boolean hashSeed; - public byte[] oid; - public boolean sparse; - public boolean fastFp; - public int polyType; - public Digest hashAlg; - - /** - * Constructs a parameter set that uses ternary private keys (i.e. <code>polyType=SIMPLE</code>). - * - * @param N number of polynomial coefficients - * @param q modulus - * @param df number of ones in the private polynomial <code>f</code> - * @param dm0 minimum acceptable number of -1's, 0's, and 1's in the polynomial <code>m'</code> in the last encryption step - * @param db number of random bits to prepend to the message - * @param c a parameter for the Index Generation Function ({@link org.bouncycastle.pqc.crypto.ntru.IndexGenerator}) - * @param minCallsR minimum number of hash calls for the IGF to make - * @param minCallsMask minimum number of calls to generate the masking polynomial - * @param hashSeed whether to hash the seed in the MGF first (true) or use the seed directly (false) - * @param oid three bytes that uniquely identify the parameter set - * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bouncycastle.pqc.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bouncycastle.pqc.math.ntru.polynomial.DenseTernaryPolynomial}) - * @param fastFp whether <code>f=1+p*F</code> for a ternary <code>F</code> (true) or <code>f</code> is ternary (false) - * @param hashAlg a valid identifier for a <code>java.security.MessageDigest</code> instance such as <code>SHA-256</code>. The <code>MessageDigest</code> must support the <code>getDigestLength()</code> method. - */ - public NTRUEncryptionKeyGenerationParameters(int N, int q, int df, int dm0, int db, int c, int minCallsR, int minCallsMask, boolean hashSeed, byte[] oid, boolean sparse, boolean fastFp, Digest hashAlg) - { - super(new SecureRandom(), db); - this.N = N; - this.q = q; - this.df = df; - this.db = db; - this.dm0 = dm0; - this.c = c; - this.minCallsR = minCallsR; - this.minCallsMask = minCallsMask; - this.hashSeed = hashSeed; - this.oid = oid; - this.sparse = sparse; - this.fastFp = fastFp; - this.polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE; - this.hashAlg = hashAlg; - init(); - } - - /** - * Constructs a parameter set that uses product-form private keys (i.e. <code>polyType=PRODUCT</code>). - * - * @param N number of polynomial coefficients - * @param q modulus - * @param df1 number of ones in the private polynomial <code>f1</code> - * @param df2 number of ones in the private polynomial <code>f2</code> - * @param df3 number of ones in the private polynomial <code>f3</code> - * @param dm0 minimum acceptable number of -1's, 0's, and 1's in the polynomial <code>m'</code> in the last encryption step - * @param db number of random bits to prepend to the message - * @param c a parameter for the Index Generation Function ({@link org.bouncycastle.pqc.crypto.ntru.IndexGenerator}) - * @param minCallsR minimum number of hash calls for the IGF to make - * @param minCallsMask minimum number of calls to generate the masking polynomial - * @param hashSeed whether to hash the seed in the MGF first (true) or use the seed directly (false) - * @param oid three bytes that uniquely identify the parameter set - * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bouncycastle.pqc.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bouncycastle.pqc.math.ntru.polynomial.DenseTernaryPolynomial}) - * @param fastFp whether <code>f=1+p*F</code> for a ternary <code>F</code> (true) or <code>f</code> is ternary (false) - * @param hashAlg a valid identifier for a <code>java.security.MessageDigest</code> instance such as <code>SHA-256</code> - */ - public NTRUEncryptionKeyGenerationParameters(int N, int q, int df1, int df2, int df3, int dm0, int db, int c, int minCallsR, int minCallsMask, boolean hashSeed, byte[] oid, boolean sparse, boolean fastFp, Digest hashAlg) - { - super(new SecureRandom(), db); - - this.N = N; - this.q = q; - this.df1 = df1; - this.df2 = df2; - this.df3 = df3; - this.db = db; - this.dm0 = dm0; - this.c = c; - this.minCallsR = minCallsR; - this.minCallsMask = minCallsMask; - this.hashSeed = hashSeed; - this.oid = oid; - this.sparse = sparse; - this.fastFp = fastFp; - this.polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT; - this.hashAlg = hashAlg; - init(); - } - - private void init() - { - dr = df; - dr1 = df1; - dr2 = df2; - dr3 = df3; - dg = N / 3; - llen = 1; // ceil(log2(maxMsgLenBytes)) - maxMsgLenBytes = N * 3 / 2 / 8 - llen - db / 8 - 1; - bufferLenBits = (N * 3 / 2 + 7) / 8 * 8 + 1; - bufferLenTrits = N - 1; - pkLen = db; - } - - /** - * Reads a parameter set from an input stream. - * - * @param is an input stream - * @throws java.io.IOException - */ - public NTRUEncryptionKeyGenerationParameters(InputStream is) - throws IOException - { - super(new SecureRandom(), -1); - DataInputStream dis = new DataInputStream(is); - N = dis.readInt(); - q = dis.readInt(); - df = dis.readInt(); - df1 = dis.readInt(); - df2 = dis.readInt(); - df3 = dis.readInt(); - db = dis.readInt(); - dm0 = dis.readInt(); - c = dis.readInt(); - minCallsR = dis.readInt(); - minCallsMask = dis.readInt(); - hashSeed = dis.readBoolean(); - oid = new byte[3]; - dis.read(oid); - sparse = dis.readBoolean(); - fastFp = dis.readBoolean(); - polyType = dis.read(); - - String alg = dis.readUTF(); - - if ("SHA-512".equals(alg)) - { - hashAlg = new SHA512Digest(); - } - else if ("SHA-256".equals(alg)) - { - hashAlg = new SHA256Digest(); - } - - init(); - } - - public NTRUEncryptionParameters getEncryptionParameters() - { - if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE) - { - return new NTRUEncryptionParameters(N, q, df, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, hashAlg); - } - else - { - return new NTRUEncryptionParameters(N, q, df1, df2, df3, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, hashAlg); - } - } - - public NTRUEncryptionKeyGenerationParameters clone() - { - if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE) - { - return new NTRUEncryptionKeyGenerationParameters(N, q, df, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, hashAlg); - } - else - { - return new NTRUEncryptionKeyGenerationParameters(N, q, df1, df2, df3, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, hashAlg); - } - } - - /** - * Returns the maximum length a plaintext message can be with this parameter set. - * - * @return the maximum length in bytes - */ - public int getMaxMessageLength() - { - return maxMsgLenBytes; - } - - /** - * Writes the parameter set to an output stream - * - * @param os an output stream - * @throws java.io.IOException - */ - public void writeTo(OutputStream os) - throws IOException - { - DataOutputStream dos = new DataOutputStream(os); - dos.writeInt(N); - dos.writeInt(q); - dos.writeInt(df); - dos.writeInt(df1); - dos.writeInt(df2); - dos.writeInt(df3); - dos.writeInt(db); - dos.writeInt(dm0); - dos.writeInt(c); - dos.writeInt(minCallsR); - dos.writeInt(minCallsMask); - dos.writeBoolean(hashSeed); - dos.write(oid); - dos.writeBoolean(sparse); - dos.writeBoolean(fastFp); - dos.write(polyType); - dos.writeUTF(hashAlg.getAlgorithmName()); - } - - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + N; - result = prime * result + bufferLenBits; - result = prime * result + bufferLenTrits; - result = prime * result + c; - result = prime * result + db; - result = prime * result + df; - result = prime * result + df1; - result = prime * result + df2; - result = prime * result + df3; - result = prime * result + dg; - result = prime * result + dm0; - result = prime * result + dr; - result = prime * result + dr1; - result = prime * result + dr2; - result = prime * result + dr3; - result = prime * result + (fastFp ? 1231 : 1237); - result = prime * result + ((hashAlg == null) ? 0 : hashAlg.getAlgorithmName().hashCode()); - result = prime * result + (hashSeed ? 1231 : 1237); - result = prime * result + llen; - result = prime * result + maxMsgLenBytes; - result = prime * result + minCallsMask; - result = prime * result + minCallsR; - result = prime * result + Arrays.hashCode(oid); - result = prime * result + pkLen; - result = prime * result + polyType; - result = prime * result + q; - result = prime * result + (sparse ? 1231 : 1237); - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - NTRUEncryptionKeyGenerationParameters other = (NTRUEncryptionKeyGenerationParameters)obj; - if (N != other.N) - { - return false; - } - if (bufferLenBits != other.bufferLenBits) - { - return false; - } - if (bufferLenTrits != other.bufferLenTrits) - { - return false; - } - if (c != other.c) - { - return false; - } - if (db != other.db) - { - return false; - } - if (df != other.df) - { - return false; - } - if (df1 != other.df1) - { - return false; - } - if (df2 != other.df2) - { - return false; - } - if (df3 != other.df3) - { - return false; - } - if (dg != other.dg) - { - return false; - } - if (dm0 != other.dm0) - { - return false; - } - if (dr != other.dr) - { - return false; - } - if (dr1 != other.dr1) - { - return false; - } - if (dr2 != other.dr2) - { - return false; - } - if (dr3 != other.dr3) - { - return false; - } - if (fastFp != other.fastFp) - { - return false; - } - if (hashAlg == null) - { - if (other.hashAlg != null) - { - return false; - } - } - else if (!hashAlg.getAlgorithmName().equals(other.hashAlg.getAlgorithmName())) - { - return false; - } - if (hashSeed != other.hashSeed) - { - return false; - } - if (llen != other.llen) - { - return false; - } - if (maxMsgLenBytes != other.maxMsgLenBytes) - { - return false; - } - if (minCallsMask != other.minCallsMask) - { - return false; - } - if (minCallsR != other.minCallsR) - { - return false; - } - if (!Arrays.equals(oid, other.oid)) - { - return false; - } - if (pkLen != other.pkLen) - { - return false; - } - if (polyType != other.polyType) - { - return false; - } - if (q != other.q) - { - return false; - } - if (sparse != other.sparse) - { - return false; - } - return true; - } - - public String toString() - { - StringBuilder output = new StringBuilder("EncryptionParameters(N=" + N + " q=" + q); - if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE) - { - output.append(" polyType=SIMPLE df=" + df); - } - else - { - output.append(" polyType=PRODUCT df1=" + df1 + " df2=" + df2 + " df3=" + df3); - } - output.append(" dm0=" + dm0 + " db=" + db + " c=" + c + " minCallsR=" + minCallsR + " minCallsMask=" + minCallsMask + - " hashSeed=" + hashSeed + " hashAlg=" + hashAlg + " oid=" + Arrays.toString(oid) + " sparse=" + sparse + ")"); - return output.toString(); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionKeyPairGenerator.java deleted file mode 100644 index f2751caa..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionKeyPairGenerator.java +++ /dev/null @@ -1,113 +0,0 @@ -package org.bouncycastle.pqc.crypto.ntru; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.pqc.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.Polynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.ProductFormPolynomial; -import org.bouncycastle.pqc.math.ntru.util.Util; - -/** - * Generates key pairs.<br> - * The parameter p is hardcoded to 3. - */ -public class NTRUEncryptionKeyPairGenerator - implements AsymmetricCipherKeyPairGenerator -{ - private NTRUEncryptionKeyGenerationParameters params; - - /** - * Constructs a new instance with a set of encryption parameters. - * - * @param param encryption parameters - */ - public void init(KeyGenerationParameters param) - { - this.params = (NTRUEncryptionKeyGenerationParameters)param; - } - - /** - * Generates a new encryption key pair. - * - * @return a key pair - */ - public AsymmetricCipherKeyPair generateKeyPair() - { - int N = params.N; - int q = params.q; - int df = params.df; - int df1 = params.df1; - int df2 = params.df2; - int df3 = params.df3; - int dg = params.dg; - boolean fastFp = params.fastFp; - boolean sparse = params.sparse; - - Polynomial t; - IntegerPolynomial fq; - IntegerPolynomial fp = null; - - // choose a random f that is invertible mod 3 and q - while (true) - { - IntegerPolynomial f; - - // choose random t, calculate f and fp - if (fastFp) - { - // if fastFp=true, f is always invertible mod 3 - t = params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? Util.generateRandomTernary(N, df, df, sparse, params.getRandom()) : ProductFormPolynomial.generateRandom(N, df1, df2, df3, df3, params.getRandom()); - f = t.toIntegerPolynomial(); - f.mult(3); - f.coeffs[0] += 1; - } - else - { - t = params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? Util.generateRandomTernary(N, df, df - 1, sparse, params.getRandom()) : ProductFormPolynomial.generateRandom(N, df1, df2, df3, df3 - 1, params.getRandom()); - f = t.toIntegerPolynomial(); - fp = f.invertF3(); - if (fp == null) - { - continue; - } - } - - fq = f.invertFq(q); - if (fq == null) - { - continue; - } - break; - } - - // if fastFp=true, fp=1 - if (fastFp) - { - fp = new IntegerPolynomial(N); - fp.coeffs[0] = 1; - } - - // choose a random g that is invertible mod q - DenseTernaryPolynomial g; - while (true) - { - g = DenseTernaryPolynomial.generateRandom(N, dg, dg - 1, params.getRandom()); - if (g.invertFq(q) != null) - { - break; - } - } - - IntegerPolynomial h = g.mult(fq, q); - h.mult3(q); - h.ensurePositive(q); - g.clear(); - fq.clear(); - - NTRUEncryptionPrivateKeyParameters priv = new NTRUEncryptionPrivateKeyParameters(h, t, fp, params.getEncryptionParameters()); - NTRUEncryptionPublicKeyParameters pub = new NTRUEncryptionPublicKeyParameters(h, params.getEncryptionParameters()); - return new AsymmetricCipherKeyPair(pub, priv); - } -}
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionKeyParameters.java deleted file mode 100644 index 27a7987c..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionKeyParameters.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.bouncycastle.pqc.crypto.ntru; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; - -public class NTRUEncryptionKeyParameters - extends AsymmetricKeyParameter -{ - final protected NTRUEncryptionParameters params; - - public NTRUEncryptionKeyParameters(boolean privateKey, NTRUEncryptionParameters params) - { - super(privateKey); - this.params = params; - } - - public NTRUEncryptionParameters getParameters() - { - return params; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionParameters.java deleted file mode 100644 index b387bc24..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionParameters.java +++ /dev/null @@ -1,410 +0,0 @@ -package org.bouncycastle.pqc.crypto.ntru; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Arrays; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; - -/** - * A set of parameters for NtruEncrypt. Several predefined parameter sets are available and new ones can be created as well. - */ -public class NTRUEncryptionParameters - implements Cloneable -{ - - public int N, q, df, df1, df2, df3; - public int dr; - public int dr1; - public int dr2; - public int dr3; - public int dg; - int llen; - public int maxMsgLenBytes; - public int db; - public int bufferLenBits; - int bufferLenTrits; - public int dm0; - public int pkLen; - public int c; - public int minCallsR; - public int minCallsMask; - public boolean hashSeed; - public byte[] oid; - public boolean sparse; - public boolean fastFp; - public int polyType; - public Digest hashAlg; - - /** - * Constructs a parameter set that uses ternary private keys (i.e. <code>polyType=SIMPLE</code>). - * - * @param N number of polynomial coefficients - * @param q modulus - * @param df number of ones in the private polynomial <code>f</code> - * @param dm0 minimum acceptable number of -1's, 0's, and 1's in the polynomial <code>m'</code> in the last encryption step - * @param db number of random bits to prepend to the message - * @param c a parameter for the Index Generation Function ({@link org.bouncycastle.pqc.crypto.ntru.IndexGenerator}) - * @param minCallsR minimum number of hash calls for the IGF to make - * @param minCallsMask minimum number of calls to generate the masking polynomial - * @param hashSeed whether to hash the seed in the MGF first (true) or use the seed directly (false) - * @param oid three bytes that uniquely identify the parameter set - * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bouncycastle.pqc.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bouncycastle.pqc.math.ntru.polynomial.DenseTernaryPolynomial}) - * @param fastFp whether <code>f=1+p*F</code> for a ternary <code>F</code> (true) or <code>f</code> is ternary (false) - * @param hashAlg a valid identifier for a <code>java.security.MessageDigest</code> instance such as <code>SHA-256</code>. The <code>MessageDigest</code> must support the <code>getDigestLength()</code> method. - */ - public NTRUEncryptionParameters(int N, int q, int df, int dm0, int db, int c, int minCallsR, int minCallsMask, boolean hashSeed, byte[] oid, boolean sparse, boolean fastFp, Digest hashAlg) - { - this.N = N; - this.q = q; - this.df = df; - this.db = db; - this.dm0 = dm0; - this.c = c; - this.minCallsR = minCallsR; - this.minCallsMask = minCallsMask; - this.hashSeed = hashSeed; - this.oid = oid; - this.sparse = sparse; - this.fastFp = fastFp; - this.polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE; - this.hashAlg = hashAlg; - init(); - } - - /** - * Constructs a parameter set that uses product-form private keys (i.e. <code>polyType=PRODUCT</code>). - * - * @param N number of polynomial coefficients - * @param q modulus - * @param df1 number of ones in the private polynomial <code>f1</code> - * @param df2 number of ones in the private polynomial <code>f2</code> - * @param df3 number of ones in the private polynomial <code>f3</code> - * @param dm0 minimum acceptable number of -1's, 0's, and 1's in the polynomial <code>m'</code> in the last encryption step - * @param db number of random bits to prepend to the message - * @param c a parameter for the Index Generation Function ({@link org.bouncycastle.pqc.crypto.ntru.IndexGenerator}) - * @param minCallsR minimum number of hash calls for the IGF to make - * @param minCallsMask minimum number of calls to generate the masking polynomial - * @param hashSeed whether to hash the seed in the MGF first (true) or use the seed directly (false) - * @param oid three bytes that uniquely identify the parameter set - * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bouncycastle.pqc.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bouncycastle.pqc.math.ntru.polynomial.DenseTernaryPolynomial}) - * @param fastFp whether <code>f=1+p*F</code> for a ternary <code>F</code> (true) or <code>f</code> is ternary (false) - * @param hashAlg a valid identifier for a <code>java.security.MessageDigest</code> instance such as <code>SHA-256</code> - */ - public NTRUEncryptionParameters(int N, int q, int df1, int df2, int df3, int dm0, int db, int c, int minCallsR, int minCallsMask, boolean hashSeed, byte[] oid, boolean sparse, boolean fastFp, Digest hashAlg) - { - this.N = N; - this.q = q; - this.df1 = df1; - this.df2 = df2; - this.df3 = df3; - this.db = db; - this.dm0 = dm0; - this.c = c; - this.minCallsR = minCallsR; - this.minCallsMask = minCallsMask; - this.hashSeed = hashSeed; - this.oid = oid; - this.sparse = sparse; - this.fastFp = fastFp; - this.polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT; - this.hashAlg = hashAlg; - init(); - } - - private void init() - { - dr = df; - dr1 = df1; - dr2 = df2; - dr3 = df3; - dg = N / 3; - llen = 1; // ceil(log2(maxMsgLenBytes)) - maxMsgLenBytes = N * 3 / 2 / 8 - llen - db / 8 - 1; - bufferLenBits = (N * 3 / 2 + 7) / 8 * 8 + 1; - bufferLenTrits = N - 1; - pkLen = db; - } - - /** - * Reads a parameter set from an input stream. - * - * @param is an input stream - * @throws IOException - */ - public NTRUEncryptionParameters(InputStream is) - throws IOException - { - DataInputStream dis = new DataInputStream(is); - N = dis.readInt(); - q = dis.readInt(); - df = dis.readInt(); - df1 = dis.readInt(); - df2 = dis.readInt(); - df3 = dis.readInt(); - db = dis.readInt(); - dm0 = dis.readInt(); - c = dis.readInt(); - minCallsR = dis.readInt(); - minCallsMask = dis.readInt(); - hashSeed = dis.readBoolean(); - oid = new byte[3]; - dis.read(oid); - sparse = dis.readBoolean(); - fastFp = dis.readBoolean(); - polyType = dis.read(); - - String alg = dis.readUTF(); - - if ("SHA-512".equals(alg)) - { - hashAlg = new SHA512Digest(); - } - else if ("SHA-256".equals(alg)) - { - hashAlg = new SHA256Digest(); - } - - init(); - } - - public NTRUEncryptionParameters clone() - { - if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE) - { - return new NTRUEncryptionParameters(N, q, df, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, hashAlg); - } - else - { - return new NTRUEncryptionParameters(N, q, df1, df2, df3, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, hashAlg); - } - } - - /** - * Returns the maximum length a plaintext message can be with this parameter set. - * - * @return the maximum length in bytes - */ - public int getMaxMessageLength() - { - return maxMsgLenBytes; - } - - /** - * Writes the parameter set to an output stream - * - * @param os an output stream - * @throws IOException - */ - public void writeTo(OutputStream os) - throws IOException - { - DataOutputStream dos = new DataOutputStream(os); - dos.writeInt(N); - dos.writeInt(q); - dos.writeInt(df); - dos.writeInt(df1); - dos.writeInt(df2); - dos.writeInt(df3); - dos.writeInt(db); - dos.writeInt(dm0); - dos.writeInt(c); - dos.writeInt(minCallsR); - dos.writeInt(minCallsMask); - dos.writeBoolean(hashSeed); - dos.write(oid); - dos.writeBoolean(sparse); - dos.writeBoolean(fastFp); - dos.write(polyType); - dos.writeUTF(hashAlg.getAlgorithmName()); - } - - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + N; - result = prime * result + bufferLenBits; - result = prime * result + bufferLenTrits; - result = prime * result + c; - result = prime * result + db; - result = prime * result + df; - result = prime * result + df1; - result = prime * result + df2; - result = prime * result + df3; - result = prime * result + dg; - result = prime * result + dm0; - result = prime * result + dr; - result = prime * result + dr1; - result = prime * result + dr2; - result = prime * result + dr3; - result = prime * result + (fastFp ? 1231 : 1237); - result = prime * result + ((hashAlg == null) ? 0 : hashAlg.getAlgorithmName().hashCode()); - result = prime * result + (hashSeed ? 1231 : 1237); - result = prime * result + llen; - result = prime * result + maxMsgLenBytes; - result = prime * result + minCallsMask; - result = prime * result + minCallsR; - result = prime * result + Arrays.hashCode(oid); - result = prime * result + pkLen; - result = prime * result + polyType; - result = prime * result + q; - result = prime * result + (sparse ? 1231 : 1237); - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - NTRUEncryptionParameters other = (NTRUEncryptionParameters)obj; - if (N != other.N) - { - return false; - } - if (bufferLenBits != other.bufferLenBits) - { - return false; - } - if (bufferLenTrits != other.bufferLenTrits) - { - return false; - } - if (c != other.c) - { - return false; - } - if (db != other.db) - { - return false; - } - if (df != other.df) - { - return false; - } - if (df1 != other.df1) - { - return false; - } - if (df2 != other.df2) - { - return false; - } - if (df3 != other.df3) - { - return false; - } - if (dg != other.dg) - { - return false; - } - if (dm0 != other.dm0) - { - return false; - } - if (dr != other.dr) - { - return false; - } - if (dr1 != other.dr1) - { - return false; - } - if (dr2 != other.dr2) - { - return false; - } - if (dr3 != other.dr3) - { - return false; - } - if (fastFp != other.fastFp) - { - return false; - } - if (hashAlg == null) - { - if (other.hashAlg != null) - { - return false; - } - } - else if (!hashAlg.getAlgorithmName().equals(other.hashAlg.getAlgorithmName())) - { - return false; - } - if (hashSeed != other.hashSeed) - { - return false; - } - if (llen != other.llen) - { - return false; - } - if (maxMsgLenBytes != other.maxMsgLenBytes) - { - return false; - } - if (minCallsMask != other.minCallsMask) - { - return false; - } - if (minCallsR != other.minCallsR) - { - return false; - } - if (!Arrays.equals(oid, other.oid)) - { - return false; - } - if (pkLen != other.pkLen) - { - return false; - } - if (polyType != other.polyType) - { - return false; - } - if (q != other.q) - { - return false; - } - if (sparse != other.sparse) - { - return false; - } - return true; - } - - public String toString() - { - StringBuilder output = new StringBuilder("EncryptionParameters(N=" + N + " q=" + q); - if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE) - { - output.append(" polyType=SIMPLE df=" + df); - } - else - { - output.append(" polyType=PRODUCT df1=" + df1 + " df2=" + df2 + " df3=" + df3); - } - output.append(" dm0=" + dm0 + " db=" + db + " c=" + c + " minCallsR=" + minCallsR + " minCallsMask=" + minCallsMask + - " hashSeed=" + hashSeed + " hashAlg=" + hashAlg + " oid=" + Arrays.toString(oid) + " sparse=" + sparse + ")"); - return output.toString(); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionPrivateKeyParameters.java deleted file mode 100644 index bcf9418e..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionPrivateKeyParameters.java +++ /dev/null @@ -1,199 +0,0 @@ -package org.bouncycastle.pqc.crypto.ntru; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.bouncycastle.pqc.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.Polynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.ProductFormPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.SparseTernaryPolynomial; - -/** - * A NtruEncrypt private key is essentially a polynomial named <code>f</code> - * which takes different forms depending on whether product-form polynomials are used, - * and on <code>fastP</code><br> - * The inverse of <code>f</code> modulo <code>p</code> is precomputed on initialization. - */ -public class NTRUEncryptionPrivateKeyParameters - extends NTRUEncryptionKeyParameters -{ - public Polynomial t; - public IntegerPolynomial fp; - public IntegerPolynomial h; - - /** - * Constructs a new private key from a polynomial - * - * @param h the public polynomial for the key. - * @param t the polynomial which determines the key: if <code>fastFp=true</code>, <code>f=1+3t</code>; otherwise, <code>f=t</code> - * @param fp the inverse of <code>f</code> - * @param params the NtruEncrypt parameters to use - */ - public NTRUEncryptionPrivateKeyParameters(IntegerPolynomial h, Polynomial t, IntegerPolynomial fp, NTRUEncryptionParameters params) - { - super(true, params); - - this.h = h; - this.t = t; - this.fp = fp; - } - - /** - * Converts a byte array to a polynomial <code>f</code> and constructs a new private key - * - * @param b an encoded polynomial - * @param params the NtruEncrypt parameters to use - * @see #getEncoded() - */ - public NTRUEncryptionPrivateKeyParameters(byte[] b, NTRUEncryptionParameters params) - throws IOException - { - this(new ByteArrayInputStream(b), params); - } - - /** - * Reads a polynomial <code>f</code> from an input stream and constructs a new private key - * - * @param is an input stream - * @param params the NtruEncrypt parameters to use - * @see #writeTo(OutputStream) - */ - public NTRUEncryptionPrivateKeyParameters(InputStream is, NTRUEncryptionParameters params) - throws IOException - { - super(true, params); - - if (params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT) - { - int N = params.N; - int df1 = params.df1; - int df2 = params.df2; - int df3Ones = params.df3; - int df3NegOnes = params.fastFp ? params.df3 : params.df3 - 1; - h = IntegerPolynomial.fromBinary(is, params.N, params.q); - t = ProductFormPolynomial.fromBinary(is, N, df1, df2, df3Ones, df3NegOnes); - } - else - { - h = IntegerPolynomial.fromBinary(is, params.N, params.q); - IntegerPolynomial fInt = IntegerPolynomial.fromBinary3Tight(is, params.N); - t = params.sparse ? new SparseTernaryPolynomial(fInt) : new DenseTernaryPolynomial(fInt); - } - - init(); - } - - /** - * Initializes <code>fp</code> from t. - */ - private void init() - { - if (params.fastFp) - { - fp = new IntegerPolynomial(params.N); - fp.coeffs[0] = 1; - } - else - { - fp = t.toIntegerPolynomial().invertF3(); - } - } - - /** - * Converts the key to a byte array - * - * @return the encoded key - * @see #NTRUEncryptionPrivateKeyParameters(byte[], NTRUEncryptionParameters) - */ - public byte[] getEncoded() - { - byte[] hBytes = h.toBinary(params.q); - byte[] tBytes; - - if (t instanceof ProductFormPolynomial) - { - tBytes = ((ProductFormPolynomial)t).toBinary(); - } - else - { - tBytes = t.toIntegerPolynomial().toBinary3Tight(); - } - - byte[] res = new byte[hBytes.length + tBytes.length]; - - System.arraycopy(hBytes, 0, res, 0, hBytes.length); - System.arraycopy(tBytes, 0, res, hBytes.length, tBytes.length); - - return res; - } - - /** - * Writes the key to an output stream - * - * @param os an output stream - * @throws IOException - * @see #NTRUEncryptionPrivateKeyParameters(InputStream, NTRUEncryptionParameters) - */ - public void writeTo(OutputStream os) - throws IOException - { - os.write(getEncoded()); - } - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + ((params == null) ? 0 : params.hashCode()); - result = prime * result + ((t == null) ? 0 : t.hashCode()); - result = prime * result + ((h == null) ? 0 : h.hashCode()); - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (!(obj instanceof NTRUEncryptionPrivateKeyParameters)) - { - return false; - } - NTRUEncryptionPrivateKeyParameters other = (NTRUEncryptionPrivateKeyParameters)obj; - if (params == null) - { - if (other.params != null) - { - return false; - } - } - else if (!params.equals(other.params)) - { - return false; - } - if (t == null) - { - if (other.t != null) - { - return false; - } - } - else if (!t.equals(other.t)) - { - return false; - } - if (!h.equals(other.h)) - { - return false; - } - return true; - } -}
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionPublicKeyParameters.java deleted file mode 100644 index 0aa03573..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEncryptionPublicKeyParameters.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.bouncycastle.pqc.crypto.ntru; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.bouncycastle.pqc.math.ntru.polynomial.IntegerPolynomial; - -/** - * A NtruEncrypt public key is essentially a polynomial named <code>h</code>. - */ -public class NTRUEncryptionPublicKeyParameters - extends NTRUEncryptionKeyParameters -{ - public IntegerPolynomial h; - - /** - * Constructs a new public key from a polynomial - * - * @param h the polynomial <code>h</code> which determines the key - * @param params the NtruEncrypt parameters to use - */ - public NTRUEncryptionPublicKeyParameters(IntegerPolynomial h, NTRUEncryptionParameters params) - { - super(false, params); - - this.h = h; - } - - /** - * Converts a byte array to a polynomial <code>h</code> and constructs a new public key - * - * @param b an encoded polynomial - * @param params the NtruEncrypt parameters to use - * @see #getEncoded() - */ - public NTRUEncryptionPublicKeyParameters(byte[] b, NTRUEncryptionParameters params) - { - super(false, params); - - h = IntegerPolynomial.fromBinary(b, params.N, params.q); - } - - /** - * Reads a polynomial <code>h</code> from an input stream and constructs a new public key - * - * @param is an input stream - * @param params the NtruEncrypt parameters to use - * @see #writeTo(OutputStream) - */ - public NTRUEncryptionPublicKeyParameters(InputStream is, NTRUEncryptionParameters params) - throws IOException - { - super(false, params); - - h = IntegerPolynomial.fromBinary(is, params.N, params.q); - } - - /** - * Converts the key to a byte array - * - * @return the encoded key - * @see #NTRUEncryptionPublicKeyParameters(byte[], NTRUEncryptionParameters) - */ - public byte[] getEncoded() - { - return h.toBinary(params.q); - } - - /** - * Writes the key to an output stream - * - * @param os an output stream - * @throws IOException - * @see #NTRUEncryptionPublicKeyParameters(InputStream, NTRUEncryptionParameters) - */ - public void writeTo(OutputStream os) - throws IOException - { - os.write(getEncoded()); - } - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + ((h == null) ? 0 : h.hashCode()); - result = prime * result + ((params == null) ? 0 : params.hashCode()); - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (!(obj instanceof NTRUEncryptionPublicKeyParameters)) - { - return false; - } - NTRUEncryptionPublicKeyParameters other = (NTRUEncryptionPublicKeyParameters)obj; - if (h == null) - { - if (other.h != null) - { - return false; - } - } - else if (!h.equals(other.h)) - { - return false; - } - if (params == null) - { - if (other.params != null) - { - return false; - } - } - else if (!params.equals(other.params)) - { - return false; - } - return true; - } -}
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEngine.java deleted file mode 100644 index 6c5fe811..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUEngine.java +++ /dev/null @@ -1,495 +0,0 @@ -package org.bouncycastle.pqc.crypto.ntru; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.AsymmetricBlockCipher; -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.Polynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.ProductFormPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.SparseTernaryPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.TernaryPolynomial; -import org.bouncycastle.util.Arrays; - -/** - * Encrypts, decrypts data and generates key pairs.<br> - * The parameter p is hardcoded to 3. - */ -public class NTRUEngine - implements AsymmetricBlockCipher -{ - private boolean forEncryption; - private NTRUEncryptionParameters params; - private NTRUEncryptionPublicKeyParameters pubKey; - private NTRUEncryptionPrivateKeyParameters privKey; - private SecureRandom random; - - /** - * Constructs a new instance with a set of encryption parameters. - * - */ - public NTRUEngine() - { - } - - public void init(boolean forEncryption, CipherParameters parameters) - { - this.forEncryption = forEncryption; - if (forEncryption) - { - if (parameters instanceof ParametersWithRandom) - { - ParametersWithRandom p = (ParametersWithRandom)parameters; - - this.random = p.getRandom(); - this.pubKey = (NTRUEncryptionPublicKeyParameters)p.getParameters(); - } - else - { - this.random = new SecureRandom(); - this.pubKey = (NTRUEncryptionPublicKeyParameters)parameters; - } - - this.params = pubKey.getParameters(); - } - else - { - this.privKey = (NTRUEncryptionPrivateKeyParameters)parameters; - this.params = privKey.getParameters(); - } - } - - public int getInputBlockSize() - { - return params.maxMsgLenBytes; - } - - public int getOutputBlockSize() - { - return ((params.N * log2(params.q)) + 7) / 8; - } - - public byte[] processBlock(byte[] in, int inOff, int len) - throws InvalidCipherTextException - { - byte[] tmp = new byte[len]; - - System.arraycopy(in, inOff, tmp, 0, len); - - if (forEncryption) - { - return encrypt(tmp, pubKey); - } - else - { - return decrypt(tmp, privKey); - } - } - - /** - * Encrypts a message.<br/> - * See P1363.1 section 9.2.2. - * - * @param m The message to encrypt - * @param pubKey the public key to encrypt the message with - * @return the encrypted message - */ - private byte[] encrypt(byte[] m, NTRUEncryptionPublicKeyParameters pubKey) - { - IntegerPolynomial pub = pubKey.h; - int N = params.N; - int q = params.q; - - int maxLenBytes = params.maxMsgLenBytes; - int db = params.db; - int bufferLenBits = params.bufferLenBits; - int dm0 = params.dm0; - int pkLen = params.pkLen; - int minCallsMask = params.minCallsMask; - boolean hashSeed = params.hashSeed; - byte[] oid = params.oid; - - int l = m.length; - if (maxLenBytes > 255) - { - throw new IllegalArgumentException("llen values bigger than 1 are not supported"); - } - if (l > maxLenBytes) - { - throw new DataLengthException("Message too long: " + l + ">" + maxLenBytes); - } - - while (true) - { - // M = b|octL|m|p0 - byte[] b = new byte[db / 8]; - random.nextBytes(b); - byte[] p0 = new byte[maxLenBytes + 1 - l]; - byte[] M = new byte[bufferLenBits / 8]; - - System.arraycopy(b, 0, M, 0, b.length); - M[b.length] = (byte)l; - System.arraycopy(m, 0, M, b.length + 1, m.length); - System.arraycopy(p0, 0, M, b.length + 1 + m.length, p0.length); - - IntegerPolynomial mTrin = IntegerPolynomial.fromBinary3Sves(M, N); - - // sData = OID|m|b|hTrunc - byte[] bh = pub.toBinary(q); - byte[] hTrunc = copyOf(bh, pkLen / 8); - byte[] sData = buildSData(oid, m, l, b, hTrunc); - - Polynomial r = generateBlindingPoly(sData, M); - IntegerPolynomial R = r.mult(pub, q); - IntegerPolynomial R4 = (IntegerPolynomial)R.clone(); - R4.modPositive(4); - byte[] oR4 = R4.toBinary(4); - IntegerPolynomial mask = MGF(oR4, N, minCallsMask, hashSeed); - mTrin.add(mask); - mTrin.mod3(); - - if (mTrin.count(-1) < dm0) - { - continue; - } - if (mTrin.count(0) < dm0) - { - continue; - } - if (mTrin.count(1) < dm0) - { - continue; - } - - R.add(mTrin, q); - R.ensurePositive(q); - return R.toBinary(q); - } - } - - private byte[] buildSData(byte[] oid, byte[] m, int l, byte[] b, byte[] hTrunc) - { - byte[] sData = new byte[oid.length + l + b.length + hTrunc.length]; - - System.arraycopy(oid, 0, sData, 0, oid.length); - System.arraycopy(m, 0, sData, oid.length, m.length); - System.arraycopy(b, 0, sData, oid.length + m.length, b.length); - System.arraycopy(hTrunc, 0, sData, oid.length + m.length + b.length, hTrunc.length); - return sData; - } - - protected IntegerPolynomial encrypt(IntegerPolynomial m, TernaryPolynomial r, IntegerPolynomial pubKey) - { - IntegerPolynomial e = r.mult(pubKey, params.q); - e.add(m, params.q); - e.ensurePositive(params.q); - return e; - } - - /** - * Deterministically generates a blinding polynomial from a seed and a message representative. - * - * @param seed - * @param M message representative - * @return a blinding polynomial - */ - private Polynomial generateBlindingPoly(byte[] seed, byte[] M) - { - IndexGenerator ig = new IndexGenerator(seed, params); - - if (params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT) - { - SparseTernaryPolynomial r1 = new SparseTernaryPolynomial(generateBlindingCoeffs(ig, params.dr1)); - SparseTernaryPolynomial r2 = new SparseTernaryPolynomial(generateBlindingCoeffs(ig, params.dr2)); - SparseTernaryPolynomial r3 = new SparseTernaryPolynomial(generateBlindingCoeffs(ig, params.dr3)); - return new ProductFormPolynomial(r1, r2, r3); - } - else - { - int dr = params.dr; - boolean sparse = params.sparse; - int[] r = generateBlindingCoeffs(ig, dr); - if (sparse) - { - return new SparseTernaryPolynomial(r); - } - else - { - return new DenseTernaryPolynomial(r); - } - } - } - - /** - * Generates an <code>int</code> array containing <code>dr</code> elements equal to <code>1</code> - * and <code>dr</code> elements equal to <code>-1</code> using an index generator. - * - * @param ig an index generator - * @param dr number of ones / negative ones - * @return an array containing numbers between <code>-1</code> and <code>1</code> - */ - private int[] generateBlindingCoeffs(IndexGenerator ig, int dr) - { - int N = params.N; - - int[] r = new int[N]; - for (int coeff = -1; coeff <= 1; coeff += 2) - { - int t = 0; - while (t < dr) - { - int i = ig.nextIndex(); - if (r[i] == 0) - { - r[i] = coeff; - t++; - } - } - } - - return r; - } - - /** - * An implementation of MGF-TP-1 from P1363.1 section 8.4.1.1. - * - * @param seed - * @param N - * @param minCallsR - * @param hashSeed whether to hash the seed - * @return - */ - private IntegerPolynomial MGF(byte[] seed, int N, int minCallsR, boolean hashSeed) - { - Digest hashAlg = params.hashAlg; - int hashLen = hashAlg.getDigestSize(); - byte[] buf = new byte[minCallsR * hashLen]; - byte[] Z = hashSeed ? calcHash(hashAlg, seed) : seed; - int counter = 0; - while (counter < minCallsR) - { - hashAlg.update(Z, 0, Z.length); - putInt(hashAlg, counter); - - byte[] hash = calcHash(hashAlg); - System.arraycopy(hash, 0, buf, counter * hashLen, hashLen); - counter++; - } - - IntegerPolynomial i = new IntegerPolynomial(N); - while (true) - { - int cur = 0; - for (int index = 0; index != buf.length; index++) - { - int O = (int)buf[index] & 0xFF; - if (O >= 243) // 243 = 3^5 - { - continue; - } - - for (int terIdx = 0; terIdx < 4; terIdx++) - { - int rem3 = O % 3; - i.coeffs[cur] = rem3 - 1; - cur++; - if (cur == N) - { - return i; - } - O = (O - rem3) / 3; - } - - i.coeffs[cur] = O - 1; - cur++; - if (cur == N) - { - return i; - } - } - - if (cur >= N) - { - return i; - } - - hashAlg.update(Z, 0, Z.length); - putInt(hashAlg, counter); - - byte[] hash = calcHash(hashAlg); - - buf = hash; - - counter++; - } - } - - private void putInt(Digest hashAlg, int counter) - { - hashAlg.update((byte)(counter >> 24)); - hashAlg.update((byte)(counter >> 16)); - hashAlg.update((byte)(counter >> 8)); - hashAlg.update((byte)counter); - } - - private byte[] calcHash(Digest hashAlg) - { - byte[] tmp = new byte[hashAlg.getDigestSize()]; - - hashAlg.doFinal(tmp, 0); - - return tmp; - } - - private byte[] calcHash(Digest hashAlg, byte[] input) - { - byte[] tmp = new byte[hashAlg.getDigestSize()]; - - hashAlg.update(input, 0, input.length); - hashAlg.doFinal(tmp, 0); - - return tmp; - } - /** - * Decrypts a message.<br/> - * See P1363.1 section 9.2.3. - * - * @param data The message to decrypt - * @param privKey the corresponding private key - * @return the decrypted message - * @throws InvalidCipherTextException if the encrypted data is invalid, or <code>maxLenBytes</code> is greater than 255 - */ - private byte[] decrypt(byte[] data, NTRUEncryptionPrivateKeyParameters privKey) - throws InvalidCipherTextException - { - Polynomial priv_t = privKey.t; - IntegerPolynomial priv_fp = privKey.fp; - IntegerPolynomial pub = privKey.h; - int N = params.N; - int q = params.q; - int db = params.db; - int maxMsgLenBytes = params.maxMsgLenBytes; - int dm0 = params.dm0; - int pkLen = params.pkLen; - int minCallsMask = params.minCallsMask; - boolean hashSeed = params.hashSeed; - byte[] oid = params.oid; - - if (maxMsgLenBytes > 255) - { - throw new DataLengthException("maxMsgLenBytes values bigger than 255 are not supported"); - } - - int bLen = db / 8; - - IntegerPolynomial e = IntegerPolynomial.fromBinary(data, N, q); - IntegerPolynomial ci = decrypt(e, priv_t, priv_fp); - - if (ci.count(-1) < dm0) - { - throw new InvalidCipherTextException("Less than dm0 coefficients equal -1"); - } - if (ci.count(0) < dm0) - { - throw new InvalidCipherTextException("Less than dm0 coefficients equal 0"); - } - if (ci.count(1) < dm0) - { - throw new InvalidCipherTextException("Less than dm0 coefficients equal 1"); - } - - IntegerPolynomial cR = (IntegerPolynomial)e.clone(); - cR.sub(ci); - cR.modPositive(q); - IntegerPolynomial cR4 = (IntegerPolynomial)cR.clone(); - cR4.modPositive(4); - byte[] coR4 = cR4.toBinary(4); - IntegerPolynomial mask = MGF(coR4, N, minCallsMask, hashSeed); - IntegerPolynomial cMTrin = ci; - cMTrin.sub(mask); - cMTrin.mod3(); - byte[] cM = cMTrin.toBinary3Sves(); - - byte[] cb = new byte[bLen]; - System.arraycopy(cM, 0, cb, 0, bLen); - int cl = cM[bLen] & 0xFF; // llen=1, so read one byte - if (cl > maxMsgLenBytes) - { - throw new InvalidCipherTextException("Message too long: " + cl + ">" + maxMsgLenBytes); - } - byte[] cm = new byte[cl]; - System.arraycopy(cM, bLen + 1, cm, 0, cl); - byte[] p0 = new byte[cM.length - (bLen + 1 + cl)]; - System.arraycopy(cM, bLen + 1 + cl, p0, 0, p0.length); - if (!Arrays.areEqual(p0, new byte[p0.length])) - { - throw new InvalidCipherTextException("The message is not followed by zeroes"); - } - - // sData = OID|m|b|hTrunc - byte[] bh = pub.toBinary(q); - byte[] hTrunc = copyOf(bh, pkLen / 8); - byte[] sData = buildSData(oid, cm, cl, cb, hTrunc); - - Polynomial cr = generateBlindingPoly(sData, cm); - IntegerPolynomial cRPrime = cr.mult(pub); - cRPrime.modPositive(q); - if (!cRPrime.equals(cR)) - { - throw new InvalidCipherTextException("Invalid message encoding"); - } - - return cm; - } - - /** - * @param e - * @param priv_t a polynomial such that if <code>fastFp=true</code>, <code>f=1+3*priv_t</code>; otherwise, <code>f=priv_t</code> - * @param priv_fp - * @return - */ - protected IntegerPolynomial decrypt(IntegerPolynomial e, Polynomial priv_t, IntegerPolynomial priv_fp) - { - IntegerPolynomial a; - if (params.fastFp) - { - a = priv_t.mult(e, params.q); - a.mult(3); - a.add(e); - } - else - { - a = priv_t.mult(e, params.q); - } - a.center0(params.q); - a.mod3(); - - IntegerPolynomial c = params.fastFp ? a : new DenseTernaryPolynomial(a).mult(priv_fp, 3); - c.center0(3); - return c; - } - - private byte[] copyOf(byte[] src, int len) - { - byte[] tmp = new byte[len]; - - System.arraycopy(src, 0, tmp, 0, len < src.length ? len : src.length); - - return tmp; - } - - private int log2(int value) - { - if (value == 2048) - { - return 11; - } - - throw new IllegalStateException("log2 not fully implemented"); - } -}
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUParameters.java deleted file mode 100644 index 158c0386..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUParameters.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.bouncycastle.pqc.crypto.ntru; - -public class NTRUParameters -{ - public static final int TERNARY_POLYNOMIAL_TYPE_SIMPLE = 0; - public static final int TERNARY_POLYNOMIAL_TYPE_PRODUCT = 1; -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigner.java deleted file mode 100644 index 19bf8024..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigner.java +++ /dev/null @@ -1,263 +0,0 @@ -package org.bouncycastle.pqc.crypto.ntru; - -import java.nio.ByteBuffer; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.pqc.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.Polynomial; - -/** -* Signs, verifies data and generates key pairs. -* @deprecated the NTRUSigner algorithm was broken in 2012 by Ducas and Nguyen. See -* <a href="http://www.di.ens.fr/~ducas/NTRUSign_Cryptanalysis/DucasNguyen_Learning.pdf"> -* http://www.di.ens.fr/~ducas/NTRUSign_Cryptanalysis/DucasNguyen_Learning.pdf</a> -* for details. -*/ -public class NTRUSigner -{ - private NTRUSigningParameters params; - private Digest hashAlg; - private NTRUSigningPrivateKeyParameters signingKeyPair; - private NTRUSigningPublicKeyParameters verificationKey; - - /** - * Constructs a new instance with a set of signature parameters. - * - * @param params signature parameters - */ - public NTRUSigner(NTRUSigningParameters params) - { - this.params = params; - } - - /** - * Resets the engine for signing a message. - * - * @param forSigning - * @param params - */ - public void init(boolean forSigning, CipherParameters params) - { - if (forSigning) - { - this.signingKeyPair = (NTRUSigningPrivateKeyParameters)params; - } - else - { - this.verificationKey = (NTRUSigningPublicKeyParameters)params; - } - hashAlg = this.params.hashAlg; - hashAlg.reset(); - } - - /** - * Adds data to sign or verify. - * - * @param b data - */ - public void update(byte b) - { - if (hashAlg == null) - { - throw new IllegalStateException("Call initSign or initVerify first!"); - } - - hashAlg.update(b); - } - - /** - * Adds data to sign or verify. - * - * @param m data - * @param off offset - * @param length number of bytes - */ - public void update(byte[] m, int off, int length) - { - if (hashAlg == null) - { - throw new IllegalStateException("Call initSign or initVerify first!"); - } - - hashAlg.update(m, off, length); - } - - /** - * Adds data to sign and computes a signature over this data and any data previously added via {@link #update(byte[], int, int)}. - * - * @return a signature - * @throws IllegalStateException if <code>initSign</code> was not called - */ - public byte[] generateSignature() - { - if (hashAlg == null || signingKeyPair == null) - { - throw new IllegalStateException("Call initSign first!"); - } - - byte[] msgHash = new byte[hashAlg.getDigestSize()]; - - hashAlg.doFinal(msgHash, 0); - return signHash(msgHash, signingKeyPair); - } - - private byte[] signHash(byte[] msgHash, NTRUSigningPrivateKeyParameters kp) - { - int r = 0; - IntegerPolynomial s; - IntegerPolynomial i; - - NTRUSigningPublicKeyParameters kPub = kp.getPublicKey(); - do - { - r++; - if (r > params.signFailTolerance) - { - throw new IllegalStateException("Signing failed: too many retries (max=" + params.signFailTolerance + ")"); - } - i = createMsgRep(msgHash, r); - s = sign(i, kp); - } - while (!verify(i, s, kPub.h)); - - byte[] rawSig = s.toBinary(params.q); - ByteBuffer sbuf = ByteBuffer.allocate(rawSig.length + 4); - sbuf.put(rawSig); - sbuf.putInt(r); - return sbuf.array(); - } - - private IntegerPolynomial sign(IntegerPolynomial i, NTRUSigningPrivateKeyParameters kp) - { - int N = params.N; - int q = params.q; - int perturbationBases = params.B; - - NTRUSigningPrivateKeyParameters kPriv = kp; - NTRUSigningPublicKeyParameters kPub = kp.getPublicKey(); - - IntegerPolynomial s = new IntegerPolynomial(N); - int iLoop = perturbationBases; - while (iLoop >= 1) - { - Polynomial f = kPriv.getBasis(iLoop).f; - Polynomial fPrime = kPriv.getBasis(iLoop).fPrime; - - IntegerPolynomial y = f.mult(i); - y.div(q); - y = fPrime.mult(y); - - IntegerPolynomial x = fPrime.mult(i); - x.div(q); - x = f.mult(x); - - IntegerPolynomial si = y; - si.sub(x); - s.add(si); - - IntegerPolynomial hi = (IntegerPolynomial)kPriv.getBasis(iLoop).h.clone(); - if (iLoop > 1) - { - hi.sub(kPriv.getBasis(iLoop - 1).h); - } - else - { - hi.sub(kPub.h); - } - i = si.mult(hi, q); - - iLoop--; - } - - Polynomial f = kPriv.getBasis(0).f; - Polynomial fPrime = kPriv.getBasis(0).fPrime; - - IntegerPolynomial y = f.mult(i); - y.div(q); - y = fPrime.mult(y); - - IntegerPolynomial x = fPrime.mult(i); - x.div(q); - x = f.mult(x); - - y.sub(x); - s.add(y); - s.modPositive(q); - return s; - } - - /** - * Verifies a signature for any data previously added via {@link #update(byte[], int, int)}. - * - * @param sig a signature - * @return whether the signature is valid - * @throws IllegalStateException if <code>initVerify</code> was not called - */ - public boolean verifySignature(byte[] sig) - { - if (hashAlg == null || verificationKey == null) - { - throw new IllegalStateException("Call initVerify first!"); - } - - byte[] msgHash = new byte[hashAlg.getDigestSize()]; - - hashAlg.doFinal(msgHash, 0); - - return verifyHash(msgHash, sig, verificationKey); - } - - private boolean verifyHash(byte[] msgHash, byte[] sig, NTRUSigningPublicKeyParameters pub) - { - ByteBuffer sbuf = ByteBuffer.wrap(sig); - byte[] rawSig = new byte[sig.length - 4]; - sbuf.get(rawSig); - IntegerPolynomial s = IntegerPolynomial.fromBinary(rawSig, params.N, params.q); - int r = sbuf.getInt(); - return verify(createMsgRep(msgHash, r), s, pub.h); - } - - private boolean verify(IntegerPolynomial i, IntegerPolynomial s, IntegerPolynomial h) - { - int q = params.q; - double normBoundSq = params.normBoundSq; - double betaSq = params.betaSq; - - IntegerPolynomial t = h.mult(s, q); - t.sub(i); - long centeredNormSq = (long)(s.centeredNormSq(q) + betaSq * t.centeredNormSq(q)); - return centeredNormSq <= normBoundSq; - } - - protected IntegerPolynomial createMsgRep(byte[] msgHash, int r) - { - int N = params.N; - int q = params.q; - - int c = 31 - Integer.numberOfLeadingZeros(q); - int B = (c + 7) / 8; - IntegerPolynomial i = new IntegerPolynomial(N); - - ByteBuffer cbuf = ByteBuffer.allocate(msgHash.length + 4); - cbuf.put(msgHash); - cbuf.putInt(r); - NTRUSignerPrng prng = new NTRUSignerPrng(cbuf.array(), params.hashAlg); - - for (int t = 0; t < N; t++) - { - byte[] o = prng.nextBytes(B); - int hi = o[o.length - 1]; - hi >>= 8 * B - c; - hi <<= 8 * B - c; - o[o.length - 1] = (byte)hi; - - ByteBuffer obuf = ByteBuffer.allocate(4); - obuf.put(o); - obuf.rewind(); - // reverse byte order so it matches the endianness of java ints - i.coeffs[t] = Integer.reverseBytes(obuf.getInt()); - } - return i; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSignerPrng.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSignerPrng.java deleted file mode 100644 index 77ed63a2..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSignerPrng.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.bouncycastle.pqc.crypto.ntru; - -import java.nio.ByteBuffer; - -import org.bouncycastle.crypto.Digest; - -/** - * An implementation of the deterministic pseudo-random generator in EESS section 3.7.3.1 - */ -public class NTRUSignerPrng -{ - private int counter; - private byte[] seed; - private Digest hashAlg; - - /** - * Constructs a new PRNG and seeds it with a byte array. - * - * @param seed a seed - * @param hashAlg the hash algorithm to use - */ - NTRUSignerPrng(byte[] seed, Digest hashAlg) - { - counter = 0; - this.seed = seed; - this.hashAlg = hashAlg; - } - - /** - * Returns <code>n</code> random bytes - * - * @param n number of bytes to return - * @return the next <code>n</code> random bytes - */ - byte[] nextBytes(int n) - { - ByteBuffer buf = ByteBuffer.allocate(n); - - while (buf.hasRemaining()) - { - ByteBuffer cbuf = ByteBuffer.allocate(seed.length + 4); - cbuf.put(seed); - cbuf.putInt(counter); - byte[] array = cbuf.array(); - byte[] hash = new byte[hashAlg.getDigestSize()]; - - hashAlg.update(array, 0, array.length); - - hashAlg.doFinal(hash, 0); - - if (buf.remaining() < hash.length) - { - buf.put(hash, 0, buf.remaining()); - } - else - { - buf.put(hash); - } - counter++; - } - - return buf.array(); - } -}
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigningKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigningKeyGenerationParameters.java deleted file mode 100644 index b6ff8c5a..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigningKeyGenerationParameters.java +++ /dev/null @@ -1,407 +0,0 @@ -package org.bouncycastle.pqc.crypto.ntru; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.SecureRandom; -import java.text.DecimalFormat; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; - -/** - * A set of parameters for NtruSign. Several predefined parameter sets are available and new ones can be created as well. - */ -public class NTRUSigningKeyGenerationParameters - extends KeyGenerationParameters - implements Cloneable -{ - public static final int BASIS_TYPE_STANDARD = 0; - public static final int BASIS_TYPE_TRANSPOSE = 1; - - public static final int KEY_GEN_ALG_RESULTANT = 0; - public static final int KEY_GEN_ALG_FLOAT = 1; - - /** - * Gives 128 bits of security - */ - public static final NTRUSigningKeyGenerationParameters APR2011_439 = new NTRUSigningKeyGenerationParameters(439, 2048, 146, 1, BASIS_TYPE_TRANSPOSE, 0.165, 490, 280, false, true, KEY_GEN_ALG_RESULTANT, new SHA256Digest()); - - /** - * Like <code>APR2011_439</code>, this parameter set gives 128 bits of security but uses product-form polynomials - */ - public static final NTRUSigningKeyGenerationParameters APR2011_439_PROD = new NTRUSigningKeyGenerationParameters(439, 2048, 9, 8, 5, 1, BASIS_TYPE_TRANSPOSE, 0.165, 490, 280, false, true, KEY_GEN_ALG_RESULTANT, new SHA256Digest()); - - /** - * Gives 256 bits of security - */ - public static final NTRUSigningKeyGenerationParameters APR2011_743 = new NTRUSigningKeyGenerationParameters(743, 2048, 248, 1, BASIS_TYPE_TRANSPOSE, 0.127, 560, 360, true, false, KEY_GEN_ALG_RESULTANT, new SHA512Digest()); - - /** - * Like <code>APR2011_439</code>, this parameter set gives 256 bits of security but uses product-form polynomials - */ - public static final NTRUSigningKeyGenerationParameters APR2011_743_PROD = new NTRUSigningKeyGenerationParameters(743, 2048, 11, 11, 15, 1, BASIS_TYPE_TRANSPOSE, 0.127, 560, 360, true, false, KEY_GEN_ALG_RESULTANT, new SHA512Digest()); - - /** - * Generates key pairs quickly. Use for testing only. - */ - public static final NTRUSigningKeyGenerationParameters TEST157 = new NTRUSigningKeyGenerationParameters(157, 256, 29, 1, BASIS_TYPE_TRANSPOSE, 0.38, 200, 80, false, false, KEY_GEN_ALG_RESULTANT, new SHA256Digest()); - /** - * Generates key pairs quickly. Use for testing only. - */ - public static final NTRUSigningKeyGenerationParameters TEST157_PROD = new NTRUSigningKeyGenerationParameters(157, 256, 5, 5, 8, 1, BASIS_TYPE_TRANSPOSE, 0.38, 200, 80, false, false, KEY_GEN_ALG_RESULTANT, new SHA256Digest()); - - - public int N; - public int q; - public int d, d1, d2, d3, B; - double beta; - public double betaSq; - double normBound; - public double normBoundSq; - public int signFailTolerance = 100; - double keyNormBound; - public double keyNormBoundSq; - public boolean primeCheck; // true if N and 2N+1 are prime - public int basisType; - int bitsF = 6; // max #bits needed to encode one coefficient of the polynomial F - public boolean sparse; // whether to treat ternary polynomials as sparsely populated - public int keyGenAlg; - public Digest hashAlg; - public int polyType; - - /** - * Constructs a parameter set that uses ternary private keys (i.e. <code>polyType=SIMPLE</code>). - * - * @param N number of polynomial coefficients - * @param q modulus - * @param d number of -1's in the private polynomials <code>f</code> and <code>g</code> - * @param B number of perturbations - * @param basisType whether to use the standard or transpose lattice - * @param beta balancing factor for the transpose lattice - * @param normBound maximum norm for valid signatures - * @param keyNormBound maximum norm for the ploynomials <code>F</code> and <code>G</code> - * @param primeCheck whether <code>2N+1</code> is prime - * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bouncycastle.pqc.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bouncycastle.pqc.math.ntru.polynomial.DenseTernaryPolynomial}) - * @param keyGenAlg <code>RESULTANT</code> produces better bases, <code>FLOAT</code> is slightly faster. <code>RESULTANT</code> follows the EESS standard while <code>FLOAT</code> is described in Hoffstein et al: An Introduction to Mathematical Cryptography. - * @param hashAlg a valid identifier for a <code>java.security.MessageDigest</code> instance such as <code>SHA-256</code>. The <code>MessageDigest</code> must support the <code>getDigestLength()</code> method. - */ - public NTRUSigningKeyGenerationParameters(int N, int q, int d, int B, int basisType, double beta, double normBound, double keyNormBound, boolean primeCheck, boolean sparse, int keyGenAlg, Digest hashAlg) - { - super(new SecureRandom(), N); - this.N = N; - this.q = q; - this.d = d; - this.B = B; - this.basisType = basisType; - this.beta = beta; - this.normBound = normBound; - this.keyNormBound = keyNormBound; - this.primeCheck = primeCheck; - this.sparse = sparse; - this.keyGenAlg = keyGenAlg; - this.hashAlg = hashAlg; - polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE; - init(); - } - - /** - * Constructs a parameter set that uses product-form private keys (i.e. <code>polyType=PRODUCT</code>). - * - * @param N number of polynomial coefficients - * @param q modulus - * @param d1 number of -1's in the private polynomials <code>f</code> and <code>g</code> - * @param d2 number of -1's in the private polynomials <code>f</code> and <code>g</code> - * @param d3 number of -1's in the private polynomials <code>f</code> and <code>g</code> - * @param B number of perturbations - * @param basisType whether to use the standard or transpose lattice - * @param beta balancing factor for the transpose lattice - * @param normBound maximum norm for valid signatures - * @param keyNormBound maximum norm for the ploynomials <code>F</code> and <code>G</code> - * @param primeCheck whether <code>2N+1</code> is prime - * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bouncycastle.pqc.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bouncycastle.pqc.math.ntru.polynomial.DenseTernaryPolynomial}) - * @param keyGenAlg <code>RESULTANT</code> produces better bases, <code>FLOAT</code> is slightly faster. <code>RESULTANT</code> follows the EESS standard while <code>FLOAT</code> is described in Hoffstein et al: An Introduction to Mathematical Cryptography. - * @param hashAlg a valid identifier for a <code>java.security.MessageDigest</code> instance such as <code>SHA-256</code>. The <code>MessageDigest</code> must support the <code>getDigestLength()</code> method. - */ - public NTRUSigningKeyGenerationParameters(int N, int q, int d1, int d2, int d3, int B, int basisType, double beta, double normBound, double keyNormBound, boolean primeCheck, boolean sparse, int keyGenAlg, Digest hashAlg) - { - super(new SecureRandom(), N); - this.N = N; - this.q = q; - this.d1 = d1; - this.d2 = d2; - this.d3 = d3; - this.B = B; - this.basisType = basisType; - this.beta = beta; - this.normBound = normBound; - this.keyNormBound = keyNormBound; - this.primeCheck = primeCheck; - this.sparse = sparse; - this.keyGenAlg = keyGenAlg; - this.hashAlg = hashAlg; - polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT; - init(); - } - - private void init() - { - betaSq = beta * beta; - normBoundSq = normBound * normBound; - keyNormBoundSq = keyNormBound * keyNormBound; - } - - /** - * Reads a parameter set from an input stream. - * - * @param is an input stream - * @throws java.io.IOException - */ - public NTRUSigningKeyGenerationParameters(InputStream is) - throws IOException - { - super(new SecureRandom(), 0); // TODO: - DataInputStream dis = new DataInputStream(is); - N = dis.readInt(); - q = dis.readInt(); - d = dis.readInt(); - d1 = dis.readInt(); - d2 = dis.readInt(); - d3 = dis.readInt(); - B = dis.readInt(); - basisType = dis.readInt(); - beta = dis.readDouble(); - normBound = dis.readDouble(); - keyNormBound = dis.readDouble(); - signFailTolerance = dis.readInt(); - primeCheck = dis.readBoolean(); - sparse = dis.readBoolean(); - bitsF = dis.readInt(); - keyGenAlg = dis.read(); - String alg = dis.readUTF(); - if ("SHA-512".equals(alg)) - { - hashAlg = new SHA512Digest(); - } - else if ("SHA-256".equals(alg)) - { - hashAlg = new SHA256Digest(); - } - polyType = dis.read(); - init(); - } - - /** - * Writes the parameter set to an output stream - * - * @param os an output stream - * @throws java.io.IOException - */ - public void writeTo(OutputStream os) - throws IOException - { - DataOutputStream dos = new DataOutputStream(os); - dos.writeInt(N); - dos.writeInt(q); - dos.writeInt(d); - dos.writeInt(d1); - dos.writeInt(d2); - dos.writeInt(d3); - dos.writeInt(B); - dos.writeInt(basisType); - dos.writeDouble(beta); - dos.writeDouble(normBound); - dos.writeDouble(keyNormBound); - dos.writeInt(signFailTolerance); - dos.writeBoolean(primeCheck); - dos.writeBoolean(sparse); - dos.writeInt(bitsF); - dos.write(keyGenAlg); - dos.writeUTF(hashAlg.getAlgorithmName()); - dos.write(polyType); - } - - public NTRUSigningParameters getSigningParameters() - { - return new NTRUSigningParameters(N, q, d, B, beta, normBound, hashAlg); - } - - public NTRUSigningKeyGenerationParameters clone() - { - if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE) - { - return new NTRUSigningKeyGenerationParameters(N, q, d, B, basisType, beta, normBound, keyNormBound, primeCheck, sparse, keyGenAlg, hashAlg); - } - else - { - return new NTRUSigningKeyGenerationParameters(N, q, d1, d2, d3, B, basisType, beta, normBound, keyNormBound, primeCheck, sparse, keyGenAlg, hashAlg); - } - } - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + B; - result = prime * result + N; - result = prime * result + basisType; - long temp; - temp = Double.doubleToLongBits(beta); - result = prime * result + (int)(temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(betaSq); - result = prime * result + (int)(temp ^ (temp >>> 32)); - result = prime * result + bitsF; - result = prime * result + d; - result = prime * result + d1; - result = prime * result + d2; - result = prime * result + d3; - result = prime * result + ((hashAlg == null) ? 0 : hashAlg.getAlgorithmName().hashCode()); - result = prime * result + keyGenAlg; - temp = Double.doubleToLongBits(keyNormBound); - result = prime * result + (int)(temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(keyNormBoundSq); - result = prime * result + (int)(temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(normBound); - result = prime * result + (int)(temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(normBoundSq); - result = prime * result + (int)(temp ^ (temp >>> 32)); - result = prime * result + polyType; - result = prime * result + (primeCheck ? 1231 : 1237); - result = prime * result + q; - result = prime * result + signFailTolerance; - result = prime * result + (sparse ? 1231 : 1237); - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (!(obj instanceof NTRUSigningKeyGenerationParameters)) - { - return false; - } - NTRUSigningKeyGenerationParameters other = (NTRUSigningKeyGenerationParameters)obj; - if (B != other.B) - { - return false; - } - if (N != other.N) - { - return false; - } - if (basisType != other.basisType) - { - return false; - } - if (Double.doubleToLongBits(beta) != Double.doubleToLongBits(other.beta)) - { - return false; - } - if (Double.doubleToLongBits(betaSq) != Double.doubleToLongBits(other.betaSq)) - { - return false; - } - if (bitsF != other.bitsF) - { - return false; - } - if (d != other.d) - { - return false; - } - if (d1 != other.d1) - { - return false; - } - if (d2 != other.d2) - { - return false; - } - if (d3 != other.d3) - { - return false; - } - if (hashAlg == null) - { - if (other.hashAlg != null) - { - return false; - } - } - else if (!hashAlg.getAlgorithmName().equals(other.hashAlg.getAlgorithmName())) - { - return false; - } - if (keyGenAlg != other.keyGenAlg) - { - return false; - } - if (Double.doubleToLongBits(keyNormBound) != Double.doubleToLongBits(other.keyNormBound)) - { - return false; - } - if (Double.doubleToLongBits(keyNormBoundSq) != Double.doubleToLongBits(other.keyNormBoundSq)) - { - return false; - } - if (Double.doubleToLongBits(normBound) != Double.doubleToLongBits(other.normBound)) - { - return false; - } - if (Double.doubleToLongBits(normBoundSq) != Double.doubleToLongBits(other.normBoundSq)) - { - return false; - } - if (polyType != other.polyType) - { - return false; - } - if (primeCheck != other.primeCheck) - { - return false; - } - if (q != other.q) - { - return false; - } - if (signFailTolerance != other.signFailTolerance) - { - return false; - } - if (sparse != other.sparse) - { - return false; - } - return true; - } - - public String toString() - { - DecimalFormat format = new DecimalFormat("0.00"); - - StringBuilder output = new StringBuilder("SignatureParameters(N=" + N + " q=" + q); - if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE) - { - output.append(" polyType=SIMPLE d=" + d); - } - else - { - output.append(" polyType=PRODUCT d1=" + d1 + " d2=" + d2 + " d3=" + d3); - } - output.append(" B=" + B + " basisType=" + basisType + " beta=" + format.format(beta) + - " normBound=" + format.format(normBound) + " keyNormBound=" + format.format(keyNormBound) + - " prime=" + primeCheck + " sparse=" + sparse + " keyGenAlg=" + keyGenAlg + " hashAlg=" + hashAlg + ")"); - return output.toString(); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigningKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigningKeyPairGenerator.java deleted file mode 100644 index 1471509a..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigningKeyPairGenerator.java +++ /dev/null @@ -1,357 +0,0 @@ -package org.bouncycastle.pqc.crypto.ntru; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.pqc.math.ntru.euclid.BigIntEuclidean; -import org.bouncycastle.pqc.math.ntru.polynomial.BigDecimalPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.BigIntPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.Polynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.ProductFormPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.Resultant; - -import static java.math.BigInteger.ONE; -import static java.math.BigInteger.ZERO; - -public class NTRUSigningKeyPairGenerator - implements AsymmetricCipherKeyPairGenerator -{ - private NTRUSigningKeyGenerationParameters params; - - public void init(KeyGenerationParameters param) - { - this.params = (NTRUSigningKeyGenerationParameters)param; - } - - /** - * Generates a new signature key pair. Starts <code>B+1</code> threads. - * - * @return a key pair - */ - public AsymmetricCipherKeyPair generateKeyPair() - { - NTRUSigningPublicKeyParameters pub = null; - ExecutorService executor = Executors.newCachedThreadPool(); - List<Future<NTRUSigningPrivateKeyParameters.Basis>> bases = new ArrayList<Future<NTRUSigningPrivateKeyParameters.Basis>>(); - for (int k = params.B; k >= 0; k--) - { - bases.add(executor.submit(new BasisGenerationTask())); - } - executor.shutdown(); - - List<NTRUSigningPrivateKeyParameters.Basis> basises = new ArrayList<NTRUSigningPrivateKeyParameters.Basis>(); - - for (int k = params.B; k >= 0; k--) - { - Future<NTRUSigningPrivateKeyParameters.Basis> basis = bases.get(k); - try - { - basises.add(basis.get()); - if (k == params.B) - { - pub = new NTRUSigningPublicKeyParameters(basis.get().h, params.getSigningParameters()); - } - } - catch (Exception e) - { - throw new IllegalStateException(e); - } - } - NTRUSigningPrivateKeyParameters priv = new NTRUSigningPrivateKeyParameters(basises, pub); - AsymmetricCipherKeyPair kp = new AsymmetricCipherKeyPair(pub, priv); - return kp; - } - - /** - * Generates a new signature key pair. Runs in a single thread. - * - * @return a key pair - */ - public AsymmetricCipherKeyPair generateKeyPairSingleThread() - { - List<NTRUSigningPrivateKeyParameters.Basis> basises = new ArrayList<NTRUSigningPrivateKeyParameters.Basis>(); - NTRUSigningPublicKeyParameters pub = null; - for (int k = params.B; k >= 0; k--) - { - NTRUSigningPrivateKeyParameters.Basis basis = generateBoundedBasis(); - basises.add(basis); - if (k == 0) - { - pub = new NTRUSigningPublicKeyParameters(basis.h, params.getSigningParameters()); - } - } - NTRUSigningPrivateKeyParameters priv = new NTRUSigningPrivateKeyParameters(basises, pub); - return new AsymmetricCipherKeyPair(pub, priv); - } - - - /** - * Implementation of the optional steps 20 through 26 in EESS1v2.pdf, section 3.5.1.1. - * This doesn't seem to have much of an effect and sometimes actually increases the - * norm of F, but on average it slightly reduces the norm.<br/> - * This method changes <code>F</code> and <code>g</code> but leaves <code>f</code> and - * <code>g</code> unchanged. - * - * @param f - * @param g - * @param F - * @param G - * @param N - */ - private void minimizeFG(IntegerPolynomial f, IntegerPolynomial g, IntegerPolynomial F, IntegerPolynomial G, int N) - { - int E = 0; - for (int j = 0; j < N; j++) - { - E += 2 * N * (f.coeffs[j] * f.coeffs[j] + g.coeffs[j] * g.coeffs[j]); - } - - // [f(1)+g(1)]^2 = 4 - E -= 4; - - IntegerPolynomial u = (IntegerPolynomial)f.clone(); - IntegerPolynomial v = (IntegerPolynomial)g.clone(); - int j = 0; - int k = 0; - int maxAdjustment = N; - while (k < maxAdjustment && j < N) - { - int D = 0; - int i = 0; - while (i < N) - { - int D1 = F.coeffs[i] * f.coeffs[i]; - int D2 = G.coeffs[i] * g.coeffs[i]; - int D3 = 4 * N * (D1 + D2); - D += D3; - i++; - } - // f(1)+g(1) = 2 - int D1 = 4 * (F.sumCoeffs() + G.sumCoeffs()); - D -= D1; - - if (D > E) - { - F.sub(u); - G.sub(v); - k++; - j = 0; - } - else if (D < -E) - { - F.add(u); - G.add(v); - k++; - j = 0; - } - j++; - u.rotate1(); - v.rotate1(); - } - } - - /** - * Creates a NTRUSigner basis consisting of polynomials <code>f, g, F, G, h</code>.<br/> - * If <code>KeyGenAlg=FLOAT</code>, the basis may not be valid and this method must be rerun if that is the case.<br/> - * - * @see #generateBoundedBasis() - */ - private FGBasis generateBasis() - { - int N = params.N; - int q = params.q; - int d = params.d; - int d1 = params.d1; - int d2 = params.d2; - int d3 = params.d3; - int basisType = params.basisType; - - Polynomial f; - IntegerPolynomial fInt; - Polynomial g; - IntegerPolynomial gInt; - IntegerPolynomial fq; - Resultant rf; - Resultant rg; - BigIntEuclidean r; - - int _2n1 = 2 * N + 1; - boolean primeCheck = params.primeCheck; - - do - { - do - { - f = params.polyType== NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? DenseTernaryPolynomial.generateRandom(N, d + 1, d, new SecureRandom()) : ProductFormPolynomial.generateRandom(N, d1, d2, d3 + 1, d3, new SecureRandom()); - fInt = f.toIntegerPolynomial(); - } - while (primeCheck && fInt.resultant(_2n1).res.equals(ZERO)); - fq = fInt.invertFq(q); - } - while (fq == null); - rf = fInt.resultant(); - - do - { - do - { - do - { - g = params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? DenseTernaryPolynomial.generateRandom(N, d + 1, d, new SecureRandom()) : ProductFormPolynomial.generateRandom(N, d1, d2, d3 + 1, d3, new SecureRandom()); - gInt = g.toIntegerPolynomial(); - } - while (primeCheck && gInt.resultant(_2n1).res.equals(ZERO)); - } - while (gInt.invertFq(q) == null); - rg = gInt.resultant(); - r = BigIntEuclidean.calculate(rf.res, rg.res); - } - while (!r.gcd.equals(ONE)); - - BigIntPolynomial A = (BigIntPolynomial)rf.rho.clone(); - A.mult(r.x.multiply(BigInteger.valueOf(q))); - BigIntPolynomial B = (BigIntPolynomial)rg.rho.clone(); - B.mult(r.y.multiply(BigInteger.valueOf(-q))); - - BigIntPolynomial C; - if (params.keyGenAlg == NTRUSigningKeyGenerationParameters.KEY_GEN_ALG_RESULTANT) - { - int[] fRevCoeffs = new int[N]; - int[] gRevCoeffs = new int[N]; - fRevCoeffs[0] = fInt.coeffs[0]; - gRevCoeffs[0] = gInt.coeffs[0]; - for (int i = 1; i < N; i++) - { - fRevCoeffs[i] = fInt.coeffs[N - i]; - gRevCoeffs[i] = gInt.coeffs[N - i]; - } - IntegerPolynomial fRev = new IntegerPolynomial(fRevCoeffs); - IntegerPolynomial gRev = new IntegerPolynomial(gRevCoeffs); - - IntegerPolynomial t = f.mult(fRev); - t.add(g.mult(gRev)); - Resultant rt = t.resultant(); - C = fRev.mult(B); // fRev.mult(B) is actually faster than new SparseTernaryPolynomial(fRev).mult(B), possibly due to cache locality? - C.add(gRev.mult(A)); - C = C.mult(rt.rho); - C.div(rt.res); - } - else - { // KeyGenAlg.FLOAT - // calculate ceil(log10(N)) - int log10N = 0; - for (int i = 1; i < N; i *= 10) - { - log10N++; - } - - // * Cdec needs to be accurate to 1 decimal place so it can be correctly rounded; - // * fInv loses up to (#digits of longest coeff of B) places in fInv.mult(B); - // * multiplying fInv by B also multiplies the rounding error by a factor of N; - // so make #decimal places of fInv the sum of the above. - BigDecimalPolynomial fInv = rf.rho.div(new BigDecimal(rf.res), B.getMaxCoeffLength() + 1 + log10N); - BigDecimalPolynomial gInv = rg.rho.div(new BigDecimal(rg.res), A.getMaxCoeffLength() + 1 + log10N); - - BigDecimalPolynomial Cdec = fInv.mult(B); - Cdec.add(gInv.mult(A)); - Cdec.halve(); - C = Cdec.round(); - } - - BigIntPolynomial F = (BigIntPolynomial)B.clone(); - F.sub(f.mult(C)); - BigIntPolynomial G = (BigIntPolynomial)A.clone(); - G.sub(g.mult(C)); - - IntegerPolynomial FInt = new IntegerPolynomial(F); - IntegerPolynomial GInt = new IntegerPolynomial(G); - minimizeFG(fInt, gInt, FInt, GInt, N); - - Polynomial fPrime; - IntegerPolynomial h; - if (basisType == NTRUSigningKeyGenerationParameters.BASIS_TYPE_STANDARD) - { - fPrime = FInt; - h = g.mult(fq, q); - } - else - { - fPrime = g; - h = FInt.mult(fq, q); - } - h.modPositive(q); - - return new FGBasis(f, fPrime, h, FInt, GInt, params); - } - - /** - * Creates a basis such that <code>|F| < keyNormBound</code> and <code>|G| < keyNormBound</code> - * - * @return a NTRUSigner basis - */ - public NTRUSigningPrivateKeyParameters.Basis generateBoundedBasis() - { - while (true) - { - FGBasis basis = generateBasis(); - if (basis.isNormOk()) - { - return basis; - } - } - } - - private class BasisGenerationTask - implements Callable<NTRUSigningPrivateKeyParameters.Basis> - { - - - public NTRUSigningPrivateKeyParameters.Basis call() - throws Exception - { - return generateBoundedBasis(); - } - } - - /** - * A subclass of Basis that additionally contains the polynomials <code>F</code> and <code>G</code>. - */ - public class FGBasis - extends NTRUSigningPrivateKeyParameters.Basis - { - public IntegerPolynomial F; - public IntegerPolynomial G; - - FGBasis(Polynomial f, Polynomial fPrime, IntegerPolynomial h, IntegerPolynomial F, IntegerPolynomial G, NTRUSigningKeyGenerationParameters params) - { - super(f, fPrime, h, params); - this.F = F; - this.G = G; - } - - /** - * Returns <code>true</code> if the norms of the polynomials <code>F</code> and <code>G</code> - * are within {@link NTRUSigningKeyGenerationParameters#keyNormBound}. - * - * @return - */ - boolean isNormOk() - { - double keyNormBoundSq = params.keyNormBoundSq; - int q = params.q; - return (F.centeredNormSq(q) < keyNormBoundSq && G.centeredNormSq(q) < keyNormBoundSq); - } - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigningParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigningParameters.java deleted file mode 100644 index 2f018b0f..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigningParameters.java +++ /dev/null @@ -1,269 +0,0 @@ -package org.bouncycastle.pqc.crypto.ntru; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.text.DecimalFormat; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; - -/** - * A set of parameters for NtruSign. Several predefined parameter sets are available and new ones can be created as well. - */ -public class NTRUSigningParameters - implements Cloneable -{ - public int N; - public int q; - public int d, d1, d2, d3, B; - double beta; - public double betaSq; - double normBound; - public double normBoundSq; - public int signFailTolerance = 100; - int bitsF = 6; // max #bits needed to encode one coefficient of the polynomial F - public Digest hashAlg; - - /** - * Constructs a parameter set that uses ternary private keys (i.e. <code>polyType=SIMPLE</code>). - * - * @param N number of polynomial coefficients - * @param q modulus - * @param d number of -1's in the private polynomials <code>f</code> and <code>g</code> - * @param B number of perturbations - * @param beta balancing factor for the transpose lattice - * @param normBound maximum norm for valid signatures - * @param hashAlg a valid identifier for a <code>java.security.MessageDigest</code> instance such as <code>SHA-256</code>. The <code>MessageDigest</code> must support the <code>getDigestLength()</code> method. - */ - public NTRUSigningParameters(int N, int q, int d, int B, double beta, double normBound, Digest hashAlg) - { - this.N = N; - this.q = q; - this.d = d; - this.B = B; - this.beta = beta; - this.normBound = normBound; - this.hashAlg = hashAlg; - init(); - } - - /** - * Constructs a parameter set that uses product-form private keys (i.e. <code>polyType=PRODUCT</code>). - * - * @param N number of polynomial coefficients - * @param q modulus - * @param d1 number of -1's in the private polynomials <code>f</code> and <code>g</code> - * @param d2 number of -1's in the private polynomials <code>f</code> and <code>g</code> - * @param d3 number of -1's in the private polynomials <code>f</code> and <code>g</code> - * @param B number of perturbations - * @param beta balancing factor for the transpose lattice - * @param normBound maximum norm for valid signatures - * @param keyNormBound maximum norm for the ploynomials <code>F</code> and <code>G</code> - * @param hashAlg a valid identifier for a <code>java.security.MessageDigest</code> instance such as <code>SHA-256</code>. The <code>MessageDigest</code> must support the <code>getDigestLength()</code> method. - */ - public NTRUSigningParameters(int N, int q, int d1, int d2, int d3, int B, double beta, double normBound, double keyNormBound, Digest hashAlg) - { - this.N = N; - this.q = q; - this.d1 = d1; - this.d2 = d2; - this.d3 = d3; - this.B = B; - this.beta = beta; - this.normBound = normBound; - this.hashAlg = hashAlg; - init(); - } - - private void init() - { - betaSq = beta * beta; - normBoundSq = normBound * normBound; - } - - /** - * Reads a parameter set from an input stream. - * - * @param is an input stream - * @throws IOException - */ - public NTRUSigningParameters(InputStream is) - throws IOException - { - DataInputStream dis = new DataInputStream(is); - N = dis.readInt(); - q = dis.readInt(); - d = dis.readInt(); - d1 = dis.readInt(); - d2 = dis.readInt(); - d3 = dis.readInt(); - B = dis.readInt(); - beta = dis.readDouble(); - normBound = dis.readDouble(); - signFailTolerance = dis.readInt(); - bitsF = dis.readInt(); - String alg = dis.readUTF(); - if ("SHA-512".equals(alg)) - { - hashAlg = new SHA512Digest(); - } - else if ("SHA-256".equals(alg)) - { - hashAlg = new SHA256Digest(); - } - init(); - } - - /** - * Writes the parameter set to an output stream - * - * @param os an output stream - * @throws IOException - */ - public void writeTo(OutputStream os) - throws IOException - { - DataOutputStream dos = new DataOutputStream(os); - dos.writeInt(N); - dos.writeInt(q); - dos.writeInt(d); - dos.writeInt(d1); - dos.writeInt(d2); - dos.writeInt(d3); - dos.writeInt(B); - dos.writeDouble(beta); - dos.writeDouble(normBound); - dos.writeInt(signFailTolerance); - dos.writeInt(bitsF); - dos.writeUTF(hashAlg.getAlgorithmName()); - } - - public NTRUSigningParameters clone() - { - return new NTRUSigningParameters(N, q, d, B, beta, normBound, hashAlg); - } - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + B; - result = prime * result + N; - long temp; - temp = Double.doubleToLongBits(beta); - result = prime * result + (int)(temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(betaSq); - result = prime * result + (int)(temp ^ (temp >>> 32)); - result = prime * result + bitsF; - result = prime * result + d; - result = prime * result + d1; - result = prime * result + d2; - result = prime * result + d3; - result = prime * result + ((hashAlg == null) ? 0 : hashAlg.getAlgorithmName().hashCode()); - temp = Double.doubleToLongBits(normBound); - result = prime * result + (int)(temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(normBoundSq); - result = prime * result + (int)(temp ^ (temp >>> 32)); - result = prime * result + q; - result = prime * result + signFailTolerance; - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (!(obj instanceof NTRUSigningParameters)) - { - return false; - } - NTRUSigningParameters other = (NTRUSigningParameters)obj; - if (B != other.B) - { - return false; - } - if (N != other.N) - { - return false; - } - if (Double.doubleToLongBits(beta) != Double.doubleToLongBits(other.beta)) - { - return false; - } - if (Double.doubleToLongBits(betaSq) != Double.doubleToLongBits(other.betaSq)) - { - return false; - } - if (bitsF != other.bitsF) - { - return false; - } - if (d != other.d) - { - return false; - } - if (d1 != other.d1) - { - return false; - } - if (d2 != other.d2) - { - return false; - } - if (d3 != other.d3) - { - return false; - } - if (hashAlg == null) - { - if (other.hashAlg != null) - { - return false; - } - } - else if (!hashAlg.getAlgorithmName().equals(other.hashAlg.getAlgorithmName())) - { - return false; - } - if (Double.doubleToLongBits(normBound) != Double.doubleToLongBits(other.normBound)) - { - return false; - } - if (Double.doubleToLongBits(normBoundSq) != Double.doubleToLongBits(other.normBoundSq)) - { - return false; - } - if (q != other.q) - { - return false; - } - if (signFailTolerance != other.signFailTolerance) - { - return false; - } - - return true; - } - - public String toString() - { - DecimalFormat format = new DecimalFormat("0.00"); - - StringBuilder output = new StringBuilder("SignatureParameters(N=" + N + " q=" + q); - - output.append(" B=" + B + " beta=" + format.format(beta) + - " normBound=" + format.format(normBound) + - " hashAlg=" + hashAlg + ")"); - return output.toString(); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigningPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigningPrivateKeyParameters.java deleted file mode 100644 index 515f3562..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigningPrivateKeyParameters.java +++ /dev/null @@ -1,385 +0,0 @@ -package org.bouncycastle.pqc.crypto.ntru; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.pqc.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.Polynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.ProductFormPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.SparseTernaryPolynomial; - -/** - * A NtruSign private key comprises one or more {@link NTRUSigningPrivateKeyParameters.Basis} of three polynomials each, - * except the zeroth basis for which <code>h</code> is undefined. - */ -public class NTRUSigningPrivateKeyParameters - extends AsymmetricKeyParameter -{ - private List<Basis> bases; - private NTRUSigningPublicKeyParameters publicKey; - - /** - * Constructs a new private key from a byte array - * - * @param b an encoded private key - * @param params the NtruSign parameters to use - */ - public NTRUSigningPrivateKeyParameters(byte[] b, NTRUSigningKeyGenerationParameters params) - throws IOException - { - this(new ByteArrayInputStream(b), params); - } - - /** - * Constructs a new private key from an input stream - * - * @param is an input stream - * @param params the NtruSign parameters to use - */ - public NTRUSigningPrivateKeyParameters(InputStream is, NTRUSigningKeyGenerationParameters params) - throws IOException - { - super(true); - bases = new ArrayList<Basis>(); - for (int i = 0; i <= params.B; i++) - // include a public key h[i] in all bases except for the first one - { - add(new Basis(is, params, i != 0)); - } - publicKey = new NTRUSigningPublicKeyParameters(is, params.getSigningParameters()); - } - - public NTRUSigningPrivateKeyParameters(List<Basis> bases, NTRUSigningPublicKeyParameters publicKey) - { - super(true); - this.bases = new ArrayList<Basis>(bases); - this.publicKey = publicKey; - } - - /** - * Adds a basis to the key. - * - * @param b a NtruSign basis - */ - private void add(Basis b) - { - bases.add(b); - } - - /** - * Returns the <code>i</code>-th basis - * - * @param i the index - * @return the basis at index <code>i</code> - */ - public Basis getBasis(int i) - { - return bases.get(i); - } - - public NTRUSigningPublicKeyParameters getPublicKey() - { - return publicKey; - } - - /** - * Converts the key to a byte array - * - * @return the encoded key - */ - public byte[] getEncoded() - throws IOException - { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - for (int i = 0; i < bases.size(); i++) - { - // all bases except for the first one contain a public key - bases.get(i).encode(os, i != 0); - } - - os.write(publicKey.getEncoded()); - - return os.toByteArray(); - } - - /** - * Writes the key to an output stream - * - * @param os an output stream - * @throws IOException - */ - public void writeTo(OutputStream os) - throws IOException - { - os.write(getEncoded()); - } - - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + ((bases == null) ? 0 : bases.hashCode()); - for (Basis basis : bases) - { - result += basis.hashCode(); - } - return result; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - NTRUSigningPrivateKeyParameters other = (NTRUSigningPrivateKeyParameters)obj; - if (bases == null) - { - if (other.bases != null) - { - return false; - } - } - if (bases.size() != other.bases.size()) - { - return false; - } - for (int i = 0; i < bases.size(); i++) - { - Basis basis1 = bases.get(i); - Basis basis2 = other.bases.get(i); - if (!basis1.f.equals(basis2.f)) - { - return false; - } - if (!basis1.fPrime.equals(basis2.fPrime)) - { - return false; - } - if (i != 0 && !basis1.h.equals(basis2.h)) // don't compare h for the 0th basis - { - return false; - } - if (!basis1.params.equals(basis2.params)) - { - return false; - } - } - return true; - } - - /** - * A NtruSign basis. Contains three polynomials <code>f, f', h</code>. - */ - public static class Basis - { - public Polynomial f; - public Polynomial fPrime; - public IntegerPolynomial h; - NTRUSigningKeyGenerationParameters params; - - /** - * Constructs a new basis from polynomials <code>f, f', h</code>. - * - * @param f - * @param fPrime - * @param h - * @param params NtruSign parameters - */ - protected Basis(Polynomial f, Polynomial fPrime, IntegerPolynomial h, NTRUSigningKeyGenerationParameters params) - { - this.f = f; - this.fPrime = fPrime; - this.h = h; - this.params = params; - } - - /** - * Reads a basis from an input stream and constructs a new basis. - * - * @param is an input stream - * @param params NtruSign parameters - * @param include_h whether to read the polynomial <code>h</code> (<code>true</code>) or only <code>f</code> and <code>f'</code> (<code>false</code>) - */ - Basis(InputStream is, NTRUSigningKeyGenerationParameters params, boolean include_h) - throws IOException - { - int N = params.N; - int q = params.q; - int d1 = params.d1; - int d2 = params.d2; - int d3 = params.d3; - boolean sparse = params.sparse; - this.params = params; - - if (params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT) - { - f = ProductFormPolynomial.fromBinary(is, N, d1, d2, d3 + 1, d3); - } - else - { - IntegerPolynomial fInt = IntegerPolynomial.fromBinary3Tight(is, N); - f = sparse ? new SparseTernaryPolynomial(fInt) : new DenseTernaryPolynomial(fInt); - } - - if (params.basisType == NTRUSigningKeyGenerationParameters.BASIS_TYPE_STANDARD) - { - IntegerPolynomial fPrimeInt = IntegerPolynomial.fromBinary(is, N, q); - for (int i = 0; i < fPrimeInt.coeffs.length; i++) - { - fPrimeInt.coeffs[i] -= q / 2; - } - fPrime = fPrimeInt; - } - else if (params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT) - { - fPrime = ProductFormPolynomial.fromBinary(is, N, d1, d2, d3 + 1, d3); - } - else - { - fPrime = IntegerPolynomial.fromBinary3Tight(is, N); - } - - if (include_h) - { - h = IntegerPolynomial.fromBinary(is, N, q); - } - } - - /** - * Writes the basis to an output stream - * - * @param os an output stream - * @param include_h whether to write the polynomial <code>h</code> (<code>true</code>) or only <code>f</code> and <code>f'</code> (<code>false</code>) - * @throws IOException - */ - void encode(OutputStream os, boolean include_h) - throws IOException - { - int q = params.q; - - os.write(getEncoded(f)); - if (params.basisType == NTRUSigningKeyGenerationParameters.BASIS_TYPE_STANDARD) - { - IntegerPolynomial fPrimeInt = fPrime.toIntegerPolynomial(); - for (int i = 0; i < fPrimeInt.coeffs.length; i++) - { - fPrimeInt.coeffs[i] += q / 2; - } - os.write(fPrimeInt.toBinary(q)); - } - else - { - os.write(getEncoded(fPrime)); - } - if (include_h) - { - os.write(h.toBinary(q)); - } - } - - private byte[] getEncoded(Polynomial p) - { - if (p instanceof ProductFormPolynomial) - { - return ((ProductFormPolynomial)p).toBinary(); - } - else - { - return p.toIntegerPolynomial().toBinary3Tight(); - } - } - - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + ((f == null) ? 0 : f.hashCode()); - result = prime * result + ((fPrime == null) ? 0 : fPrime.hashCode()); - result = prime * result + ((h == null) ? 0 : h.hashCode()); - result = prime * result + ((params == null) ? 0 : params.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (!(obj instanceof Basis)) - { - return false; - } - Basis other = (Basis)obj; - if (f == null) - { - if (other.f != null) - { - return false; - } - } - else if (!f.equals(other.f)) - { - return false; - } - if (fPrime == null) - { - if (other.fPrime != null) - { - return false; - } - } - else if (!fPrime.equals(other.fPrime)) - { - return false; - } - if (h == null) - { - if (other.h != null) - { - return false; - } - } - else if (!h.equals(other.h)) - { - return false; - } - if (params == null) - { - if (other.params != null) - { - return false; - } - } - else if (!params.equals(other.params)) - { - return false; - } - return true; - } - } -}
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigningPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigningPublicKeyParameters.java deleted file mode 100644 index be51d0af..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUSigningPublicKeyParameters.java +++ /dev/null @@ -1,132 +0,0 @@ -package org.bouncycastle.pqc.crypto.ntru; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.pqc.math.ntru.polynomial.IntegerPolynomial; - -/** - * A NtruSign public key is essentially a polynomial named <code>h</code>. - */ -public class NTRUSigningPublicKeyParameters - extends AsymmetricKeyParameter -{ - private NTRUSigningParameters params; - public IntegerPolynomial h; - - /** - * Constructs a new public key from a polynomial - * - * @param h the polynomial <code>h</code> which determines the key - * @param params the NtruSign parameters to use - */ - public NTRUSigningPublicKeyParameters(IntegerPolynomial h, NTRUSigningParameters params) - { - super(false); - this.h = h; - this.params = params; - } - - /** - * Converts a byte array to a polynomial <code>h</code> and constructs a new public key - * - * @param b an encoded polynomial - * @param params the NtruSign parameters to use - */ - public NTRUSigningPublicKeyParameters(byte[] b, NTRUSigningParameters params) - { - super(false); - h = IntegerPolynomial.fromBinary(b, params.N, params.q); - this.params = params; - } - - /** - * Reads a polynomial <code>h</code> from an input stream and constructs a new public key - * - * @param is an input stream - * @param params the NtruSign parameters to use - */ - public NTRUSigningPublicKeyParameters(InputStream is, NTRUSigningParameters params) - throws IOException - { - super(false); - h = IntegerPolynomial.fromBinary(is, params.N, params.q); - this.params = params; - } - - - /** - * Converts the key to a byte array - * - * @return the encoded key - */ - public byte[] getEncoded() - { - return h.toBinary(params.q); - } - - /** - * Writes the key to an output stream - * - * @param os an output stream - * @throws IOException - */ - public void writeTo(OutputStream os) - throws IOException - { - os.write(getEncoded()); - } - - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + ((h == null) ? 0 : h.hashCode()); - result = prime * result + ((params == null) ? 0 : params.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - NTRUSigningPublicKeyParameters other = (NTRUSigningPublicKeyParameters)obj; - if (h == null) - { - if (other.h != null) - { - return false; - } - } - else if (!h.equals(other.h)) - { - return false; - } - if (params == null) - { - if (other.params != null) - { - return false; - } - } - else if (!params.equals(other.params)) - { - return false; - } - return true; - } -}
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/Layer.java b/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/Layer.java deleted file mode 100644 index ae76922c..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/Layer.java +++ /dev/null @@ -1,322 +0,0 @@ -package org.bouncycastle.pqc.crypto.rainbow; - -import java.security.SecureRandom; - -import org.bouncycastle.pqc.crypto.rainbow.util.GF2Field; -import org.bouncycastle.pqc.crypto.rainbow.util.RainbowUtil; -import org.bouncycastle.util.Arrays; - - -/** - * This class represents a layer of the Rainbow Oil- and Vinegar Map. Each Layer - * consists of oi polynomials with their coefficients, generated at random. - * <p> - * To sign a document, we solve a LES (linear equation system) for each layer in - * order to find the oil variables of that layer and to be able to use the - * variables to compute the signature. This functionality is implemented in the - * RainbowSignature-class, by the aid of the private key. - * <p> - * Each layer is a part of the private key. - * <p> - * More information about the layer can be found in the paper of Jintai Ding, - * Dieter Schmidt: Rainbow, a New Multivariable Polynomial Signature Scheme. - * ACNS 2005: 164-175 (http://dx.doi.org/10.1007/11496137_12) - */ -public class Layer -{ - private int vi; // number of vinegars in this layer - private int viNext; // number of vinegars in next layer - private int oi; // number of oils in this layer - - /* - * k : index of polynomial - * - * i,j : indices of oil and vinegar variables - */ - private short[/* k */][/* i */][/* j */] coeff_alpha; - private short[/* k */][/* i */][/* j */] coeff_beta; - private short[/* k */][/* i */] coeff_gamma; - private short[/* k */] coeff_eta; - - /** - * Constructor - * - * @param vi number of vinegar variables of this layer - * @param viNext number of vinegar variables of next layer. It's the same as - * (num of oils) + (num of vinegars) of this layer. - * @param coeffAlpha alpha-coefficients in the polynomials of this layer - * @param coeffBeta beta-coefficients in the polynomials of this layer - * @param coeffGamma gamma-coefficients in the polynomials of this layer - * @param coeffEta eta-coefficients in the polynomials of this layer - */ - public Layer(byte vi, byte viNext, short[][][] coeffAlpha, - short[][][] coeffBeta, short[][] coeffGamma, short[] coeffEta) - { - this.vi = vi & 0xff; - this.viNext = viNext & 0xff; - this.oi = this.viNext - this.vi; - - // the secret coefficients of all polynomials in this layer - this.coeff_alpha = coeffAlpha; - this.coeff_beta = coeffBeta; - this.coeff_gamma = coeffGamma; - this.coeff_eta = coeffEta; - } - - /** - * This function generates the coefficients of all polynomials in this layer - * at random using random generator. - * - * @param sr the random generator which is to be used - */ - public Layer(int vi, int viNext, SecureRandom sr) - { - this.vi = vi; - this.viNext = viNext; - this.oi = viNext - vi; - - // the coefficients of all polynomials in this layer - this.coeff_alpha = new short[this.oi][this.oi][this.vi]; - this.coeff_beta = new short[this.oi][this.vi][this.vi]; - this.coeff_gamma = new short[this.oi][this.viNext]; - this.coeff_eta = new short[this.oi]; - - int numOfPoly = this.oi; // number of polynomials per layer - - // Alpha coeffs - for (int k = 0; k < numOfPoly; k++) - { - for (int i = 0; i < this.oi; i++) - { - for (int j = 0; j < this.vi; j++) - { - coeff_alpha[k][i][j] = (short)(sr.nextInt() & GF2Field.MASK); - } - } - } - // Beta coeffs - for (int k = 0; k < numOfPoly; k++) - { - for (int i = 0; i < this.vi; i++) - { - for (int j = 0; j < this.vi; j++) - { - coeff_beta[k][i][j] = (short)(sr.nextInt() & GF2Field.MASK); - } - } - } - // Gamma coeffs - for (int k = 0; k < numOfPoly; k++) - { - for (int i = 0; i < this.viNext; i++) - { - coeff_gamma[k][i] = (short)(sr.nextInt() & GF2Field.MASK); - } - } - // Eta - for (int k = 0; k < numOfPoly; k++) - { - coeff_eta[k] = (short)(sr.nextInt() & GF2Field.MASK); - } - } - - /** - * This method plugs in the vinegar variables into the polynomials of this - * layer and computes the coefficients of the Oil-variables as well as the - * free coefficient in each polynomial. - * <p> - * It is needed for computing the Oil variables while signing. - * - * @param x vinegar variables of this layer that should be plugged into - * the polynomials. - * @return coeff the coefficients of Oil variables and the free coeff in the - * polynomials of this layer. - */ - public short[][] plugInVinegars(short[] x) - { - // temporary variable needed for the multiplication - short tmpMult = 0; - // coeff: 1st index = which polynomial, 2nd index=which variable - short[][] coeff = new short[oi][oi + 1]; // gets returned - // free coefficient per polynomial - short[] sum = new short[oi]; - - /* - * evaluate the beta-part of the polynomials (it contains no oil - * variables) - */ - for (int k = 0; k < oi; k++) - { - for (int i = 0; i < vi; i++) - { - for (int j = 0; j < vi; j++) - { - // tmp = beta * xi (plug in) - tmpMult = GF2Field.multElem(coeff_beta[k][i][j], x[i]); - // tmp = tmp * xj - tmpMult = GF2Field.multElem(tmpMult, x[j]); - // accumulate into the array for the free coefficients. - sum[k] = GF2Field.addElem(sum[k], tmpMult); - } - } - } - - /* evaluate the alpha-part (it contains oils) */ - for (int k = 0; k < oi; k++) - { - for (int i = 0; i < oi; i++) - { - for (int j = 0; j < vi; j++) - { - // alpha * xj (plug in) - tmpMult = GF2Field.multElem(coeff_alpha[k][i][j], x[j]); - // accumulate - coeff[k][i] = GF2Field.addElem(coeff[k][i], tmpMult); - } - } - } - /* evaluate the gama-part of the polynomial (containing no oils) */ - for (int k = 0; k < oi; k++) - { - for (int i = 0; i < vi; i++) - { - // gamma * xi (plug in) - tmpMult = GF2Field.multElem(coeff_gamma[k][i], x[i]); - // accumulate in the array for the free coefficients (per - // polynomial). - sum[k] = GF2Field.addElem(sum[k], tmpMult); - } - } - /* evaluate the gama-part of the polynomial (but containing oils) */ - for (int k = 0; k < oi; k++) - { - for (int i = vi; i < viNext; i++) - { // oils - // accumulate the coefficients of the oil variables (per - // polynomial). - coeff[k][i - vi] = GF2Field.addElem(coeff_gamma[k][i], - coeff[k][i - vi]); - } - } - /* evaluate the eta-part of the polynomial */ - for (int k = 0; k < oi; k++) - { - // accumulate in the array for the free coefficients per polynomial. - sum[k] = GF2Field.addElem(sum[k], coeff_eta[k]); - } - - /* put the free coefficients (sum) into the coeff-array as last column */ - for (int k = 0; k < oi; k++) - { - coeff[k][oi] = sum[k]; - } - return coeff; - } - - /** - * Getter for the number of vinegar variables of this layer. - * - * @return the number of vinegar variables of this layer. - */ - public int getVi() - { - return vi; - } - - /** - * Getter for the number of vinegar variables of the next layer. - * - * @return the number of vinegar variables of the next layer. - */ - public int getViNext() - { - return viNext; - } - - /** - * Getter for the number of Oil variables of this layer. - * - * @return the number of oil variables of this layer. - */ - public int getOi() - { - return oi; - } - - /** - * Getter for the alpha-coefficients of the polynomials in this layer. - * - * @return the coefficients of alpha-terms of this layer. - */ - public short[][][] getCoeffAlpha() - { - return coeff_alpha; - } - - /** - * Getter for the beta-coefficients of the polynomials in this layer. - * - * @return the coefficients of beta-terms of this layer. - */ - - public short[][][] getCoeffBeta() - { - return coeff_beta; - } - - /** - * Getter for the gamma-coefficients of the polynomials in this layer. - * - * @return the coefficients of gamma-terms of this layer - */ - public short[][] getCoeffGamma() - { - return coeff_gamma; - } - - /** - * Getter for the eta-coefficients of the polynomials in this layer. - * - * @return the coefficients eta of this layer - */ - public short[] getCoeffEta() - { - return coeff_eta; - } - - /** - * This function compares this Layer with another object. - * - * @param other the other object - * @return the result of the comparison - */ - public boolean equals(Object other) - { - if (other == null || !(other instanceof Layer)) - { - return false; - } - Layer otherLayer = (Layer)other; - - return vi == otherLayer.getVi() - && viNext == otherLayer.getViNext() - && oi == otherLayer.getOi() - && RainbowUtil.equals(coeff_alpha, otherLayer.getCoeffAlpha()) - && RainbowUtil.equals(coeff_beta, otherLayer.getCoeffBeta()) - && RainbowUtil.equals(coeff_gamma, otherLayer.getCoeffGamma()) - && RainbowUtil.equals(coeff_eta, otherLayer.getCoeffEta()); - } - - public int hashCode() - { - int hash = vi; - hash = hash * 37 + viNext; - hash = hash * 37 + oi; - hash = hash * 37 + Arrays.hashCode(coeff_alpha); - hash = hash * 37 + Arrays.hashCode(coeff_beta); - hash = hash * 37 + Arrays.hashCode(coeff_gamma); - hash = hash * 37 + Arrays.hashCode(coeff_eta); - - return hash; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowKeyGenerationParameters.java deleted file mode 100644 index b634f9cc..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowKeyGenerationParameters.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.bouncycastle.pqc.crypto.rainbow; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.KeyGenerationParameters; - -public class RainbowKeyGenerationParameters - extends KeyGenerationParameters -{ - private RainbowParameters params; - - public RainbowKeyGenerationParameters( - SecureRandom random, - RainbowParameters params) - { - // TODO: key size? - super(random, params.getVi()[params.getVi().length - 1] - params.getVi()[0]); - this.params = params; - } - - public RainbowParameters getParameters() - { - return params; - } -} - diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowKeyPairGenerator.java deleted file mode 100644 index 8ef15337..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowKeyPairGenerator.java +++ /dev/null @@ -1,413 +0,0 @@ -package org.bouncycastle.pqc.crypto.rainbow; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.pqc.crypto.rainbow.util.ComputeInField; -import org.bouncycastle.pqc.crypto.rainbow.util.GF2Field; - -/** - * This class implements AsymmetricCipherKeyPairGenerator. It is used - * as a generator for the private and public key of the Rainbow Signature - * Scheme. - * <p> - * Detailed information about the key generation is to be found in the paper of - * Jintai Ding, Dieter Schmidt: Rainbow, a New Multivariable Polynomial - * Signature Scheme. ACNS 2005: 164-175 (http://dx.doi.org/10.1007/11496137_12) - */ -public class RainbowKeyPairGenerator - implements AsymmetricCipherKeyPairGenerator -{ - private boolean initialized = false; - private SecureRandom sr; - private RainbowKeyGenerationParameters rainbowParams; - - /* linear affine map L1: */ - private short[][] A1; // matrix of the lin. affine map L1(n-v1 x n-v1 matrix) - private short[][] A1inv; // inverted A1 - private short[] b1; // translation element of the lin.affine map L1 - - /* linear affine map L2: */ - private short[][] A2; // matrix of the lin. affine map (n x n matrix) - private short[][] A2inv; // inverted A2 - private short[] b2; // translation elemt of the lin.affine map L2 - - /* components of F: */ - private int numOfLayers; // u (number of sets S) - private Layer layers[]; // layers of polynomials of F - private int[] vi; // set of vinegar vars per layer. - - /* components of Public Key */ - private short[][] pub_quadratic; // quadratic(mixed) coefficients - private short[][] pub_singular; // singular coefficients - private short[] pub_scalar; // scalars - - // TODO - - /** - * The standard constructor tries to generate the Rainbow algorithm identifier - * with the corresponding OID. - */ - public RainbowKeyPairGenerator() - { - } - - - /** - * This function generates a Rainbow key pair. - * - * @return the generated key pair - */ - public AsymmetricCipherKeyPair genKeyPair() - { - RainbowPrivateKeyParameters privKey; - RainbowPublicKeyParameters pubKey; - - if (!initialized) - { - initializeDefault(); - } - - /* choose all coefficients at random */ - keygen(); - - /* now marshall them to PrivateKey */ - privKey = new RainbowPrivateKeyParameters(A1inv, b1, A2inv, b2, vi, layers); - - - /* marshall to PublicKey */ - pubKey = new RainbowPublicKeyParameters(vi[vi.length - 1] - vi[0], pub_quadratic, pub_singular, pub_scalar); - - return new AsymmetricCipherKeyPair(pubKey, privKey); - } - - // TODO - public void initialize( - KeyGenerationParameters param) - { - this.rainbowParams = (RainbowKeyGenerationParameters)param; - - // set source of randomness - this.sr = new SecureRandom(); - - // unmarshalling: - this.vi = this.rainbowParams.getParameters().getVi(); - this.numOfLayers = this.rainbowParams.getParameters().getNumOfLayers(); - - this.initialized = true; - } - - private void initializeDefault() - { - RainbowKeyGenerationParameters rbKGParams = new RainbowKeyGenerationParameters(new SecureRandom(), new RainbowParameters()); - initialize(rbKGParams); - } - - /** - * This function calls the functions for the random generation of the coefficients - * and the matrices needed for the private key and the method for computing the public key. - */ - private void keygen() - { - generateL1(); - generateL2(); - generateF(); - computePublicKey(); - } - - /** - * This function generates the invertible affine linear map L1 = A1*x + b1 - * <p/> - * The translation part b1, is stored in a separate array. The inverse of - * the matrix-part of L1 A1inv is also computed here. - * <p/> - * This linear map hides the output of the map F. It is on k^(n-v1). - */ - private void generateL1() - { - - // dimension = n-v1 = vi[last] - vi[first] - int dim = vi[vi.length - 1] - vi[0]; - this.A1 = new short[dim][dim]; - this.A1inv = null; - ComputeInField c = new ComputeInField(); - - /* generation of A1 at random */ - while (A1inv == null) - { - for (int i = 0; i < dim; i++) - { - for (int j = 0; j < dim; j++) - { - A1[i][j] = (short)(sr.nextInt() & GF2Field.MASK); - } - } - A1inv = c.inverse(A1); - } - - /* generation of the translation vector at random */ - b1 = new short[dim]; - for (int i = 0; i < dim; i++) - { - b1[i] = (short)(sr.nextInt() & GF2Field.MASK); - } - } - - /** - * This function generates the invertible affine linear map L2 = A2*x + b2 - * <p/> - * The translation part b2, is stored in a separate array. The inverse of - * the matrix-part of L2 A2inv is also computed here. - * <p/> - * This linear map hides the output of the map F. It is on k^(n). - */ - private void generateL2() - { - - // dimension = n = vi[last] - int dim = vi[vi.length - 1]; - this.A2 = new short[dim][dim]; - this.A2inv = null; - ComputeInField c = new ComputeInField(); - - /* generation of A2 at random */ - while (this.A2inv == null) - { - for (int i = 0; i < dim; i++) - { - for (int j = 0; j < dim; j++) - { // one col extra for b - A2[i][j] = (short)(sr.nextInt() & GF2Field.MASK); - } - } - this.A2inv = c.inverse(A2); - } - /* generation of the translation vector at random */ - b2 = new short[dim]; - for (int i = 0; i < dim; i++) - { - b2[i] = (short)(sr.nextInt() & GF2Field.MASK); - } - - } - - /** - * This function generates the private map F, which consists of u-1 layers. - * Each layer consists of oi polynomials where oi = vi[i+1]-vi[i]. - * <p/> - * The methods for the generation of the coefficients of these polynomials - * are called here. - */ - private void generateF() - { - - this.layers = new Layer[this.numOfLayers]; - for (int i = 0; i < this.numOfLayers; i++) - { - layers[i] = new Layer(this.vi[i], this.vi[i + 1], sr); - } - } - - /** - * This function computes the public key from the private key. - * <p/> - * The composition of F with L2 is computed, followed by applying L1 to the - * composition's result. The singular and scalar values constitute to the - * public key as is, the quadratic terms are compacted in - * <tt>compactPublicKey()</tt> - */ - private void computePublicKey() - { - - ComputeInField c = new ComputeInField(); - int rows = this.vi[this.vi.length - 1] - this.vi[0]; - int vars = this.vi[this.vi.length - 1]; - // Fpub - short[][][] coeff_quadratic_3dim = new short[rows][vars][vars]; - this.pub_singular = new short[rows][vars]; - this.pub_scalar = new short[rows]; - - // Coefficients of layers of Private Key F - short[][][] coeff_alpha; - short[][][] coeff_beta; - short[][] coeff_gamma; - short[] coeff_eta; - - // Needed for counters; - int oils = 0; - int vins = 0; - int crnt_row = 0; // current row (polynomial) - - short vect_tmp[] = new short[vars]; // vector tmp; - short sclr_tmp = 0; - - // Composition of F and L2: Insert L2 = A2*x+b2 in F - for (int l = 0; l < this.layers.length; l++) - { - // get coefficients of current layer - coeff_alpha = this.layers[l].getCoeffAlpha(); - coeff_beta = this.layers[l].getCoeffBeta(); - coeff_gamma = this.layers[l].getCoeffGamma(); - coeff_eta = this.layers[l].getCoeffEta(); - oils = coeff_alpha[0].length;// this.layers[l].getOi(); - vins = coeff_beta[0].length;// this.layers[l].getVi(); - // compute polynomials of layer - for (int p = 0; p < oils; p++) - { - // multiply alphas - for (int x1 = 0; x1 < oils; x1++) - { - for (int x2 = 0; x2 < vins; x2++) - { - // multiply polynomial1 with polynomial2 - vect_tmp = c.multVect(coeff_alpha[p][x1][x2], - this.A2[x1 + vins]); - coeff_quadratic_3dim[crnt_row + p] = c.addSquareMatrix( - coeff_quadratic_3dim[crnt_row + p], c - .multVects(vect_tmp, this.A2[x2])); - // mul poly1 with scalar2 - vect_tmp = c.multVect(this.b2[x2], vect_tmp); - this.pub_singular[crnt_row + p] = c.addVect(vect_tmp, - this.pub_singular[crnt_row + p]); - // mul scalar1 with poly2 - vect_tmp = c.multVect(coeff_alpha[p][x1][x2], - this.A2[x2]); - vect_tmp = c.multVect(b2[x1 + vins], vect_tmp); - this.pub_singular[crnt_row + p] = c.addVect(vect_tmp, - this.pub_singular[crnt_row + p]); - // mul scalar1 with scalar2 - sclr_tmp = GF2Field.multElem(coeff_alpha[p][x1][x2], - this.b2[x1 + vins]); - this.pub_scalar[crnt_row + p] = GF2Field.addElem( - this.pub_scalar[crnt_row + p], GF2Field - .multElem(sclr_tmp, this.b2[x2])); - } - } - // multiply betas - for (int x1 = 0; x1 < vins; x1++) - { - for (int x2 = 0; x2 < vins; x2++) - { - // multiply polynomial1 with polynomial2 - vect_tmp = c.multVect(coeff_beta[p][x1][x2], - this.A2[x1]); - coeff_quadratic_3dim[crnt_row + p] = c.addSquareMatrix( - coeff_quadratic_3dim[crnt_row + p], c - .multVects(vect_tmp, this.A2[x2])); - // mul poly1 with scalar2 - vect_tmp = c.multVect(this.b2[x2], vect_tmp); - this.pub_singular[crnt_row + p] = c.addVect(vect_tmp, - this.pub_singular[crnt_row + p]); - // mul scalar1 with poly2 - vect_tmp = c.multVect(coeff_beta[p][x1][x2], - this.A2[x2]); - vect_tmp = c.multVect(this.b2[x1], vect_tmp); - this.pub_singular[crnt_row + p] = c.addVect(vect_tmp, - this.pub_singular[crnt_row + p]); - // mul scalar1 with scalar2 - sclr_tmp = GF2Field.multElem(coeff_beta[p][x1][x2], - this.b2[x1]); - this.pub_scalar[crnt_row + p] = GF2Field.addElem( - this.pub_scalar[crnt_row + p], GF2Field - .multElem(sclr_tmp, this.b2[x2])); - } - } - // multiply gammas - for (int n = 0; n < vins + oils; n++) - { - // mul poly with scalar - vect_tmp = c.multVect(coeff_gamma[p][n], this.A2[n]); - this.pub_singular[crnt_row + p] = c.addVect(vect_tmp, - this.pub_singular[crnt_row + p]); - // mul scalar with scalar - this.pub_scalar[crnt_row + p] = GF2Field.addElem( - this.pub_scalar[crnt_row + p], GF2Field.multElem( - coeff_gamma[p][n], this.b2[n])); - } - // add eta - this.pub_scalar[crnt_row + p] = GF2Field.addElem( - this.pub_scalar[crnt_row + p], coeff_eta[p]); - } - crnt_row = crnt_row + oils; - } - - // Apply L1 = A1*x+b1 to composition of F and L2 - { - // temporary coefficient arrays - short[][][] tmp_c_quad = new short[rows][vars][vars]; - short[][] tmp_c_sing = new short[rows][vars]; - short[] tmp_c_scal = new short[rows]; - for (int r = 0; r < rows; r++) - { - for (int q = 0; q < A1.length; q++) - { - tmp_c_quad[r] = c.addSquareMatrix(tmp_c_quad[r], c - .multMatrix(A1[r][q], coeff_quadratic_3dim[q])); - tmp_c_sing[r] = c.addVect(tmp_c_sing[r], c.multVect( - A1[r][q], this.pub_singular[q])); - tmp_c_scal[r] = GF2Field.addElem(tmp_c_scal[r], GF2Field - .multElem(A1[r][q], this.pub_scalar[q])); - } - tmp_c_scal[r] = GF2Field.addElem(tmp_c_scal[r], b1[r]); - } - // set public key - coeff_quadratic_3dim = tmp_c_quad; - this.pub_singular = tmp_c_sing; - this.pub_scalar = tmp_c_scal; - } - compactPublicKey(coeff_quadratic_3dim); - } - - /** - * The quadratic (or mixed) terms of the public key are compacted from a n x - * n matrix per polynomial to an upper diagonal matrix stored in one integer - * array of n (n + 1) / 2 elements per polynomial. The ordering of elements - * is lexicographic and the result is updating <tt>this.pub_quadratic</tt>, - * which stores the quadratic elements of the public key. - * - * @param coeff_quadratic_to_compact 3-dimensional array containing a n x n Matrix for each of the - * n - v1 polynomials - */ - private void compactPublicKey(short[][][] coeff_quadratic_to_compact) - { - int polynomials = coeff_quadratic_to_compact.length; - int n = coeff_quadratic_to_compact[0].length; - int entries = n * (n + 1) / 2;// the small gauss - this.pub_quadratic = new short[polynomials][entries]; - int offset = 0; - - for (int p = 0; p < polynomials; p++) - { - offset = 0; - for (int x = 0; x < n; x++) - { - for (int y = x; y < n; y++) - { - if (y == x) - { - this.pub_quadratic[p][offset] = coeff_quadratic_to_compact[p][x][y]; - } - else - { - this.pub_quadratic[p][offset] = GF2Field.addElem( - coeff_quadratic_to_compact[p][x][y], - coeff_quadratic_to_compact[p][y][x]); - } - offset++; - } - } - } - } - - public void init(KeyGenerationParameters param) - { - this.initialize(param); - } - - public AsymmetricCipherKeyPair generateKeyPair() - { - return genKeyPair(); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowKeyParameters.java deleted file mode 100644 index 9dec6853..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowKeyParameters.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.pqc.crypto.rainbow; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; - -public class RainbowKeyParameters - extends AsymmetricKeyParameter -{ - private int docLength; - - public RainbowKeyParameters( - boolean isPrivate, - int docLength) - { - super(isPrivate); - this.docLength = docLength; - } - - /** - * @return the docLength - */ - public int getDocLength() - { - return this.docLength; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowParameters.java deleted file mode 100644 index 147c55e9..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowParameters.java +++ /dev/null @@ -1,111 +0,0 @@ -package org.bouncycastle.pqc.crypto.rainbow; - -import org.bouncycastle.crypto.CipherParameters; - -public class RainbowParameters - implements CipherParameters -{ - - /** - * DEFAULT PARAMS - */ - /* - * Vi = vinegars per layer whereas n is vu (vu = 33 = n) such that - * - * v1 = 6; o1 = 12-6 = 6 - * - * v2 = 12; o2 = 17-12 = 5 - * - * v3 = 17; o3 = 22-17 = 5 - * - * v4 = 22; o4 = 33-22 = 11 - * - * v5 = 33; (o5 = 0) - */ - private final int[] DEFAULT_VI = {6, 12, 17, 22, 33}; - - private int[] vi;// set of vinegar vars per layer. - - /** - * Default Constructor The elements of the array containing the number of - * Vinegar variables in each layer are set to the default values here. - */ - public RainbowParameters() - { - this.vi = this.DEFAULT_VI; - } - - /** - * Constructor with parameters - * - * @param vi The elements of the array containing the number of Vinegar - * variables per layer are set to the values of the input array. - */ - public RainbowParameters(int[] vi) - { - this.vi = vi; - try - { - checkParams(); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - - private void checkParams() - throws Exception - { - if (vi == null) - { - throw new Exception("no layers defined."); - } - if (vi.length > 1) - { - for (int i = 0; i < vi.length - 1; i++) - { - if (vi[i] >= vi[i + 1]) - { - throw new Exception( - "v[i] has to be smaller than v[i+1]"); - } - } - } - else - { - throw new Exception( - "Rainbow needs at least 1 layer, such that v1 < v2."); - } - } - - /** - * Getter for the number of layers - * - * @return the number of layers - */ - public int getNumOfLayers() - { - return this.vi.length - 1; - } - - /** - * Getter for the number of all the polynomials in Rainbow - * - * @return the number of the polynomials - */ - public int getDocLength() - { - return vi[vi.length - 1] - vi[0]; - } - - /** - * Getter for the array containing the number of Vinegar-variables per layer - * - * @return the numbers of vinegars per layer - */ - public int[] getVi() - { - return this.vi; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowPrivateKeyParameters.java deleted file mode 100644 index 98768820..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowPrivateKeyParameters.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.bouncycastle.pqc.crypto.rainbow; - -public class RainbowPrivateKeyParameters - extends RainbowKeyParameters -{ - /** - * Constructor - * - * @param A1inv the inverse of A1(the matrix part of the affine linear map L1) - * (n-v1 x n-v1 matrix) - * @param b1 translation vector, part of the linear affine map L1 - * @param A2inv the inverse of A2(the matrix part of the affine linear map L2) - * (n x n matrix) - * @param b2 translation vector, part of the linear affine map L2 - * @param vi the number of Vinegar-variables per layer - * @param layers the polynomials with their coefficients of private map F - */ - public RainbowPrivateKeyParameters(short[][] A1inv, short[] b1, - short[][] A2inv, short[] b2, int[] vi, Layer[] layers) - { - super(true, vi[vi.length - 1] - vi[0]); - - this.A1inv = A1inv; - this.b1 = b1; - this.A2inv = A2inv; - this.b2 = b2; - this.vi = vi; - this.layers = layers; - } - - /* - * invertible affine linear map L1 - */ - // the inverse of A1, (n-v1 x n-v1 matrix) - private short[][] A1inv; - - // translation vector of L1 - private short[] b1; - - /* - * invertible affine linear map L2 - */ - // the inverse of A2, (n x n matrix) - private short[][] A2inv; - - // translation vector of L2 - private short[] b2; - - /* - * components of F - */ - // the number of Vinegar-variables per layer. - private int[] vi; - - // contains the polynomials with their coefficients of private map F - private Layer[] layers; - - /** - * Getter for the translation part of the private quadratic map L1. - * - * @return b1 the translation part of L1 - */ - public short[] getB1() - { - return this.b1; - } - - /** - * Getter for the inverse matrix of A1. - * - * @return the A1inv inverse - */ - public short[][] getInvA1() - { - return this.A1inv; - } - - /** - * Getter for the translation part of the private quadratic map L2. - * - * @return b2 the translation part of L2 - */ - public short[] getB2() - { - return this.b2; - } - - /** - * Getter for the inverse matrix of A2 - * - * @return the A2inv - */ - public short[][] getInvA2() - { - return this.A2inv; - } - - /** - * 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 vi; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowPublicKeyParameters.java deleted file mode 100644 index 6f3e46f2..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowPublicKeyParameters.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.bouncycastle.pqc.crypto.rainbow; - -public class RainbowPublicKeyParameters - extends RainbowKeyParameters -{ - private short[][] coeffquadratic; - private short[][] coeffsingular; - private short[] coeffscalar; - - /** - * Constructor - * - * @param docLength - * @param coeffQuadratic - * @param coeffSingular - * @param coeffScalar - */ - public RainbowPublicKeyParameters(int docLength, - short[][] coeffQuadratic, short[][] coeffSingular, - short[] coeffScalar) - { - super(false, docLength); - - this.coeffquadratic = coeffQuadratic; - this.coeffsingular = coeffSingular; - this.coeffscalar = coeffScalar; - - } - - /** - * @return the coeffquadratic - */ - public short[][] getCoeffQuadratic() - { - return coeffquadratic; - } - - /** - * @return the coeffsingular - */ - public short[][] getCoeffSingular() - { - return coeffsingular; - } - - /** - * @return the coeffscalar - */ - public short[] getCoeffScalar() - { - return coeffscalar; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowSigner.java deleted file mode 100644 index 979e759b..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/RainbowSigner.java +++ /dev/null @@ -1,301 +0,0 @@ -package org.bouncycastle.pqc.crypto.rainbow; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.MessageSigner; -import org.bouncycastle.pqc.crypto.rainbow.util.ComputeInField; -import org.bouncycastle.pqc.crypto.rainbow.util.GF2Field; - -/** - * It implements the sign and verify functions for the Rainbow Signature Scheme. - * Here the message, which has to be signed, is updated. The use of - * different hash functions is possible. - * <p> - * Detailed information about the signature and the verify-method is to be found - * in the paper of Jintai Ding, Dieter Schmidt: Rainbow, a New Multivariable - * Polynomial Signature Scheme. ACNS 2005: 164-175 - * (http://dx.doi.org/10.1007/11496137_12) - */ -public class RainbowSigner - implements MessageSigner -{ - // Source of randomness - private SecureRandom random; - - // The length of a document that can be signed with the privKey - int signableDocumentLength; - - // Container for the oil and vinegar variables of all the layers - private short[] x; - - private ComputeInField cf = new ComputeInField(); - - RainbowKeyParameters key; - - public void init(boolean forSigning, - CipherParameters param) - { - if (forSigning) - { - if (param instanceof ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom)param; - - this.random = rParam.getRandom(); - this.key = (RainbowPrivateKeyParameters)rParam.getParameters(); - - } - else - { - - this.random = new SecureRandom(); - this.key = (RainbowPrivateKeyParameters)param; - } - } - else - { - this.key = (RainbowPublicKeyParameters)param; - } - - this.signableDocumentLength = this.key.getDocLength(); - } - - - /** - * initial operations before solving the Linear equation system. - * - * @param layer the current layer for which a LES is to be solved. - * @param msg the message that should be signed. - * @return Y_ the modified document needed for solving LES, (Y_ = - * A1^{-1}*(Y-b1)) linear map L1 = A1 x + b1. - */ - private short[] initSign(Layer[] layer, short[] msg) - { - - /* preparation: Modifies the document with the inverse of L1 */ - // tmp = Y - b1: - short[] tmpVec = new short[msg.length]; - - tmpVec = cf.addVect(((RainbowPrivateKeyParameters)this.key).getB1(), msg); - - // Y_ = A1^{-1} * (Y - b1) : - short[] Y_ = cf.multiplyMatrix(((RainbowPrivateKeyParameters)this.key).getInvA1(), tmpVec); - - /* generates the vinegar vars of the first layer at random */ - for (int i = 0; i < layer[0].getVi(); i++) - { - x[i] = (short)random.nextInt(); - x[i] = (short)(x[i] & GF2Field.MASK); - } - - return Y_; - } - - /** - * This function signs the message that has been updated, making use of the - * private key. - * <p> - * For computing the signature, L1 and L2 are needed, as well as LES should - * be solved for each layer in order to find the Oil-variables in the layer. - * <p> - * The Vinegar-variables of the first layer are random generated. - * - * @param message the message - * @return the signature of the message. - */ - public byte[] generateSignature(byte[] message) - { - Layer[] layer = ((RainbowPrivateKeyParameters)this.key).getLayers(); - int numberOfLayers = layer.length; - - x = new short[((RainbowPrivateKeyParameters)this.key).getInvA2().length]; // all variables - - short[] Y_; // modified document - short[] y_i; // part of Y_ each polynomial - int counter; // index of the current part of the doc - - short[] solVec; // the solution of LES pro layer - short[] tmpVec; - - // the signature as an array of shorts: - short[] signature; - // the signature as a byte-array: - byte[] S = new byte[layer[numberOfLayers - 1].getViNext()]; - - short[] msgHashVals = makeMessageRepresentative(message); - - // shows if an exception is caught - boolean ok; - do - { - ok = true; - counter = 0; - try - { - Y_ = initSign(layer, msgHashVals); - - for (int i = 0; i < numberOfLayers; i++) - { - - y_i = new short[layer[i].getOi()]; - solVec = new short[layer[i].getOi()]; // solution of LES - - /* copy oi elements of Y_ into y_i */ - for (int k = 0; k < layer[i].getOi(); k++) - { - y_i[k] = Y_[counter]; - counter++; // current index of Y_ - } - - /* - * plug in the vars of the previous layer in order to get - * the vars of the current layer - */ - solVec = cf.solveEquation(layer[i].plugInVinegars(x), y_i); - - if (solVec == null) - { // LES is not solveable - throw new Exception("LES is not solveable!"); - } - - /* copy the new vars into the x-array */ - for (int j = 0; j < solVec.length; j++) - { - x[layer[i].getVi() + j] = solVec[j]; - } - } - - /* apply the inverse of L2: (signature = A2^{-1}*(b2+x)) */ - tmpVec = cf.addVect(((RainbowPrivateKeyParameters)this.key).getB2(), x); - signature = cf.multiplyMatrix(((RainbowPrivateKeyParameters)this.key).getInvA2(), tmpVec); - - /* cast signature from short[] to byte[] */ - for (int i = 0; i < S.length; i++) - { - S[i] = ((byte)signature[i]); - } - } - catch (Exception se) - { - // if one of the LESs was not solveable - sign again - ok = false; - } - } - while (!ok); - /* return the signature in bytes */ - return S; - } - - /** - * This function verifies the signature of the message that has been - * updated, with the aid of the public key. - * - * @param message the message - * @param signature the signature of the message - * @return true if the signature has been verified, false otherwise. - */ - public boolean verifySignature(byte[] message, byte[] signature) - { - short[] sigInt = new short[signature.length]; - short tmp; - - for (int i = 0; i < signature.length; i++) - { - tmp = (short)signature[i]; - tmp &= (short)0xff; - sigInt[i] = tmp; - } - - short[] msgHashVal = makeMessageRepresentative(message); - - // verify - short[] verificationResult = verifySignatureIntern(sigInt); - - // compare - boolean verified = true; - if (msgHashVal.length != verificationResult.length) - { - return false; - } - for (int i = 0; i < msgHashVal.length; i++) - { - verified = verified && msgHashVal[i] == verificationResult[i]; - } - - return verified; - } - - /** - * Signature verification using public key - * - * @param signature vector of dimension n - * @return document hash of length n - v1 - */ - private short[] verifySignatureIntern(short[] signature) - { - - short[][] coeff_quadratic = ((RainbowPublicKeyParameters)this.key).getCoeffQuadratic(); - short[][] coeff_singular = ((RainbowPublicKeyParameters)this.key).getCoeffSingular(); - short[] coeff_scalar = ((RainbowPublicKeyParameters)this.key).getCoeffScalar(); - - short[] rslt = new short[coeff_quadratic.length];// n - v1 - int n = coeff_singular[0].length; - int offset = 0; // array position - short tmp = 0; // for scalar - - for (int p = 0; p < coeff_quadratic.length; p++) - { // no of polynomials - offset = 0; - for (int x = 0; x < n; x++) - { - // calculate quadratic terms - for (int y = x; y < n; y++) - { - tmp = GF2Field.multElem(coeff_quadratic[p][offset], - GF2Field.multElem(signature[x], signature[y])); - rslt[p] = GF2Field.addElem(rslt[p], tmp); - offset++; - } - // calculate singular terms - tmp = GF2Field.multElem(coeff_singular[p][x], signature[x]); - rslt[p] = GF2Field.addElem(rslt[p], tmp); - } - // add scalar - rslt[p] = GF2Field.addElem(rslt[p], coeff_scalar[p]); - } - - return rslt; - } - - /** - * This function creates the representative of the message which gets signed - * or verified. - * - * @param message the message - * @return message representative - */ - private short[] makeMessageRepresentative(byte[] message) - { - // the message representative - short[] output = new short[this.signableDocumentLength]; - - int h = 0; - int i = 0; - do - { - if (i >= message.length) - { - break; - } - output[i] = (short)message[h]; - output[i] &= (short)0xff; - h++; - i++; - } - while (i < output.length); - - return output; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/util/ComputeInField.java b/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/util/ComputeInField.java deleted file mode 100644 index 3517ba30..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/util/ComputeInField.java +++ /dev/null @@ -1,490 +0,0 @@ -package org.bouncycastle.pqc.crypto.rainbow.util; - -/** - * This class offers different operations on matrices in field GF2^8. - * <p> - * Implemented are functions: - * - finding inverse of a matrix - * - solving linear equation systems using the Gauss-Elimination method - * - basic operations like matrix multiplication, addition and so on. - */ - -public class ComputeInField -{ - - private short[][] A; // used by solveEquation and inverse - short[] x; - - /** - * Constructor with no parameters - */ - public ComputeInField() - { - } - - - /** - * This function finds a solution of the equation Bx = b. - * Exception is thrown if the linear equation system has no solution - * - * @param B this matrix is the left part of the - * equation (B in the equation above) - * @param b the right part of the equation - * (b in the equation above) - * @return x the solution of the equation if it is solvable - * null otherwise - * @throws RuntimeException if LES is not solvable - */ - public short[] solveEquation(short[][] B, short[] b) - { - try - { - - if (B.length != b.length) - { - throw new RuntimeException( - "The equation system is not solvable"); - } - - /** initialize **/ - // this matrix stores B and b from the equation B*x = b - // b is stored as the last column. - // B contains one column more than rows. - // In this column we store a free coefficient that should be later subtracted from b - A = new short[B.length][B.length + 1]; - // stores the solution of the LES - x = new short[B.length]; - - /** copy B into the global matrix A **/ - for (int i = 0; i < B.length; i++) - { // rows - for (int j = 0; j < B[0].length; j++) - { // cols - A[i][j] = B[i][j]; - } - } - - /** copy the vector b into the global A **/ - //the free coefficient, stored in the last column of A( A[i][b.length] - // is to be subtracted from b - for (int i = 0; i < b.length; i++) - { - A[i][b.length] = GF2Field.addElem(b[i], A[i][b.length]); - } - - /** call the methods for gauss elimination and backward substitution **/ - computeZerosUnder(false); // obtain zeros under the diagonal - substitute(); - - return x; - - } - catch (RuntimeException rte) - { - return null; // the LES is not solvable! - } - } - - /** - * This function computes the inverse of a given matrix using the Gauss- - * Elimination method. - * <p> - * An exception is thrown if the matrix has no inverse - * - * @param coef the matrix which inverse matrix is needed - * @return inverse matrix of the input matrix. - * If the matrix is singular, null is returned. - * @throws RuntimeException if the given matrix is not invertible - */ - public short[][] inverse(short[][] coef) - { - try - { - /** Initialization: **/ - short factor; - short[][] inverse; - A = new short[coef.length][2 * coef.length]; - if (coef.length != coef[0].length) - { - throw new RuntimeException( - "The matrix is not invertible. Please choose another one!"); - } - - /** prepare: Copy coef and the identity matrix into the global A. **/ - for (int i = 0; i < coef.length; i++) - { - for (int j = 0; j < coef.length; j++) - { - //copy the input matrix coef into A - A[i][j] = coef[i][j]; - } - // copy the identity matrix into A. - for (int j = coef.length; j < 2 * coef.length; j++) - { - A[i][j] = 0; - } - A[i][i + A.length] = 1; - } - - /** Elimination operations to get the identity matrix from the left side of A. **/ - // modify A to get 0s under the diagonal. - computeZerosUnder(true); - - // modify A to get only 1s on the diagonal: A[i][j] =A[i][j]/A[i][i]. - for (int i = 0; i < A.length; i++) - { - factor = GF2Field.invElem(A[i][i]); - for (int j = i; j < 2 * A.length; j++) - { - A[i][j] = GF2Field.multElem(A[i][j], factor); - } - } - - //modify A to get only 0s above the diagonal. - computeZerosAbove(); - - // copy the result (the second half of A) in the matrix inverse. - inverse = new short[A.length][A.length]; - for (int i = 0; i < A.length; i++) - { - for (int j = A.length; j < 2 * A.length; j++) - { - inverse[i][j - A.length] = A[i][j]; - } - } - return inverse; - - } - catch (RuntimeException rte) - { - // The matrix is not invertible! A new one should be generated! - return null; - } - } - - /** - * Elimination under the diagonal. - * This function changes a matrix so that it contains only zeros under the - * diagonal(Ai,i) using only Gauss-Elimination operations. - * <p/> - * It is used in solveEquaton as well as in the function for - * finding an inverse of a matrix: {@link}inverse. Both of them use the - * Gauss-Elimination Method. - * <p/> - * The result is stored in the global matrix A - * - * @param usedForInverse This parameter shows if the function is used by the - * solveEquation-function or by the inverse-function and according - * to this creates matrices of different sizes. - * @throws RuntimeException in case a multiplicative inverse of 0 is needed - */ - private void computeZerosUnder(boolean usedForInverse) - throws RuntimeException - { - - //the number of columns in the global A where the tmp results are stored - int length; - short tmp = 0; - - //the function is used in inverse() - A should have 2 times more columns than rows - if (usedForInverse) - { - length = 2 * A.length; - } - //the function is used in solveEquation - A has 1 column more than rows - else - { - length = A.length + 1; - } - - //elimination operations to modify A so that that it contains only 0s under the diagonal - for (int k = 0; k < A.length - 1; k++) - { // the fixed row - for (int i = k + 1; i < A.length; i++) - { // rows - short factor1 = A[i][k]; - short factor2 = GF2Field.invElem(A[k][k]); - - //The element which multiplicative inverse is needed, is 0 - //in this case is the input matrix not invertible - if (factor2 == 0) - { - throw new RuntimeException("Matrix not invertible! We have to choose another one!"); - } - - for (int j = k; j < length; j++) - {// columns - // tmp=A[k,j] / A[k,k] - tmp = GF2Field.multElem(A[k][j], factor2); - // tmp = A[i,k] * A[k,j] / A[k,k] - tmp = GF2Field.multElem(factor1, tmp); - // A[i,j]=A[i,j]-A[i,k]/A[k,k]*A[k,j]; - A[i][j] = GF2Field.addElem(A[i][j], tmp); - } - } - } - } - - /** - * Elimination above the diagonal. - * This function changes a matrix so that it contains only zeros above the - * diagonal(Ai,i) using only Gauss-Elimination operations. - * <p/> - * It is used in the inverse-function - * The result is stored in the global matrix A - * - * @throws RuntimeException in case a multiplicative inverse of 0 is needed - */ - private void computeZerosAbove() - throws RuntimeException - { - short tmp = 0; - for (int k = A.length - 1; k > 0; k--) - { // the fixed row - for (int i = k - 1; i >= 0; i--) - { // rows - short factor1 = A[i][k]; - short factor2 = GF2Field.invElem(A[k][k]); - if (factor2 == 0) - { - throw new RuntimeException("The matrix is not invertible"); - } - for (int j = k; j < 2 * A.length; j++) - { // columns - // tmp = A[k,j] / A[k,k] - tmp = GF2Field.multElem(A[k][j], factor2); - // tmp = A[i,k] * A[k,j] / A[k,k] - tmp = GF2Field.multElem(factor1, tmp); - // A[i,j] = A[i,j] - A[i,k] / A[k,k] * A[k,j]; - A[i][j] = GF2Field.addElem(A[i][j], tmp); - } - } - } - } - - - /** - * This function uses backward substitution to find x - * of the linear equation system (LES) B*x = b, - * where A a triangle-matrix is (contains only zeros under the diagonal) - * and b is a vector - * <p/> - * If the multiplicative inverse of 0 is needed, an exception is thrown. - * In this case is the LES not solvable - * - * @throws RuntimeException in case a multiplicative inverse of 0 is needed - */ - private void substitute() - throws RuntimeException - { - - // for the temporary results of the operations in field - short tmp, temp; - - temp = GF2Field.invElem(A[A.length - 1][A.length - 1]); - if (temp == 0) - { - throw new RuntimeException("The equation system is not solvable"); - } - - /** backward substitution **/ - x[A.length - 1] = GF2Field.multElem(A[A.length - 1][A.length], temp); - for (int i = A.length - 2; i >= 0; i--) - { - tmp = A[i][A.length]; - for (int j = A.length - 1; j > i; j--) - { - temp = GF2Field.multElem(A[i][j], x[j]); - tmp = GF2Field.addElem(tmp, temp); - } - - temp = GF2Field.invElem(A[i][i]); - if (temp == 0) - { - throw new RuntimeException("Not solvable equation system"); - } - x[i] = GF2Field.multElem(tmp, temp); - } - } - - - /** - * This function multiplies two given matrices. - * If the given matrices cannot be multiplied due - * to different sizes, an exception is thrown. - * - * @param M1 -the 1st matrix - * @param M2 -the 2nd matrix - * @return A = M1*M2 - * @throws RuntimeException in case the given matrices cannot be multiplied - * due to different dimensions. - */ - public short[][] multiplyMatrix(short[][] M1, short[][] M2) - throws RuntimeException - { - - if (M1[0].length != M2.length) - { - throw new RuntimeException("Multiplication is not possible!"); - } - short tmp = 0; - A = new short[M1.length][M2[0].length]; - for (int i = 0; i < M1.length; i++) - { - for (int j = 0; j < M2.length; j++) - { - for (int k = 0; k < M2[0].length; k++) - { - tmp = GF2Field.multElem(M1[i][j], M2[j][k]); - A[i][k] = GF2Field.addElem(A[i][k], tmp); - } - } - } - return A; - } - - /** - * This function multiplies a given matrix with a one-dimensional array. - * <p> - * An exception is thrown, if the number of columns in the matrix and - * the number of rows in the one-dim. array differ. - * - * @param M1 the matrix to be multiplied - * @param m the one-dimensional array to be multiplied - * @return M1*m - * @throws RuntimeException in case of dimension inconsistency - */ - public short[] multiplyMatrix(short[][] M1, short[] m) - throws RuntimeException - { - if (M1[0].length != m.length) - { - throw new RuntimeException("Multiplication is not possible!"); - } - short tmp = 0; - short[] B = new short[M1.length]; - for (int i = 0; i < M1.length; i++) - { - for (int j = 0; j < m.length; j++) - { - tmp = GF2Field.multElem(M1[i][j], m[j]); - B[i] = GF2Field.addElem(B[i], tmp); - } - } - return B; - } - - /** - * Addition of two vectors - * - * @param vector1 first summand, always of dim n - * @param vector2 second summand, always of dim n - * @return addition of vector1 and vector2 - * @throws RuntimeException in case the addition is impossible - * due to inconsistency in the dimensions - */ - public short[] addVect(short[] vector1, short[] vector2) - { - if (vector1.length != vector2.length) - { - throw new RuntimeException("Multiplication is not possible!"); - } - short rslt[] = new short[vector1.length]; - for (int n = 0; n < rslt.length; n++) - { - rslt[n] = GF2Field.addElem(vector1[n], vector2[n]); - } - return rslt; - } - - /** - * Multiplication of column vector with row vector - * - * @param vector1 column vector, always n x 1 - * @param vector2 row vector, always 1 x n - * @return resulting n x n matrix of multiplication - * @throws RuntimeException in case the multiplication is impossible due to - * inconsistency in the dimensions - */ - public short[][] multVects(short[] vector1, short[] vector2) - { - if (vector1.length != vector2.length) - { - throw new RuntimeException("Multiplication is not possible!"); - } - short rslt[][] = new short[vector1.length][vector2.length]; - for (int i = 0; i < vector1.length; i++) - { - for (int j = 0; j < vector2.length; j++) - { - rslt[i][j] = GF2Field.multElem(vector1[i], vector2[j]); - } - } - return rslt; - } - - /** - * Multiplies vector with scalar - * - * @param scalar galois element to multiply vector with - * @param vector vector to be multiplied - * @return vector multiplied with scalar - */ - public short[] multVect(short scalar, short[] vector) - { - short rslt[] = new short[vector.length]; - for (int n = 0; n < rslt.length; n++) - { - rslt[n] = GF2Field.multElem(scalar, vector[n]); - } - return rslt; - } - - /** - * Multiplies matrix with scalar - * - * @param scalar galois element to multiply matrix with - * @param matrix 2-dim n x n matrix to be multiplied - * @return matrix multiplied with scalar - */ - public short[][] multMatrix(short scalar, short[][] matrix) - { - short[][] rslt = new short[matrix.length][matrix[0].length]; - for (int i = 0; i < matrix.length; i++) - { - for (int j = 0; j < matrix[0].length; j++) - { - rslt[i][j] = GF2Field.multElem(scalar, matrix[i][j]); - } - } - return rslt; - } - - /** - * Adds the n x n matrices matrix1 and matrix2 - * - * @param matrix1 first summand - * @param matrix2 second summand - * @return addition of matrix1 and matrix2; both having the dimensions n x n - * @throws RuntimeException in case the addition is not possible because of - * different dimensions of the matrices - */ - public short[][] addSquareMatrix(short[][] matrix1, short[][] matrix2) - { - if (matrix1.length != matrix2.length || matrix1[0].length != matrix2[0].length) - { - throw new RuntimeException("Addition is not possible!"); - } - - short[][] rslt = new short[matrix1.length][matrix1.length];// - for (int i = 0; i < matrix1.length; i++) - { - for (int j = 0; j < matrix2.length; j++) - { - rslt[i][j] = GF2Field.addElem(matrix1[i][j], matrix2[i][j]); - } - } - return rslt; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/util/GF2Field.java b/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/util/GF2Field.java deleted file mode 100644 index 8d542799..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/util/GF2Field.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.bouncycastle.pqc.crypto.rainbow.util; - -/** - * This class provides the basic operations like addition, multiplication and - * finding the multiplicative inverse of an element in GF2^8. - * <p> - * The operations are implemented using the irreducible polynomial - * 1+x^2+x^3+x^6+x^8 ( 1 0100 1101 = 0x14d ) - * <p> - * This class makes use of lookup tables(exps and logs) for implementing the - * operations in order to increase the efficiency of Rainbow. - */ -public class GF2Field -{ - - public static final int MASK = 0xff; - - /* - * this lookup table is needed for multiplication and computing the - * multiplicative inverse - */ - static final short exps[] = {1, 2, 4, 8, 16, 32, 64, 128, 77, 154, 121, 242, - 169, 31, 62, 124, 248, 189, 55, 110, 220, 245, 167, 3, 6, 12, 24, - 48, 96, 192, 205, 215, 227, 139, 91, 182, 33, 66, 132, 69, 138, 89, - 178, 41, 82, 164, 5, 10, 20, 40, 80, 160, 13, 26, 52, 104, 208, - 237, 151, 99, 198, 193, 207, 211, 235, 155, 123, 246, 161, 15, 30, - 60, 120, 240, 173, 23, 46, 92, 184, 61, 122, 244, 165, 7, 14, 28, - 56, 112, 224, 141, 87, 174, 17, 34, 68, 136, 93, 186, 57, 114, 228, - 133, 71, 142, 81, 162, 9, 18, 36, 72, 144, 109, 218, 249, 191, 51, - 102, 204, 213, 231, 131, 75, 150, 97, 194, 201, 223, 243, 171, 27, - 54, 108, 216, 253, 183, 35, 70, 140, 85, 170, 25, 50, 100, 200, - 221, 247, 163, 11, 22, 44, 88, 176, 45, 90, 180, 37, 74, 148, 101, - 202, 217, 255, 179, 43, 86, 172, 21, 42, 84, 168, 29, 58, 116, 232, - 157, 119, 238, 145, 111, 222, 241, 175, 19, 38, 76, 152, 125, 250, - 185, 63, 126, 252, 181, 39, 78, 156, 117, 234, 153, 127, 254, 177, - 47, 94, 188, 53, 106, 212, 229, 135, 67, 134, 65, 130, 73, 146, - 105, 210, 233, 159, 115, 230, 129, 79, 158, 113, 226, 137, 95, 190, - 49, 98, 196, 197, 199, 195, 203, 219, 251, 187, 59, 118, 236, 149, - 103, 206, 209, 239, 147, 107, 214, 225, 143, 83, 166, 1}; - - /* - * this lookup table is needed for multiplication and computing the - * multiplicative inverse - */ - static final short logs[] = {0, 0, 1, 23, 2, 46, 24, 83, 3, 106, 47, 147, - 25, 52, 84, 69, 4, 92, 107, 182, 48, 166, 148, 75, 26, 140, 53, - 129, 85, 170, 70, 13, 5, 36, 93, 135, 108, 155, 183, 193, 49, 43, - 167, 163, 149, 152, 76, 202, 27, 230, 141, 115, 54, 205, 130, 18, - 86, 98, 171, 240, 71, 79, 14, 189, 6, 212, 37, 210, 94, 39, 136, - 102, 109, 214, 156, 121, 184, 8, 194, 223, 50, 104, 44, 253, 168, - 138, 164, 90, 150, 41, 153, 34, 77, 96, 203, 228, 28, 123, 231, 59, - 142, 158, 116, 244, 55, 216, 206, 249, 131, 111, 19, 178, 87, 225, - 99, 220, 172, 196, 241, 175, 72, 10, 80, 66, 15, 186, 190, 199, 7, - 222, 213, 120, 38, 101, 211, 209, 95, 227, 40, 33, 137, 89, 103, - 252, 110, 177, 215, 248, 157, 243, 122, 58, 185, 198, 9, 65, 195, - 174, 224, 219, 51, 68, 105, 146, 45, 82, 254, 22, 169, 12, 139, - 128, 165, 74, 91, 181, 151, 201, 42, 162, 154, 192, 35, 134, 78, - 188, 97, 239, 204, 17, 229, 114, 29, 61, 124, 235, 232, 233, 60, - 234, 143, 125, 159, 236, 117, 30, 245, 62, 56, 246, 217, 63, 207, - 118, 250, 31, 132, 160, 112, 237, 20, 144, 179, 126, 88, 251, 226, - 32, 100, 208, 221, 119, 173, 218, 197, 64, 242, 57, 176, 247, 73, - 180, 11, 127, 81, 21, 67, 145, 16, 113, 187, 238, 191, 133, 200, - 161}; - - /** - * This function calculates the sum of two elements as an operation in GF2^8 - * - * @param x the first element that is to be added - * @param y the second element that should be add - * @return the sum of the two elements x and y in GF2^8 - */ - public static short addElem(short x, short y) - { - return (short)(x ^ y); - } - - /** - * This function computes the multiplicative inverse of a given element in - * GF2^8 The 0 has no multiplicative inverse and in this case 0 is returned. - * - * @param x the element which multiplicative inverse is to be computed - * @return the multiplicative inverse of the given element, in case it - * exists or 0, otherwise - */ - public static short invElem(short x) - { - if (x == 0) - { - return 0; - } - return (exps[255 - logs[x]]); - } - - /** - * This function multiplies two elements in GF2^8. If one of the two - * elements is 0, 0 is returned. - * - * @param x the first element to be multiplied. - * @param y the second element to be multiplied. - * @return the product of the two input elements in GF2^8. - */ - public static short multElem(short x, short y) - { - if (x == 0 || y == 0) - { - return 0; - } - else - { - return (exps[(logs[x] + logs[y]) % 255]); - } - } - - /** - * This function returns the values of exps-lookup table which correspond to - * the input - * - * @param x the index in the lookup table exps - * @return exps-value, corresponding to the input - */ - public static short getExp(short x) - { - return exps[x]; - } - - /** - * This function returns the values of logs-lookup table which correspond to - * the input - * - * @param x the index in the lookup table logs - * @return logs-value, corresponding to the input - */ - public static short getLog(short x) - { - return logs[x]; - } - - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/util/RainbowUtil.java b/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/util/RainbowUtil.java deleted file mode 100644 index 2b073b1b..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/rainbow/util/RainbowUtil.java +++ /dev/null @@ -1,230 +0,0 @@ -package org.bouncycastle.pqc.crypto.rainbow.util; - -/** - * This class is needed for the conversions while encoding and decoding, as well as for - * comparison between arrays of some dimensions - */ -public class RainbowUtil -{ - - /** - * This function converts an one-dimensional array of bytes into a - * one-dimensional array of int - * - * @param in the array to be converted - * @return out - * the one-dimensional int-array that corresponds the input - */ - public static int[] convertArraytoInt(byte[] in) - { - int[] out = new int[in.length]; - for (int i = 0; i < in.length; i++) - { - out[i] = in[i] & GF2Field.MASK; - } - return out; - } - - /** - * This function converts an one-dimensional array of bytes into a - * one-dimensional array of type short - * - * @param in the array to be converted - * @return out - * one-dimensional short-array that corresponds the input - */ - public static short[] convertArray(byte[] in) - { - short[] out = new short[in.length]; - for (int i = 0; i < in.length; i++) - { - out[i] = (short)(in[i] & GF2Field.MASK); - } - return out; - } - - /** - * This function converts a matrix of bytes into a matrix of type short - * - * @param in the matrix to be converted - * @return out - * short-matrix that corresponds the input - */ - public static short[][] convertArray(byte[][] in) - { - short[][] out = new short[in.length][in[0].length]; - for (int i = 0; i < in.length; i++) - { - for (int j = 0; j < in[0].length; j++) - { - out[i][j] = (short)(in[i][j] & GF2Field.MASK); - } - } - return out; - } - - /** - * This function converts a 3-dimensional array of bytes into a 3-dimensional array of type short - * - * @param in the array to be converted - * @return out - * short-array that corresponds the input - */ - public static short[][][] convertArray(byte[][][] in) - { - short[][][] out = new short[in.length][in[0].length][in[0][0].length]; - for (int i = 0; i < in.length; i++) - { - for (int j = 0; j < in[0].length; j++) - { - for (int k = 0; k < in[0][0].length; k++) - { - out[i][j][k] = (short)(in[i][j][k] & GF2Field.MASK); - } - } - } - return out; - } - - /** - * This function converts an array of type int into an array of type byte - * - * @param in the array to be converted - * @return out - * the byte-array that corresponds the input - */ - public static byte[] convertIntArray(int[] in) - { - byte[] out = new byte[in.length]; - for (int i = 0; i < in.length; i++) - { - out[i] = (byte)in[i]; - } - return out; - } - - - /** - * This function converts an array of type short into an array of type byte - * - * @param in the array to be converted - * @return out - * the byte-array that corresponds the input - */ - public static byte[] convertArray(short[] in) - { - byte[] out = new byte[in.length]; - for (int i = 0; i < in.length; i++) - { - out[i] = (byte)in[i]; - } - return out; - } - - /** - * This function converts a matrix of type short into a matrix of type byte - * - * @param in the matrix to be converted - * @return out - * the byte-matrix that corresponds the input - */ - public static byte[][] convertArray(short[][] in) - { - byte[][] out = new byte[in.length][in[0].length]; - for (int i = 0; i < in.length; i++) - { - for (int j = 0; j < in[0].length; j++) - { - out[i][j] = (byte)in[i][j]; - } - } - return out; - } - - /** - * This function converts a 3-dimensional array of type short into a 3-dimensional array of type byte - * - * @param in the array to be converted - * @return out - * the byte-array that corresponds the input - */ - public static byte[][][] convertArray(short[][][] in) - { - byte[][][] out = new byte[in.length][in[0].length][in[0][0].length]; - for (int i = 0; i < in.length; i++) - { - for (int j = 0; j < in[0].length; j++) - { - for (int k = 0; k < in[0][0].length; k++) - { - out[i][j][k] = (byte)in[i][j][k]; - } - } - } - return out; - } - - /** - * Compare two short arrays. No null checks are performed. - * - * @param left the first short array - * @param right the second short array - * @return the result of the comparison - */ - public static boolean equals(short[] left, short[] right) - { - if (left.length != right.length) - { - return false; - } - boolean result = true; - for (int i = left.length - 1; i >= 0; i--) - { - result &= left[i] == right[i]; - } - return result; - } - - /** - * Compare two two-dimensional short arrays. No null checks are performed. - * - * @param left the first short array - * @param right the second short array - * @return the result of the comparison - */ - public static boolean equals(short[][] left, short[][] right) - { - if (left.length != right.length) - { - return false; - } - boolean result = true; - for (int i = left.length - 1; i >= 0; i--) - { - result &= equals(left[i], right[i]); - } - return result; - } - - /** - * Compare two three-dimensional short arrays. No null checks are performed. - * - * @param left the first short array - * @param right the second short array - * @return the result of the comparison - */ - public static boolean equals(short[][][] left, short[][][] right) - { - if (left.length != right.length) - { - return false; - } - boolean result = true; - for (int i = left.length - 1; i >= 0; i--) - { - result &= equals(left[i], right[i]); - } - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/BigEndianConversions.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/BigEndianConversions.java deleted file mode 100644 index 90926f67..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/BigEndianConversions.java +++ /dev/null @@ -1,306 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - - -/** - * This is a utility class containing data type conversions using big-endian - * byte order. - * - * @see LittleEndianConversions - */ -public final class BigEndianConversions -{ - - /** - * Default constructor (private). - */ - private BigEndianConversions() - { - // empty - } - - /** - * Convert an integer to an octet string of length 4 according to IEEE 1363, - * Section 5.5.3. - * - * @param x the integer to convert - * @return the converted integer - */ - public static byte[] I2OSP(int x) - { - byte[] result = new byte[4]; - result[0] = (byte)(x >>> 24); - result[1] = (byte)(x >>> 16); - result[2] = (byte)(x >>> 8); - result[3] = (byte)x; - return result; - } - - /** - * Convert an integer to an octet string according to IEEE 1363, Section - * 5.5.3. Length checking is performed. - * - * @param x the integer to convert - * @param oLen the desired length of the octet string - * @return an octet string of length <tt>oLen</tt> representing the - * integer <tt>x</tt>, or <tt>null</tt> if the integer is - * negative - * @throws ArithmeticException if <tt>x</tt> can't be encoded into <tt>oLen</tt> - * octets. - */ - public static byte[] I2OSP(int x, int oLen) - throws ArithmeticException - { - if (x < 0) - { - return null; - } - int octL = IntegerFunctions.ceilLog256(x); - if (octL > oLen) - { - throw new ArithmeticException( - "Cannot encode given integer into specified number of octets."); - } - byte[] result = new byte[oLen]; - for (int i = oLen - 1; i >= oLen - octL; i--) - { - result[i] = (byte)(x >>> (8 * (oLen - 1 - i))); - } - return result; - } - - /** - * Convert an integer to an octet string of length 4 according to IEEE 1363, - * Section 5.5.3. - * - * @param input the integer to convert - * @param output byte array holding the output - * @param outOff offset in output array where the result is stored - */ - public static void I2OSP(int input, byte[] output, int outOff) - { - output[outOff++] = (byte)(input >>> 24); - output[outOff++] = (byte)(input >>> 16); - output[outOff++] = (byte)(input >>> 8); - output[outOff] = (byte)input; - } - - /** - * Convert an integer to an octet string of length 8 according to IEEE 1363, - * Section 5.5.3. - * - * @param input the integer to convert - * @return the converted integer - */ - public static byte[] I2OSP(long input) - { - byte[] output = new byte[8]; - output[0] = (byte)(input >>> 56); - output[1] = (byte)(input >>> 48); - output[2] = (byte)(input >>> 40); - output[3] = (byte)(input >>> 32); - output[4] = (byte)(input >>> 24); - output[5] = (byte)(input >>> 16); - output[6] = (byte)(input >>> 8); - output[7] = (byte)input; - return output; - } - - /** - * Convert an integer to an octet string of length 8 according to IEEE 1363, - * Section 5.5.3. - * - * @param input the integer to convert - * @param output byte array holding the output - * @param outOff offset in output array where the result is stored - */ - public static void I2OSP(long input, byte[] output, int outOff) - { - output[outOff++] = (byte)(input >>> 56); - output[outOff++] = (byte)(input >>> 48); - output[outOff++] = (byte)(input >>> 40); - output[outOff++] = (byte)(input >>> 32); - output[outOff++] = (byte)(input >>> 24); - output[outOff++] = (byte)(input >>> 16); - output[outOff++] = (byte)(input >>> 8); - output[outOff] = (byte)input; - } - - /** - * Convert an integer to an octet string of the specified length according - * to IEEE 1363, Section 5.5.3. No length checking is performed (i.e., if - * the integer cannot be encoded into <tt>length</tt> octets, it is - * truncated). - * - * @param input the integer to convert - * @param output byte array holding the output - * @param outOff offset in output array where the result is stored - * @param length the length of the encoding - */ - public static void I2OSP(int input, byte[] output, int outOff, int length) - { - for (int i = length - 1; i >= 0; i--) - { - output[outOff + i] = (byte)(input >>> (8 * (length - 1 - i))); - } - } - - /** - * Convert an octet string to an integer according to IEEE 1363, Section - * 5.5.3. - * - * @param input the byte array holding the octet string - * @return an integer representing the octet string <tt>input</tt>, or - * <tt>0</tt> if the represented integer is negative or too large - * or the byte array is empty - * @throws ArithmeticException if the length of the given octet string is larger than 4. - */ - public static int OS2IP(byte[] input) - { - if (input.length > 4) - { - throw new ArithmeticException("invalid input length"); - } - if (input.length == 0) - { - return 0; - } - int result = 0; - for (int j = 0; j < input.length; j++) - { - result |= (input[j] & 0xff) << (8 * (input.length - 1 - j)); - } - return result; - } - - /** - * Convert a byte array of length 4 beginning at <tt>offset</tt> into an - * integer. - * - * @param input the byte array - * @param inOff the offset into the byte array - * @return the resulting integer - */ - public static int OS2IP(byte[] input, int inOff) - { - int result = (input[inOff++] & 0xff) << 24; - result |= (input[inOff++] & 0xff) << 16; - result |= (input[inOff++] & 0xff) << 8; - result |= input[inOff] & 0xff; - return result; - } - - /** - * Convert an octet string to an integer according to IEEE 1363, Section - * 5.5.3. - * - * @param input the byte array holding the octet string - * @param inOff the offset in the input byte array where the octet string - * starts - * @param inLen the length of the encoded integer - * @return an integer representing the octet string <tt>bytes</tt>, or - * <tt>0</tt> if the represented integer is negative or too large - * or the byte array is empty - */ - public static int OS2IP(byte[] input, int inOff, int inLen) - { - if ((input.length == 0) || input.length < inOff + inLen - 1) - { - return 0; - } - int result = 0; - for (int j = 0; j < inLen; j++) - { - result |= (input[inOff + j] & 0xff) << (8 * (inLen - j - 1)); - } - return result; - } - - /** - * Convert a byte array of length 8 beginning at <tt>inOff</tt> into a - * long integer. - * - * @param input the byte array - * @param inOff the offset into the byte array - * @return the resulting long integer - */ - public static long OS2LIP(byte[] input, int inOff) - { - long result = ((long)input[inOff++] & 0xff) << 56; - result |= ((long)input[inOff++] & 0xff) << 48; - result |= ((long)input[inOff++] & 0xff) << 40; - result |= ((long)input[inOff++] & 0xff) << 32; - result |= ((long)input[inOff++] & 0xff) << 24; - result |= (input[inOff++] & 0xff) << 16; - result |= (input[inOff++] & 0xff) << 8; - result |= input[inOff] & 0xff; - return result; - } - - /** - * Convert an int array into a byte array. - * - * @param input the int array - * @return the converted array - */ - public static byte[] toByteArray(final int[] input) - { - byte[] result = new byte[input.length << 2]; - for (int i = 0; i < input.length; i++) - { - I2OSP(input[i], result, i << 2); - } - return result; - } - - /** - * Convert an int array into a byte array of the specified length. No length - * checking is performed (i.e., if the last integer cannot be encoded into - * <tt>length % 4</tt> octets, it is truncated). - * - * @param input the int array - * @param length the length of the converted array - * @return the converted array - */ - public static byte[] toByteArray(final int[] input, int length) - { - final int intLen = input.length; - byte[] result = new byte[length]; - int index = 0; - for (int i = 0; i <= intLen - 2; i++, index += 4) - { - I2OSP(input[i], result, index); - } - I2OSP(input[intLen - 1], result, index, length - index); - return result; - } - - /** - * Convert a byte array into an int array. - * - * @param input the byte array - * @return the converted array - */ - public static int[] toIntArray(byte[] input) - { - final int intLen = (input.length + 3) / 4; - final int lastLen = input.length & 0x03; - int[] result = new int[intLen]; - - int index = 0; - for (int i = 0; i <= intLen - 2; i++, index += 4) - { - result[i] = OS2IP(input, index); - } - if (lastLen != 0) - { - result[intLen - 1] = OS2IP(input, index, lastLen); - } - else - { - result[intLen - 1] = OS2IP(input, index); - } - - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/BigIntUtils.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/BigIntUtils.java deleted file mode 100644 index b99ed41b..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/BigIntUtils.java +++ /dev/null @@ -1,138 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -import java.math.BigInteger; - -/** - * FIXME: is this really necessary?! - */ -public final class BigIntUtils -{ - - /** - * Default constructor (private). - */ - private BigIntUtils() - { - // empty - } - - /** - * Checks if two BigInteger arrays contain the same entries - * - * @param a first BigInteger array - * @param b second BigInteger array - * @return true or false - */ - public static boolean equals(BigInteger[] a, BigInteger[] b) - { - int flag = 0; - - if (a.length != b.length) - { - return false; - } - for (int i = 0; i < a.length; i++) - { - // avoid branches here! - // problem: compareTo on BigIntegers is not - // guaranteed constant-time! - flag |= a[i].compareTo(b[i]); - } - return flag == 0; - } - - /** - * Fill the given BigInteger array with the given value. - * - * @param array the array - * @param value the value - */ - public static void fill(BigInteger[] array, BigInteger value) - { - for (int i = array.length - 1; i >= 0; i--) - { - array[i] = value; - } - } - - /** - * Generates a subarray of a given BigInteger array. - * - * @param input - - * the input BigInteger array - * @param start - - * the start index - * @param end - - * the end index - * @return a subarray of <tt>input</tt>, ranging from <tt>start</tt> to - * <tt>end</tt> - */ - public static BigInteger[] subArray(BigInteger[] input, int start, int end) - { - BigInteger[] result = new BigInteger[end - start]; - System.arraycopy(input, start, result, 0, end - start); - return result; - } - - /** - * Converts a BigInteger array into an integer array - * - * @param input - - * the BigInteger array - * @return the integer array - */ - public static int[] toIntArray(BigInteger[] input) - { - int[] result = new int[input.length]; - for (int i = 0; i < input.length; i++) - { - result[i] = input[i].intValue(); - } - return result; - } - - /** - * Converts a BigInteger array into an integer array, reducing all - * BigIntegers mod q. - * - * @param q - - * the modulus - * @param input - - * the BigInteger array - * @return the integer array - */ - public static int[] toIntArrayModQ(int q, BigInteger[] input) - { - BigInteger bq = BigInteger.valueOf(q); - int[] result = new int[input.length]; - for (int i = 0; i < input.length; i++) - { - result[i] = input[i].mod(bq).intValue(); - } - return result; - } - - /** - * Return the value of <tt>big</tt> as a byte array. Although BigInteger - * has such a method, it uses an extra bit to indicate the sign of the - * number. For elliptic curve cryptography, the numbers usually are - * positive. Thus, this helper method returns a byte array of minimal - * length, ignoring the sign of the number. - * - * @param value the <tt>BigInteger</tt> value to be converted to a byte - * array - * @return the value <tt>big</tt> as byte array - */ - public static byte[] toMinimalByteArray(BigInteger value) - { - byte[] valBytes = value.toByteArray(); - if ((valBytes.length == 1) || (value.bitLength() & 0x07) != 0) - { - return valBytes; - } - byte[] result = new byte[value.bitLength() >> 3]; - System.arraycopy(valBytes, 1, result, 0, result.length); - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/ByteUtils.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/ByteUtils.java deleted file mode 100644 index 5ad91f41..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/ByteUtils.java +++ /dev/null @@ -1,414 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -/** - * This class is a utility class for manipulating byte arrays. - */ -public final class ByteUtils -{ - - private static final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5', - '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - - /** - * Default constructor (private) - */ - private ByteUtils() - { - // empty - } - - /** - * Compare two byte arrays (perform null checks beforehand). - * - * @param left the first byte array - * @param right the second byte array - * @return the result of the comparison - */ - public static boolean equals(byte[] left, byte[] right) - { - if (left == null) - { - return right == null; - } - if (right == null) - { - return false; - } - - if (left.length != right.length) - { - return false; - } - boolean result = true; - for (int i = left.length - 1; i >= 0; i--) - { - result &= left[i] == right[i]; - } - return result; - } - - /** - * Compare two two-dimensional byte arrays. No null checks are performed. - * - * @param left the first byte array - * @param right the second byte array - * @return the result of the comparison - */ - public static boolean equals(byte[][] left, byte[][] right) - { - if (left.length != right.length) - { - return false; - } - - boolean result = true; - for (int i = left.length - 1; i >= 0; i--) - { - result &= ByteUtils.equals(left[i], right[i]); - } - - return result; - } - - /** - * Compare two three-dimensional byte arrays. No null checks are performed. - * - * @param left the first byte array - * @param right the second byte array - * @return the result of the comparison - */ - public static boolean equals(byte[][][] left, byte[][][] right) - { - if (left.length != right.length) - { - return false; - } - - boolean result = true; - for (int i = left.length - 1; i >= 0; i--) - { - if (left[i].length != right[i].length) - { - return false; - } - for (int j = left[i].length - 1; j >= 0; j--) - { - result &= ByteUtils.equals(left[i][j], right[i][j]); - } - } - - return result; - } - - /** - * Computes a hashcode based on the contents of a one-dimensional byte array - * rather than its identity. - * - * @param array the array to compute the hashcode of - * @return the hashcode - */ - public static int deepHashCode(byte[] array) - { - int result = 1; - for (int i = 0; i < array.length; i++) - { - result = 31 * result + array[i]; - } - return result; - } - - /** - * Computes a hashcode based on the contents of a two-dimensional byte array - * rather than its identity. - * - * @param array the array to compute the hashcode of - * @return the hashcode - */ - public static int deepHashCode(byte[][] array) - { - int result = 1; - for (int i = 0; i < array.length; i++) - { - result = 31 * result + deepHashCode(array[i]); - } - return result; - } - - /** - * Computes a hashcode based on the contents of a three-dimensional byte - * array rather than its identity. - * - * @param array the array to compute the hashcode of - * @return the hashcode - */ - public static int deepHashCode(byte[][][] array) - { - int result = 1; - for (int i = 0; i < array.length; i++) - { - result = 31 * result + deepHashCode(array[i]); - } - return result; - } - - - /** - * Return a clone of the given byte array (performs null check beforehand). - * - * @param array the array to clone - * @return the clone of the given array, or <tt>null</tt> if the array is - * <tt>null</tt> - */ - public static byte[] clone(byte[] array) - { - if (array == null) - { - return null; - } - byte[] result = new byte[array.length]; - System.arraycopy(array, 0, result, 0, array.length); - return result; - } - - /** - * Convert a string containing hexadecimal characters to a byte-array. - * - * @param s a hex string - * @return a byte array with the corresponding value - */ - public static byte[] fromHexString(String s) - { - char[] rawChars = s.toUpperCase().toCharArray(); - - int hexChars = 0; - for (int i = 0; i < rawChars.length; i++) - { - if ((rawChars[i] >= '0' && rawChars[i] <= '9') - || (rawChars[i] >= 'A' && rawChars[i] <= 'F')) - { - hexChars++; - } - } - - byte[] byteString = new byte[(hexChars + 1) >> 1]; - - int pos = hexChars & 1; - - for (int i = 0; i < rawChars.length; i++) - { - if (rawChars[i] >= '0' && rawChars[i] <= '9') - { - byteString[pos >> 1] <<= 4; - byteString[pos >> 1] |= rawChars[i] - '0'; - } - else if (rawChars[i] >= 'A' && rawChars[i] <= 'F') - { - byteString[pos >> 1] <<= 4; - byteString[pos >> 1] |= rawChars[i] - 'A' + 10; - } - else - { - continue; - } - pos++; - } - - return byteString; - } - - /** - * Convert a byte array to the corresponding hexstring. - * - * @param input the byte array to be converted - * @return the corresponding hexstring - */ - public static String toHexString(byte[] input) - { - String result = ""; - for (int i = 0; i < input.length; i++) - { - result += HEX_CHARS[(input[i] >>> 4) & 0x0f]; - result += HEX_CHARS[(input[i]) & 0x0f]; - } - return result; - } - - /** - * Convert a byte array to the corresponding hex string. - * - * @param input the byte array to be converted - * @param prefix the prefix to put at the beginning of the hex string - * @param seperator a separator string - * @return the corresponding hex string - */ - public static String toHexString(byte[] input, String prefix, - String seperator) - { - String result = new String(prefix); - for (int i = 0; i < input.length; i++) - { - result += HEX_CHARS[(input[i] >>> 4) & 0x0f]; - result += HEX_CHARS[(input[i]) & 0x0f]; - if (i < input.length - 1) - { - result += seperator; - } - } - return result; - } - - /** - * Convert a byte array to the corresponding bit string. - * - * @param input the byte array to be converted - * @return the corresponding bit string - */ - public static String toBinaryString(byte[] input) - { - String result = ""; - int i; - for (i = 0; i < input.length; i++) - { - int e = input[i]; - for (int ii = 0; ii < 8; ii++) - { - int b = (e >>> ii) & 1; - result += b; - } - if (i != input.length - 1) - { - result += " "; - } - } - return result; - } - - /** - * Compute the bitwise XOR of two arrays of bytes. The arrays have to be of - * same length. No length checking is performed. - * - * @param x1 the first array - * @param x2 the second array - * @return x1 XOR x2 - */ - public static byte[] xor(byte[] x1, byte[] x2) - { - byte[] out = new byte[x1.length]; - - for (int i = x1.length - 1; i >= 0; i--) - { - out[i] = (byte)(x1[i] ^ x2[i]); - } - return out; - } - - /** - * Concatenate two byte arrays. No null checks are performed. - * - * @param x1 the first array - * @param x2 the second array - * @return (x2||x1) (little-endian order, i.e. x1 is at lower memory - * addresses) - */ - public static byte[] concatenate(byte[] x1, byte[] x2) - { - byte[] result = new byte[x1.length + x2.length]; - - System.arraycopy(x1, 0, result, 0, x1.length); - System.arraycopy(x2, 0, result, x1.length, x2.length); - - return result; - } - - /** - * Convert a 2-dimensional byte array into a 1-dimensional byte array by - * concatenating all entries. - * - * @param array a 2-dimensional byte array - * @return the concatenated input array - */ - public static byte[] concatenate(byte[][] array) - { - int rowLength = array[0].length; - byte[] result = new byte[array.length * rowLength]; - int index = 0; - for (int i = 0; i < array.length; i++) - { - System.arraycopy(array[i], 0, result, index, rowLength); - index += rowLength; - } - return result; - } - - /** - * Split a byte array <tt>input</tt> into two arrays at <tt>index</tt>, - * i.e. the first array will have the lower <tt>index</tt> bytes, the - * second one the higher <tt>input.length - index</tt> bytes. - * - * @param input the byte array to be split - * @param index the index where the byte array is split - * @return the splitted input array as an array of two byte arrays - * @throws ArrayIndexOutOfBoundsException if <tt>index</tt> is out of bounds - */ - public static byte[][] split(byte[] input, int index) - throws ArrayIndexOutOfBoundsException - { - if (index > input.length) - { - throw new ArrayIndexOutOfBoundsException(); - } - byte[][] result = new byte[2][]; - result[0] = new byte[index]; - result[1] = new byte[input.length - index]; - System.arraycopy(input, 0, result[0], 0, index); - System.arraycopy(input, index, result[1], 0, input.length - index); - return result; - } - - /** - * Generate a subarray of a given byte array. - * - * @param input the input byte array - * @param start the start index - * @param end the end index - * @return a subarray of <tt>input</tt>, ranging from <tt>start</tt> - * (inclusively) to <tt>end</tt> (exclusively) - */ - public static byte[] subArray(byte[] input, int start, int end) - { - byte[] result = new byte[end - start]; - System.arraycopy(input, start, result, 0, end - start); - return result; - } - - /** - * Generate a subarray of a given byte array. - * - * @param input the input byte array - * @param start the start index - * @return a subarray of <tt>input</tt>, ranging from <tt>start</tt> to - * the end of the array - */ - public static byte[] subArray(byte[] input, int start) - { - return subArray(input, start, input.length); - } - - /** - * Rewrite a byte array as a char array - * - * @param input - - * the byte array - * @return char array - */ - public static char[] toCharArray(byte[] input) - { - char[] result = new char[input.length]; - for (int i = 0; i < input.length; i++) - { - result[i] = (char)input[i]; - } - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/CharUtils.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/CharUtils.java deleted file mode 100644 index 1800685d..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/CharUtils.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -public final class CharUtils -{ - - /** - * Default constructor (private) - */ - private CharUtils() - { - // empty - } - - /** - * Return a clone of the given char array. No null checks are performed. - * - * @param array the array to clone - * @return the clone of the given array - */ - public static char[] clone(char[] array) - { - char[] result = new char[array.length]; - System.arraycopy(array, 0, result, 0, array.length); - return result; - } - - /** - * Convert the given char array into a byte array. - * - * @param chars the char array - * @return the converted array - */ - public static byte[] toByteArray(char[] chars) - { - byte[] result = new byte[chars.length]; - for (int i = chars.length - 1; i >= 0; i--) - { - result[i] = (byte)chars[i]; - } - return result; - } - - /** - * Convert the given char array into a - * byte array for use with PBE encryption. - * - * @param chars the char array - * @return the converted array - */ - public static byte[] toByteArrayForPBE(char[] chars) - { - - byte[] out = new byte[chars.length]; - - for (int i = 0; i < chars.length; i++) - { - out[i] = (byte)chars[i]; - } - - int length = out.length * 2; - byte[] ret = new byte[length + 2]; - - int j = 0; - for (int i = 0; i < out.length; i++) - { - j = i * 2; - ret[j] = 0; - ret[j + 1] = out[i]; - } - - ret[length] = 0; - ret[length + 1] = 0; - - return ret; - } - - /** - * Compare two char arrays. No null checks are performed. - * - * @param left the char byte array - * @param right the second char array - * @return the result of the comparison - */ - public static boolean equals(char[] left, char[] right) - { - if (left.length != right.length) - { - return false; - } - boolean result = true; - for (int i = left.length - 1; i >= 0; i--) - { - result &= left[i] == right[i]; - } - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2Matrix.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2Matrix.java deleted file mode 100644 index a61f9507..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2Matrix.java +++ /dev/null @@ -1,1323 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -import java.security.SecureRandom; - -/** - * This class describes some operations with matrices over finite field GF(2) - * and is used in ecc and MQ-PKC (also has some specific methods and - * implementation) - */ -public class GF2Matrix - extends Matrix -{ - - /** - * For the matrix representation the array of type int[][] is used, thus one - * element of the array keeps 32 elements of the matrix (from one row and 32 - * columns) - */ - private int[][] matrix; - - /** - * the length of each array representing a row of this matrix, computed as - * <tt>(numColumns + 31) / 32</tt> - */ - private int length; - - /** - * Create the matrix from encoded form. - * - * @param enc the encoded matrix - */ - public GF2Matrix(byte[] enc) - { - if (enc.length < 9) - { - throw new ArithmeticException( - "given array is not an encoded matrix over GF(2)"); - } - - numRows = LittleEndianConversions.OS2IP(enc, 0); - numColumns = LittleEndianConversions.OS2IP(enc, 4); - - int n = ((numColumns + 7) >>> 3) * numRows; - - if ((numRows <= 0) || (n != (enc.length - 8))) - { - throw new ArithmeticException( - "given array is not an encoded matrix over GF(2)"); - } - - length = (numColumns + 31) >>> 5; - matrix = new int[numRows][length]; - - // number of "full" integer - int q = numColumns >> 5; - // number of bits in non-full integer - int r = numColumns & 0x1f; - - int count = 8; - for (int i = 0; i < numRows; i++) - { - for (int j = 0; j < q; j++, count += 4) - { - matrix[i][j] = LittleEndianConversions.OS2IP(enc, count); - } - for (int j = 0; j < r; j += 8) - { - matrix[i][q] ^= (enc[count++] & 0xff) << j; - } - } - } - - /** - * Create the matrix with the contents of the given array. The matrix is not - * copied. Unused coefficients are masked out. - * - * @param numColumns the number of columns - * @param matrix the element array - */ - public GF2Matrix(int numColumns, int[][] matrix) - { - if (matrix[0].length != (numColumns + 31) >> 5) - { - throw new ArithmeticException( - "Int array does not match given number of columns."); - } - this.numColumns = numColumns; - numRows = matrix.length; - length = matrix[0].length; - int rest = numColumns & 0x1f; - int bitMask; - if (rest == 0) - { - bitMask = 0xffffffff; - } - else - { - bitMask = (1 << rest) - 1; - } - for (int i = 0; i < numRows; i++) - { - matrix[i][length - 1] &= bitMask; - } - this.matrix = matrix; - } - - /** - * Create an nxn matrix of the given type. - * - * @param n the number of rows (and columns) - * @param typeOfMatrix the martix type (see {@link Matrix} for predefined - * constants) - */ - public GF2Matrix(int n, char typeOfMatrix) - { - this(n, typeOfMatrix, new java.security.SecureRandom()); - } - - /** - * Create an nxn matrix of the given type. - * - * @param n the matrix size - * @param typeOfMatrix the matrix type - * @param sr the source of randomness - */ - public GF2Matrix(int n, char typeOfMatrix, SecureRandom sr) - { - if (n <= 0) - { - throw new ArithmeticException("Size of matrix is non-positive."); - } - - switch (typeOfMatrix) - { - - case Matrix.MATRIX_TYPE_ZERO: - assignZeroMatrix(n, n); - break; - - case Matrix.MATRIX_TYPE_UNIT: - assignUnitMatrix(n); - break; - - case Matrix.MATRIX_TYPE_RANDOM_LT: - assignRandomLowerTriangularMatrix(n, sr); - break; - - case Matrix.MATRIX_TYPE_RANDOM_UT: - assignRandomUpperTriangularMatrix(n, sr); - break; - - case Matrix.MATRIX_TYPE_RANDOM_REGULAR: - assignRandomRegularMatrix(n, sr); - break; - - default: - throw new ArithmeticException("Unknown matrix type."); - } - } - - /** - * Copy constructor. - * - * @param a another {@link GF2Matrix} - */ - public GF2Matrix(GF2Matrix a) - { - numColumns = a.getNumColumns(); - numRows = a.getNumRows(); - length = a.length; - matrix = new int[a.matrix.length][]; - for (int i = 0; i < matrix.length; i++) - { - matrix[i] = IntUtils.clone(a.matrix[i]); - } - - } - - /** - * create the mxn zero matrix - */ - private GF2Matrix(int m, int n) - { - if ((n <= 0) || (m <= 0)) - { - throw new ArithmeticException("size of matrix is non-positive"); - } - - assignZeroMatrix(m, n); - } - - /** - * Create the mxn zero matrix. - * - * @param m number of rows - * @param n number of columns - */ - private void assignZeroMatrix(int m, int n) - { - numRows = m; - numColumns = n; - length = (n + 31) >>> 5; - matrix = new int[numRows][length]; - for (int i = 0; i < numRows; i++) - { - for (int j = 0; j < length; j++) - { - matrix[i][j] = 0; - } - } - } - - /** - * Create the mxn unit matrix. - * - * @param n number of rows (and columns) - */ - private void assignUnitMatrix(int n) - { - numRows = n; - numColumns = n; - length = (n + 31) >>> 5; - matrix = new int[numRows][length]; - for (int i = 0; i < numRows; i++) - { - for (int j = 0; j < length; j++) - { - matrix[i][j] = 0; - } - } - for (int i = 0; i < numRows; i++) - { - int rest = i & 0x1f; - matrix[i][i >>> 5] = 1 << rest; - } - } - - /** - * Create a nxn random lower triangular matrix. - * - * @param n number of rows (and columns) - * @param sr source of randomness - */ - private void assignRandomLowerTriangularMatrix(int n, SecureRandom sr) - { - numRows = n; - numColumns = n; - length = (n + 31) >>> 5; - matrix = new int[numRows][length]; - for (int i = 0; i < numRows; i++) - { - int q = i >>> 5; - int r = i & 0x1f; - int s = 31 - r; - r = 1 << r; - for (int j = 0; j < q; j++) - { - matrix[i][j] = sr.nextInt(); - } - matrix[i][q] = (sr.nextInt() >>> s) | r; - for (int j = q + 1; j < length; j++) - { - matrix[i][j] = 0; - } - - } - - } - - /** - * Create a nxn random upper triangular matrix. - * - * @param n number of rows (and columns) - * @param sr source of randomness - */ - private void assignRandomUpperTriangularMatrix(int n, SecureRandom sr) - { - numRows = n; - numColumns = n; - length = (n + 31) >>> 5; - matrix = new int[numRows][length]; - int rest = n & 0x1f; - int help; - if (rest == 0) - { - help = 0xffffffff; - } - else - { - help = (1 << rest) - 1; - } - for (int i = 0; i < numRows; i++) - { - int q = i >>> 5; - int r = i & 0x1f; - int s = r; - r = 1 << r; - for (int j = 0; j < q; j++) - { - matrix[i][j] = 0; - } - matrix[i][q] = (sr.nextInt() << s) | r; - for (int j = q + 1; j < length; j++) - { - matrix[i][j] = sr.nextInt(); - } - matrix[i][length - 1] &= help; - } - - } - - /** - * Create an nxn random regular matrix. - * - * @param n number of rows (and columns) - * @param sr source of randomness - */ - private void assignRandomRegularMatrix(int n, SecureRandom sr) - { - numRows = n; - numColumns = n; - length = (n + 31) >>> 5; - matrix = new int[numRows][length]; - GF2Matrix lm = new GF2Matrix(n, Matrix.MATRIX_TYPE_RANDOM_LT, sr); - GF2Matrix um = new GF2Matrix(n, Matrix.MATRIX_TYPE_RANDOM_UT, sr); - GF2Matrix rm = (GF2Matrix)lm.rightMultiply(um); - Permutation perm = new Permutation(n, sr); - int[] p = perm.getVector(); - for (int i = 0; i < n; i++) - { - System.arraycopy(rm.matrix[i], 0, matrix[p[i]], 0, length); - } - } - - /** - * Create a nxn random regular matrix and its inverse. - * - * @param n number of rows (and columns) - * @param sr source of randomness - * @return the created random regular matrix and its inverse - */ - public static GF2Matrix[] createRandomRegularMatrixAndItsInverse(int n, - SecureRandom sr) - { - - GF2Matrix[] result = new GF2Matrix[2]; - - // ------------------------------------ - // First part: create regular matrix - // ------------------------------------ - - // ------ - int length = (n + 31) >> 5; - GF2Matrix lm = new GF2Matrix(n, Matrix.MATRIX_TYPE_RANDOM_LT, sr); - GF2Matrix um = new GF2Matrix(n, Matrix.MATRIX_TYPE_RANDOM_UT, sr); - GF2Matrix rm = (GF2Matrix)lm.rightMultiply(um); - Permutation p = new Permutation(n, sr); - int[] pVec = p.getVector(); - - int[][] matrix = new int[n][length]; - for (int i = 0; i < n; i++) - { - System.arraycopy(rm.matrix[pVec[i]], 0, matrix[i], 0, length); - } - - result[0] = new GF2Matrix(n, matrix); - - // ------------------------------------ - // Second part: create inverse matrix - // ------------------------------------ - - // inverse to lm - GF2Matrix invLm = new GF2Matrix(n, Matrix.MATRIX_TYPE_UNIT); - for (int i = 0; i < n; i++) - { - int rest = i & 0x1f; - int q = i >>> 5; - int r = 1 << rest; - for (int j = i + 1; j < n; j++) - { - int b = (lm.matrix[j][q]) & r; - if (b != 0) - { - for (int k = 0; k <= q; k++) - { - invLm.matrix[j][k] ^= invLm.matrix[i][k]; - } - } - } - } - // inverse to um - GF2Matrix invUm = new GF2Matrix(n, Matrix.MATRIX_TYPE_UNIT); - for (int i = n - 1; i >= 0; i--) - { - int rest = i & 0x1f; - int q = i >>> 5; - int r = 1 << rest; - for (int j = i - 1; j >= 0; j--) - { - int b = (um.matrix[j][q]) & r; - if (b != 0) - { - for (int k = q; k < length; k++) - { - invUm.matrix[j][k] ^= invUm.matrix[i][k]; - } - } - } - } - - // inverse matrix - result[1] = (GF2Matrix)invUm.rightMultiply(invLm.rightMultiply(p)); - - return result; - } - - /** - * @return the array keeping the matrix elements - */ - public int[][] getIntArray() - { - return matrix; - } - - /** - * @return the length of each array representing a row of this matrix - */ - public int getLength() - { - return length; - } - - /** - * Return the row of this matrix with the given index. - * - * @param index the index - * @return the row of this matrix with the given index - */ - public int[] getRow(int index) - { - return matrix[index]; - } - - /** - * Returns encoded matrix, i.e., this matrix in byte array form - * - * @return the encoded matrix - */ - public byte[] getEncoded() - { - int n = (numColumns + 7) >>> 3; - n *= numRows; - n += 8; - byte[] enc = new byte[n]; - - LittleEndianConversions.I2OSP(numRows, enc, 0); - LittleEndianConversions.I2OSP(numColumns, enc, 4); - - // number of "full" integer - int q = numColumns >>> 5; - // number of bits in non-full integer - int r = numColumns & 0x1f; - - int count = 8; - for (int i = 0; i < numRows; i++) - { - for (int j = 0; j < q; j++, count += 4) - { - LittleEndianConversions.I2OSP(matrix[i][j], enc, count); - } - for (int j = 0; j < r; j += 8) - { - enc[count++] = (byte)((matrix[i][q] >>> j) & 0xff); - } - - } - return enc; - } - - - /** - * Returns the percentage of the number of "ones" in this matrix. - * - * @return the Hamming weight of this matrix (as a ratio). - */ - public double getHammingWeight() - { - double counter = 0.0; - double elementCounter = 0.0; - int rest = numColumns & 0x1f; - int d; - if (rest == 0) - { - d = length; - } - else - { - d = length - 1; - } - - for (int i = 0; i < numRows; i++) - { - - for (int j = 0; j < d; j++) - { - int a = matrix[i][j]; - for (int k = 0; k < 32; k++) - { - int b = (a >>> k) & 1; - counter = counter + b; - elementCounter = elementCounter + 1; - } - } - int a = matrix[i][length - 1]; - for (int k = 0; k < rest; k++) - { - int b = (a >>> k) & 1; - counter = counter + b; - elementCounter = elementCounter + 1; - } - } - - return counter / elementCounter; - } - - /** - * Check if this is the zero matrix (i.e., all entries are zero). - * - * @return <tt>true</tt> if this is the zero matrix - */ - public boolean isZero() - { - for (int i = 0; i < numRows; i++) - { - for (int j = 0; j < length; j++) - { - if (matrix[i][j] != 0) - { - return false; - } - } - } - return true; - } - - /** - * Get the quadratic submatrix of this matrix consisting of the leftmost - * <tt>numRows</tt> columns. - * - * @return the <tt>(numRows x numRows)</tt> submatrix - */ - public GF2Matrix getLeftSubMatrix() - { - if (numColumns <= numRows) - { - throw new ArithmeticException("empty submatrix"); - } - int length = (numRows + 31) >> 5; - int[][] result = new int[numRows][length]; - int bitMask = (1 << (numRows & 0x1f)) - 1; - if (bitMask == 0) - { - bitMask = -1; - } - for (int i = numRows - 1; i >= 0; i--) - { - System.arraycopy(matrix[i], 0, result[i], 0, length); - result[i][length - 1] &= bitMask; - } - return new GF2Matrix(numRows, result); - } - - /** - * Compute the full form matrix <tt>(this | Id)</tt> from this matrix in - * left compact form, where <tt>Id</tt> is the <tt>k x k</tt> identity - * matrix and <tt>k</tt> is the number of rows of this matrix. - * - * @return <tt>(this | Id)</tt> - */ - public GF2Matrix extendLeftCompactForm() - { - int newNumColumns = numColumns + numRows; - GF2Matrix result = new GF2Matrix(numRows, newNumColumns); - - int ind = numRows - 1 + numColumns; - for (int i = numRows - 1; i >= 0; i--, ind--) - { - // copy this matrix to first columns - System.arraycopy(matrix[i], 0, result.matrix[i], 0, length); - // store the identity in last columns - result.matrix[i][ind >> 5] |= 1 << (ind & 0x1f); - } - - return result; - } - - /** - * Get the submatrix of this matrix consisting of the rightmost - * <tt>numColumns-numRows</tt> columns. - * - * @return the <tt>(numRows x (numColumns-numRows))</tt> submatrix - */ - public GF2Matrix getRightSubMatrix() - { - if (numColumns <= numRows) - { - throw new ArithmeticException("empty submatrix"); - } - - int q = numRows >> 5; - int r = numRows & 0x1f; - - GF2Matrix result = new GF2Matrix(numRows, numColumns - numRows); - - for (int i = numRows - 1; i >= 0; i--) - { - // if words have to be shifted - if (r != 0) - { - int ind = q; - // process all but last word - for (int j = 0; j < result.length - 1; j++) - { - // shift to correct position - result.matrix[i][j] = (matrix[i][ind++] >>> r) - | (matrix[i][ind] << (32 - r)); - } - // process last word - result.matrix[i][result.length - 1] = matrix[i][ind++] >>> r; - if (ind < length) - { - result.matrix[i][result.length - 1] |= matrix[i][ind] << (32 - r); - } - } - else - { - // no shifting necessary - System.arraycopy(matrix[i], q, result.matrix[i], 0, - result.length); - } - } - return result; - } - - /** - * Compute the full form matrix <tt>(Id | this)</tt> from this matrix in - * right compact form, where <tt>Id</tt> is the <tt>k x k</tt> identity - * matrix and <tt>k</tt> is the number of rows of this matrix. - * - * @return <tt>(Id | this)</tt> - */ - public GF2Matrix extendRightCompactForm() - { - GF2Matrix result = new GF2Matrix(numRows, numRows + numColumns); - - int q = numRows >> 5; - int r = numRows & 0x1f; - - for (int i = numRows - 1; i >= 0; i--) - { - // store the identity in first columns - result.matrix[i][i >> 5] |= 1 << (i & 0x1f); - - // copy this matrix to last columns - - // if words have to be shifted - if (r != 0) - { - int ind = q; - // process all but last word - for (int j = 0; j < length - 1; j++) - { - // obtain matrix word - int mw = matrix[i][j]; - // shift to correct position - result.matrix[i][ind++] |= mw << r; - result.matrix[i][ind] |= mw >>> (32 - r); - } - // process last word - int mw = matrix[i][length - 1]; - result.matrix[i][ind++] |= mw << r; - if (ind < result.length) - { - result.matrix[i][ind] |= mw >>> (32 - r); - } - } - else - { - // no shifting necessary - System.arraycopy(matrix[i], 0, result.matrix[i], q, length); - } - } - - return result; - } - - /** - * Compute the transpose of this matrix. - * - * @return <tt>(this)<sup>T</sup></tt> - */ - public Matrix computeTranspose() - { - int[][] result = new int[numColumns][(numRows + 31) >>> 5]; - for (int i = 0; i < numRows; i++) - { - for (int j = 0; j < numColumns; j++) - { - int qs = j >>> 5; - int rs = j & 0x1f; - int b = (matrix[i][qs] >>> rs) & 1; - int qt = i >>> 5; - int rt = i & 0x1f; - if (b == 1) - { - result[j][qt] |= 1 << rt; - } - } - } - - return new GF2Matrix(numRows, result); - } - - /** - * Compute the inverse of this matrix. - * - * @return the inverse of this matrix (newly created). - * @throws ArithmeticException if this matrix is not invertible. - */ - public Matrix computeInverse() - { - if (numRows != numColumns) - { - throw new ArithmeticException("Matrix is not invertible."); - } - - // clone this matrix - int[][] tmpMatrix = new int[numRows][length]; - for (int i = numRows - 1; i >= 0; i--) - { - tmpMatrix[i] = IntUtils.clone(matrix[i]); - } - - // initialize inverse matrix as unit matrix - int[][] invMatrix = new int[numRows][length]; - for (int i = numRows - 1; i >= 0; i--) - { - int q = i >> 5; - int r = i & 0x1f; - invMatrix[i][q] = 1 << r; - } - - // simultaneously compute Gaussian reduction of tmpMatrix and unit - // matrix - for (int i = 0; i < numRows; i++) - { - // i = q * 32 + (i mod 32) - int q = i >> 5; - int bitMask = 1 << (i & 0x1f); - // if diagonal element is zero - if ((tmpMatrix[i][q] & bitMask) == 0) - { - boolean foundNonZero = false; - // find a non-zero element in the same column - for (int j = i + 1; j < numRows; j++) - { - if ((tmpMatrix[j][q] & bitMask) != 0) - { - // found it, swap rows ... - foundNonZero = true; - swapRows(tmpMatrix, i, j); - swapRows(invMatrix, i, j); - // ... and quit searching - j = numRows; - continue; - } - } - // if no non-zero element was found ... - if (!foundNonZero) - { - // ... the matrix is not invertible - throw new ArithmeticException("Matrix is not invertible."); - } - } - - // normalize all but i-th row - for (int j = numRows - 1; j >= 0; j--) - { - if ((j != i) && ((tmpMatrix[j][q] & bitMask) != 0)) - { - addToRow(tmpMatrix[i], tmpMatrix[j], q); - addToRow(invMatrix[i], invMatrix[j], 0); - } - } - } - - return new GF2Matrix(numColumns, invMatrix); - } - - /** - * Compute the product of a permutation matrix (which is generated from an - * n-permutation) and this matrix. - * - * @param p the permutation - * @return {@link GF2Matrix} <tt>P*this</tt> - */ - public Matrix leftMultiply(Permutation p) - { - int[] pVec = p.getVector(); - if (pVec.length != numRows) - { - throw new ArithmeticException("length mismatch"); - } - - int[][] result = new int[numRows][]; - - for (int i = numRows - 1; i >= 0; i--) - { - result[i] = IntUtils.clone(matrix[pVec[i]]); - } - - return new GF2Matrix(numRows, result); - } - - /** - * compute product a row vector and this matrix - * - * @param vec a vector over GF(2) - * @return Vector product a*matrix - */ - public Vector leftMultiply(Vector vec) - { - - if (!(vec instanceof GF2Vector)) - { - throw new ArithmeticException("vector is not defined over GF(2)"); - } - - if (vec.length != numRows) - { - throw new ArithmeticException("length mismatch"); - } - - int[] v = ((GF2Vector)vec).getVecArray(); - int[] res = new int[length]; - - int q = numRows >> 5; - int r = 1 << (numRows & 0x1f); - - // compute scalar products with full words of vector - int row = 0; - for (int i = 0; i < q; i++) - { - int bitMask = 1; - do - { - int b = v[i] & bitMask; - if (b != 0) - { - for (int j = 0; j < length; j++) - { - res[j] ^= matrix[row][j]; - } - } - row++; - bitMask <<= 1; - } - while (bitMask != 0); - } - - // compute scalar products with last word of vector - int bitMask = 1; - while (bitMask != r) - { - int b = v[q] & bitMask; - if (b != 0) - { - for (int j = 0; j < length; j++) - { - res[j] ^= matrix[row][j]; - } - } - row++; - bitMask <<= 1; - } - - return new GF2Vector(res, numColumns); - } - - /** - * Compute the product of the matrix <tt>(this | Id)</tt> and a column - * vector, where <tt>Id</tt> is a <tt>(numRows x numRows)</tt> unit - * matrix. - * - * @param vec the vector over GF(2) - * @return <tt>(this | Id)*vector</tt> - */ - public Vector leftMultiplyLeftCompactForm(Vector vec) - { - if (!(vec instanceof GF2Vector)) - { - throw new ArithmeticException("vector is not defined over GF(2)"); - } - - if (vec.length != numRows) - { - throw new ArithmeticException("length mismatch"); - } - - int[] v = ((GF2Vector)vec).getVecArray(); - int[] res = new int[(numRows + numColumns + 31) >>> 5]; - - // process full words of vector - int words = numRows >>> 5; - int row = 0; - for (int i = 0; i < words; i++) - { - int bitMask = 1; - do - { - int b = v[i] & bitMask; - if (b != 0) - { - // compute scalar product part - for (int j = 0; j < length; j++) - { - res[j] ^= matrix[row][j]; - } - // set last bit - int q = (numColumns + row) >>> 5; - int r = (numColumns + row) & 0x1f; - res[q] |= 1 << r; - } - row++; - bitMask <<= 1; - } - while (bitMask != 0); - } - - // process last word of vector - int rem = 1 << (numRows & 0x1f); - int bitMask = 1; - while (bitMask != rem) - { - int b = v[words] & bitMask; - if (b != 0) - { - // compute scalar product part - for (int j = 0; j < length; j++) - { - res[j] ^= matrix[row][j]; - } - // set last bit - int q = (numColumns + row) >>> 5; - int r = (numColumns + row) & 0x1f; - res[q] |= 1 << r; - } - row++; - bitMask <<= 1; - } - - return new GF2Vector(res, numRows + numColumns); - } - - /** - * Compute the product of this matrix and a matrix A over GF(2). - * - * @param mat a matrix A over GF(2) - * @return matrix product <tt>this*matrixA</tt> - */ - public Matrix rightMultiply(Matrix mat) - { - if (!(mat instanceof GF2Matrix)) - { - throw new ArithmeticException("matrix is not defined over GF(2)"); - } - - if (mat.numRows != numColumns) - { - throw new ArithmeticException("length mismatch"); - } - - GF2Matrix a = (GF2Matrix)mat; - GF2Matrix result = new GF2Matrix(numRows, mat.numColumns); - - int d; - int rest = numColumns & 0x1f; - if (rest == 0) - { - d = length; - } - else - { - d = length - 1; - } - for (int i = 0; i < numRows; i++) - { - int count = 0; - for (int j = 0; j < d; j++) - { - int e = matrix[i][j]; - for (int h = 0; h < 32; h++) - { - int b = e & (1 << h); - if (b != 0) - { - for (int g = 0; g < a.length; g++) - { - result.matrix[i][g] ^= a.matrix[count][g]; - } - } - count++; - } - } - int e = matrix[i][length - 1]; - for (int h = 0; h < rest; h++) - { - int b = e & (1 << h); - if (b != 0) - { - for (int g = 0; g < a.length; g++) - { - result.matrix[i][g] ^= a.matrix[count][g]; - } - } - count++; - } - - } - - return result; - } - - /** - * Compute the product of this matrix and a permutation matrix which is - * generated from an n-permutation. - * - * @param p the permutation - * @return {@link GF2Matrix} <tt>this*P</tt> - */ - public Matrix rightMultiply(Permutation p) - { - - int[] pVec = p.getVector(); - if (pVec.length != numColumns) - { - throw new ArithmeticException("length mismatch"); - } - - GF2Matrix result = new GF2Matrix(numRows, numColumns); - - for (int i = numColumns - 1; i >= 0; i--) - { - int q = i >>> 5; - int r = i & 0x1f; - int pq = pVec[i] >>> 5; - int pr = pVec[i] & 0x1f; - for (int j = numRows - 1; j >= 0; j--) - { - result.matrix[j][q] |= ((matrix[j][pq] >>> pr) & 1) << r; - } - } - - return result; - } - - /** - * Compute the product of this matrix and the given column vector. - * - * @param vec the vector over GF(2) - * @return <tt>this*vector</tt> - */ - public Vector rightMultiply(Vector vec) - { - if (!(vec instanceof GF2Vector)) - { - throw new ArithmeticException("vector is not defined over GF(2)"); - } - - if (vec.length != numColumns) - { - throw new ArithmeticException("length mismatch"); - } - - int[] v = ((GF2Vector)vec).getVecArray(); - int[] res = new int[(numRows + 31) >>> 5]; - - for (int i = 0; i < numRows; i++) - { - // compute full word scalar products - int help = 0; - for (int j = 0; j < length; j++) - { - help ^= matrix[i][j] & v[j]; - } - // compute single word scalar product - int bitValue = 0; - for (int j = 0; j < 32; j++) - { - bitValue ^= (help >>> j) & 1; - } - // set result bit - if (bitValue == 1) - { - res[i >>> 5] |= 1 << (i & 0x1f); - } - } - - return new GF2Vector(res, numRows); - } - - /** - * Compute the product of the matrix <tt>(Id | this)</tt> and a column - * vector, where <tt>Id</tt> is a <tt>(numRows x numRows)</tt> unit - * matrix. - * - * @param vec the vector over GF(2) - * @return <tt>(Id | this)*vector</tt> - */ - public Vector rightMultiplyRightCompactForm(Vector vec) - { - if (!(vec instanceof GF2Vector)) - { - throw new ArithmeticException("vector is not defined over GF(2)"); - } - - if (vec.length != numColumns + numRows) - { - throw new ArithmeticException("length mismatch"); - } - - int[] v = ((GF2Vector)vec).getVecArray(); - int[] res = new int[(numRows + 31) >>> 5]; - - int q = numRows >> 5; - int r = numRows & 0x1f; - - // for all rows - for (int i = 0; i < numRows; i++) - { - // get vector bit - int help = (v[i >> 5] >>> (i & 0x1f)) & 1; - - // compute full word scalar products - int vInd = q; - // if words have to be shifted - if (r != 0) - { - int vw = 0; - // process all but last word - for (int j = 0; j < length - 1; j++) - { - // shift to correct position - vw = (v[vInd++] >>> r) | (v[vInd] << (32 - r)); - help ^= matrix[i][j] & vw; - } - // process last word - vw = v[vInd++] >>> r; - if (vInd < v.length) - { - vw |= v[vInd] << (32 - r); - } - help ^= matrix[i][length - 1] & vw; - } - else - { - // no shifting necessary - for (int j = 0; j < length; j++) - { - help ^= matrix[i][j] & v[vInd++]; - } - } - - // compute single word scalar product - int bitValue = 0; - for (int j = 0; j < 32; j++) - { - bitValue ^= help & 1; - help >>>= 1; - } - - // set result bit - if (bitValue == 1) - { - res[i >> 5] |= 1 << (i & 0x1f); - } - } - - return new GF2Vector(res, numRows); - } - - /** - * Compare this matrix with another object. - * - * @param other another object - * @return the result of the comparison - */ - public boolean equals(Object other) - { - - if (!(other instanceof GF2Matrix)) - { - return false; - } - GF2Matrix otherMatrix = (GF2Matrix)other; - - if ((numRows != otherMatrix.numRows) - || (numColumns != otherMatrix.numColumns) - || (length != otherMatrix.length)) - { - return false; - } - - for (int i = 0; i < numRows; i++) - { - if (!IntUtils.equals(matrix[i], otherMatrix.matrix[i])) - { - return false; - } - } - - return true; - } - - /** - * @return the hash code of this matrix - */ - public int hashCode() - { - int hash = (numRows * 31 + numColumns) * 31 + length; - for (int i = 0; i < numRows; i++) - { - hash = hash * 31 + matrix[i].hashCode(); - } - return hash; - } - - /** - * @return a human readable form of the matrix - */ - public String toString() - { - int rest = numColumns & 0x1f; - int d; - if (rest == 0) - { - d = length; - } - else - { - d = length - 1; - } - - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < numRows; i++) - { - buf.append(i + ": "); - for (int j = 0; j < d; j++) - { - int a = matrix[i][j]; - for (int k = 0; k < 32; k++) - { - int b = (a >>> k) & 1; - if (b == 0) - { - buf.append('0'); - } - else - { - buf.append('1'); - } - } - buf.append(' '); - } - int a = matrix[i][length - 1]; - for (int k = 0; k < rest; k++) - { - int b = (a >>> k) & 1; - if (b == 0) - { - buf.append('0'); - } - else - { - buf.append('1'); - } - } - buf.append('\n'); - } - - return buf.toString(); - } - - /** - * Swap two rows of the given matrix. - * - * @param matrix the matrix - * @param first the index of the first row - * @param second the index of the second row - */ - private static void swapRows(int[][] matrix, int first, int second) - { - int[] tmp = matrix[first]; - matrix[first] = matrix[second]; - matrix[second] = tmp; - } - - /** - * Partially add one row to another. - * - * @param fromRow the addend - * @param toRow the row to add to - * @param startIndex the array index to start from - */ - private static void addToRow(int[] fromRow, int[] toRow, int startIndex) - { - for (int i = toRow.length - 1; i >= startIndex; i--) - { - toRow[i] = fromRow[i] ^ toRow[i]; - } - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2Polynomial.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2Polynomial.java deleted file mode 100644 index 3ef1fbbc..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2Polynomial.java +++ /dev/null @@ -1,2039 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - - -import java.math.BigInteger; -import java.util.Random; - - -/** - * This class stores very long strings of bits and does some basic arithmetics. - * It is used by <tt>GF2nField</tt>, <tt>GF2nPolynomialField</tt> and - * <tt>GFnPolynomialElement</tt>. - * - * @see GF2nPolynomialElement - * @see GF2nField - */ -public class GF2Polynomial -{ - - // number of bits stored in this GF2Polynomial - private int len; - - // number of int used in value - private int blocks; - - // storage - private int[] value; - - // Random source - private static Random rand = new Random(); - - // Lookup-Table for vectorMult: parity[a]= #1(a) mod 2 == 1 - private static final boolean[] parity = {false, true, true, false, true, - false, false, true, true, false, false, true, false, true, true, - false, true, false, false, true, false, true, true, false, false, - true, true, false, true, false, false, true, true, false, false, - true, false, true, true, false, false, true, true, false, true, - false, false, true, false, true, true, false, true, false, false, - true, true, false, false, true, false, true, true, false, true, - false, false, true, false, true, true, false, false, true, true, - false, true, false, false, true, false, true, true, false, true, - false, false, true, true, false, false, true, false, true, true, - false, false, true, true, false, true, false, false, true, true, - false, false, true, false, true, true, false, true, false, false, - true, false, true, true, false, false, true, true, false, true, - false, false, true, true, false, false, true, false, true, true, - false, false, true, true, false, true, false, false, true, false, - true, true, false, true, false, false, true, true, false, false, - true, false, true, true, false, false, true, true, false, true, - false, false, true, true, false, false, true, false, true, true, - false, true, false, false, true, false, true, true, false, false, - true, true, false, true, false, false, true, false, true, true, - false, true, false, false, true, true, false, false, true, false, - true, true, false, true, false, false, true, false, true, true, - false, false, true, true, false, true, false, false, true, true, - false, false, true, false, true, true, false, false, true, true, - false, true, false, false, true, false, true, true, false, true, - false, false, true, true, false, false, true, false, true, true, - false}; - - // Lookup-Table for Squaring: squaringTable[a]=a^2 - private static final short[] squaringTable = {0x0000, 0x0001, 0x0004, - 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, 0x0040, 0x0041, 0x0044, - 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, 0x0100, 0x0101, 0x0104, - 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, 0x0140, 0x0141, 0x0144, - 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, 0x0400, 0x0401, 0x0404, - 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, 0x0440, 0x0441, 0x0444, - 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, 0x0500, 0x0501, 0x0504, - 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, 0x0540, 0x0541, 0x0544, - 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, 0x1000, 0x1001, 0x1004, - 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, 0x1040, 0x1041, 0x1044, - 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, 0x1100, 0x1101, 0x1104, - 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, 0x1140, 0x1141, 0x1144, - 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, 0x1400, 0x1401, 0x1404, - 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, 0x1440, 0x1441, 0x1444, - 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, 0x1500, 0x1501, 0x1504, - 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, 0x1540, 0x1541, 0x1544, - 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, 0x4000, 0x4001, 0x4004, - 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, 0x4040, 0x4041, 0x4044, - 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, 0x4100, 0x4101, 0x4104, - 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, 0x4140, 0x4141, 0x4144, - 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, 0x4400, 0x4401, 0x4404, - 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, 0x4440, 0x4441, 0x4444, - 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, 0x4500, 0x4501, 0x4504, - 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, 0x4540, 0x4541, 0x4544, - 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, 0x5000, 0x5001, 0x5004, - 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, 0x5040, 0x5041, 0x5044, - 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, 0x5100, 0x5101, 0x5104, - 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, 0x5140, 0x5141, 0x5144, - 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, 0x5400, 0x5401, 0x5404, - 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, 0x5440, 0x5441, 0x5444, - 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, 0x5500, 0x5501, 0x5504, - 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, 0x5540, 0x5541, 0x5544, - 0x5545, 0x5550, 0x5551, 0x5554, 0x5555}; - - // pre-computed Bitmask for fast masking, bitMask[a]=0x1 << a - private static final int[] bitMask = {0x00000001, 0x00000002, 0x00000004, - 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080, - 0x00000100, 0x00000200, 0x00000400, 0x00000800, 0x00001000, - 0x00002000, 0x00004000, 0x00008000, 0x00010000, 0x00020000, - 0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000, - 0x00800000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x00000000}; - - // pre-computed Bitmask for fast masking, rightMask[a]=0xffffffff >>> (32-a) - private static final int[] reverseRightMask = {0x00000000, 0x00000001, - 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, - 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, - 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, - 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, - 0x003fffff, 0x007fffff, 0x00ffffff, 0x01ffffff, 0x03ffffff, - 0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, - 0xffffffff}; - - /** - * Creates a new GF2Polynomial of the given <i>length</i> and value zero. - * - * @param length the desired number of bits to store - */ - public GF2Polynomial(int length) - { - int l = length; - if (l < 1) - { - l = 1; - } - blocks = ((l - 1) >> 5) + 1; - value = new int[blocks]; - len = l; - } - - /** - * Creates a new GF2Polynomial of the given <i>length</i> and random value. - * - * @param length the desired number of bits to store - * @param rand SecureRandom to use for randomization - */ - public GF2Polynomial(int length, Random rand) - { - int l = length; - if (l < 1) - { - l = 1; - } - blocks = ((l - 1) >> 5) + 1; - value = new int[blocks]; - len = l; - randomize(rand); - } - - /** - * Creates a new GF2Polynomial of the given <i>length</i> and value - * selected by <i>value</i>: - * <UL> - * <LI>ZERO</LI> - * <LI>ONE</LI> - * <LI>RANDOM</LI> - * <LI>X</LI> - * <LI>ALL</LI> - * </UL> - * - * @param length the desired number of bits to store - * @param value the value described by a String - */ - public GF2Polynomial(int length, String value) - { - int l = length; - if (l < 1) - { - l = 1; - } - blocks = ((l - 1) >> 5) + 1; - this.value = new int[blocks]; - len = l; - if (value.equalsIgnoreCase("ZERO")) - { - assignZero(); - } - else if (value.equalsIgnoreCase("ONE")) - { - assignOne(); - } - else if (value.equalsIgnoreCase("RANDOM")) - { - randomize(); - } - else if (value.equalsIgnoreCase("X")) - { - assignX(); - } - else if (value.equalsIgnoreCase("ALL")) - { - assignAll(); - } - else - { - throw new IllegalArgumentException( - "Error: GF2Polynomial was called using " + value - + " as value!"); - } - - } - - /** - * Creates a new GF2Polynomial of the given <i>length</i> using the given - * int[]. LSB is contained in bs[0]. - * - * @param length the desired number of bits to store - * @param bs contains the desired value, LSB in bs[0] - */ - public GF2Polynomial(int length, int[] bs) - { - int leng = length; - if (leng < 1) - { - leng = 1; - } - blocks = ((leng - 1) >> 5) + 1; - value = new int[blocks]; - len = leng; - int l = Math.min(blocks, bs.length); - System.arraycopy(bs, 0, value, 0, l); - zeroUnusedBits(); - } - - /** - * Creates a new GF2Polynomial by converting the given byte[] <i>os</i> - * according to 1363 and using the given <i>length</i>. - * - * @param length the intended length of this polynomial - * @param os the octet string to assign to this polynomial - * @see "P1363 5.5.2 p22f, OS2BSP" - */ - public GF2Polynomial(int length, byte[] os) - { - int l = length; - if (l < 1) - { - l = 1; - } - blocks = ((l - 1) >> 5) + 1; - value = new int[blocks]; - len = l; - int i, m; - int k = Math.min(((os.length - 1) >> 2) + 1, blocks); - for (i = 0; i < k - 1; i++) - { - m = os.length - (i << 2) - 1; - value[i] = (os[m]) & 0x000000ff; - value[i] |= (os[m - 1] << 8) & 0x0000ff00; - value[i] |= (os[m - 2] << 16) & 0x00ff0000; - value[i] |= (os[m - 3] << 24) & 0xff000000; - } - i = k - 1; - m = os.length - (i << 2) - 1; - value[i] = os[m] & 0x000000ff; - if (m > 0) - { - value[i] |= (os[m - 1] << 8) & 0x0000ff00; - } - if (m > 1) - { - value[i] |= (os[m - 2] << 16) & 0x00ff0000; - } - if (m > 2) - { - value[i] |= (os[m - 3] << 24) & 0xff000000; - } - zeroUnusedBits(); - reduceN(); - } - - /** - * Creates a new GF2Polynomial by converting the given FlexiBigInt <i>bi</i> - * according to 1363 and using the given <i>length</i>. - * - * @param length the intended length of this polynomial - * @param bi the FlexiBigInt to assign to this polynomial - * @see "P1363 5.5.1 p22, I2BSP" - */ - public GF2Polynomial(int length, BigInteger bi) - { - int l = length; - if (l < 1) - { - l = 1; - } - blocks = ((l - 1) >> 5) + 1; - value = new int[blocks]; - len = l; - int i; - byte[] val = bi.toByteArray(); - if (val[0] == 0) - { - byte[] dummy = new byte[val.length - 1]; - System.arraycopy(val, 1, dummy, 0, dummy.length); - val = dummy; - } - int ov = val.length & 0x03; - int k = ((val.length - 1) >> 2) + 1; - for (i = 0; i < ov; i++) - { - value[k - 1] |= (val[i] & 0x000000ff) << ((ov - 1 - i) << 3); - } - int m = 0; - for (i = 0; i <= (val.length - 4) >> 2; i++) - { - m = val.length - 1 - (i << 2); - value[i] = (val[m]) & 0x000000ff; - value[i] |= ((val[m - 1]) << 8) & 0x0000ff00; - value[i] |= ((val[m - 2]) << 16) & 0x00ff0000; - value[i] |= ((val[m - 3]) << 24) & 0xff000000; - } - if ((len & 0x1f) != 0) - { - value[blocks - 1] &= reverseRightMask[len & 0x1f]; - } - reduceN(); - } - - /** - * Creates a new GF2Polynomial by cloneing the given GF2Polynomial <i>b</i>. - * - * @param b the GF2Polynomial to clone - */ - public GF2Polynomial(GF2Polynomial b) - { - len = b.len; - blocks = b.blocks; - value = IntUtils.clone(b.value); - } - - /** - * @return a copy of this GF2Polynomial - */ - public Object clone() - { - return new GF2Polynomial(this); - } - - /** - * Returns the length of this GF2Polynomial. The length can be greater than - * the degree. To get the degree call reduceN() before calling getLength(). - * - * @return the length of this GF2Polynomial - */ - public int getLength() - { - return len; - } - - /** - * Returns the value of this GF2Polynomial in an int[]. - * - * @return the value of this GF2Polynomial in a new int[], LSB in int[0] - */ - public int[] toIntegerArray() - { - int[] result; - result = new int[blocks]; - System.arraycopy(value, 0, result, 0, blocks); - return result; - } - - /** - * Returns a string representing this GF2Polynomials value using hexadecimal - * or binary radix in MSB-first order. - * - * @param radix the radix to use (2 or 16, otherwise 2 is used) - * @return a String representing this GF2Polynomials value. - */ - public String toString(int radix) - { - final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', - '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - final String[] BIN_CHARS = {"0000", "0001", "0010", "0011", "0100", - "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", - "1101", "1110", "1111"}; - String res; - int i; - res = new String(); - if (radix == 16) - { - for (i = blocks - 1; i >= 0; i--) - { - res += HEX_CHARS[(value[i] >>> 28) & 0x0f]; - res += HEX_CHARS[(value[i] >>> 24) & 0x0f]; - res += HEX_CHARS[(value[i] >>> 20) & 0x0f]; - res += HEX_CHARS[(value[i] >>> 16) & 0x0f]; - res += HEX_CHARS[(value[i] >>> 12) & 0x0f]; - res += HEX_CHARS[(value[i] >>> 8) & 0x0f]; - res += HEX_CHARS[(value[i] >>> 4) & 0x0f]; - res += HEX_CHARS[(value[i]) & 0x0f]; - res += " "; - } - } - else - { - for (i = blocks - 1; i >= 0; i--) - { - res += BIN_CHARS[(value[i] >>> 28) & 0x0f]; - res += BIN_CHARS[(value[i] >>> 24) & 0x0f]; - res += BIN_CHARS[(value[i] >>> 20) & 0x0f]; - res += BIN_CHARS[(value[i] >>> 16) & 0x0f]; - res += BIN_CHARS[(value[i] >>> 12) & 0x0f]; - res += BIN_CHARS[(value[i] >>> 8) & 0x0f]; - res += BIN_CHARS[(value[i] >>> 4) & 0x0f]; - res += BIN_CHARS[(value[i]) & 0x0f]; - res += " "; - } - } - return res; - } - - /** - * Converts this polynomial to a byte[] (octet string) according to 1363. - * - * @return a byte[] representing the value of this polynomial - * @see "P1363 5.5.2 p22f, BS2OSP" - */ - public byte[] toByteArray() - { - int k = ((len - 1) >> 3) + 1; - int ov = k & 0x03; - int m; - byte[] res = new byte[k]; - int i; - for (i = 0; i < (k >> 2); i++) - { - m = k - (i << 2) - 1; - res[m] = (byte)((value[i] & 0x000000ff)); - res[m - 1] = (byte)((value[i] & 0x0000ff00) >>> 8); - res[m - 2] = (byte)((value[i] & 0x00ff0000) >>> 16); - res[m - 3] = (byte)((value[i] & 0xff000000) >>> 24); - } - for (i = 0; i < ov; i++) - { - m = (ov - i - 1) << 3; - res[i] = (byte)((value[blocks - 1] & (0x000000ff << m)) >>> m); - } - return res; - } - - /** - * Converts this polynomial to an integer according to 1363. - * - * @return a FlexiBigInt representing the value of this polynomial - * @see "P1363 5.5.1 p22, BS2IP" - */ - public BigInteger toFlexiBigInt() - { - if (len == 0 || isZero()) - { - return new BigInteger(0, new byte[0]); - } - return new BigInteger(1, toByteArray()); - } - - /** - * Sets the LSB to 1 and all other to 0, assigning 'one' to this - * GF2Polynomial. - */ - public void assignOne() - { - int i; - for (i = 1; i < blocks; i++) - { - value[i] = 0x00; - } - value[0] = 0x01; - } - - /** - * Sets Bit 1 to 1 and all other to 0, assigning 'x' to this GF2Polynomial. - */ - public void assignX() - { - int i; - for (i = 1; i < blocks; i++) - { - value[i] = 0x00; - } - value[0] = 0x02; - } - - /** - * Sets all Bits to 1. - */ - public void assignAll() - { - int i; - for (i = 0; i < blocks; i++) - { - value[i] = 0xffffffff; - } - zeroUnusedBits(); - } - - /** - * Resets all bits to zero. - */ - public void assignZero() - { - int i; - for (i = 0; i < blocks; i++) - { - value[i] = 0x00; - } - } - - /** - * Fills all len bits of this GF2Polynomial with random values. - */ - public void randomize() - { - int i; - for (i = 0; i < blocks; i++) - { - value[i] = rand.nextInt(); - } - zeroUnusedBits(); - } - - /** - * Fills all len bits of this GF2Polynomial with random values using the - * specified source of randomness. - * - * @param rand the source of randomness - */ - public void randomize(Random rand) - { - int i; - for (i = 0; i < blocks; i++) - { - value[i] = rand.nextInt(); - } - zeroUnusedBits(); - } - - /** - * Returns true if two GF2Polynomials have the same size and value and thus - * are equal. - * - * @param other the other GF2Polynomial - * @return true if this GF2Polynomial equals <i>b</i> (<i>this</i> == - * <i>b</i>) - */ - public boolean equals(Object other) - { - if (other == null || !(other instanceof GF2Polynomial)) - { - return false; - } - - GF2Polynomial otherPol = (GF2Polynomial)other; - - if (len != otherPol.len) - { - return false; - } - for (int i = 0; i < blocks; i++) - { - if (value[i] != otherPol.value[i]) - { - return false; - } - } - return true; - } - - /** - * @return the hash code of this polynomial - */ - public int hashCode() - { - return len + value.hashCode(); - } - - /** - * Tests if all bits equal zero. - * - * @return true if this GF2Polynomial equals 'zero' (<i>this</i> == 0) - */ - public boolean isZero() - { - int i; - if (len == 0) - { - return true; - } - for (i = 0; i < blocks; i++) - { - if (value[i] != 0) - { - return false; - } - } - return true; - } - - /** - * Tests if all bits are reset to 0 and LSB is set to 1. - * - * @return true if this GF2Polynomial equals 'one' (<i>this</i> == 1) - */ - public boolean isOne() - { - int i; - for (i = 1; i < blocks; i++) - { - if (value[i] != 0) - { - return false; - } - } - if (value[0] != 0x01) - { - return false; - } - return true; - } - - /** - * Adds <i>b</i> to this GF2Polynomial and assigns the result to this - * GF2Polynomial. <i>b</i> can be of different size. - * - * @param b GF2Polynomial to add to this GF2Polynomial - */ - public void addToThis(GF2Polynomial b) - { - expandN(b.len); - xorThisBy(b); - } - - /** - * Adds two GF2Polynomials, <i>this</i> and <i>b</i>, and returns the - * result. <i>this</i> and <i>b</i> can be of different size. - * - * @param b a GF2Polynomial - * @return a new GF2Polynomial (<i>this</i> + <i>b</i>) - */ - public GF2Polynomial add(GF2Polynomial b) - { - return xor(b); - } - - /** - * Subtracts <i>b</i> from this GF2Polynomial and assigns the result to - * this GF2Polynomial. <i>b</i> can be of different size. - * - * @param b a GF2Polynomial - */ - public void subtractFromThis(GF2Polynomial b) - { - expandN(b.len); - xorThisBy(b); - } - - /** - * Subtracts two GF2Polynomials, <i>this</i> and <i>b</i>, and returns the - * result in a new GF2Polynomial. <i>this</i> and <i>b</i> can be of - * different size. - * - * @param b a GF2Polynomial - * @return a new GF2Polynomial (<i>this</i> - <i>b</i>) - */ - public GF2Polynomial subtract(GF2Polynomial b) - { - return xor(b); - } - - /** - * Toggles the LSB of this GF2Polynomial, increasing its value by 'one'. - */ - public void increaseThis() - { - xorBit(0); - } - - /** - * Toggles the LSB of this GF2Polynomial, increasing the value by 'one' and - * returns the result in a new GF2Polynomial. - * - * @return <tt>this + 1</tt> - */ - public GF2Polynomial increase() - { - GF2Polynomial result = new GF2Polynomial(this); - result.increaseThis(); - return result; - } - - /** - * Multiplies this GF2Polynomial with <i>b</i> and returns the result in a - * new GF2Polynomial. This method does not reduce the result in GF(2^N). - * This method uses classic multiplication (schoolbook). - * - * @param b a GF2Polynomial - * @return a new GF2Polynomial (<i>this</i> * <i>b</i>) - */ - public GF2Polynomial multiplyClassic(GF2Polynomial b) - { - GF2Polynomial result = new GF2Polynomial(Math.max(len, b.len) << 1); - GF2Polynomial[] m = new GF2Polynomial[32]; - int i, j; - m[0] = new GF2Polynomial(this); - for (i = 1; i <= 31; i++) - { - m[i] = m[i - 1].shiftLeft(); - } - for (i = 0; i < b.blocks; i++) - { - for (j = 0; j <= 31; j++) - { - if ((b.value[i] & bitMask[j]) != 0) - { - result.xorThisBy(m[j]); - } - } - for (j = 0; j <= 31; j++) - { - m[j].shiftBlocksLeft(); - } - } - return result; - } - - /** - * Multiplies this GF2Polynomial with <i>b</i> and returns the result in a - * new GF2Polynomial. This method does not reduce the result in GF(2^N). - * This method uses Karatzuba multiplication. - * - * @param b a GF2Polynomial - * @return a new GF2Polynomial (<i>this</i> * <i>b</i>) - */ - public GF2Polynomial multiply(GF2Polynomial b) - { - int n = Math.max(len, b.len); - expandN(n); - b.expandN(n); - return karaMult(b); - } - - /** - * Does the recursion for Karatzuba multiplication. - */ - private GF2Polynomial karaMult(GF2Polynomial b) - { - GF2Polynomial result = new GF2Polynomial(len << 1); - if (len <= 32) - { - result.value = mult32(value[0], b.value[0]); - return result; - } - if (len <= 64) - { - result.value = mult64(value, b.value); - return result; - } - if (len <= 128) - { - result.value = mult128(value, b.value); - return result; - } - if (len <= 256) - { - result.value = mult256(value, b.value); - return result; - } - if (len <= 512) - { - result.value = mult512(value, b.value); - return result; - } - - int n = IntegerFunctions.floorLog(len - 1); - n = bitMask[n]; - - GF2Polynomial a0 = lower(((n - 1) >> 5) + 1); - GF2Polynomial a1 = upper(((n - 1) >> 5) + 1); - GF2Polynomial b0 = b.lower(((n - 1) >> 5) + 1); - GF2Polynomial b1 = b.upper(((n - 1) >> 5) + 1); - - GF2Polynomial c = a1.karaMult(b1); // c = a1*b1 - GF2Polynomial e = a0.karaMult(b0); // e = a0*b0 - a0.addToThis(a1); // a0 = a0 + a1 - b0.addToThis(b1); // b0 = b0 + b1 - GF2Polynomial d = a0.karaMult(b0); // d = (a0+a1)*(b0+b1) - - result.shiftLeftAddThis(c, n << 1); - result.shiftLeftAddThis(c, n); - result.shiftLeftAddThis(d, n); - result.shiftLeftAddThis(e, n); - result.addToThis(e); - return result; - } - - /** - * 16-Integer Version of Karatzuba multiplication. - */ - private static int[] mult512(int[] a, int[] b) - { - int[] result = new int[32]; - int[] a0 = new int[8]; - System.arraycopy(a, 0, a0, 0, Math.min(8, a.length)); - int[] a1 = new int[8]; - if (a.length > 8) - { - System.arraycopy(a, 8, a1, 0, Math.min(8, a.length - 8)); - } - int[] b0 = new int[8]; - System.arraycopy(b, 0, b0, 0, Math.min(8, b.length)); - int[] b1 = new int[8]; - if (b.length > 8) - { - System.arraycopy(b, 8, b1, 0, Math.min(8, b.length - 8)); - } - int[] c = mult256(a1, b1); - result[31] ^= c[15]; - result[30] ^= c[14]; - result[29] ^= c[13]; - result[28] ^= c[12]; - result[27] ^= c[11]; - result[26] ^= c[10]; - result[25] ^= c[9]; - result[24] ^= c[8]; - result[23] ^= c[7] ^ c[15]; - result[22] ^= c[6] ^ c[14]; - result[21] ^= c[5] ^ c[13]; - result[20] ^= c[4] ^ c[12]; - result[19] ^= c[3] ^ c[11]; - result[18] ^= c[2] ^ c[10]; - result[17] ^= c[1] ^ c[9]; - result[16] ^= c[0] ^ c[8]; - result[15] ^= c[7]; - result[14] ^= c[6]; - result[13] ^= c[5]; - result[12] ^= c[4]; - result[11] ^= c[3]; - result[10] ^= c[2]; - result[9] ^= c[1]; - result[8] ^= c[0]; - a1[0] ^= a0[0]; - a1[1] ^= a0[1]; - a1[2] ^= a0[2]; - a1[3] ^= a0[3]; - a1[4] ^= a0[4]; - a1[5] ^= a0[5]; - a1[6] ^= a0[6]; - a1[7] ^= a0[7]; - b1[0] ^= b0[0]; - b1[1] ^= b0[1]; - b1[2] ^= b0[2]; - b1[3] ^= b0[3]; - b1[4] ^= b0[4]; - b1[5] ^= b0[5]; - b1[6] ^= b0[6]; - b1[7] ^= b0[7]; - int[] d = mult256(a1, b1); - result[23] ^= d[15]; - result[22] ^= d[14]; - result[21] ^= d[13]; - result[20] ^= d[12]; - result[19] ^= d[11]; - result[18] ^= d[10]; - result[17] ^= d[9]; - result[16] ^= d[8]; - result[15] ^= d[7]; - result[14] ^= d[6]; - result[13] ^= d[5]; - result[12] ^= d[4]; - result[11] ^= d[3]; - result[10] ^= d[2]; - result[9] ^= d[1]; - result[8] ^= d[0]; - int[] e = mult256(a0, b0); - result[23] ^= e[15]; - result[22] ^= e[14]; - result[21] ^= e[13]; - result[20] ^= e[12]; - result[19] ^= e[11]; - result[18] ^= e[10]; - result[17] ^= e[9]; - result[16] ^= e[8]; - result[15] ^= e[7] ^ e[15]; - result[14] ^= e[6] ^ e[14]; - result[13] ^= e[5] ^ e[13]; - result[12] ^= e[4] ^ e[12]; - result[11] ^= e[3] ^ e[11]; - result[10] ^= e[2] ^ e[10]; - result[9] ^= e[1] ^ e[9]; - result[8] ^= e[0] ^ e[8]; - result[7] ^= e[7]; - result[6] ^= e[6]; - result[5] ^= e[5]; - result[4] ^= e[4]; - result[3] ^= e[3]; - result[2] ^= e[2]; - result[1] ^= e[1]; - result[0] ^= e[0]; - return result; - } - - /** - * 8-Integer Version of Karatzuba multiplication. - */ - private static int[] mult256(int[] a, int[] b) - { - int[] result = new int[16]; - int[] a0 = new int[4]; - System.arraycopy(a, 0, a0, 0, Math.min(4, a.length)); - int[] a1 = new int[4]; - if (a.length > 4) - { - System.arraycopy(a, 4, a1, 0, Math.min(4, a.length - 4)); - } - int[] b0 = new int[4]; - System.arraycopy(b, 0, b0, 0, Math.min(4, b.length)); - int[] b1 = new int[4]; - if (b.length > 4) - { - System.arraycopy(b, 4, b1, 0, Math.min(4, b.length - 4)); - } - if (a1[3] == 0 && a1[2] == 0 && b1[3] == 0 && b1[2] == 0) - { - if (a1[1] == 0 && b1[1] == 0) - { - if (a1[0] != 0 || b1[0] != 0) - { // [3]=[2]=[1]=0, [0]!=0 - int[] c = mult32(a1[0], b1[0]); - result[9] ^= c[1]; - result[8] ^= c[0]; - result[5] ^= c[1]; - result[4] ^= c[0]; - } - } - else - { // [3]=[2]=0 [1]!=0, [0]!=0 - int[] c = mult64(a1, b1); - result[11] ^= c[3]; - result[10] ^= c[2]; - result[9] ^= c[1]; - result[8] ^= c[0]; - result[7] ^= c[3]; - result[6] ^= c[2]; - result[5] ^= c[1]; - result[4] ^= c[0]; - } - } - else - { // [3]!=0 [2]!=0 [1]!=0, [0]!=0 - int[] c = mult128(a1, b1); - result[15] ^= c[7]; - result[14] ^= c[6]; - result[13] ^= c[5]; - result[12] ^= c[4]; - result[11] ^= c[3] ^ c[7]; - result[10] ^= c[2] ^ c[6]; - result[9] ^= c[1] ^ c[5]; - result[8] ^= c[0] ^ c[4]; - result[7] ^= c[3]; - result[6] ^= c[2]; - result[5] ^= c[1]; - result[4] ^= c[0]; - } - a1[0] ^= a0[0]; - a1[1] ^= a0[1]; - a1[2] ^= a0[2]; - a1[3] ^= a0[3]; - b1[0] ^= b0[0]; - b1[1] ^= b0[1]; - b1[2] ^= b0[2]; - b1[3] ^= b0[3]; - int[] d = mult128(a1, b1); - result[11] ^= d[7]; - result[10] ^= d[6]; - result[9] ^= d[5]; - result[8] ^= d[4]; - result[7] ^= d[3]; - result[6] ^= d[2]; - result[5] ^= d[1]; - result[4] ^= d[0]; - int[] e = mult128(a0, b0); - result[11] ^= e[7]; - result[10] ^= e[6]; - result[9] ^= e[5]; - result[8] ^= e[4]; - result[7] ^= e[3] ^ e[7]; - result[6] ^= e[2] ^ e[6]; - result[5] ^= e[1] ^ e[5]; - result[4] ^= e[0] ^ e[4]; - result[3] ^= e[3]; - result[2] ^= e[2]; - result[1] ^= e[1]; - result[0] ^= e[0]; - return result; - } - - /** - * 4-Integer Version of Karatzuba multiplication. - */ - private static int[] mult128(int[] a, int[] b) - { - int[] result = new int[8]; - int[] a0 = new int[2]; - System.arraycopy(a, 0, a0, 0, Math.min(2, a.length)); - int[] a1 = new int[2]; - if (a.length > 2) - { - System.arraycopy(a, 2, a1, 0, Math.min(2, a.length - 2)); - } - int[] b0 = new int[2]; - System.arraycopy(b, 0, b0, 0, Math.min(2, b.length)); - int[] b1 = new int[2]; - if (b.length > 2) - { - System.arraycopy(b, 2, b1, 0, Math.min(2, b.length - 2)); - } - if (a1[1] == 0 && b1[1] == 0) - { - if (a1[0] != 0 || b1[0] != 0) - { - int[] c = mult32(a1[0], b1[0]); - result[5] ^= c[1]; - result[4] ^= c[0]; - result[3] ^= c[1]; - result[2] ^= c[0]; - } - } - else - { - int[] c = mult64(a1, b1); - result[7] ^= c[3]; - result[6] ^= c[2]; - result[5] ^= c[1] ^ c[3]; - result[4] ^= c[0] ^ c[2]; - result[3] ^= c[1]; - result[2] ^= c[0]; - } - a1[0] ^= a0[0]; - a1[1] ^= a0[1]; - b1[0] ^= b0[0]; - b1[1] ^= b0[1]; - if (a1[1] == 0 && b1[1] == 0) - { - int[] d = mult32(a1[0], b1[0]); - result[3] ^= d[1]; - result[2] ^= d[0]; - } - else - { - int[] d = mult64(a1, b1); - result[5] ^= d[3]; - result[4] ^= d[2]; - result[3] ^= d[1]; - result[2] ^= d[0]; - } - if (a0[1] == 0 && b0[1] == 0) - { - int[] e = mult32(a0[0], b0[0]); - result[3] ^= e[1]; - result[2] ^= e[0]; - result[1] ^= e[1]; - result[0] ^= e[0]; - } - else - { - int[] e = mult64(a0, b0); - result[5] ^= e[3]; - result[4] ^= e[2]; - result[3] ^= e[1] ^ e[3]; - result[2] ^= e[0] ^ e[2]; - result[1] ^= e[1]; - result[0] ^= e[0]; - } - return result; - } - - /** - * 2-Integer Version of Karatzuba multiplication. - */ - private static int[] mult64(int[] a, int[] b) - { - int[] result = new int[4]; - int a0 = a[0]; - int a1 = 0; - if (a.length > 1) - { - a1 = a[1]; - } - int b0 = b[0]; - int b1 = 0; - if (b.length > 1) - { - b1 = b[1]; - } - if (a1 != 0 || b1 != 0) - { - int[] c = mult32(a1, b1); - result[3] ^= c[1]; - result[2] ^= c[0] ^ c[1]; - result[1] ^= c[0]; - } - int[] d = mult32(a0 ^ a1, b0 ^ b1); - result[2] ^= d[1]; - result[1] ^= d[0]; - int[] e = mult32(a0, b0); - result[2] ^= e[1]; - result[1] ^= e[0] ^ e[1]; - result[0] ^= e[0]; - return result; - } - - /** - * 4-Byte Version of Karatzuba multiplication. Here the actual work is done. - */ - private static int[] mult32(int a, int b) - { - int[] result = new int[2]; - if (a == 0 || b == 0) - { - return result; - } - long b2 = b; - b2 &= 0x00000000ffffffffL; - int i; - long h = 0; - for (i = 1; i <= 32; i++) - { - if ((a & bitMask[i - 1]) != 0) - { - h ^= b2; - } - b2 <<= 1; - } - result[1] = (int)(h >>> 32); - result[0] = (int)(h & 0x00000000ffffffffL); - return result; - } - - /** - * Returns a new GF2Polynomial containing the upper <i>k</i> bytes of this - * GF2Polynomial. - * - * @param k - * @return a new GF2Polynomial containing the upper <i>k</i> bytes of this - * GF2Polynomial - * @see GF2Polynomial#karaMult - */ - private GF2Polynomial upper(int k) - { - int j = Math.min(k, blocks - k); - GF2Polynomial result = new GF2Polynomial(j << 5); - if (blocks >= k) - { - System.arraycopy(value, k, result.value, 0, j); - } - return result; - } - - /** - * Returns a new GF2Polynomial containing the lower <i>k</i> bytes of this - * GF2Polynomial. - * - * @param k - * @return a new GF2Polynomial containing the lower <i>k</i> bytes of this - * GF2Polynomial - * @see GF2Polynomial#karaMult - */ - private GF2Polynomial lower(int k) - { - GF2Polynomial result = new GF2Polynomial(k << 5); - System.arraycopy(value, 0, result.value, 0, Math.min(k, blocks)); - return result; - } - - /** - * Returns the remainder of <i>this</i> divided by <i>g</i> in a new - * GF2Polynomial. - * - * @param g GF2Polynomial != 0 - * @return a new GF2Polynomial (<i>this</i> % <i>g</i>) - * @throws PolynomialIsZeroException if <i>g</i> equals zero - */ - public GF2Polynomial remainder(GF2Polynomial g) - throws RuntimeException - { - /* a div b = q / r */ - GF2Polynomial a = new GF2Polynomial(this); - GF2Polynomial b = new GF2Polynomial(g); - GF2Polynomial j; - int i; - if (b.isZero()) - { - throw new RuntimeException(); - } - a.reduceN(); - b.reduceN(); - if (a.len < b.len) - { - return a; - } - i = a.len - b.len; - while (i >= 0) - { - j = b.shiftLeft(i); - a.subtractFromThis(j); - a.reduceN(); - i = a.len - b.len; - } - return a; - } - - /** - * Returns the absolute quotient of <i>this</i> divided by <i>g</i> in a - * new GF2Polynomial. - * - * @param g GF2Polynomial != 0 - * @return a new GF2Polynomial |_ <i>this</i> / <i>g</i> _| - * @throws PolynomialIsZeroException if <i>g</i> equals zero - */ - public GF2Polynomial quotient(GF2Polynomial g) - throws RuntimeException - { - /* a div b = q / r */ - GF2Polynomial q = new GF2Polynomial(len); - GF2Polynomial a = new GF2Polynomial(this); - GF2Polynomial b = new GF2Polynomial(g); - GF2Polynomial j; - int i; - if (b.isZero()) - { - throw new RuntimeException(); - } - a.reduceN(); - b.reduceN(); - if (a.len < b.len) - { - return new GF2Polynomial(0); - } - i = a.len - b.len; - q.expandN(i + 1); - - while (i >= 0) - { - j = b.shiftLeft(i); - a.subtractFromThis(j); - a.reduceN(); - q.xorBit(i); - i = a.len - b.len; - } - - return q; - } - - /** - * Divides <i>this</i> by <i>g</i> and returns the quotient and remainder - * in a new GF2Polynomial[2], quotient in [0], remainder in [1]. - * - * @param g GF2Polynomial != 0 - * @return a new GF2Polynomial[2] containing quotient and remainder - * @throws PolynomialIsZeroException if <i>g</i> equals zero - */ - public GF2Polynomial[] divide(GF2Polynomial g) - throws RuntimeException - { - /* a div b = q / r */ - GF2Polynomial[] result = new GF2Polynomial[2]; - GF2Polynomial q = new GF2Polynomial(len); - GF2Polynomial a = new GF2Polynomial(this); - GF2Polynomial b = new GF2Polynomial(g); - GF2Polynomial j; - int i; - if (b.isZero()) - { - throw new RuntimeException(); - } - a.reduceN(); - b.reduceN(); - if (a.len < b.len) - { - result[0] = new GF2Polynomial(0); - result[1] = a; - return result; - } - i = a.len - b.len; - q.expandN(i + 1); - - while (i >= 0) - { - j = b.shiftLeft(i); - a.subtractFromThis(j); - a.reduceN(); - q.xorBit(i); - i = a.len - b.len; - } - - result[0] = q; - result[1] = a; - return result; - } - - /** - * Returns the greatest common divisor of <i>this</i> and <i>g</i> in a - * new GF2Polynomial. - * - * @param g GF2Polynomial != 0 - * @return a new GF2Polynomial gcd(<i>this</i>,<i>g</i>) - * @throws ArithmeticException if <i>this</i> and <i>g</i> both are equal to zero - * @throws PolynomialIsZeroException to be API-compliant (should never be thrown). - */ - public GF2Polynomial gcd(GF2Polynomial g) - throws RuntimeException - { - if (isZero() && g.isZero()) - { - throw new ArithmeticException("Both operands of gcd equal zero."); - } - if (isZero()) - { - return new GF2Polynomial(g); - } - if (g.isZero()) - { - return new GF2Polynomial(this); - } - GF2Polynomial a = new GF2Polynomial(this); - GF2Polynomial b = new GF2Polynomial(g); - GF2Polynomial c; - - while (!b.isZero()) - { - c = a.remainder(b); - a = b; - b = c; - } - - return a; - } - - /** - * Checks if <i>this</i> is irreducible, according to IEEE P1363, A.5.5, - * p103.<br> - * Note: The algorithm from IEEE P1363, A5.5 can be used to check a - * polynomial with coefficients in GF(2^r) for irreducibility. As this class - * only represents polynomials with coefficients in GF(2), the algorithm is - * adapted to the case r=1. - * - * @return true if <i>this</i> is irreducible - * @see "P1363, A.5.5, p103" - */ - public boolean isIrreducible() - { - if (isZero()) - { - return false; - } - GF2Polynomial f = new GF2Polynomial(this); - int d, i; - GF2Polynomial u, g; - GF2Polynomial dummy; - f.reduceN(); - d = f.len - 1; - u = new GF2Polynomial(f.len, "X"); - - for (i = 1; i <= (d >> 1); i++) - { - u.squareThisPreCalc(); - u = u.remainder(f); - dummy = u.add(new GF2Polynomial(32, "X")); - if (!dummy.isZero()) - { - g = f.gcd(dummy); - if (!g.isOne()) - { - return false; - } - } - else - { - return false; - } - } - - return true; - } - - /** - * Reduces this GF2Polynomial using the trinomial x^<i>m</i> + x^<i>tc</i> + - * 1. - * - * @param m the degree of the used field - * @param tc degree of the middle x in the trinomial - */ - void reduceTrinomial(int m, int tc) - { - int i; - int p0, p1; - int q0, q1; - long t; - p0 = m >>> 5; // block which contains 2^m - q0 = 32 - (m & 0x1f); // (32-index) of 2^m within block p0 - p1 = (m - tc) >>> 5; // block which contains 2^tc - q1 = 32 - ((m - tc) & 0x1f); // (32-index) of 2^tc within block q1 - int max = ((m << 1) - 2) >>> 5; // block which contains 2^(2m-2) - int min = p0; // block which contains 2^m - for (i = max; i > min; i--) - { // for i = maxBlock to minBlock - // reduce coefficients contained in t - // t = block[i] - t = value[i] & 0x00000000ffffffffL; - // block[i-p0-1] ^= t << q0 - value[i - p0 - 1] ^= (int)(t << q0); - // block[i-p0] ^= t >>> (32-q0) - value[i - p0] ^= t >>> (32 - q0); - // block[i-p1-1] ^= << q1 - value[i - p1 - 1] ^= (int)(t << q1); - // block[i-p1] ^= t >>> (32-q1) - value[i - p1] ^= t >>> (32 - q1); - value[i] = 0x00; - } - // reduce last coefficients in block containing 2^m - t = value[min] & 0x00000000ffffffffL & (0xffffffffL << (m & 0x1f)); // t - // contains the last coefficients > m - value[0] ^= t >>> (32 - q0); - if (min - p1 - 1 >= 0) - { - value[min - p1 - 1] ^= (int)(t << q1); - } - value[min - p1] ^= t >>> (32 - q1); - - value[min] &= reverseRightMask[m & 0x1f]; - blocks = ((m - 1) >>> 5) + 1; - len = m; - } - - /** - * Reduces this GF2Polynomial using the pentanomial x^<i>m</i> + x^<i>pc[2]</i> + - * x^<i>pc[1]</i> + x^<i>pc[0]</i> + 1. - * - * @param m the degree of the used field - * @param pc degrees of the middle x's in the pentanomial - */ - void reducePentanomial(int m, int[] pc) - { - int i; - int p0, p1, p2, p3; - int q0, q1, q2, q3; - long t; - p0 = m >>> 5; - q0 = 32 - (m & 0x1f); - p1 = (m - pc[0]) >>> 5; - q1 = 32 - ((m - pc[0]) & 0x1f); - p2 = (m - pc[1]) >>> 5; - q2 = 32 - ((m - pc[1]) & 0x1f); - p3 = (m - pc[2]) >>> 5; - q3 = 32 - ((m - pc[2]) & 0x1f); - int max = ((m << 1) - 2) >>> 5; - int min = p0; - for (i = max; i > min; i--) - { - t = value[i] & 0x00000000ffffffffL; - value[i - p0 - 1] ^= (int)(t << q0); - value[i - p0] ^= t >>> (32 - q0); - value[i - p1 - 1] ^= (int)(t << q1); - value[i - p1] ^= t >>> (32 - q1); - value[i - p2 - 1] ^= (int)(t << q2); - value[i - p2] ^= t >>> (32 - q2); - value[i - p3 - 1] ^= (int)(t << q3); - value[i - p3] ^= t >>> (32 - q3); - value[i] = 0; - } - t = value[min] & 0x00000000ffffffffL & (0xffffffffL << (m & 0x1f)); - value[0] ^= t >>> (32 - q0); - if (min - p1 - 1 >= 0) - { - value[min - p1 - 1] ^= (int)(t << q1); - } - value[min - p1] ^= t >>> (32 - q1); - if (min - p2 - 1 >= 0) - { - value[min - p2 - 1] ^= (int)(t << q2); - } - value[min - p2] ^= t >>> (32 - q2); - if (min - p3 - 1 >= 0) - { - value[min - p3 - 1] ^= (int)(t << q3); - } - value[min - p3] ^= t >>> (32 - q3); - value[min] &= reverseRightMask[m & 0x1f]; - - blocks = ((m - 1) >>> 5) + 1; - len = m; - } - - /** - * Reduces len by finding the most significant bit set to one and reducing - * len and blocks. - */ - public void reduceN() - { - int i, j, h; - i = blocks - 1; - while ((value[i] == 0) && (i > 0)) - { - i--; - } - h = value[i]; - j = 0; - while (h != 0) - { - h >>>= 1; - j++; - } - len = (i << 5) + j; - blocks = i + 1; - } - - /** - * Expands len and int[] value to <i>i</i>. This is useful before adding - * two GF2Polynomials of different size. - * - * @param i the intended length - */ - public void expandN(int i) - { - int k; - int[] bs; - if (len >= i) - { - return; - } - len = i; - k = ((i - 1) >>> 5) + 1; - if (blocks >= k) - { - return; - } - if (value.length >= k) - { - int j; - for (j = blocks; j < k; j++) - { - value[j] = 0; - } - blocks = k; - return; - } - bs = new int[k]; - System.arraycopy(value, 0, bs, 0, blocks); - blocks = k; - value = null; - value = bs; - } - - /** - * Squares this GF2Polynomial and expands it accordingly. This method does - * not reduce the result in GF(2^N). There exists a faster method for - * squaring in GF(2^N). - * - * @see GF2nPolynomialElement#square - */ - public void squareThisBitwise() - { - int i, h, j, k; - if (isZero()) - { - return; - } - int[] result = new int[blocks << 1]; - for (i = blocks - 1; i >= 0; i--) - { - h = value[i]; - j = 0x00000001; - for (k = 0; k < 16; k++) - { - if ((h & 0x01) != 0) - { - result[i << 1] |= j; - } - if ((h & 0x00010000) != 0) - { - result[(i << 1) + 1] |= j; - } - j <<= 2; - h >>>= 1; - } - } - value = null; - value = result; - blocks = result.length; - len = (len << 1) - 1; - } - - /** - * Squares this GF2Polynomial by using precomputed values of squaringTable. - * This method does not reduce the result in GF(2^N). - */ - public void squareThisPreCalc() - { - int i; - if (isZero()) - { - return; - } - if (value.length >= (blocks << 1)) - { - for (i = blocks - 1; i >= 0; i--) - { - value[(i << 1) + 1] = GF2Polynomial.squaringTable[(value[i] & 0x00ff0000) >>> 16] - | (GF2Polynomial.squaringTable[(value[i] & 0xff000000) >>> 24] << 16); - value[i << 1] = GF2Polynomial.squaringTable[value[i] & 0x000000ff] - | (GF2Polynomial.squaringTable[(value[i] & 0x0000ff00) >>> 8] << 16); - } - blocks <<= 1; - len = (len << 1) - 1; - } - else - { - int[] result = new int[blocks << 1]; - for (i = 0; i < blocks; i++) - { - result[i << 1] = GF2Polynomial.squaringTable[value[i] & 0x000000ff] - | (GF2Polynomial.squaringTable[(value[i] & 0x0000ff00) >>> 8] << 16); - result[(i << 1) + 1] = GF2Polynomial.squaringTable[(value[i] & 0x00ff0000) >>> 16] - | (GF2Polynomial.squaringTable[(value[i] & 0xff000000) >>> 24] << 16); - } - value = null; - value = result; - blocks <<= 1; - len = (len << 1) - 1; - } - } - - /** - * Does a vector-multiplication modulo 2 and returns the result as boolean. - * - * @param b GF2Polynomial - * @return this x <i>b</i> as boolean (1->true, 0->false) - * @throws PolynomialsHaveDifferentLengthException if <i>this</i> and <i>b</i> have a different length and - * thus cannot be vector-multiplied - */ - public boolean vectorMult(GF2Polynomial b) - throws RuntimeException - { - int i; - int h; - boolean result = false; - if (len != b.len) - { - throw new RuntimeException(); - } - for (i = 0; i < blocks; i++) - { - h = value[i] & b.value[i]; - result ^= parity[h & 0x000000ff]; - result ^= parity[(h >>> 8) & 0x000000ff]; - result ^= parity[(h >>> 16) & 0x000000ff]; - result ^= parity[(h >>> 24) & 0x000000ff]; - } - return result; - } - - /** - * Returns the bitwise exclusive-or of <i>this</i> and <i>b</i> in a new - * GF2Polynomial. <i>this</i> and <i>b</i> can be of different size. - * - * @param b GF2Polynomial - * @return a new GF2Polynomial (<i>this</i> ^ <i>b</i>) - */ - public GF2Polynomial xor(GF2Polynomial b) - { - int i; - GF2Polynomial result; - int k = Math.min(blocks, b.blocks); - if (len >= b.len) - { - result = new GF2Polynomial(this); - for (i = 0; i < k; i++) - { - result.value[i] ^= b.value[i]; - } - } - else - { - result = new GF2Polynomial(b); - for (i = 0; i < k; i++) - { - result.value[i] ^= value[i]; - } - } - // If we xor'ed some bits too many by proceeding blockwise, - // restore them to zero: - result.zeroUnusedBits(); - return result; - } - - /** - * Computes the bitwise exclusive-or of this GF2Polynomial and <i>b</i> and - * stores the result in this GF2Polynomial. <i>b</i> can be of different - * size. - * - * @param b GF2Polynomial - */ - public void xorThisBy(GF2Polynomial b) - { - int i; - for (i = 0; i < Math.min(blocks, b.blocks); i++) - { - value[i] ^= b.value[i]; - } - // If we xor'ed some bits too many by proceeding blockwise, - // restore them to zero: - zeroUnusedBits(); - } - - /** - * If {@link #len} is not a multiple of the block size (32), some extra bits - * of the last block might have been modified during a blockwise operation. - * This method compensates for that by restoring these "extra" bits to zero. - */ - private void zeroUnusedBits() - { - if ((len & 0x1f) != 0) - { - value[blocks - 1] &= reverseRightMask[len & 0x1f]; - } - } - - /** - * Sets the bit at position <i>i</i>. - * - * @param i int - * @throws BitDoesNotExistException if (<i>i</i> < 0) || (<i>i</i> > (len - 1)) - */ - public void setBit(int i) - throws RuntimeException - { - if (i < 0 || i > (len - 1)) - { - throw new RuntimeException(); - } - if (i > (len - 1)) - { - return; - } - value[i >>> 5] |= bitMask[i & 0x1f]; - return; - } - - /** - * Returns the bit at position <i>i</i>. - * - * @param i int - * @return the bit at position <i>i</i> if <i>i</i> is a valid position, 0 - * otherwise. - */ - public int getBit(int i) - { - if (i < 0 || i > (len - 1)) - { - return 0; - } - return ((value[i >>> 5] & bitMask[i & 0x1f]) != 0) ? 1 : 0; - } - - /** - * Resets the bit at position <i>i</i>. - * - * @param i int - * @throws BitDoesNotExistException if (<i>i</i> < 0) || (<i>i</i> > (len - 1)) - */ - public void resetBit(int i) - throws RuntimeException - { - if (i < 0 || i > (len - 1)) - { - throw new RuntimeException(); - } - if (i > (len - 1)) - { - return; - } - value[i >>> 5] &= ~bitMask[i & 0x1f]; - } - - /** - * Xors the bit at position <i>i</i>. - * - * @param i int - * @throws BitDoesNotExistException if (<i>i</i> < 0) || (<i>i</i> > (len - 1)) - */ - public void xorBit(int i) - throws RuntimeException - { - if (i < 0 || i > (len - 1)) - { - throw new RuntimeException(); - } - if (i > (len - 1)) - { - return; - } - value[i >>> 5] ^= bitMask[i & 0x1f]; - } - - /** - * Tests the bit at position <i>i</i>. - * - * @param i the position of the bit to be tested - * @return true if the bit at position <i>i</i> is set (a(<i>i</i>) == - * 1). False if (<i>i</i> < 0) || (<i>i</i> > (len - 1)) - */ - public boolean testBit(int i) - { - if (i < 0 || i > (len - 1)) - { - return false; - } - return (value[i >>> 5] & bitMask[i & 0x1f]) != 0; - } - - /** - * Returns this GF2Polynomial shift-left by 1 in a new GF2Polynomial. - * - * @return a new GF2Polynomial (this << 1) - */ - public GF2Polynomial shiftLeft() - { - GF2Polynomial result = new GF2Polynomial(len + 1, value); - int i; - for (i = result.blocks - 1; i >= 1; i--) - { - result.value[i] <<= 1; - result.value[i] |= result.value[i - 1] >>> 31; - } - result.value[0] <<= 1; - return result; - } - - /** - * Shifts-left this by one and enlarges the size of value if necesary. - */ - public void shiftLeftThis() - { - /** @todo This is untested. */ - int i; - if ((len & 0x1f) == 0) - { // check if blocks increases - len += 1; - blocks += 1; - if (blocks > value.length) - { // enlarge value - int[] bs = new int[blocks]; - System.arraycopy(value, 0, bs, 0, value.length); - value = null; - value = bs; - } - for (i = blocks - 1; i >= 1; i--) - { - value[i] |= value[i - 1] >>> 31; - value[i - 1] <<= 1; - } - } - else - { - len += 1; - for (i = blocks - 1; i >= 1; i--) - { - value[i] <<= 1; - value[i] |= value[i - 1] >>> 31; - } - value[0] <<= 1; - } - } - - /** - * Returns this GF2Polynomial shift-left by <i>k</i> in a new - * GF2Polynomial. - * - * @param k int - * @return a new GF2Polynomial (this << <i>k</i>) - */ - public GF2Polynomial shiftLeft(int k) - { - // Variant 2, requiring a modified shiftBlocksLeft(k) - // In case of modification, consider a rename to doShiftBlocksLeft() - // with an explicit note that this method assumes that the polynomial - // has already been resized. Or consider doing things inline. - // Construct the resulting polynomial of appropriate length: - GF2Polynomial result = new GF2Polynomial(len + k, value); - // Shift left as many multiples of the block size as possible: - if (k >= 32) - { - result.doShiftBlocksLeft(k >>> 5); - } - // Shift left by the remaining (<32) amount: - final int remaining = k & 0x1f; - if (remaining != 0) - { - for (int i = result.blocks - 1; i >= 1; i--) - { - result.value[i] <<= remaining; - result.value[i] |= result.value[i - 1] >>> (32 - remaining); - } - result.value[0] <<= remaining; - } - return result; - } - - /** - * Shifts left b and adds the result to Its a fast version of - * <tt>this = add(b.shl(k));</tt> - * - * @param b GF2Polynomial to shift and add to this - * @param k the amount to shift - * @see GF2nPolynomialElement#invertEEA - */ - public void shiftLeftAddThis(GF2Polynomial b, int k) - { - if (k == 0) - { - addToThis(b); - return; - } - int i; - expandN(b.len + k); - int d = k >>> 5; - for (i = b.blocks - 1; i >= 0; i--) - { - if ((i + d + 1 < blocks) && ((k & 0x1f) != 0)) - { - value[i + d + 1] ^= b.value[i] >>> (32 - (k & 0x1f)); - } - value[i + d] ^= b.value[i] << (k & 0x1f); - } - } - - /** - * Shifts-left this GF2Polynomial's value blockwise 1 block resulting in a - * shift-left by 32. - * - * @see GF2Polynomial#multiply - */ - void shiftBlocksLeft() - { - blocks += 1; - len += 32; - if (blocks <= value.length) - { - int i; - for (i = blocks - 1; i >= 1; i--) - { - value[i] = value[i - 1]; - } - value[0] = 0x00; - } - else - { - int[] result = new int[blocks]; - System.arraycopy(value, 0, result, 1, blocks - 1); - value = null; - value = result; - } - } - - /** - * Shifts left this GF2Polynomial's value blockwise <i>b</i> blocks - * resulting in a shift-left by b*32. This method assumes that {@link #len} - * and {@link #blocks} have already been updated to reflect the final state. - * - * @param b shift amount (in blocks) - */ - private void doShiftBlocksLeft(int b) - { - if (blocks <= value.length) - { - int i; - for (i = blocks - 1; i >= b; i--) - { - value[i] = value[i - b]; - } - for (i = 0; i < b; i++) - { - value[i] = 0x00; - } - } - else - { - int[] result = new int[blocks]; - System.arraycopy(value, 0, result, b, blocks - b); - value = null; - value = result; - } - } - - /** - * Returns this GF2Polynomial shift-right by 1 in a new GF2Polynomial. - * - * @return a new GF2Polynomial (this << 1) - */ - public GF2Polynomial shiftRight() - { - GF2Polynomial result = new GF2Polynomial(len - 1); - int i; - System.arraycopy(value, 0, result.value, 0, result.blocks); - for (i = 0; i <= result.blocks - 2; i++) - { - result.value[i] >>>= 1; - result.value[i] |= result.value[i + 1] << 31; - } - result.value[result.blocks - 1] >>>= 1; - if (result.blocks < blocks) - { - result.value[result.blocks - 1] |= value[result.blocks] << 31; - } - return result; - } - - /** - * Shifts-right this GF2Polynomial by 1. - */ - public void shiftRightThis() - { - int i; - len -= 1; - blocks = ((len - 1) >>> 5) + 1; - for (i = 0; i <= blocks - 2; i++) - { - value[i] >>>= 1; - value[i] |= value[i + 1] << 31; - } - value[blocks - 1] >>>= 1; - if ((len & 0x1f) == 0) - { - value[blocks - 1] |= value[blocks] << 31; - } - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2Vector.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2Vector.java deleted file mode 100644 index ec35b682..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2Vector.java +++ /dev/null @@ -1,539 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -import java.security.SecureRandom; - -/** - * This class implements the abstract class <tt>Vector</tt> for the case of - * vectors over the finite field GF(2). <br> - * For the vector representation the array of type int[] is used, thus one - * element of the array holds 32 elements of the vector. - * - * @see Vector - */ -public class GF2Vector - extends Vector -{ - - /** - * holds the elements of this vector - */ - private int[] v; - - /** - * Construct the zero vector of the given length. - * - * @param length the length of the vector - */ - public GF2Vector(int length) - { - if (length < 0) - { - throw new ArithmeticException("Negative length."); - } - this.length = length; - v = new int[(length + 31) >> 5]; - } - - /** - * Construct a random GF2Vector of the given length. - * - * @param length the length of the vector - * @param sr the source of randomness - */ - public GF2Vector(int length, SecureRandom sr) - { - this.length = length; - - int size = (length + 31) >> 5; - v = new int[size]; - - // generate random elements - for (int i = size - 1; i >= 0; i--) - { - v[i] = sr.nextInt(); - } - - // erase unused bits - int r = length & 0x1f; - if (r != 0) - { - // erase unused bits - v[size - 1] &= (1 << r) - 1; - } - } - - /** - * Construct a random GF2Vector of the given length with the specified - * number of non-zero coefficients. - * - * @param length the length of the vector - * @param t the number of non-zero coefficients - * @param sr the source of randomness - */ - public GF2Vector(int length, int t, SecureRandom sr) - { - if (t > length) - { - throw new ArithmeticException( - "The hamming weight is greater than the length of vector."); - } - this.length = length; - - int size = (length + 31) >> 5; - v = new int[size]; - - int[] help = new int[length]; - for (int i = 0; i < length; i++) - { - help[i] = i; - } - - int m = length; - for (int i = 0; i < t; i++) - { - int j = RandUtils.nextInt(sr, m); - setBit(help[j]); - m--; - help[j] = help[m]; - } - } - - /** - * Construct a GF2Vector of the given length and with elements from the - * given array. The array is copied and unused bits are masked out. - * - * @param length the length of the vector - * @param v the element array - */ - public GF2Vector(int length, int[] v) - { - if (length < 0) - { - throw new ArithmeticException("negative length"); - } - this.length = length; - - int size = (length + 31) >> 5; - - if (v.length != size) - { - throw new ArithmeticException("length mismatch"); - } - - this.v = IntUtils.clone(v); - - int r = length & 0x1f; - if (r != 0) - { - // erase unused bits - this.v[size - 1] &= (1 << r) - 1; - } - } - - /** - * Copy constructor. - * - * @param other another {@link GF2Vector} - */ - public GF2Vector(GF2Vector other) - { - this.length = other.length; - this.v = IntUtils.clone(other.v); - } - - /** - * Construct a new {@link GF2Vector} of the given length and with the given - * element array. The array is not changed and only a reference to the array - * is stored. No length checking is performed either. - * - * @param v the element array - * @param length the length of the vector - */ - protected GF2Vector(int[] v, int length) - { - this.v = v; - this.length = length; - } - - /** - * Construct a new GF2Vector with the given length out of the encoded - * vector. - * - * @param length the length of the vector - * @param encVec the encoded vector - * @return the decoded vector - */ - public static GF2Vector OS2VP(int length, byte[] encVec) - { - if (length < 0) - { - throw new ArithmeticException("negative length"); - } - - int byteLen = (length + 7) >> 3; - - if (encVec.length > byteLen) - { - throw new ArithmeticException("length mismatch"); - } - - return new GF2Vector(length, LittleEndianConversions.toIntArray(encVec)); - } - - /** - * Encode this vector as byte array. - * - * @return the encoded vector - */ - public byte[] getEncoded() - { - int byteLen = (length + 7) >> 3; - return LittleEndianConversions.toByteArray(v, byteLen); - } - - /** - * @return the int array representation of this vector - */ - public int[] getVecArray() - { - return v; - } - - /** - * Return the Hamming weight of this vector, i.e., compute the number of - * units of this vector. - * - * @return the Hamming weight of this vector - */ - public int getHammingWeight() - { - int weight = 0; - for (int i = 0; i < v.length; i++) - { - int e = v[i]; - for (int j = 0; j < 32; j++) - { - int b = e & 1; - if (b != 0) - { - weight++; - } - e >>>= 1; - } - } - return weight; - } - - /** - * @return whether this is the zero vector (i.e., all elements are zero) - */ - public boolean isZero() - { - for (int i = v.length - 1; i >= 0; i--) - { - if (v[i] != 0) - { - return false; - } - } - return true; - } - - /** - * Return the value of the bit of this vector at the specified index. - * - * @param index the index - * @return the value of the bit (0 or 1) - */ - public int getBit(int index) - { - if (index >= length) - { - throw new IndexOutOfBoundsException(); - } - int q = index >> 5; - int r = index & 0x1f; - return (v[q] & (1 << r)) >>> r; - } - - /** - * Set the coefficient at the given index to 1. If the index is out of - * bounds, do nothing. - * - * @param index the index of the coefficient to set - */ - public void setBit(int index) - { - if (index >= length) - { - throw new IndexOutOfBoundsException(); - } - v[index >> 5] |= 1 << (index & 0x1f); - } - - /** - * Adds another GF2Vector to this vector. - * - * @param other another GF2Vector - * @return <tt>this + other</tt> - * @throws ArithmeticException if the other vector is not a GF2Vector or has another - * length. - */ - public Vector add(Vector other) - { - if (!(other instanceof GF2Vector)) - { - throw new ArithmeticException("vector is not defined over GF(2)"); - } - - GF2Vector otherVec = (GF2Vector)other; - if (length != otherVec.length) - { - throw new ArithmeticException("length mismatch"); - } - - int[] vec = IntUtils.clone(((GF2Vector)other).v); - - for (int i = vec.length - 1; i >= 0; i--) - { - vec[i] ^= v[i]; - } - - return new GF2Vector(length, vec); - } - - /** - * Multiply this vector with a permutation. - * - * @param p the permutation - * @return <tt>this*p = p*this</tt> - */ - public Vector multiply(Permutation p) - { - int[] pVec = p.getVector(); - if (length != pVec.length) - { - throw new ArithmeticException("length mismatch"); - } - - GF2Vector result = new GF2Vector(length); - - for (int i = 0; i < pVec.length; i++) - { - int e = v[pVec[i] >> 5] & (1 << (pVec[i] & 0x1f)); - if (e != 0) - { - result.v[i >> 5] |= 1 << (i & 0x1f); - } - } - - return result; - } - - /** - * Return a new vector consisting of the elements of this vector with the - * indices given by the set <tt>setJ</tt>. - * - * @param setJ the set of indices of elements to extract - * @return the new {@link GF2Vector} - * <tt>[this_setJ[0], this_setJ[1], ..., this_setJ[#setJ-1]]</tt> - */ - public GF2Vector extractVector(int[] setJ) - { - int k = setJ.length; - if (setJ[k - 1] > length) - { - throw new ArithmeticException("invalid index set"); - } - - GF2Vector result = new GF2Vector(k); - - for (int i = 0; i < k; i++) - { - int e = v[setJ[i] >> 5] & (1 << (setJ[i] & 0x1f)); - if (e != 0) - { - result.v[i >> 5] |= 1 << (i & 0x1f); - } - } - - return result; - } - - /** - * Return a new vector consisting of the first <tt>k</tt> elements of this - * vector. - * - * @param k the number of elements to extract - * @return a new {@link GF2Vector} consisting of the first <tt>k</tt> - * elements of this vector - */ - public GF2Vector extractLeftVector(int k) - { - if (k > length) - { - throw new ArithmeticException("invalid length"); - } - - if (k == length) - { - return new GF2Vector(this); - } - - GF2Vector result = new GF2Vector(k); - - int q = k >> 5; - int r = k & 0x1f; - - System.arraycopy(v, 0, result.v, 0, q); - if (r != 0) - { - result.v[q] = v[q] & ((1 << r) - 1); - } - - return result; - } - - /** - * Return a new vector consisting of the last <tt>k</tt> elements of this - * vector. - * - * @param k the number of elements to extract - * @return a new {@link GF2Vector} consisting of the last <tt>k</tt> - * elements of this vector - */ - public GF2Vector extractRightVector(int k) - { - if (k > length) - { - throw new ArithmeticException("invalid length"); - } - - if (k == length) - { - return new GF2Vector(this); - } - - GF2Vector result = new GF2Vector(k); - - int q = (length - k) >> 5; - int r = (length - k) & 0x1f; - int length = (k + 31) >> 5; - - int ind = q; - // if words have to be shifted - if (r != 0) - { - // process all but last word - for (int i = 0; i < length - 1; i++) - { - result.v[i] = (v[ind++] >>> r) | (v[ind] << (32 - r)); - } - // process last word - result.v[length - 1] = v[ind++] >>> r; - if (ind < v.length) - { - result.v[length - 1] |= v[ind] << (32 - r); - } - } - else - { - // no shift necessary - System.arraycopy(v, q, result.v, 0, length); - } - - return result; - } - - /** - * Rewrite this vector as a vector over <tt>GF(2<sup>m</sup>)</tt> with - * <tt>t</tt> elements. - * - * @param field the finite field <tt>GF(2<sup>m</sup>)</tt> - * @return the converted vector over <tt>GF(2<sup>m</sup>)</tt> - */ - public GF2mVector toExtensionFieldVector(GF2mField field) - { - int m = field.getDegree(); - if ((length % m) != 0) - { - throw new ArithmeticException("conversion is impossible"); - } - - int t = length / m; - int[] result = new int[t]; - int count = 0; - for (int i = t - 1; i >= 0; i--) - { - for (int j = field.getDegree() - 1; j >= 0; j--) - { - int q = count >>> 5; - int r = count & 0x1f; - - int e = (v[q] >>> r) & 1; - if (e == 1) - { - result[i] ^= 1 << j; - } - count++; - } - } - return new GF2mVector(field, result); - } - - /** - * Check if the given object is equal to this vector. - * - * @param other vector - * @return the result of the comparison - */ - public boolean equals(Object other) - { - - if (!(other instanceof GF2Vector)) - { - return false; - } - GF2Vector otherVec = (GF2Vector)other; - - return (length == otherVec.length) && IntUtils.equals(v, otherVec.v); - } - - /** - * @return the hash code of this vector - */ - public int hashCode() - { - int hash = length; - hash = hash * 31 + v.hashCode(); - return hash; - } - - /** - * @return a human readable form of this vector - */ - public String toString() - { - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < length; i++) - { - if ((i != 0) && ((i & 0x1f) == 0)) - { - buf.append(' '); - } - int q = i >> 5; - int r = i & 0x1f; - int bit = v[q] & (1 << r); - if (bit == 0) - { - buf.append('0'); - } - else - { - buf.append('1'); - } - } - return buf.toString(); - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2mField.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2mField.java deleted file mode 100644 index 37298a1e..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2mField.java +++ /dev/null @@ -1,365 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -import java.security.SecureRandom; - -/** - * This class describes operations with elements from the finite field F = - * GF(2^m). ( GF(2^m)= GF(2)[A] where A is a root of irreducible polynomial with - * degree m, each field element B has a polynomial basis representation, i.e. it - * is represented by a different binary polynomial of degree less than m, B = - * poly(A) ) All operations are defined only for field with 1< m <32. For the - * representation of field elements the map f: F->Z, poly(A)->poly(2) is used, - * where integers have the binary representation. For example: A^7+A^3+A+1 -> - * (00...0010001011)=139 Also for elements type Integer is used. - * - * @see PolynomialRingGF2 - */ -public class GF2mField -{ - - /* - * degree - degree of the field polynomial - the field polynomial ring - - * polynomial ring over the finite field GF(2) - */ - - private int degree = 0; - - private int polynomial; - - /** - * create a finite field GF(2^m) - * - * @param degree the degree of the field - */ - public GF2mField(int degree) - { - if (degree >= 32) - { - throw new IllegalArgumentException( - " Error: the degree of field is too large "); - } - if (degree < 1) - { - throw new IllegalArgumentException( - " Error: the degree of field is non-positive "); - } - this.degree = degree; - polynomial = PolynomialRingGF2.getIrreduciblePolynomial(degree); - } - - /** - * create a finite field GF(2^m) with the fixed field polynomial - * - * @param degree the degree of the field - * @param poly the field polynomial - */ - public GF2mField(int degree, int poly) - { - if (degree != PolynomialRingGF2.degree(poly)) - { - throw new IllegalArgumentException( - " Error: the degree is not correct"); - } - if (!PolynomialRingGF2.isIrreducible(poly)) - { - throw new IllegalArgumentException( - " Error: given polynomial is reducible"); - } - this.degree = degree; - polynomial = poly; - - } - - public GF2mField(byte[] enc) - { - if (enc.length != 4) - { - throw new IllegalArgumentException( - "byte array is not an encoded finite field"); - } - polynomial = LittleEndianConversions.OS2IP(enc); - if (!PolynomialRingGF2.isIrreducible(polynomial)) - { - throw new IllegalArgumentException( - "byte array is not an encoded finite field"); - } - - degree = PolynomialRingGF2.degree(polynomial); - } - - public GF2mField(GF2mField field) - { - degree = field.degree; - polynomial = field.polynomial; - } - - /** - * return degree of the field - * - * @return degree of the field - */ - public int getDegree() - { - return degree; - } - - /** - * return the field polynomial - * - * @return the field polynomial - */ - public int getPolynomial() - { - return polynomial; - } - - /** - * return the encoded form of this field - * - * @return the field in byte array form - */ - public byte[] getEncoded() - { - return LittleEndianConversions.I2OSP(polynomial); - } - - /** - * Return sum of two elements - * - * @param a - * @param b - * @return a+b - */ - public int add(int a, int b) - { - return a ^ b; - } - - /** - * Return product of two elements - * - * @param a - * @param b - * @return a*b - */ - public int mult(int a, int b) - { - return PolynomialRingGF2.modMultiply(a, b, polynomial); - } - - /** - * compute exponentiation a^k - * - * @param a a field element a - * @param k k degree - * @return a^k - */ - public int exp(int a, int k) - { - if (a == 0) - { - return 0; - } - if (a == 1) - { - return 1; - } - int result = 1; - if (k < 0) - { - a = inverse(a); - k = -k; - } - while (k != 0) - { - if ((k & 1) == 1) - { - result = mult(result, a); - } - a = mult(a, a); - k >>>= 1; - } - return result; - } - - /** - * compute the multiplicative inverse of a - * - * @param a a field element a - * @return a<sup>-1</sup> - */ - public int inverse(int a) - { - int d = (1 << degree) - 2; - - return exp(a, d); - } - - /** - * compute the square root of an integer - * - * @param a a field element a - * @return a<sup>1/2</sup> - */ - public int sqRoot(int a) - { - for (int i = 1; i < degree; i++) - { - a = mult(a, a); - } - return a; - } - - /** - * create a random field element using PRNG sr - * - * @param sr SecureRandom - * @return a random element - */ - public int getRandomElement(SecureRandom sr) - { - int result = RandUtils.nextInt(sr, 1 << degree); - return result; - } - - /** - * create a random non-zero field element - * - * @return a random element - */ - public int getRandomNonZeroElement() - { - return getRandomNonZeroElement(new SecureRandom()); - } - - /** - * create a random non-zero field element using PRNG sr - * - * @param sr SecureRandom - * @return a random non-zero element - */ - public int getRandomNonZeroElement(SecureRandom sr) - { - int controltime = 1 << 20; - int count = 0; - int result = RandUtils.nextInt(sr, 1 << degree); - while ((result == 0) && (count < controltime)) - { - result = RandUtils.nextInt(sr, 1 << degree); - count++; - } - if (count == controltime) - { - result = 1; - } - return result; - } - - /** - * @return true if e is encoded element of this field and false otherwise - */ - public boolean isElementOfThisField(int e) - { - // e is encoded element of this field iff 0<= e < |2^m| - if (degree == 31) - { - return e >= 0; - } - return e >= 0 && e < (1 << degree); - } - - /* - * help method for visual control - */ - public String elementToStr(int a) - { - String s = ""; - for (int i = 0; i < degree; i++) - { - if (((byte)a & 0x01) == 0) - { - s = "0" + s; - } - else - { - s = "1" + s; - } - a >>>= 1; - } - return s; - } - - /** - * checks if given object is equal to this field. - * <p> - * The method returns false whenever the given object is not GF2m. - * - * @param other object - * @return true or false - */ - public boolean equals(Object other) - { - if ((other == null) || !(other instanceof GF2mField)) - { - return false; - } - - GF2mField otherField = (GF2mField)other; - - if ((degree == otherField.degree) - && (polynomial == otherField.polynomial)) - { - return true; - } - - return false; - } - - public int hashCode() - { - return polynomial; - } - - /** - * Returns a human readable form of this field. - * - * @return a human readable form of this field. - */ - public String toString() - { - String str = "Finite Field GF(2^" + degree + ") = " + "GF(2)[X]/<" - + polyToString(polynomial) + "> "; - return str; - } - - private static String polyToString(int p) - { - String str = ""; - if (p == 0) - { - str = "0"; - } - else - { - byte b = (byte)(p & 0x01); - if (b == 1) - { - str = "1"; - } - p >>>= 1; - int i = 1; - while (p != 0) - { - b = (byte)(p & 0x01); - if (b == 1) - { - str = str + "+x^" + i; - } - p >>>= 1; - i++; - } - } - return str; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2mMatrix.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2mMatrix.java deleted file mode 100644 index 8dfdb9b1..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2mMatrix.java +++ /dev/null @@ -1,377 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -/** - * This class describes some operations with matrices over finite field <i>GF(2<sup>m</sup>)</i> - * with small <i>m</i> (1< m <32). - * - * @see Matrix - */ -public class GF2mMatrix - extends Matrix -{ - - /** - * finite field GF(2^m) - */ - protected GF2mField field; - - /** - * For the matrix representation the array of type int[][] is used, thus - * every element of the array keeps one element of the matrix (element from - * finite field GF(2^m)) - */ - protected int[][] matrix; - - /** - * Constructor. - * - * @param field a finite field GF(2^m) - * @param enc byte[] matrix in byte array form - */ - public GF2mMatrix(GF2mField field, byte[] enc) - { - - this.field = field; - - // decode matrix - int d = 8; - int count = 1; - while (field.getDegree() > d) - { - count++; - d += 8; - } - - if (enc.length < 5) - { - throw new IllegalArgumentException( - " Error: given array is not encoded matrix over GF(2^m)"); - } - - this.numRows = ((enc[3] & 0xff) << 24) ^ ((enc[2] & 0xff) << 16) - ^ ((enc[1] & 0xff) << 8) ^ (enc[0] & 0xff); - - int n = count * this.numRows; - - if ((this.numRows <= 0) || (((enc.length - 4) % n) != 0)) - { - throw new IllegalArgumentException( - " Error: given array is not encoded matrix over GF(2^m)"); - } - - this.numColumns = (enc.length - 4) / n; - - matrix = new int[this.numRows][this.numColumns]; - count = 4; - for (int i = 0; i < this.numRows; i++) - { - for (int j = 0; j < this.numColumns; j++) - { - for (int jj = 0; jj < d; jj += 8) - { - matrix[i][j] ^= (enc[count++] & 0x000000ff) << jj; - } - if (!this.field.isElementOfThisField(matrix[i][j])) - { - throw new IllegalArgumentException( - " Error: given array is not encoded matrix over GF(2^m)"); - } - } - } - } - - /** - * Copy constructor. - * - * @param other another {@link GF2mMatrix} - */ - public GF2mMatrix(GF2mMatrix other) - { - numRows = other.numRows; - numColumns = other.numColumns; - field = other.field; - matrix = new int[numRows][]; - for (int i = 0; i < numRows; i++) - { - matrix[i] = IntUtils.clone(other.matrix[i]); - } - } - - /** - * Constructor. - * - * @param field a finite field GF(2^m) - * @param matrix the matrix as int array. Only the reference is copied. - */ - protected GF2mMatrix(GF2mField field, int[][] matrix) - { - this.field = field; - this.matrix = matrix; - numRows = matrix.length; - numColumns = matrix[0].length; - } - - /** - * @return a byte array encoding of this matrix - */ - public byte[] getEncoded() - { - int d = 8; - int count = 1; - while (field.getDegree() > d) - { - count++; - d += 8; - } - - byte[] bf = new byte[this.numRows * this.numColumns * count + 4]; - bf[0] = (byte)(this.numRows & 0xff); - bf[1] = (byte)((this.numRows >>> 8) & 0xff); - bf[2] = (byte)((this.numRows >>> 16) & 0xff); - bf[3] = (byte)((this.numRows >>> 24) & 0xff); - - count = 4; - for (int i = 0; i < this.numRows; i++) - { - for (int j = 0; j < this.numColumns; j++) - { - for (int jj = 0; jj < d; jj += 8) - { - bf[count++] = (byte)(matrix[i][j] >>> jj); - } - } - } - - return bf; - } - - /** - * Check if this is the zero matrix (i.e., all entries are zero). - * - * @return <tt>true</tt> if this is the zero matrix - */ - public boolean isZero() - { - for (int i = 0; i < numRows; i++) - { - for (int j = 0; j < numColumns; j++) - { - if (matrix[i][j] != 0) - { - return false; - } - } - } - return true; - } - - /** - * Compute the inverse of this matrix. - * - * @return the inverse of this matrix (newly created). - */ - public Matrix computeInverse() - { - if (numRows != numColumns) - { - throw new ArithmeticException("Matrix is not invertible."); - } - - // clone this matrix - int[][] tmpMatrix = new int[numRows][numRows]; - for (int i = numRows - 1; i >= 0; i--) - { - tmpMatrix[i] = IntUtils.clone(matrix[i]); - } - - // initialize inverse matrix as unit matrix - int[][] invMatrix = new int[numRows][numRows]; - for (int i = numRows - 1; i >= 0; i--) - { - invMatrix[i][i] = 1; - } - - // simultaneously compute Gaussian reduction of tmpMatrix and unit - // matrix - for (int i = 0; i < numRows; i++) - { - // if diagonal element is zero - if (tmpMatrix[i][i] == 0) - { - boolean foundNonZero = false; - // find a non-zero element in the same column - for (int j = i + 1; j < numRows; j++) - { - if (tmpMatrix[j][i] != 0) - { - // found it, swap rows ... - foundNonZero = true; - swapColumns(tmpMatrix, i, j); - swapColumns(invMatrix, i, j); - // ... and quit searching - j = numRows; - continue; - } - } - // if no non-zero element was found - if (!foundNonZero) - { - // the matrix is not invertible - throw new ArithmeticException("Matrix is not invertible."); - } - } - - // normalize i-th row - int coef = tmpMatrix[i][i]; - int invCoef = field.inverse(coef); - multRowWithElementThis(tmpMatrix[i], invCoef); - multRowWithElementThis(invMatrix[i], invCoef); - - // normalize all other rows - for (int j = 0; j < numRows; j++) - { - if (j != i) - { - coef = tmpMatrix[j][i]; - if (coef != 0) - { - int[] tmpRow = multRowWithElement(tmpMatrix[i], coef); - int[] tmpInvRow = multRowWithElement(invMatrix[i], coef); - addToRow(tmpRow, tmpMatrix[j]); - addToRow(tmpInvRow, invMatrix[j]); - } - } - } - } - - return new GF2mMatrix(field, invMatrix); - } - - private static void swapColumns(int[][] matrix, int first, int second) - { - int[] tmp = matrix[first]; - matrix[first] = matrix[second]; - matrix[second] = tmp; - } - - private void multRowWithElementThis(int[] row, int element) - { - for (int i = row.length - 1; i >= 0; i--) - { - row[i] = field.mult(row[i], element); - } - } - - private int[] multRowWithElement(int[] row, int element) - { - int[] result = new int[row.length]; - for (int i = row.length - 1; i >= 0; i--) - { - result[i] = field.mult(row[i], element); - } - return result; - } - - /** - * Add one row to another. - * - * @param fromRow the addend - * @param toRow the row to add to - */ - private void addToRow(int[] fromRow, int[] toRow) - { - for (int i = toRow.length - 1; i >= 0; i--) - { - toRow[i] = field.add(fromRow[i], toRow[i]); - } - } - - public Matrix rightMultiply(Matrix a) - { - throw new RuntimeException("Not implemented."); - } - - public Matrix rightMultiply(Permutation perm) - { - throw new RuntimeException("Not implemented."); - } - - public Vector leftMultiply(Vector vector) - { - throw new RuntimeException("Not implemented."); - } - - public Vector rightMultiply(Vector vector) - { - throw new RuntimeException("Not implemented."); - } - - /** - * Checks if given object is equal to this matrix. The method returns false - * whenever the given object is not a matrix over GF(2^m). - * - * @param other object - * @return true or false - */ - public boolean equals(Object other) - { - - if (other == null || !(other instanceof GF2mMatrix)) - { - return false; - } - - GF2mMatrix otherMatrix = (GF2mMatrix)other; - - if ((!this.field.equals(otherMatrix.field)) - || (otherMatrix.numRows != this.numColumns) - || (otherMatrix.numColumns != this.numColumns)) - { - return false; - } - - for (int i = 0; i < this.numRows; i++) - { - for (int j = 0; j < this.numColumns; j++) - { - if (this.matrix[i][j] != otherMatrix.matrix[i][j]) - { - return false; - } - } - } - - return true; - } - - public int hashCode() - { - int hash = (this.field.hashCode() * 31 + numRows) * 31 + numColumns; - for (int i = 0; i < this.numRows; i++) - { - for (int j = 0; j < this.numColumns; j++) - { - hash = hash * 31 + matrix[i][j]; - } - } - return hash; - } - - public String toString() - { - String str = this.numRows + " x " + this.numColumns + " Matrix over " - + this.field.toString() + ": \n"; - - for (int i = 0; i < this.numRows; i++) - { - for (int j = 0; j < this.numColumns; j++) - { - str = str + this.field.elementToStr(matrix[i][j]) + " : "; - } - str = str + "\n"; - } - - return str; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2mVector.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2mVector.java deleted file mode 100644 index f2527f67..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2mVector.java +++ /dev/null @@ -1,256 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - - -/** - * This class implements vectors over the finite field - * <tt>GF(2<sup>m</sup>)</tt> for small <tt>m</tt> (i.e., - * <tt>1<m<32</tt>). It extends the abstract class {@link Vector}. - */ -public class GF2mVector - extends Vector -{ - - /** - * the finite field this vector is defined over - */ - private GF2mField field; - - /** - * the element array - */ - private int[] vector; - - /** - * creates the vector over GF(2^m) of given length and with elements from - * array v (beginning at the first bit) - * - * @param field finite field - * @param v array with elements of vector - */ - public GF2mVector(GF2mField field, byte[] v) - { - this.field = new GF2mField(field); - - // decode vector - int d = 8; - int count = 1; - while (field.getDegree() > d) - { - count++; - d += 8; - } - - if ((v.length % count) != 0) - { - throw new IllegalArgumentException( - "Byte array is not an encoded vector over the given finite field."); - } - - length = v.length / count; - vector = new int[length]; - count = 0; - for (int i = 0; i < vector.length; i++) - { - for (int j = 0; j < d; j += 8) - { - vector[i] |= (v[count++] & 0xff) << j; - } - if (!field.isElementOfThisField(vector[i])) - { - throw new IllegalArgumentException( - "Byte array is not an encoded vector over the given finite field."); - } - } - } - - /** - * Create a new vector over <tt>GF(2<sup>m</sup>)</tt> of the given - * length and element array. - * - * @param field the finite field <tt>GF(2<sup>m</sup>)</tt> - * @param vector the element array - */ - public GF2mVector(GF2mField field, int[] vector) - { - this.field = field; - length = vector.length; - for (int i = vector.length - 1; i >= 0; i--) - { - if (!field.isElementOfThisField(vector[i])) - { - throw new ArithmeticException( - "Element array is not specified over the given finite field."); - } - } - this.vector = IntUtils.clone(vector); - } - - /** - * Copy constructor. - * - * @param other another {@link GF2mVector} - */ - public GF2mVector(GF2mVector other) - { - field = new GF2mField(other.field); - length = other.length; - vector = IntUtils.clone(other.vector); - } - - /** - * @return the finite field this vector is defined over - */ - public GF2mField getField() - { - return field; - } - - /** - * @return int[] form of this vector - */ - public int[] getIntArrayForm() - { - return IntUtils.clone(vector); - } - - /** - * @return a byte array encoding of this vector - */ - public byte[] getEncoded() - { - int d = 8; - int count = 1; - while (field.getDegree() > d) - { - count++; - d += 8; - } - - byte[] res = new byte[vector.length * count]; - count = 0; - for (int i = 0; i < vector.length; i++) - { - for (int j = 0; j < d; j += 8) - { - res[count++] = (byte)(vector[i] >>> j); - } - } - - return res; - } - - /** - * @return whether this is the zero vector (i.e., all elements are zero) - */ - public boolean isZero() - { - for (int i = vector.length - 1; i >= 0; i--) - { - if (vector[i] != 0) - { - return false; - } - } - return true; - } - - /** - * Add another vector to this vector. Method is not yet implemented. - * - * @param addend the other vector - * @return <tt>this + addend</tt> - * @throws ArithmeticException if the other vector is not defined over the same field as - * this vector. - * <p> - * TODO: implement this method - */ - public Vector add(Vector addend) - { - throw new RuntimeException("not implemented"); - } - - /** - * Multiply this vector with a permutation. - * - * @param p the permutation - * @return <tt>this*p = p*this</tt> - */ - public Vector multiply(Permutation p) - { - int[] pVec = p.getVector(); - if (length != pVec.length) - { - throw new ArithmeticException( - "permutation size and vector size mismatch"); - } - - int[] result = new int[length]; - for (int i = 0; i < pVec.length; i++) - { - result[i] = vector[pVec[i]]; - } - - return new GF2mVector(field, result); - } - - /** - * Compare this vector with another object. - * - * @param other the other object - * @return the result of the comparison - */ - public boolean equals(Object other) - { - - if (!(other instanceof GF2mVector)) - { - return false; - } - GF2mVector otherVec = (GF2mVector)other; - - if (!field.equals(otherVec.field)) - { - return false; - } - - return IntUtils.equals(vector, otherVec.vector); - } - - /** - * @return the hash code of this vector - */ - public int hashCode() - { - int hash = this.field.hashCode(); - hash = hash * 31 + vector.hashCode(); - return hash; - } - - /** - * @return a human readable form of this vector - */ - public String toString() - { - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < vector.length; i++) - { - for (int j = 0; j < field.getDegree(); j++) - { - int r = j & 0x1f; - int bitMask = 1 << r; - int coeff = vector[i] & bitMask; - if (coeff != 0) - { - buf.append('1'); - } - else - { - buf.append('0'); - } - } - buf.append(' '); - } - return buf.toString(); - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nElement.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nElement.java deleted file mode 100644 index faa99dcb..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nElement.java +++ /dev/null @@ -1,186 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - - -/** - * This abstract class implements an element of the finite field <i>GF(2)<sup>n - * </sup></i> in either <i>optimal normal basis</i> representation (<i>ONB</i>) - * or in <i>polynomial</i> representation. It is extended by the classes <a - * href = GF2nONBElement.html><tt> GF2nONBElement</tt></a> and <a href = - * GF2nPolynomialElement.html> <tt>GF2nPolynomialElement</tt> </a>. - * - * @see GF2nPolynomialElement - * @see GF2nONBElement - * @see GF2nONBField - */ -public abstract class GF2nElement - implements GFElement -{ - - // ///////////////////////////////////////////////////////////////////// - // member variables - // ///////////////////////////////////////////////////////////////////// - - /** - * holds a pointer to this element's corresponding field. - */ - protected GF2nField mField; - - /** - * holds the extension degree <i>n</i> of this element's corresponding - * field. - */ - protected int mDegree; - - // ///////////////////////////////////////////////////////////////////// - // pseudo-constructors - // ///////////////////////////////////////////////////////////////////// - - /** - * @return a copy of this GF2nElement - */ - public abstract Object clone(); - - // ///////////////////////////////////////////////////////////////////// - // assignments - // ///////////////////////////////////////////////////////////////////// - - /** - * Assign the value 0 to this element. - */ - abstract void assignZero(); - - /** - * Assigns the value 1 to this element. - */ - abstract void assignOne(); - - // ///////////////////////////////////////////////////////////////////// - // access - // ///////////////////////////////////////////////////////////////////// - - /** - * Returns whether the rightmost bit of the bit representation is set. This - * is needed for data conversion according to 1363. - * - * @return true if the rightmost bit of this element is set - */ - public abstract boolean testRightmostBit(); - - /** - * Checks whether the indexed bit of the bit representation is set - * - * @param index the index of the bit to test - * @return <tt>true</tt> if the indexed bit is set - */ - abstract boolean testBit(int index); - - /** - * Returns the field of this element. - * - * @return the field of this element - */ - public final GF2nField getField() - { - return mField; - } - - // ///////////////////////////////////////////////////////////////////// - // arithmetic - // ///////////////////////////////////////////////////////////////////// - - /** - * Returns <tt>this</tt> element + 1. - * - * @return <tt>this</tt> + 1 - */ - public abstract GF2nElement increase(); - - /** - * Increases this element by one. - */ - public abstract void increaseThis(); - - /** - * Compute the difference of this element and <tt>minuend</tt>. - * - * @param minuend the minuend - * @return <tt>this - minuend</tt> (newly created) - * @throws DifferentFieldsException if the elements are of different fields. - */ - public final GFElement subtract(GFElement minuend) - throws RuntimeException - { - return add(minuend); - } - - /** - * Compute the difference of this element and <tt>minuend</tt>, - * overwriting this element. - * - * @param minuend the minuend - * @throws DifferentFieldsException if the elements are of different fields. - */ - public final void subtractFromThis(GFElement minuend) - { - addToThis(minuend); - } - - /** - * Returns <tt>this</tt> element to the power of 2. - * - * @return <tt>this</tt><sup>2</sup> - */ - public abstract GF2nElement square(); - - /** - * Squares <tt>this</tt> element. - */ - public abstract void squareThis(); - - /** - * Compute the square root of this element and return the result in a new - * {@link GF2nElement}. - * - * @return <tt>this<sup>1/2</sup></tt> (newly created) - */ - public abstract GF2nElement squareRoot(); - - /** - * Compute the square root of this element. - */ - public abstract void squareRootThis(); - - /** - * Performs a basis transformation of this element to the given GF2nField - * <tt>basis</tt>. - * - * @param basis the GF2nField representation to transform this element to - * @return this element in the representation of <tt>basis</tt> - * @throws DifferentFieldsException if <tt>this</tt> cannot be converted according to - * <tt>basis</tt>. - */ - public final GF2nElement convert(GF2nField basis) - throws RuntimeException - { - return mField.convert(this, basis); - } - - /** - * Returns the trace of this element. - * - * @return the trace of this element - */ - public abstract int trace(); - - /** - * Solves a quadratic equation.<br> - * Let z<sup>2</sup> + z = <tt>this</tt>. Then this method returns z. - * - * @return z with z<sup>2</sup> + z = <tt>this</tt> - * @throws NoSolutionException if z<sup>2</sup> + z = <tt>this</tt> does not have a - * solution - */ - public abstract GF2nElement solveQuadraticEquation() - throws RuntimeException; - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nField.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nField.java deleted file mode 100644 index 907afd76..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nField.java +++ /dev/null @@ -1,292 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - - -import java.util.Vector; - - -/** - * This abstract class defines the finite field <i>GF(2<sup>n</sup>)</i>. It - * holds the extension degree <i>n</i>, the characteristic, the irreducible - * fieldpolynomial and conversion matrices. GF2nField is implemented by the - * classes GF2nPolynomialField and GF2nONBField. - * - * @see GF2nONBField - * @see GF2nPolynomialField - */ -public abstract class GF2nField -{ - - /** - * the degree of this field - */ - protected int mDegree; - - /** - * the irreducible fieldPolynomial stored in normal order (also for ONB) - */ - protected GF2Polynomial fieldPolynomial; - - /** - * holds a list of GF2nFields to which elements have been converted and thus - * a COB-Matrix exists - */ - protected Vector fields; - - /** - * the COB matrices - */ - protected Vector matrices; - - /** - * Returns the degree <i>n</i> of this field. - * - * @return the degree <i>n</i> of this field - */ - public final int getDegree() - { - return mDegree; - } - - /** - * Returns the fieldpolynomial as a new Bitstring. - * - * @return a copy of the fieldpolynomial as a new Bitstring - */ - public final GF2Polynomial getFieldPolynomial() - { - if (fieldPolynomial == null) - { - computeFieldPolynomial(); - } - return new GF2Polynomial(fieldPolynomial); - } - - /** - * Decides whether the given object <tt>other</tt> is the same as this - * field. - * - * @param other another object - * @return (this == other) - */ - public final boolean equals(Object other) - { - if (other == null || !(other instanceof GF2nField)) - { - return false; - } - - GF2nField otherField = (GF2nField)other; - - if (otherField.mDegree != mDegree) - { - return false; - } - if (!fieldPolynomial.equals(otherField.fieldPolynomial)) - { - return false; - } - if ((this instanceof GF2nPolynomialField) - && !(otherField instanceof GF2nPolynomialField)) - { - return false; - } - if ((this instanceof GF2nONBField) - && !(otherField instanceof GF2nONBField)) - { - return false; - } - return true; - } - - /** - * @return the hash code of this field - */ - public int hashCode() - { - return mDegree + fieldPolynomial.hashCode(); - } - - /** - * Computes a random root from the given irreducible fieldpolynomial - * according to IEEE 1363 algorithm A.5.6. This cal take very long for big - * degrees. - * - * @param B0FieldPolynomial the fieldpolynomial if the other basis as a Bitstring - * @return a random root of BOFieldPolynomial in representation according to - * this field - * @see "P1363 A.5.6, p103f" - */ - protected abstract GF2nElement getRandomRoot(GF2Polynomial B0FieldPolynomial); - - /** - * Computes the change-of-basis matrix for basis conversion according to - * 1363. The result is stored in the lists fields and matrices. - * - * @param B1 the GF2nField to convert to - * @see "P1363 A.7.3, p111ff" - */ - protected abstract void computeCOBMatrix(GF2nField B1); - - /** - * Computes the fieldpolynomial. This can take a long time for big degrees. - */ - protected abstract void computeFieldPolynomial(); - - /** - * Inverts the given matrix represented as bitstrings. - * - * @param matrix the matrix to invert as a Bitstring[] - * @return matrix^(-1) - */ - protected final GF2Polynomial[] invertMatrix(GF2Polynomial[] matrix) - { - GF2Polynomial[] a = new GF2Polynomial[matrix.length]; - GF2Polynomial[] inv = new GF2Polynomial[matrix.length]; - GF2Polynomial dummy; - int i, j; - // initialize a as a copy of matrix and inv as E(inheitsmatrix) - for (i = 0; i < mDegree; i++) - { - try - { - a[i] = new GF2Polynomial(matrix[i]); - inv[i] = new GF2Polynomial(mDegree); - inv[i].setBit(mDegree - 1 - i); - } - catch (RuntimeException BDNEExc) - { - BDNEExc.printStackTrace(); - } - } - // construct triangle matrix so that for each a[i] the first i bits are - // zero - for (i = 0; i < mDegree - 1; i++) - { - // find column where bit i is set - j = i; - while ((j < mDegree) && !a[j].testBit(mDegree - 1 - i)) - { - j++; - } - if (j >= mDegree) - { - throw new RuntimeException( - "GF2nField.invertMatrix: Matrix cannot be inverted!"); - } - if (i != j) - { // swap a[i]/a[j] and inv[i]/inv[j] - dummy = a[i]; - a[i] = a[j]; - a[j] = dummy; - dummy = inv[i]; - inv[i] = inv[j]; - inv[j] = dummy; - } - for (j = i + 1; j < mDegree; j++) - { // add column i to all columns>i - // having their i-th bit set - if (a[j].testBit(mDegree - 1 - i)) - { - a[j].addToThis(a[i]); - inv[j].addToThis(inv[i]); - } - } - } - // construct Einheitsmatrix from a - for (i = mDegree - 1; i > 0; i--) - { - for (j = i - 1; j >= 0; j--) - { // eliminate the i-th bit in all - // columns < i - if (a[j].testBit(mDegree - 1 - i)) - { - a[j].addToThis(a[i]); - inv[j].addToThis(inv[i]); - } - } - } - return inv; - } - - /** - * Converts the given element in representation according to this field to a - * new element in representation according to B1 using the change-of-basis - * matrix calculated by computeCOBMatrix. - * - * @param elem the GF2nElement to convert - * @param basis the basis to convert <tt>elem</tt> to - * @return <tt>elem</tt> converted to a new element representation - * according to <tt>basis</tt> - * @throws DifferentFieldsException if <tt>elem</tt> cannot be converted according to - * <tt>basis</tt>. - * @see GF2nField#computeCOBMatrix - * @see GF2nField#getRandomRoot - * @see GF2nPolynomial - * @see "P1363 A.7 p109ff" - */ - public final GF2nElement convert(GF2nElement elem, GF2nField basis) - throws RuntimeException - { - if (basis == this) - { - return (GF2nElement)elem.clone(); - } - if (fieldPolynomial.equals(basis.fieldPolynomial)) - { - return (GF2nElement)elem.clone(); - } - if (mDegree != basis.mDegree) - { - throw new RuntimeException("GF2nField.convert: B1 has a" - + " different degree and thus cannot be coverted to!"); - } - - int i; - GF2Polynomial[] COBMatrix; - i = fields.indexOf(basis); - if (i == -1) - { - computeCOBMatrix(basis); - i = fields.indexOf(basis); - } - COBMatrix = (GF2Polynomial[])matrices.elementAt(i); - - GF2nElement elemCopy = (GF2nElement)elem.clone(); - if (elemCopy instanceof GF2nONBElement) - { - // remember: ONB treats its bits in reverse order - ((GF2nONBElement)elemCopy).reverseOrder(); - } - GF2Polynomial bs = new GF2Polynomial(mDegree, elemCopy.toFlexiBigInt()); - bs.expandN(mDegree); - GF2Polynomial result = new GF2Polynomial(mDegree); - for (i = 0; i < mDegree; i++) - { - if (bs.vectorMult(COBMatrix[i])) - { - result.setBit(mDegree - 1 - i); - } - } - if (basis instanceof GF2nPolynomialField) - { - return new GF2nPolynomialElement((GF2nPolynomialField)basis, - result); - } - else if (basis instanceof GF2nONBField) - { - GF2nONBElement res = new GF2nONBElement((GF2nONBField)basis, - result.toFlexiBigInt()); - // TODO Remember: ONB treats its Bits in reverse order !!! - res.reverseOrder(); - return res; - } - else - { - throw new RuntimeException( - "GF2nField.convert: B1 must be an instance of " - + "GF2nPolynomialField or GF2nONBField!"); - } - - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nONBElement.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nONBElement.java deleted file mode 100644 index 8b4b473f..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nONBElement.java +++ /dev/null @@ -1,1154 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - - -import java.math.BigInteger; -import java.util.Random; - -/** - * This class implements an element of the finite field <i>GF(2<sup>n </sup>)</i>. - * It is represented in an optimal normal basis representation and holds the - * pointer <tt>mField</tt> to its corresponding field. - * - * @see GF2nField - * @see GF2nElement - */ -public class GF2nONBElement - extends GF2nElement -{ - - // ///////////////////////////////////////////////////////////////////// - // member variables - // ///////////////////////////////////////////////////////////////////// - - private static final long[] mBitmask = new long[]{0x0000000000000001L, - 0x0000000000000002L, 0x0000000000000004L, 0x0000000000000008L, - 0x0000000000000010L, 0x0000000000000020L, 0x0000000000000040L, - 0x0000000000000080L, 0x0000000000000100L, 0x0000000000000200L, - 0x0000000000000400L, 0x0000000000000800L, 0x0000000000001000L, - 0x0000000000002000L, 0x0000000000004000L, 0x0000000000008000L, - 0x0000000000010000L, 0x0000000000020000L, 0x0000000000040000L, - 0x0000000000080000L, 0x0000000000100000L, 0x0000000000200000L, - 0x0000000000400000L, 0x0000000000800000L, 0x0000000001000000L, - 0x0000000002000000L, 0x0000000004000000L, 0x0000000008000000L, - 0x0000000010000000L, 0x0000000020000000L, 0x0000000040000000L, - 0x0000000080000000L, 0x0000000100000000L, 0x0000000200000000L, - 0x0000000400000000L, 0x0000000800000000L, 0x0000001000000000L, - 0x0000002000000000L, 0x0000004000000000L, 0x0000008000000000L, - 0x0000010000000000L, 0x0000020000000000L, 0x0000040000000000L, - 0x0000080000000000L, 0x0000100000000000L, 0x0000200000000000L, - 0x0000400000000000L, 0x0000800000000000L, 0x0001000000000000L, - 0x0002000000000000L, 0x0004000000000000L, 0x0008000000000000L, - 0x0010000000000000L, 0x0020000000000000L, 0x0040000000000000L, - 0x0080000000000000L, 0x0100000000000000L, 0x0200000000000000L, - 0x0400000000000000L, 0x0800000000000000L, 0x1000000000000000L, - 0x2000000000000000L, 0x4000000000000000L, 0x8000000000000000L}; - - private static final long[] mMaxmask = new long[]{0x0000000000000001L, - 0x0000000000000003L, 0x0000000000000007L, 0x000000000000000FL, - 0x000000000000001FL, 0x000000000000003FL, 0x000000000000007FL, - 0x00000000000000FFL, 0x00000000000001FFL, 0x00000000000003FFL, - 0x00000000000007FFL, 0x0000000000000FFFL, 0x0000000000001FFFL, - 0x0000000000003FFFL, 0x0000000000007FFFL, 0x000000000000FFFFL, - 0x000000000001FFFFL, 0x000000000003FFFFL, 0x000000000007FFFFL, - 0x00000000000FFFFFL, 0x00000000001FFFFFL, 0x00000000003FFFFFL, - 0x00000000007FFFFFL, 0x0000000000FFFFFFL, 0x0000000001FFFFFFL, - 0x0000000003FFFFFFL, 0x0000000007FFFFFFL, 0x000000000FFFFFFFL, - 0x000000001FFFFFFFL, 0x000000003FFFFFFFL, 0x000000007FFFFFFFL, - 0x00000000FFFFFFFFL, 0x00000001FFFFFFFFL, 0x00000003FFFFFFFFL, - 0x00000007FFFFFFFFL, 0x0000000FFFFFFFFFL, 0x0000001FFFFFFFFFL, - 0x0000003FFFFFFFFFL, 0x0000007FFFFFFFFFL, 0x000000FFFFFFFFFFL, - 0x000001FFFFFFFFFFL, 0x000003FFFFFFFFFFL, 0x000007FFFFFFFFFFL, - 0x00000FFFFFFFFFFFL, 0x00001FFFFFFFFFFFL, 0x00003FFFFFFFFFFFL, - 0x00007FFFFFFFFFFFL, 0x0000FFFFFFFFFFFFL, 0x0001FFFFFFFFFFFFL, - 0x0003FFFFFFFFFFFFL, 0x0007FFFFFFFFFFFFL, 0x000FFFFFFFFFFFFFL, - 0x001FFFFFFFFFFFFFL, 0x003FFFFFFFFFFFFFL, 0x007FFFFFFFFFFFFFL, - 0x00FFFFFFFFFFFFFFL, 0x01FFFFFFFFFFFFFFL, 0x03FFFFFFFFFFFFFFL, - 0x07FFFFFFFFFFFFFFL, 0x0FFFFFFFFFFFFFFFL, 0x1FFFFFFFFFFFFFFFL, - 0x3FFFFFFFFFFFFFFFL, 0x7FFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL}; - - // mIBy64[j * 16 + i] = (j * 16 + i)/64 - // i = - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - // - private static final int[] mIBY64 = new int[]{ - // j = - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 8 - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 9 - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 10 - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 11 - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 12 - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 13 - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 14 - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 15 - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 16 - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 17 - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 18 - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 19 - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 20 - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 21 - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 22 - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 // 23 - }; - - private static final int MAXLONG = 64; - - /** - * holds the lenght of the polynomial with 64 bit sized fields. - */ - private int mLength; - - /** - * holds the value of mDeg % MAXLONG. - */ - private int mBit; - - /** - * holds this element in ONB representation. - */ - private long[] mPol; - - // ///////////////////////////////////////////////////////////////////// - // constructors - // ///////////////////////////////////////////////////////////////////// - - /** - * Construct a random element over the field <tt>gf2n</tt>, using the - * specified source of randomness. - * - * @param gf2n the field - * @param rand the source of randomness - */ - public GF2nONBElement(GF2nONBField gf2n, Random rand) - { - mField = gf2n; - mDegree = mField.getDegree(); - mLength = gf2n.getONBLength(); - mBit = gf2n.getONBBit(); - mPol = new long[mLength]; - if (mLength > 1) - { - for (int j = 0; j < mLength - 1; j++) - { - mPol[j] = rand.nextLong(); - } - long last = rand.nextLong(); - mPol[mLength - 1] = last >>> (MAXLONG - mBit); - } - else - { - mPol[0] = rand.nextLong(); - mPol[0] = mPol[0] >>> (MAXLONG - mBit); - } - } - - /** - * Construct a new GF2nONBElement from its encoding. - * - * @param gf2n the field - * @param e the encoded element - */ - public GF2nONBElement(GF2nONBField gf2n, byte[] e) - { - mField = gf2n; - mDegree = mField.getDegree(); - mLength = gf2n.getONBLength(); - mBit = gf2n.getONBBit(); - mPol = new long[mLength]; - assign(e); - } - - /** - * Construct the element of the field <tt>gf2n</tt> with the specified - * value <tt>val</tt>. - * - * @param gf2n the field - * @param val the value represented by a BigInteger - */ - public GF2nONBElement(GF2nONBField gf2n, BigInteger val) - { - mField = gf2n; - mDegree = mField.getDegree(); - mLength = gf2n.getONBLength(); - mBit = gf2n.getONBBit(); - mPol = new long[mLength]; - assign(val); - } - - /** - * Construct the element of the field <tt>gf2n</tt> with the specified - * value <tt>val</tt>. - * - * @param gf2n the field - * @param val the value in ONB representation - */ - private GF2nONBElement(GF2nONBField gf2n, long[] val) - { - mField = gf2n; - mDegree = mField.getDegree(); - mLength = gf2n.getONBLength(); - mBit = gf2n.getONBBit(); - mPol = val; - } - - // ///////////////////////////////////////////////////////////////////// - // pseudo-constructors - // ///////////////////////////////////////////////////////////////////// - - /** - * Copy constructor. - * - * @param gf2n the field - */ - public GF2nONBElement(GF2nONBElement gf2n) - { - - mField = gf2n.mField; - mDegree = mField.getDegree(); - mLength = ((GF2nONBField)mField).getONBLength(); - mBit = ((GF2nONBField)mField).getONBBit(); - mPol = new long[mLength]; - assign(gf2n.getElement()); - } - - /** - * Create a new GF2nONBElement by cloning this GF2nPolynomialElement. - * - * @return a copy of this element - */ - public Object clone() - { - return new GF2nONBElement(this); - } - - /** - * Create the zero element. - * - * @param gf2n the finite field - * @return the zero element in the given finite field - */ - public static GF2nONBElement ZERO(GF2nONBField gf2n) - { - long[] polynomial = new long[gf2n.getONBLength()]; - return new GF2nONBElement(gf2n, polynomial); - } - - /** - * Create the one element. - * - * @param gf2n the finite field - * @return the one element in the given finite field - */ - public static GF2nONBElement ONE(GF2nONBField gf2n) - { - int mLength = gf2n.getONBLength(); - long[] polynomial = new long[mLength]; - - // fill mDegree coefficients with one's - for (int i = 0; i < mLength - 1; i++) - { - polynomial[i] = 0xffffffffffffffffL; - } - polynomial[mLength - 1] = mMaxmask[gf2n.getONBBit() - 1]; - - return new GF2nONBElement(gf2n, polynomial); - } - - // ///////////////////////////////////////////////////////////////////// - // assignments - // ///////////////////////////////////////////////////////////////////// - - /** - * assigns to this element the zero element - */ - void assignZero() - { - mPol = new long[mLength]; - } - - /** - * assigns to this element the one element - */ - void assignOne() - { - // fill mDegree coefficients with one's - for (int i = 0; i < mLength - 1; i++) - { - mPol[i] = 0xffffffffffffffffL; - } - mPol[mLength - 1] = mMaxmask[mBit - 1]; - } - - /** - * assigns to this element the value <tt>val</tt>. - * - * @param val the value represented by a BigInteger - */ - private void assign(BigInteger val) - { - assign(val.toByteArray()); - } - - /** - * assigns to this element the value <tt>val</tt>. - * - * @param val the value in ONB representation - */ - private void assign(long[] val) - { - System.arraycopy(val, 0, mPol, 0, mLength); - } - - /** - * assigns to this element the value <tt>val</tt>. First: inverting the - * order of val into reversed[]. That means: reversed[0] = val[length - 1], - * ..., reversed[reversed.length - 1] = val[0]. Second: mPol[0] = sum{i = 0, - * ... 7} (val[i]<<(i*8)) .... mPol[1] = sum{i = 8, ... 15} (val[i]<<(i*8)) - * - * @param val the value in ONB representation - */ - private void assign(byte[] val) - { - int j; - mPol = new long[mLength]; - for (j = 0; j < val.length; j++) - { - mPol[j >>> 3] |= (val[val.length - 1 - j] & 0x00000000000000ffL) << ((j & 0x07) << 3); - } - } - - // ///////////////////////////////////////////////////////////////// - // comparison - // ///////////////////////////////////////////////////////////////// - - /** - * Checks whether this element is zero. - * - * @return <tt>true</tt> if <tt>this</tt> is the zero element - */ - public boolean isZero() - { - - boolean result = true; - - for (int i = 0; i < mLength && result; i++) - { - result = result && ((mPol[i] & 0xFFFFFFFFFFFFFFFFL) == 0); - } - - return result; - } - - /** - * Checks whether this element is one. - * - * @return <tt>true</tt> if <tt>this</tt> is the one element - */ - public boolean isOne() - { - - boolean result = true; - - for (int i = 0; i < mLength - 1 && result; i++) - { - result = result - && ((mPol[i] & 0xFFFFFFFFFFFFFFFFL) == 0xFFFFFFFFFFFFFFFFL); - } - - if (result) - { - result = result - && ((mPol[mLength - 1] & mMaxmask[mBit - 1]) == mMaxmask[mBit - 1]); - } - - return result; - } - - /** - * Compare this element with another object. - * - * @param other the other object - * @return <tt>true</tt> if the two objects are equal, <tt>false</tt> - * otherwise - */ - public boolean equals(Object other) - { - if (other == null || !(other instanceof GF2nONBElement)) - { - return false; - } - - GF2nONBElement otherElem = (GF2nONBElement)other; - - for (int i = 0; i < mLength; i++) - { - if (mPol[i] != otherElem.mPol[i]) - { - return false; - } - } - - return true; - } - - /** - * @return the hash code of this element - */ - public int hashCode() - { - return mPol.hashCode(); - } - - // ///////////////////////////////////////////////////////////////////// - // access - // ///////////////////////////////////////////////////////////////////// - - /** - * Returns whether the highest bit of the bit representation is set - * - * @return true, if the highest bit of mPol is set, false, otherwise - */ - public boolean testRightmostBit() - { - // due to the reverse bit order (compared to 1363) this method returns - // the value of the leftmost bit - return (mPol[mLength - 1] & mBitmask[mBit - 1]) != 0L; - } - - /** - * Checks whether the indexed bit of the bit representation is set. Warning: - * GF2nONBElement currently stores its bits in reverse order (compared to - * 1363) !!! - * - * @param index the index of the bit to test - * @return <tt>true</tt> if the indexed bit of mPol is set, <tt>false</tt> - * otherwise. - */ - boolean testBit(int index) - { - if (index < 0 || index > mDegree) - { - return false; - } - long test = mPol[index >>> 6] & mBitmask[index & 0x3f]; - return test != 0x0L; - } - - /** - * @return this element in its ONB representation - */ - private long[] getElement() - { - - long[] result = new long[mPol.length]; - System.arraycopy(mPol, 0, result, 0, mPol.length); - - return result; - } - - /** - * Returns the ONB representation of this element. The Bit-Order is - * exchanged (according to 1363)! - * - * @return this element in its representation and reverse bit-order - */ - private long[] getElementReverseOrder() - { - long[] result = new long[mPol.length]; - for (int i = 0; i < mDegree; i++) - { - if (testBit(mDegree - i - 1)) - { - result[i >>> 6] |= mBitmask[i & 0x3f]; - } - } - return result; - } - - /** - * Reverses the bit-order in this element(according to 1363). This is a - * hack! - */ - void reverseOrder() - { - mPol = getElementReverseOrder(); - } - - // ///////////////////////////////////////////////////////////////////// - // arithmetic - // ///////////////////////////////////////////////////////////////////// - - /** - * Compute the sum of this element and <tt>addend</tt>. - * - * @param addend the addend - * @return <tt>this + other</tt> (newly created) - * @throws DifferentFieldsException if the elements are of different fields. - */ - public GFElement add(GFElement addend) - throws RuntimeException - { - GF2nONBElement result = new GF2nONBElement(this); - result.addToThis(addend); - return result; - } - - /** - * Compute <tt>this + addend</tt> (overwrite <tt>this</tt>). - * - * @param addend the addend - * @throws DifferentFieldsException if the elements are of different fields. - */ - public void addToThis(GFElement addend) - throws RuntimeException - { - if (!(addend instanceof GF2nONBElement)) - { - throw new RuntimeException(); - } - if (!mField.equals(((GF2nONBElement)addend).mField)) - { - throw new RuntimeException(); - } - - for (int i = 0; i < mLength; i++) - { - mPol[i] ^= ((GF2nONBElement)addend).mPol[i]; - } - } - - /** - * returns <tt>this</tt> element + 1. - * - * @return <tt>this</tt> + 1 - */ - public GF2nElement increase() - { - GF2nONBElement result = new GF2nONBElement(this); - result.increaseThis(); - return result; - } - - /** - * increases <tt>this</tt> element. - */ - public void increaseThis() - { - addToThis(ONE((GF2nONBField)mField)); - } - - /** - * Compute the product of this element and <tt>factor</tt>. - * - * @param factor the factor - * @return <tt>this * factor</tt> (newly created) - * @throws DifferentFieldsException if the elements are of different fields. - */ - public GFElement multiply(GFElement factor) - throws RuntimeException - { - GF2nONBElement result = new GF2nONBElement(this); - result.multiplyThisBy(factor); - return result; - } - - /** - * Compute <tt>this * factor</tt> (overwrite <tt>this</tt>). - * - * @param factor the factor - * @throws DifferentFieldsException if the elements are of different fields. - */ - public void multiplyThisBy(GFElement factor) - throws RuntimeException - { - - if (!(factor instanceof GF2nONBElement)) - { - throw new RuntimeException("The elements have different" - + " representation: not yet" + " implemented"); - } - if (!mField.equals(((GF2nONBElement)factor).mField)) - { - throw new RuntimeException(); - } - - if (equals(factor)) - { - squareThis(); - } - else - { - - long[] a = mPol; - long[] b = ((GF2nONBElement)factor).mPol; - long[] c = new long[mLength]; - - int[][] m = ((GF2nONBField)mField).mMult; - - int degf, degb, s, fielda, fieldb, bita, bitb; - degf = mLength - 1; - degb = mBit - 1; - s = 0; - - long TWOTOMAXLONGM1 = mBitmask[MAXLONG - 1]; - long TWOTODEGB = mBitmask[degb]; - - boolean old, now; - - // the product c of a and b (a*b = c) is calculated in mDegree - // cicles - // in every cicle one coefficient of c is calculated and stored - // k indicates the coefficient - // - for (int k = 0; k < mDegree; k++) - { - - s = 0; - - for (int i = 0; i < mDegree; i++) - { - - // fielda = i / MAXLONG - // - fielda = mIBY64[i]; - - // bita = i % MAXLONG - // - bita = i & (MAXLONG - 1); - - // fieldb = m[i][0] / MAXLONG - // - fieldb = mIBY64[m[i][0]]; - - // bitb = m[i][0] % MAXLONG - // - bitb = m[i][0] & (MAXLONG - 1); - - if ((a[fielda] & mBitmask[bita]) != 0) - { - - if ((b[fieldb] & mBitmask[bitb]) != 0) - { - s ^= 1; - } - - if (m[i][1] != -1) - { - - // fieldb = m[i][1] / MAXLONG - // - fieldb = mIBY64[m[i][1]]; - - // bitb = m[i][1] % MAXLONG - // - bitb = m[i][1] & (MAXLONG - 1); - - if ((b[fieldb] & mBitmask[bitb]) != 0) - { - s ^= 1; - } - - } - } - } - fielda = mIBY64[k]; - bita = k & (MAXLONG - 1); - - if (s != 0) - { - c[fielda] ^= mBitmask[bita]; - } - - // Circular shift of x and y one bit to the right, - // respectively. - - if (mLength > 1) - { - - // Shift x. - // - old = (a[degf] & 1) == 1; - - for (int i = degf - 1; i >= 0; i--) - { - now = (a[i] & 1) != 0; - - a[i] = a[i] >>> 1; - - if (old) - { - a[i] ^= TWOTOMAXLONGM1; - } - - old = now; - } - a[degf] = a[degf] >>> 1; - - if (old) - { - a[degf] ^= TWOTODEGB; - } - - // Shift y. - // - old = (b[degf] & 1) == 1; - - for (int i = degf - 1; i >= 0; i--) - { - now = (b[i] & 1) != 0; - - b[i] = b[i] >>> 1; - - if (old) - { - b[i] ^= TWOTOMAXLONGM1; - } - - old = now; - } - - b[degf] = b[degf] >>> 1; - - if (old) - { - b[degf] ^= TWOTODEGB; - } - } - else - { - old = (a[0] & 1) == 1; - a[0] = a[0] >>> 1; - - if (old) - { - a[0] ^= TWOTODEGB; - } - - old = (b[0] & 1) == 1; - b[0] = b[0] >>> 1; - - if (old) - { - b[0] ^= TWOTODEGB; - } - } - } - assign(c); - } - } - - /** - * returns <tt>this</tt> element to the power of 2. - * - * @return <tt>this</tt><sup>2</sup> - */ - public GF2nElement square() - { - GF2nONBElement result = new GF2nONBElement(this); - result.squareThis(); - return result; - } - - /** - * squares <tt>this</tt> element. - */ - public void squareThis() - { - - long[] pol = getElement(); - - int f = mLength - 1; - int b = mBit - 1; - - // Shift the coefficients one bit to the left. - // - long TWOTOMAXLONGM1 = mBitmask[MAXLONG - 1]; - boolean old, now; - - old = (pol[f] & mBitmask[b]) != 0; - - for (int i = 0; i < f; i++) - { - - now = (pol[i] & TWOTOMAXLONGM1) != 0; - - pol[i] = pol[i] << 1; - - if (old) - { - pol[i] ^= 1; - } - - old = now; - } - now = (pol[f] & mBitmask[b]) != 0; - - pol[f] = pol[f] << 1; - - if (old) - { - pol[f] ^= 1; - } - - // Set the bit with index mDegree to zero. - // - if (now) - { - pol[f] ^= mBitmask[b + 1]; - } - - assign(pol); - } - - /** - * Compute the multiplicative inverse of this element. - * - * @return <tt>this<sup>-1</sup></tt> (newly created) - * @throws ArithmeticException if <tt>this</tt> is the zero element. - */ - public GFElement invert() - throws ArithmeticException - { - GF2nONBElement result = new GF2nONBElement(this); - result.invertThis(); - return result; - } - - /** - * Multiplicatively invert of this element (overwrite <tt>this</tt>). - * - * @throws ArithmeticException if <tt>this</tt> is the zero element. - */ - public void invertThis() - throws ArithmeticException - { - - if (isZero()) - { - throw new ArithmeticException(); - } - int r = 31; // mDegree kann nur 31 Bits lang sein!!! - - // Bitlaenge von mDegree: - for (boolean found = false; !found && r >= 0; r--) - { - - if (((mDegree - 1) & mBitmask[r]) != 0) - { - found = true; - } - } - r++; - - GF2nElement m = ZERO((GF2nONBField)mField); - GF2nElement n = new GF2nONBElement(this); - - int k = 1; - - for (int i = r - 1; i >= 0; i--) - { - m = (GF2nElement)n.clone(); - for (int j = 1; j <= k; j++) - { - m.squareThis(); - } - - n.multiplyThisBy(m); - - k <<= 1; - if (((mDegree - 1) & mBitmask[i]) != 0) - { - n.squareThis(); - - n.multiplyThisBy(this); - - k++; - } - } - n.squareThis(); - } - - /** - * returns the root of<tt>this</tt> element. - * - * @return <tt>this</tt><sup>1/2</sup> - */ - public GF2nElement squareRoot() - { - GF2nONBElement result = new GF2nONBElement(this); - result.squareRootThis(); - return result; - } - - /** - * square roots <tt>this</tt> element. - */ - public void squareRootThis() - { - - long[] pol = getElement(); - - int f = mLength - 1; - int b = mBit - 1; - - // Shift the coefficients one bit to the right. - // - long TWOTOMAXLONGM1 = mBitmask[MAXLONG - 1]; - boolean old, now; - - old = (pol[0] & 1) != 0; - - for (int i = f; i >= 0; i--) - { - now = (pol[i] & 1) != 0; - pol[i] = pol[i] >>> 1; - - if (old) - { - if (i == f) - { - pol[i] ^= mBitmask[b]; - } - else - { - pol[i] ^= TWOTOMAXLONGM1; - } - } - old = now; - } - assign(pol); - } - - /** - * Returns the trace of this element. - * - * @return the trace of this element - */ - public int trace() - { - - // trace = sum of coefficients - // - - int result = 0; - - int max = mLength - 1; - - for (int i = 0; i < max; i++) - { - - for (int j = 0; j < MAXLONG; j++) - { - - if ((mPol[i] & mBitmask[j]) != 0) - { - result ^= 1; - } - } - } - - int b = mBit; - - for (int j = 0; j < b; j++) - { - - if ((mPol[max] & mBitmask[j]) != 0) - { - result ^= 1; - } - } - return result; - } - - /** - * Solves a quadratic equation.<br> - * Let z<sup>2</sup> + z = <tt>this</tt>. Then this method returns z. - * - * @return z with z<sup>2</sup> + z = <tt>this</tt> - * @throws NoSolutionException if z<sup>2</sup> + z = <tt>this</tt> does not have a - * solution - */ - public GF2nElement solveQuadraticEquation() - throws RuntimeException - { - - if (trace() == 1) - { - throw new RuntimeException(); - } - - long TWOTOMAXLONGM1 = mBitmask[MAXLONG - 1]; - long ZERO = 0L; - long ONE = 1L; - - long[] p = new long[mLength]; - long z = 0L; - int j = 1; - for (int i = 0; i < mLength - 1; i++) - { - - for (j = 1; j < MAXLONG; j++) - { - - // - if (!((((mBitmask[j] & mPol[i]) != ZERO) && ((z & mBitmask[j - 1]) != ZERO)) || (((mPol[i] & mBitmask[j]) == ZERO) && ((z & mBitmask[j - 1]) == ZERO)))) - { - z ^= mBitmask[j]; - } - } - p[i] = z; - - if (((TWOTOMAXLONGM1 & z) != ZERO && (ONE & mPol[i + 1]) == ONE) - || ((TWOTOMAXLONGM1 & z) == ZERO && (ONE & mPol[i + 1]) == ZERO)) - { - z = ZERO; - } - else - { - z = ONE; - } - } - - int b = mDegree & (MAXLONG - 1); - - long LASTLONG = mPol[mLength - 1]; - - for (j = 1; j < b; j++) - { - if (!((((mBitmask[j] & LASTLONG) != ZERO) && ((mBitmask[j - 1] & z) != ZERO)) || (((mBitmask[j] & LASTLONG) == ZERO) && ((mBitmask[j - 1] & z) == ZERO)))) - { - z ^= mBitmask[j]; - } - } - p[mLength - 1] = z; - return new GF2nONBElement((GF2nONBField)mField, p); - } - - // ///////////////////////////////////////////////////////////////// - // conversion - // ///////////////////////////////////////////////////////////////// - - /** - * Returns a String representation of this element. - * - * @return String representation of this element with the specified radix - */ - public String toString() - { - return toString(16); - } - - /** - * Returns a String representation of this element. <tt>radix</tt> - * specifies the radix of the String representation.<br> - * NOTE: ONLY <tt>radix = 2</tt> or <tt>radix = 16</tt> IS IMPLEMENTED - * - * @param radix specifies the radix of the String representation - * @return String representation of this element with the specified radix - */ - public String toString(int radix) - { - String s = ""; - - long[] a = getElement(); - int b = mBit; - - if (radix == 2) - { - - for (int j = b - 1; j >= 0; j--) - { - if ((a[a.length - 1] & ((long)1 << j)) == 0) - { - s += "0"; - } - else - { - s += "1"; - } - } - - for (int i = a.length - 2; i >= 0; i--) - { - for (int j = MAXLONG - 1; j >= 0; j--) - { - if ((a[i] & mBitmask[j]) == 0) - { - s += "0"; - } - else - { - s += "1"; - } - } - } - } - else if (radix == 16) - { - final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - for (int i = a.length - 1; i >= 0; i--) - { - s += HEX_CHARS[(int)(a[i] >>> 60) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 56) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 52) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 48) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 44) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 40) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 36) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 32) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 28) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 24) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 20) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 16) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 12) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 8) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 4) & 0x0f]; - s += HEX_CHARS[(int)(a[i]) & 0x0f]; - s += " "; - } - } - return s; - } - - /** - * Returns this element as FlexiBigInt. The conversion is <a href = - * "http://grouper.ieee.org/groups/1363/">P1363</a>-conform. - * - * @return this element as BigInteger - */ - public BigInteger toFlexiBigInt() - { - /** @todo this method does not reverse the bit-order as it should!!! */ - - return new BigInteger(1, toByteArray()); - } - - /** - * Returns this element as byte array. The conversion is <a href = - * "http://grouper.ieee.org/groups/1363/">P1363</a>-conform. - * - * @return this element as byte array - */ - public byte[] toByteArray() - { - /** @todo this method does not reverse the bit-order as it should!!! */ - - int k = ((mDegree - 1) >> 3) + 1; - byte[] result = new byte[k]; - int i; - for (i = 0; i < k; i++) - { - result[k - i - 1] = (byte)((mPol[i >>> 3] & (0x00000000000000ffL << ((i & 0x07) << 3))) >>> ((i & 0x07) << 3)); - } - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nONBField.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nONBField.java deleted file mode 100644 index 1e4c8b26..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nONBField.java +++ /dev/null @@ -1,546 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - - -import java.util.Random; -import java.util.Vector; - - -/** - * This class implements the abstract class <tt>GF2nField</tt> for ONB - * representation. It computes the fieldpolynomial, multiplication matrix and - * one of its roots mONBRoot, (see for example <a - * href=http://www2.certicom.com/ecc/intro.htm>Certicoms Whitepapers</a>). - * GF2nField is used by GF2nONBElement which implements the elements of this - * field. - * - * @see GF2nField - * @see GF2nONBElement - */ -public class GF2nONBField - extends GF2nField -{ - - // /////////////////////////////////////////////////////////////////// - // Hashtable for irreducible normal polynomials // - // /////////////////////////////////////////////////////////////////// - - // i*5 + 0 i*5 + 1 i*5 + 2 i*5 + 3 i*5 + 4 - /* - * private static int[][] mNB = {{0, 0, 0}, {0, 0, 0}, {1, 0, 0}, {1, 0, 0}, - * {1, 0, 0}, // i = 0 {2, 0, 0}, {1, 0, 0}, {1, 0, 0}, {4, 3, 1}, {1, 0, - * 0}, // i = 1 {3, 0, 0}, {2, 0, 0}, {3, 0, 0}, {4, 3, 1}, {5, 0, 0}, // i = - * 2 {1, 0, 0}, {5, 3, 1}, {3, 0, 0}, {3, 0, 0}, {5, 2, 1}, // i = 3 {3, 0, - * 0}, {2, 0, 0}, {1, 0, 0}, {5, 0, 0}, {4, 3, 1}, // i = 4 {3, 0, 0}, {4, - * 3, 1}, {5, 2, 1}, {1, 0, 0}, {2, 0, 0}, // i = 5 {1, 0, 0}, {3, 0, 0}, - * {7, 3, 2}, {10, 0, 0}, {7, 0, 0}, // i = 6 {2, 0, 0}, {9, 0, 0}, {6, 4, - * 1}, {6, 5, 1}, {4, 0, 0}, // i = 7 {5, 4, 3}, {3, 0, 0}, {7, 0, 0}, {6, - * 4, 3}, {5, 0, 0}, // i = 8 {4, 3, 1}, {1, 0, 0}, {5, 0, 0}, {5, 3, 2}, - * {9, 0, 0}, // i = 9 {4, 3, 2}, {6, 3, 1}, {3, 0, 0}, {6, 2, 1}, {9, 0, - * 0}, // i = 10 {7, 0, 0}, {7, 4, 2}, {4, 0, 0}, {19, 0, 0}, {7, 4, 2}, // - * i = 11 {1, 0, 0}, {5, 2, 1}, {29, 0, 0}, {1, 0, 0}, {4, 3, 1}, // i = 12 - * {18, 0, 0}, {3, 0, 0}, {5, 2, 1}, {9, 0, 0}, {6, 5, 2}, // i = 13 {5, 3, - * 1}, {6, 0, 0}, {10, 9, 3}, {25, 0, 0}, {35, 0, 0}, // i = 14 {6, 3, 1}, - * {21, 0, 0}, {6, 5, 2}, {6, 5, 3}, {9, 0, 0}, // i = 15 {9, 4, 2}, {4, 0, - * 0}, {8, 3, 1}, {7, 4, 2}, {5, 0, 0}, // i = 16 {8, 2, 1}, {21, 0, 0}, - * {13, 0, 0}, {7, 6, 2}, {38, 0, 0}, // i = 17 {27, 0, 0}, {8, 5, 1}, {21, - * 0, 0}, {2, 0, 0}, {21, 0, 0}, // i = 18 {11, 0, 0}, {10, 9, 6}, {6, 0, - * 0}, {11, 0, 0}, {6, 3, 1}, // i = 19 {15, 0, 0}, {7, 6, 1}, {29, 0, 0}, - * {9, 0, 0}, {4, 3, 1}, // i = 20 {4, 0, 0}, {15, 0, 0}, {9, 7, 4}, {17, 0, - * 0}, {5, 4, 2}, // i = 21 {33, 0, 0}, {10, 0, 0}, {5, 4, 3}, {9, 0, 0}, - * {5, 3, 2}, // i = 22 {8, 7, 5}, {4, 2, 1}, {5, 2, 1}, {33, 0, 0}, {8, 0, - * 0}, // i = 23 {4, 3, 1}, {18, 0, 0}, {6, 2, 1}, {2, 0, 0}, {19, 0, 0}, // - * i = 24 {7, 6, 5}, {21, 0, 0}, {1, 0, 0}, {7, 2, 1}, {5, 0, 0}, // i = 25 - * {3, 0, 0}, {8, 3, 2}, {17, 0, 0}, {9, 8, 2}, {57, 0, 0}, // i = 26 {11, - * 0, 0}, {5, 3, 2}, {21, 0, 0}, {8, 7, 1}, {8, 5, 3}, // i = 27 {15, 0, 0}, - * {10, 4, 1}, {21, 0, 0}, {5, 3, 2}, {7, 4, 2}, // i = 28 {52, 0, 0}, {71, - * 0, 0}, {14, 0, 0}, {27, 0, 0}, {10, 9, 7}, // i = 29 {53, 0, 0}, {3, 0, - * 0}, {6, 3, 2}, {1, 0, 0}, {15, 0, 0}, // i = 30 {62, 0, 0}, {9, 0, 0}, - * {6, 5, 2}, {8, 6, 5}, {31, 0, 0}, // i = 31 {5, 3, 2}, {18, 0, 0 }, {27, - * 0, 0}, {7, 6, 3}, {10, 8, 7}, // i = 32 {9, 8, 3}, {37, 0, 0}, {6, 0, 0}, - * {15, 3, 2}, {34, 0, 0}, // i = 33 {11, 0, 0}, {6, 5, 2}, {1, 0, 0}, {8, - * 5, 2}, {13, 0, 0}, // i = 34 {6, 0, 0}, {11, 3, 2}, {8, 0, 0}, {31, 0, - * 0}, {4, 2, 1}, // i = 35 {3, 0, 0}, {7, 6, 1}, {81, 0, 0}, {56, 0, 0}, - * {9, 8, 7}, // i = 36 {24, 0, 0}, {11, 0, 0}, {7, 6, 5}, {6, 5, 2}, {6, 5, - * 2}, // i = 37 {8, 7, 6}, {9, 0, 0}, {7, 2, 1}, {15, 0, 0}, {87, 0, 0}, // - * i = 38 {8, 3, 2}, {3, 0, 0}, {9, 4, 2}, {9, 0, 0}, {34, 0, 0}, // i = 39 - * {5, 3, 2}, {14, 0, 0}, {55, 0, 0}, {8, 7, 1}, {27, 0, 0}, // i = 40 {9, - * 5, 2}, {10, 9, 5}, {43, 0, 0}, {8, 6, 2}, {6, 0, 0}, // i = 41 {7, 0, 0}, - * {11, 10, 8}, {105, 0, 0}, {6, 5, 2}, {73, 0, 0}}; // i = 42 - */ - // ///////////////////////////////////////////////////////////////////// - // member variables - // ///////////////////////////////////////////////////////////////////// - private static final int MAXLONG = 64; - - /** - * holds the length of the array-representation of degree mDegree. - */ - private int mLength; - - /** - * holds the number of relevant bits in mONBPol[mLength-1]. - */ - private int mBit; - - /** - * holds the type of mONB - */ - private int mType; - - /** - * holds the multiplication matrix - */ - int[][] mMult; - - // ///////////////////////////////////////////////////////////////////// - // constructors - // ///////////////////////////////////////////////////////////////////// - - /** - * constructs an instance of the finite field with 2<sup>deg</sup> - * elements and characteristic 2. - * - * @param deg - - * the extention degree of this field - * @throws NoSuchBasisException if an ONB-implementation other than type 1 or type 2 is - * requested. - */ - public GF2nONBField(int deg) - throws RuntimeException - { - if (deg < 3) - { - throw new IllegalArgumentException("k must be at least 3"); - } - - mDegree = deg; - mLength = mDegree / MAXLONG; - mBit = mDegree & (MAXLONG - 1); - if (mBit == 0) - { - mBit = MAXLONG; - } - else - { - mLength++; - } - - computeType(); - - // only ONB-implementations for type 1 and type 2 - // - if (mType < 3) - { - mMult = new int[mDegree][2]; - for (int i = 0; i < mDegree; i++) - { - mMult[i][0] = -1; - mMult[i][1] = -1; - } - computeMultMatrix(); - } - else - { - throw new RuntimeException("\nThe type of this field is " - + mType); - } - computeFieldPolynomial(); - fields = new Vector(); - matrices = new Vector(); - } - - // ///////////////////////////////////////////////////////////////////// - // access - // ///////////////////////////////////////////////////////////////////// - - int getONBLength() - { - return mLength; - } - - int getONBBit() - { - return mBit; - } - - // ///////////////////////////////////////////////////////////////////// - // arithmetic - // ///////////////////////////////////////////////////////////////////// - - /** - * Computes a random root of the given polynomial. - * - * @param polynomial a polynomial - * @return a random root of the polynomial - * @see "P1363 A.5.6, p103f" - */ - protected GF2nElement getRandomRoot(GF2Polynomial polynomial) - { - // We are in B1!!! - GF2nPolynomial c; - GF2nPolynomial ut; - GF2nElement u; - GF2nPolynomial h; - int hDegree; - // 1. Set g(t) <- f(t) - GF2nPolynomial g = new GF2nPolynomial(polynomial, this); - int gDegree = g.getDegree(); - int i; - - // 2. while deg(g) > 1 - while (gDegree > 1) - { - do - { - // 2.1 choose random u (element of) GF(2^m) - u = new GF2nONBElement(this, new Random()); - ut = new GF2nPolynomial(2, GF2nONBElement.ZERO(this)); - // 2.2 Set c(t) <- ut - ut.set(1, u); - c = new GF2nPolynomial(ut); - // 2.3 For i from 1 to m-1 do - for (i = 1; i <= mDegree - 1; i++) - { - // 2.3.1 c(t) <- (c(t)^2 + ut) mod g(t) - c = c.multiplyAndReduce(c, g); - c = c.add(ut); - } - // 2.4 set h(t) <- GCD(c(t), g(t)) - h = c.gcd(g); - // 2.5 if h(t) is constant or deg(g) = deg(h) then go to - // step 2.1 - hDegree = h.getDegree(); - gDegree = g.getDegree(); - } - while ((hDegree == 0) || (hDegree == gDegree)); - // 2.6 If 2deg(h) > deg(g) then set g(t) <- g(t)/h(t) ... - if ((hDegree << 1) > gDegree) - { - g = g.quotient(h); - } - else - { - // ... else g(t) <- h(t) - g = new GF2nPolynomial(h); - } - gDegree = g.getDegree(); - } - // 3. Output g(0) - return g.at(0); - - } - - /** - * Computes the change-of-basis matrix for basis conversion according to - * 1363. The result is stored in the lists fields and matrices. - * - * @param B1 the GF2nField to convert to - * @see "P1363 A.7.3, p111ff" - */ - protected void computeCOBMatrix(GF2nField B1) - { - // we are in B0 here! - if (mDegree != B1.mDegree) - { - throw new IllegalArgumentException( - "GF2nField.computeCOBMatrix: B1 has a " - + "different degree and thus cannot be coverted to!"); - } - int i, j; - GF2nElement[] gamma; - GF2nElement u; - GF2Polynomial[] COBMatrix = new GF2Polynomial[mDegree]; - for (i = 0; i < mDegree; i++) - { - COBMatrix[i] = new GF2Polynomial(mDegree); - } - - // find Random Root - do - { - // u is in representation according to B1 - u = B1.getRandomRoot(fieldPolynomial); - } - while (u.isZero()); - - gamma = new GF2nPolynomialElement[mDegree]; - // build gamma matrix by squaring - gamma[0] = (GF2nElement)u.clone(); - for (i = 1; i < mDegree; i++) - { - gamma[i] = gamma[i - 1].square(); - } - // convert horizontal gamma matrix by vertical Bitstrings - for (i = 0; i < mDegree; i++) - { - for (j = 0; j < mDegree; j++) - { - if (gamma[i].testBit(j)) - { - COBMatrix[mDegree - j - 1].setBit(mDegree - i - 1); - } - } - } - - fields.addElement(B1); - matrices.addElement(COBMatrix); - B1.fields.addElement(this); - B1.matrices.addElement(invertMatrix(COBMatrix)); - } - - /** - * Computes the field polynomial for a ONB according to IEEE 1363 A.7.2 - * (p110f). - * - * @see "P1363 A.7.2, p110f" - */ - protected void computeFieldPolynomial() - { - if (mType == 1) - { - fieldPolynomial = new GF2Polynomial(mDegree + 1, "ALL"); - } - else if (mType == 2) - { - // 1. q = 1 - GF2Polynomial q = new GF2Polynomial(mDegree + 1, "ONE"); - // 2. p = t+1 - GF2Polynomial p = new GF2Polynomial(mDegree + 1, "X"); - p.addToThis(q); - GF2Polynomial r; - int i; - // 3. for i = 1 to (m-1) do - for (i = 1; i < mDegree; i++) - { - // r <- q - r = q; - // q <- p - q = p; - // p = tq+r - p = q.shiftLeft(); - p.addToThis(r); - } - fieldPolynomial = p; - } - } - - /** - * Compute the inverse of a matrix <tt>a</tt>. - * - * @param a the matrix - * @return <tt>a<sup>-1</sup></tt> - */ - int[][] invMatrix(int[][] a) - { - - int[][] A = new int[mDegree][mDegree]; - A = a; - int[][] inv = new int[mDegree][mDegree]; - - for (int i = 0; i < mDegree; i++) - { - inv[i][i] = 1; - } - - for (int i = 0; i < mDegree; i++) - { - for (int j = i; j < mDegree; j++) - { - A[mDegree - 1 - i][j] = A[i][i]; - } - } - return null; - } - - private void computeType() - throws RuntimeException - { - if ((mDegree & 7) == 0) - { - throw new RuntimeException( - "The extension degree is divisible by 8!"); - } - // checking for the type - int s = 0; - int k = 0; - mType = 1; - for (int d = 0; d != 1; mType++) - { - s = mType * mDegree + 1; - if (IntegerFunctions.isPrime(s)) - { - k = IntegerFunctions.order(2, s); - d = IntegerFunctions.gcd(mType * mDegree / k, mDegree); - } - } - mType--; - if (mType == 1) - { - s = (mDegree << 1) + 1; - if (IntegerFunctions.isPrime(s)) - { - k = IntegerFunctions.order(2, s); - int d = IntegerFunctions.gcd((mDegree << 1) / k, mDegree); - if (d == 1) - { - mType++; - } - } - } - } - - private void computeMultMatrix() - { - - if ((mType & 7) != 0) - { - int p = mType * mDegree + 1; - - // compute sequence F[1] ... F[p-1] via A.3.7. of 1363. - // F[0] will not be filled! - // - int[] F = new int[p]; - - int u; - if (mType == 1) - { - u = 1; - } - else if (mType == 2) - { - u = p - 1; - } - else - { - u = elementOfOrder(mType, p); - } - - int w = 1; - int n; - for (int j = 0; j < mType; j++) - { - n = w; - - for (int i = 0; i < mDegree; i++) - { - F[n] = i; - n = (n << 1) % p; - if (n < 0) - { - n += p; - } - } - w = u * w % p; - if (w < 0) - { - w += p; - } - } - - // building the matrix (mDegree * 2) - // - if (mType == 1) - { - for (int k = 1; k < p - 1; k++) - { - if (mMult[F[k + 1]][0] == -1) - { - mMult[F[k + 1]][0] = F[p - k]; - } - else - { - mMult[F[k + 1]][1] = F[p - k]; - } - } - - int m_2 = mDegree >> 1; - for (int k = 1; k <= m_2; k++) - { - - if (mMult[k - 1][0] == -1) - { - mMult[k - 1][0] = m_2 + k - 1; - } - else - { - mMult[k - 1][1] = m_2 + k - 1; - } - - if (mMult[m_2 + k - 1][0] == -1) - { - mMult[m_2 + k - 1][0] = k - 1; - } - else - { - mMult[m_2 + k - 1][1] = k - 1; - } - } - } - else if (mType == 2) - { - for (int k = 1; k < p - 1; k++) - { - if (mMult[F[k + 1]][0] == -1) - { - mMult[F[k + 1]][0] = F[p - k]; - } - else - { - mMult[F[k + 1]][1] = F[p - k]; - } - } - } - else - { - throw new RuntimeException("only type 1 or type 2 implemented"); - } - } - else - { - throw new RuntimeException("bisher nur fuer Gausssche Normalbasen" - + " implementiert"); - } - } - - private int elementOfOrder(int k, int p) - { - Random random = new Random(); - int m = 0; - while (m == 0) - { - m = random.nextInt(); - m %= p - 1; - if (m < 0) - { - m += p - 1; - } - } - - int l = IntegerFunctions.order(m, p); - - while (l % k != 0 || l == 0) - { - while (m == 0) - { - m = random.nextInt(); - m %= p - 1; - if (m < 0) - { - m += p - 1; - } - } - l = IntegerFunctions.order(m, p); - } - int r = m; - - l = k / l; - - for (int i = 2; i <= l; i++) - { - r *= m; - } - - return r; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nPolynomial.java deleted file mode 100644 index f122be03..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nPolynomial.java +++ /dev/null @@ -1,587 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - - -/** - * This class implements polynomials over GF2nElements. - * - * @see GF2nElement - */ - -public class GF2nPolynomial -{ - - private GF2nElement[] coeff; // keeps the coefficients of this polynomial - - private int size; // the size of this polynomial - - /** - * Creates a new PolynomialGF2n of size <i>deg</i> and elem as - * coefficients. - * - * @param deg - - * the maximum degree + 1 - * @param elem - - * a GF2nElement - */ - public GF2nPolynomial(int deg, GF2nElement elem) - { - size = deg; - coeff = new GF2nElement[size]; - for (int i = 0; i < size; i++) - { - coeff[i] = (GF2nElement)elem.clone(); - } - } - - /** - * Creates a new PolynomialGF2n of size <i>deg</i>. - * - * @param deg the maximum degree + 1 - */ - private GF2nPolynomial(int deg) - { - size = deg; - coeff = new GF2nElement[size]; - } - - /** - * Creates a new PolynomialGF2n by cloning the given PolynomialGF2n <i>a</i>. - * - * @param a the PolynomialGF2n to clone - */ - public GF2nPolynomial(GF2nPolynomial a) - { - int i; - coeff = new GF2nElement[a.size]; - size = a.size; - for (i = 0; i < size; i++) - { - coeff[i] = (GF2nElement)a.coeff[i].clone(); - } - } - - /** - * Creates a new PolynomialGF2n from the given Bitstring <i>polynomial</i> - * over the GF2nField <i>B1</i>. - * - * @param polynomial the Bitstring to use - * @param B1 the field - */ - public GF2nPolynomial(GF2Polynomial polynomial, GF2nField B1) - { - size = B1.getDegree() + 1; - coeff = new GF2nElement[size]; - int i; - if (B1 instanceof GF2nONBField) - { - for (i = 0; i < size; i++) - { - if (polynomial.testBit(i)) - { - coeff[i] = GF2nONBElement.ONE((GF2nONBField)B1); - } - else - { - coeff[i] = GF2nONBElement.ZERO((GF2nONBField)B1); - } - } - } - else if (B1 instanceof GF2nPolynomialField) - { - for (i = 0; i < size; i++) - { - if (polynomial.testBit(i)) - { - coeff[i] = GF2nPolynomialElement - .ONE((GF2nPolynomialField)B1); - } - else - { - coeff[i] = GF2nPolynomialElement - .ZERO((GF2nPolynomialField)B1); - } - } - } - else - { - throw new IllegalArgumentException( - "PolynomialGF2n(Bitstring, GF2nField): B1 must be " - + "an instance of GF2nONBField or GF2nPolynomialField!"); - } - } - - public final void assignZeroToElements() - { - int i; - for (i = 0; i < size; i++) - { - coeff[i].assignZero(); - } - } - - /** - * Returns the size (=maximum degree + 1) of this PolynomialGF2n. This is - * not the degree, use getDegree instead. - * - * @return the size (=maximum degree + 1) of this PolynomialGF2n. - */ - public final int size() - { - return size; - } - - /** - * Returns the degree of this PolynomialGF2n. - * - * @return the degree of this PolynomialGF2n. - */ - public final int getDegree() - { - int i; - for (i = size - 1; i >= 0; i--) - { - if (!coeff[i].isZero()) - { - return i; - } - } - return -1; - } - - /** - * Enlarges the size of this PolynomialGF2n to <i>k</i> + 1. - * - * @param k the new maximum degree - */ - public final void enlarge(int k) - { - if (k <= size) - { - return; - } - int i; - GF2nElement[] res = new GF2nElement[k]; - System.arraycopy(coeff, 0, res, 0, size); - GF2nField f = coeff[0].getField(); - if (coeff[0] instanceof GF2nPolynomialElement) - { - for (i = size; i < k; i++) - { - res[i] = GF2nPolynomialElement.ZERO((GF2nPolynomialField)f); - } - } - else if (coeff[0] instanceof GF2nONBElement) - { - for (i = size; i < k; i++) - { - res[i] = GF2nONBElement.ZERO((GF2nONBField)f); - } - } - size = k; - coeff = res; - } - - public final void shrink() - { - int i = size - 1; - while (coeff[i].isZero() && (i > 0)) - { - i--; - } - i++; - if (i < size) - { - GF2nElement[] res = new GF2nElement[i]; - System.arraycopy(coeff, 0, res, 0, i); - coeff = res; - size = i; - } - } - - /** - * Sets the coefficient at <i>index</i> to <i>elem</i>. - * - * @param index the index - * @param elem the GF2nElement to store as coefficient <i>index</i> - */ - public final void set(int index, GF2nElement elem) - { - if (!(elem instanceof GF2nPolynomialElement) - && !(elem instanceof GF2nONBElement)) - { - throw new IllegalArgumentException( - "PolynomialGF2n.set f must be an " - + "instance of either GF2nPolynomialElement or GF2nONBElement!"); - } - coeff[index] = (GF2nElement)elem.clone(); - } - - /** - * Returns the coefficient at <i>index</i>. - * - * @param index the index - * @return the GF2nElement stored as coefficient <i>index</i> - */ - public final GF2nElement at(int index) - { - return coeff[index]; - } - - /** - * Returns true if all coefficients equal zero. - * - * @return true if all coefficients equal zero. - */ - public final boolean isZero() - { - int i; - for (i = 0; i < size; i++) - { - if (coeff[i] != null) - { - if (!coeff[i].isZero()) - { - return false; - } - } - } - return true; - } - - public final boolean equals(Object other) - { - if (other == null || !(other instanceof GF2nPolynomial)) - { - return false; - } - - GF2nPolynomial otherPol = (GF2nPolynomial)other; - - if (getDegree() != otherPol.getDegree()) - { - return false; - } - int i; - for (i = 0; i < size; i++) - { - if (!coeff[i].equals(otherPol.coeff[i])) - { - return false; - } - } - return true; - } - - /** - * @return the hash code of this polynomial - */ - public int hashCode() - { - return getDegree() + coeff.hashCode(); - } - - /** - * Adds the PolynomialGF2n <tt>b</tt> to <tt>this</tt> and returns the - * result in a new <tt>PolynomialGF2n</tt>. - * - * @param b - - * the <tt>PolynomialGF2n</tt> to add - * @return <tt>this + b</tt> - * @throws DifferentFieldsException if <tt>this</tt> and <tt>b</tt> are not defined over - * the same field. - */ - public final GF2nPolynomial add(GF2nPolynomial b) - throws RuntimeException - { - GF2nPolynomial result; - if (size() >= b.size()) - { - result = new GF2nPolynomial(size()); - int i; - for (i = 0; i < b.size(); i++) - { - result.coeff[i] = (GF2nElement)coeff[i].add(b.coeff[i]); - } - for (; i < size(); i++) - { - result.coeff[i] = coeff[i]; - } - } - else - { - result = new GF2nPolynomial(b.size()); - int i; - for (i = 0; i < size(); i++) - { - result.coeff[i] = (GF2nElement)coeff[i].add(b.coeff[i]); - } - for (; i < b.size(); i++) - { - result.coeff[i] = b.coeff[i]; - } - } - return result; - } - - /** - * Multiplies the scalar <i>s</i> to each coefficient of this - * PolynomialGF2n and returns the result in a new PolynomialGF2n. - * - * @param s the scalar to multiply - * @return <i>this</i> x <i>s</i> - * @throws DifferentFieldsException if <tt>this</tt> and <tt>s</tt> are not defined over - * the same field. - */ - public final GF2nPolynomial scalarMultiply(GF2nElement s) - throws RuntimeException - { - GF2nPolynomial result = new GF2nPolynomial(size()); - int i; - for (i = 0; i < size(); i++) - { - result.coeff[i] = (GF2nElement)coeff[i].multiply(s); // result[i] - // = - // a[i]*s - } - return result; - } - - /** - * Multiplies <i>this</i> by <i>b</i> and returns the result in a new - * PolynomialGF2n. - * - * @param b the PolynomialGF2n to multiply - * @return <i>this</i> * <i>b</i> - * @throws DifferentFieldsException if <tt>this</tt> and <tt>b</tt> are not defined over - * the same field. - */ - public final GF2nPolynomial multiply(GF2nPolynomial b) - throws RuntimeException - { - int i, j; - int aDegree = size(); - int bDegree = b.size(); - if (aDegree != bDegree) - { - throw new IllegalArgumentException( - "PolynomialGF2n.multiply: this and b must " - + "have the same size!"); - } - GF2nPolynomial result = new GF2nPolynomial((aDegree << 1) - 1); - for (i = 0; i < size(); i++) - { - for (j = 0; j < b.size(); j++) - { - if (result.coeff[i + j] == null) - { - result.coeff[i + j] = (GF2nElement)coeff[i] - .multiply(b.coeff[j]); - } - else - { - result.coeff[i + j] = (GF2nElement)result.coeff[i + j] - .add(coeff[i].multiply(b.coeff[j])); - } - } - } - return result; - } - - /** - * Multiplies <i>this</i> by <i>b</i>, reduces the result by <i>g</i> and - * returns it in a new PolynomialGF2n. - * - * @param b the PolynomialGF2n to multiply - * @param g the modul - * @return <i>this</i> * <i>b</i> mod <i>g</i> - * @throws DifferentFieldsException if <tt>this</tt>, <tt>b</tt> and <tt>g</tt> are - * not all defined over the same field. - */ - public final GF2nPolynomial multiplyAndReduce(GF2nPolynomial b, - GF2nPolynomial g) - throws RuntimeException, - ArithmeticException - { - return multiply(b).reduce(g); - } - - /** - * Reduces <i>this</i> by <i>g</i> and returns the result in a new - * PolynomialGF2n. - * - * @param g - - * the modulus - * @return <i>this</i> % <i>g</i> - * @throws DifferentFieldsException if <tt>this</tt> and <tt>g</tt> are not defined over - * the same field. - */ - public final GF2nPolynomial reduce(GF2nPolynomial g) - throws RuntimeException, ArithmeticException - { - return remainder(g); // return this % g - } - - /** - * Shifts left <i>this</i> by <i>amount</i> and stores the result in - * <i>this</i> PolynomialGF2n. - * - * @param amount the amount to shift the coefficients - */ - public final void shiftThisLeft(int amount) - { - if (amount > 0) - { - int i; - int oldSize = size; - GF2nField f = coeff[0].getField(); - enlarge(size + amount); - for (i = oldSize - 1; i >= 0; i--) - { - coeff[i + amount] = coeff[i]; - } - if (coeff[0] instanceof GF2nPolynomialElement) - { - for (i = amount - 1; i >= 0; i--) - { - coeff[i] = GF2nPolynomialElement - .ZERO((GF2nPolynomialField)f); - } - } - else if (coeff[0] instanceof GF2nONBElement) - { - for (i = amount - 1; i >= 0; i--) - { - coeff[i] = GF2nONBElement.ZERO((GF2nONBField)f); - } - } - } - } - - public final GF2nPolynomial shiftLeft(int amount) - { - if (amount <= 0) - { - return new GF2nPolynomial(this); - } - GF2nPolynomial result = new GF2nPolynomial(size + amount, coeff[0]); - result.assignZeroToElements(); - for (int i = 0; i < size; i++) - { - result.coeff[i + amount] = coeff[i]; - } - return result; - } - - /** - * Divides <i>this</i> by <i>b</i> and stores the result in a new - * PolynomialGF2n[2], quotient in result[0] and remainder in result[1]. - * - * @param b the divisor - * @return the quotient and remainder of <i>this</i> / <i>b</i> - * @throws DifferentFieldsException if <tt>this</tt> and <tt>b</tt> are not defined over - * the same field. - */ - public final GF2nPolynomial[] divide(GF2nPolynomial b) - throws RuntimeException, ArithmeticException - { - GF2nPolynomial[] result = new GF2nPolynomial[2]; - GF2nPolynomial a = new GF2nPolynomial(this); - a.shrink(); - GF2nPolynomial shift; - GF2nElement factor; - int bDegree = b.getDegree(); - GF2nElement inv = (GF2nElement)b.coeff[bDegree].invert(); - if (a.getDegree() < bDegree) - { - result[0] = new GF2nPolynomial(this); - result[0].assignZeroToElements(); - result[0].shrink(); - result[1] = new GF2nPolynomial(this); - result[1].shrink(); - return result; - } - result[0] = new GF2nPolynomial(this); - result[0].assignZeroToElements(); - int i = a.getDegree() - bDegree; - while (i >= 0) - { - factor = (GF2nElement)a.coeff[a.getDegree()].multiply(inv); - shift = b.scalarMultiply(factor); - shift.shiftThisLeft(i); - a = a.add(shift); - a.shrink(); - result[0].coeff[i] = (GF2nElement)factor.clone(); - i = a.getDegree() - bDegree; - } - result[1] = a; - result[0].shrink(); - return result; - } - - /** - * Divides <i>this</i> by <i>b</i> and stores the remainder in a new - * PolynomialGF2n. - * - * @param b the divisor - * @return the remainder <i>this</i> % <i>b</i> - * @throws DifferentFieldsException if <tt>this</tt> and <tt>b</tt> are not defined over - * the same field. - */ - public final GF2nPolynomial remainder(GF2nPolynomial b) - throws RuntimeException, ArithmeticException - { - GF2nPolynomial[] result = new GF2nPolynomial[2]; - result = divide(b); - return result[1]; - } - - /** - * Divides <i>this</i> by <i>b</i> and stores the quotient in a new - * PolynomialGF2n. - * - * @param b the divisor - * @return the quotient <i>this</i> / <i>b</i> - * @throws DifferentFieldsException if <tt>this</tt> and <tt>b</tt> are not defined over - * the same field. - */ - public final GF2nPolynomial quotient(GF2nPolynomial b) - throws RuntimeException, ArithmeticException - { - GF2nPolynomial[] result = new GF2nPolynomial[2]; - result = divide(b); - return result[0]; - } - - /** - * Computes the greatest common divisor of <i>this</i> and <i>g</i> and - * returns the result in a new PolynomialGF2n. - * - * @param g - - * a GF2nPolynomial - * @return gcd(<i>this</i>, <i>g</i>) - * @throws DifferentFieldsException if the coefficients of <i>this</i> and <i>g</i> use - * different fields - * @throws ArithmeticException if coefficients are zero. - */ - public final GF2nPolynomial gcd(GF2nPolynomial g) - throws RuntimeException, ArithmeticException - { - GF2nPolynomial a = new GF2nPolynomial(this); - GF2nPolynomial b = new GF2nPolynomial(g); - a.shrink(); - b.shrink(); - GF2nPolynomial c; - GF2nPolynomial result; - GF2nElement alpha; - while (!b.isZero()) - { - c = a.remainder(b); - a = b; - b = c; - } - alpha = a.coeff[a.getDegree()]; - result = a.scalarMultiply((GF2nElement)alpha.invert()); - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nPolynomialElement.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nPolynomialElement.java deleted file mode 100644 index f1753653..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nPolynomialElement.java +++ /dev/null @@ -1,1021 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - - -import java.math.BigInteger; -import java.util.Random; - - -/** - * This class implements elements of finite binary fields <i>GF(2<sup>n</sup>)</i> - * using polynomial representation. For more information on the arithmetic see - * for example IEEE Standard 1363 or <a - * href=http://www.certicom.com/research/online.html> Certicom online-tutorial</a>. - * - * @see "GF2nField" - * @see GF2nPolynomialField - * @see GF2nONBElement - * @see GF2Polynomial - */ -public class GF2nPolynomialElement - extends GF2nElement -{ - - // pre-computed Bitmask for fast masking, bitMask[a]=0x1 << a - private static final int[] bitMask = {0x00000001, 0x00000002, 0x00000004, - 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080, - 0x00000100, 0x00000200, 0x00000400, 0x00000800, 0x00001000, - 0x00002000, 0x00004000, 0x00008000, 0x00010000, 0x00020000, - 0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000, - 0x00800000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x00000000}; - - // the used GF2Polynomial which stores the coefficients - private GF2Polynomial polynomial; - - /** - * Create a new random GF2nPolynomialElement using the given field and - * source of randomness. - * - * @param f the GF2nField to use - * @param rand the source of randomness - */ - public GF2nPolynomialElement(GF2nPolynomialField f, Random rand) - { - mField = f; - mDegree = mField.getDegree(); - polynomial = new GF2Polynomial(mDegree); - randomize(rand); - } - - /** - * Creates a new GF2nPolynomialElement using the given field and Bitstring. - * - * @param f the GF2nPolynomialField to use - * @param bs the desired value as Bitstring - */ - public GF2nPolynomialElement(GF2nPolynomialField f, GF2Polynomial bs) - { - mField = f; - mDegree = mField.getDegree(); - polynomial = new GF2Polynomial(bs); - polynomial.expandN(mDegree); - } - - /** - * Creates a new GF2nPolynomialElement using the given field <i>f</i> and - * byte[] <i>os</i> as value. The conversion is done according to 1363. - * - * @param f the GF2nField to use - * @param os the octet string to assign to this GF2nPolynomialElement - * @see "P1363 5.5.5 p23, OS2FEP/OS2BSP" - */ - public GF2nPolynomialElement(GF2nPolynomialField f, byte[] os) - { - mField = f; - mDegree = mField.getDegree(); - polynomial = new GF2Polynomial(mDegree, os); - polynomial.expandN(mDegree); - } - - /** - * Creates a new GF2nPolynomialElement using the given field <i>f</i> and - * int[] <i>is</i> as value. - * - * @param f the GF2nField to use - * @param is the integer string to assign to this GF2nPolynomialElement - */ - public GF2nPolynomialElement(GF2nPolynomialField f, int[] is) - { - mField = f; - mDegree = mField.getDegree(); - polynomial = new GF2Polynomial(mDegree, is); - polynomial.expandN(f.mDegree); - } - - /** - * Creates a new GF2nPolynomialElement by cloning the given - * GF2nPolynomialElement <i>b</i>. - * - * @param other the GF2nPolynomialElement to clone - */ - public GF2nPolynomialElement(GF2nPolynomialElement other) - { - mField = other.mField; - mDegree = other.mDegree; - polynomial = new GF2Polynomial(other.polynomial); - } - - // ///////////////////////////////////////////////////////////////////// - // pseudo-constructors - // ///////////////////////////////////////////////////////////////////// - - /** - * Creates a new GF2nPolynomialElement by cloning this - * GF2nPolynomialElement. - * - * @return a copy of this element - */ - public Object clone() - { - return new GF2nPolynomialElement(this); - } - - // ///////////////////////////////////////////////////////////////////// - // assignments - // ///////////////////////////////////////////////////////////////////// - - /** - * Assigns the value 'zero' to this Polynomial. - */ - void assignZero() - { - polynomial.assignZero(); - } - - /** - * Create the zero element. - * - * @param f the finite field - * @return the zero element in the given finite field - */ - public static GF2nPolynomialElement ZERO(GF2nPolynomialField f) - { - GF2Polynomial polynomial = new GF2Polynomial(f.getDegree()); - return new GF2nPolynomialElement(f, polynomial); - } - - /** - * Create the one element. - * - * @param f the finite field - * @return the one element in the given finite field - */ - public static GF2nPolynomialElement ONE(GF2nPolynomialField f) - { - GF2Polynomial polynomial = new GF2Polynomial(f.getDegree(), - new int[]{1}); - return new GF2nPolynomialElement(f, polynomial); - } - - /** - * Assigns the value 'one' to this Polynomial. - */ - void assignOne() - { - polynomial.assignOne(); - } - - /** - * Assign a random value to this GF2nPolynomialElement using the specified - * source of randomness. - * - * @param rand the source of randomness - */ - private void randomize(Random rand) - { - polynomial.expandN(mDegree); - polynomial.randomize(rand); - } - - // ///////////////////////////////////////////////////////////////////// - // comparison - // ///////////////////////////////////////////////////////////////////// - - /** - * Checks whether this element is zero. - * - * @return <tt>true</tt> if <tt>this</tt> is the zero element - */ - public boolean isZero() - { - return polynomial.isZero(); - } - - /** - * Tests if the GF2nPolynomialElement has 'one' as value. - * - * @return true if <i>this</i> equals one (this == 1) - */ - public boolean isOne() - { - return polynomial.isOne(); - } - - /** - * Compare this element with another object. - * - * @param other the other object - * @return <tt>true</tt> if the two objects are equal, <tt>false</tt> - * otherwise - */ - public boolean equals(Object other) - { - if (other == null || !(other instanceof GF2nPolynomialElement)) - { - return false; - } - GF2nPolynomialElement otherElem = (GF2nPolynomialElement)other; - - if (mField != otherElem.mField) - { - if (!mField.getFieldPolynomial().equals( - otherElem.mField.getFieldPolynomial())) - { - return false; - } - } - - return polynomial.equals(otherElem.polynomial); - } - - /** - * @return the hash code of this element - */ - public int hashCode() - { - return mField.hashCode() + polynomial.hashCode(); - } - - // ///////////////////////////////////////////////////////////////////// - // access - // ///////////////////////////////////////////////////////////////////// - - /** - * Returns the value of this GF2nPolynomialElement in a new Bitstring. - * - * @return the value of this GF2nPolynomialElement in a new Bitstring - */ - private GF2Polynomial getGF2Polynomial() - { - return new GF2Polynomial(polynomial); - } - - /** - * Checks whether the indexed bit of the bit representation is set. - * - * @param index the index of the bit to test - * @return <tt>true</tt> if the indexed bit is set - */ - boolean testBit(int index) - { - return polynomial.testBit(index); - } - - /** - * Returns whether the rightmost bit of the bit representation is set. This - * is needed for data conversion according to 1363. - * - * @return true if the rightmost bit of this element is set - */ - public boolean testRightmostBit() - { - return polynomial.testBit(0); - } - - /** - * Compute the sum of this element and <tt>addend</tt>. - * - * @param addend the addend - * @return <tt>this + other</tt> (newly created) - * @throws DifferentFieldsException if the elements are of different fields. - */ - public GFElement add(GFElement addend) - throws RuntimeException - { - GF2nPolynomialElement result = new GF2nPolynomialElement(this); - result.addToThis(addend); - return result; - } - - /** - * Compute <tt>this + addend</tt> (overwrite <tt>this</tt>). - * - * @param addend the addend - * @throws DifferentFieldsException if the elements are of different fields. - */ - public void addToThis(GFElement addend) - throws RuntimeException - { - if (!(addend instanceof GF2nPolynomialElement)) - { - throw new RuntimeException(); - } - if (!mField.equals(((GF2nPolynomialElement)addend).mField)) - { - throw new RuntimeException(); - } - polynomial.addToThis(((GF2nPolynomialElement)addend).polynomial); - } - - /** - * Returns <tt>this</tt> element + 'one". - * - * @return <tt>this</tt> + 'one' - */ - public GF2nElement increase() - { - GF2nPolynomialElement result = new GF2nPolynomialElement(this); - result.increaseThis(); - return result; - } - - /** - * Increases this element by 'one'. - */ - public void increaseThis() - { - polynomial.increaseThis(); - } - - /** - * Compute the product of this element and <tt>factor</tt>. - * - * @param factor the factor - * @return <tt>this * factor</tt> (newly created) - * @throws DifferentFieldsException if the elements are of different fields. - */ - public GFElement multiply(GFElement factor) - throws RuntimeException - { - GF2nPolynomialElement result = new GF2nPolynomialElement(this); - result.multiplyThisBy(factor); - return result; - } - - /** - * Compute <tt>this * factor</tt> (overwrite <tt>this</tt>). - * - * @param factor the factor - * @throws DifferentFieldsException if the elements are of different fields. - */ - public void multiplyThisBy(GFElement factor) - throws RuntimeException - { - if (!(factor instanceof GF2nPolynomialElement)) - { - throw new RuntimeException(); - } - if (!mField.equals(((GF2nPolynomialElement)factor).mField)) - { - throw new RuntimeException(); - } - if (equals(factor)) - { - squareThis(); - return; - } - polynomial = polynomial - .multiply(((GF2nPolynomialElement)factor).polynomial); - reduceThis(); - } - - /** - * Compute the multiplicative inverse of this element. - * - * @return <tt>this<sup>-1</sup></tt> (newly created) - * @throws ArithmeticException if <tt>this</tt> is the zero element. - * @see GF2nPolynomialElement#invertMAIA - * @see GF2nPolynomialElement#invertEEA - * @see GF2nPolynomialElement#invertSquare - */ - public GFElement invert() - throws ArithmeticException - { - return invertMAIA(); - } - - /** - * Calculates the multiplicative inverse of <i>this</i> and returns the - * result in a new GF2nPolynomialElement. - * - * @return <i>this</i>^(-1) - * @throws ArithmeticException if <i>this</i> equals zero - */ - public GF2nPolynomialElement invertEEA() - throws ArithmeticException - { - if (isZero()) - { - throw new ArithmeticException(); - } - GF2Polynomial b = new GF2Polynomial(mDegree + 32, "ONE"); - b.reduceN(); - GF2Polynomial c = new GF2Polynomial(mDegree + 32); - c.reduceN(); - GF2Polynomial u = getGF2Polynomial(); - GF2Polynomial v = mField.getFieldPolynomial(); - GF2Polynomial h; - int j; - u.reduceN(); - while (!u.isOne()) - { - u.reduceN(); - v.reduceN(); - j = u.getLength() - v.getLength(); - if (j < 0) - { - h = u; - u = v; - v = h; - h = b; - b = c; - c = h; - j = -j; - c.reduceN(); // this increases the performance - } - u.shiftLeftAddThis(v, j); - b.shiftLeftAddThis(c, j); - } - b.reduceN(); - return new GF2nPolynomialElement((GF2nPolynomialField)mField, b); - } - - /** - * Calculates the multiplicative inverse of <i>this</i> and returns the - * result in a new GF2nPolynomialElement. - * - * @return <i>this</i>^(-1) - * @throws ArithmeticException if <i>this</i> equals zero - */ - public GF2nPolynomialElement invertSquare() - throws ArithmeticException - { - GF2nPolynomialElement n; - GF2nPolynomialElement u; - int i, j, k, b; - - if (isZero()) - { - throw new ArithmeticException(); - } - // b = (n-1) - b = mField.getDegree() - 1; - // n = a - n = new GF2nPolynomialElement(this); - n.polynomial.expandN((mDegree << 1) + 32); // increase performance - n.polynomial.reduceN(); - // k = 1 - k = 1; - - // for i = (r-1) downto 0 do, r=bitlength(b) - for (i = IntegerFunctions.floorLog(b) - 1; i >= 0; i--) - { - // u = n - u = new GF2nPolynomialElement(n); - // for j = 1 to k do - for (j = 1; j <= k; j++) - { - // u = u^2 - u.squareThisPreCalc(); - } - // n = nu - n.multiplyThisBy(u); - // k = 2k - k <<= 1; - // if b(i)==1 - if ((b & bitMask[i]) != 0) - { - // n = n^2 * b - n.squareThisPreCalc(); - n.multiplyThisBy(this); - // k = k+1 - k += 1; - } - } - - // outpur n^2 - n.squareThisPreCalc(); - return n; - } - - /** - * Calculates the multiplicative inverse of <i>this</i> using the modified - * almost inverse algorithm and returns the result in a new - * GF2nPolynomialElement. - * - * @return <i>this</i>^(-1) - * @throws ArithmeticException if <i>this</i> equals zero - */ - public GF2nPolynomialElement invertMAIA() - throws ArithmeticException - { - if (isZero()) - { - throw new ArithmeticException(); - } - GF2Polynomial b = new GF2Polynomial(mDegree, "ONE"); - GF2Polynomial c = new GF2Polynomial(mDegree); - GF2Polynomial u = getGF2Polynomial(); - GF2Polynomial v = mField.getFieldPolynomial(); - GF2Polynomial h; - while (true) - { - while (!u.testBit(0)) - { // x|u (x divides u) - u.shiftRightThis(); // u = u / x - if (!b.testBit(0)) - { - b.shiftRightThis(); - } - else - { - b.addToThis(mField.getFieldPolynomial()); - b.shiftRightThis(); - } - } - if (u.isOne()) - { - return new GF2nPolynomialElement((GF2nPolynomialField)mField, - b); - } - u.reduceN(); - v.reduceN(); - if (u.getLength() < v.getLength()) - { - h = u; - u = v; - v = h; - h = b; - b = c; - c = h; - } - u.addToThis(v); - b.addToThis(c); - } - } - - /** - * This method is used internally to map the square()-calls within - * GF2nPolynomialElement to one of the possible squaring methods. - * - * @return <tt>this<sup>2</sup></tt> (newly created) - * @see GF2nPolynomialElement#squarePreCalc - */ - public GF2nElement square() - { - return squarePreCalc(); - } - - /** - * This method is used internally to map the square()-calls within - * GF2nPolynomialElement to one of the possible squaring methods. - */ - public void squareThis() - { - squareThisPreCalc(); - } - - /** - * Squares this GF2nPolynomialElement using GF2nField's squaring matrix. - * This is supposed to be fast when using a polynomial (no tri- or - * pentanomial) as fieldpolynomial. Use squarePreCalc when using a tri- or - * pentanomial as fieldpolynomial instead. - * - * @return <tt>this<sup>2</sup></tt> (newly created) - * @see GF2Polynomial#vectorMult - * @see GF2nPolynomialElement#squarePreCalc - * @see GF2nPolynomialElement#squareBitwise - */ - public GF2nPolynomialElement squareMatrix() - { - GF2nPolynomialElement result = new GF2nPolynomialElement(this); - result.squareThisMatrix(); - result.reduceThis(); - return result; - } - - /** - * Squares this GF2nPolynomialElement using GF2nFields squaring matrix. This - * is supposed to be fast when using a polynomial (no tri- or pentanomial) - * as fieldpolynomial. Use squarePreCalc when using a tri- or pentanomial as - * fieldpolynomial instead. - * - * @see GF2Polynomial#vectorMult - * @see GF2nPolynomialElement#squarePreCalc - * @see GF2nPolynomialElement#squareBitwise - */ - public void squareThisMatrix() - { - GF2Polynomial result = new GF2Polynomial(mDegree); - for (int i = 0; i < mDegree; i++) - { - if (polynomial - .vectorMult(((GF2nPolynomialField)mField).squaringMatrix[mDegree - - i - 1])) - { - result.setBit(i); - - } - } - polynomial = result; - } - - /** - * Squares this GF2nPolynomialElement by shifting left its Bitstring and - * reducing. This is supposed to be the slowest method. Use squarePreCalc or - * squareMatrix instead. - * - * @return <tt>this<sup>2</sup></tt> (newly created) - * @see GF2nPolynomialElement#squareMatrix - * @see GF2nPolynomialElement#squarePreCalc - * @see GF2Polynomial#squareThisBitwise - */ - public GF2nPolynomialElement squareBitwise() - { - GF2nPolynomialElement result = new GF2nPolynomialElement(this); - result.squareThisBitwise(); - result.reduceThis(); - return result; - } - - /** - * Squares this GF2nPolynomialElement by shifting left its Bitstring and - * reducing. This is supposed to be the slowest method. Use squarePreCalc or - * squareMatrix instead. - * - * @see GF2nPolynomialElement#squareMatrix - * @see GF2nPolynomialElement#squarePreCalc - * @see GF2Polynomial#squareThisBitwise - */ - public void squareThisBitwise() - { - polynomial.squareThisBitwise(); - reduceThis(); - } - - /** - * Squares this GF2nPolynomialElement by using precalculated values and - * reducing. This is supposed to de fastest when using a trinomial or - * pentanomial as field polynomial. Use squareMatrix when using a ordinary - * polynomial as field polynomial. - * - * @return <tt>this<sup>2</sup></tt> (newly created) - * @see GF2nPolynomialElement#squareMatrix - * @see GF2Polynomial#squareThisPreCalc - */ - public GF2nPolynomialElement squarePreCalc() - { - GF2nPolynomialElement result = new GF2nPolynomialElement(this); - result.squareThisPreCalc(); - result.reduceThis(); - return result; - } - - /** - * Squares this GF2nPolynomialElement by using precalculated values and - * reducing. This is supposed to de fastest when using a tri- or pentanomial - * as fieldpolynomial. Use squareMatrix when using a ordinary polynomial as - * fieldpolynomial. - * - * @see GF2nPolynomialElement#squareMatrix - * @see GF2Polynomial#squareThisPreCalc - */ - public void squareThisPreCalc() - { - polynomial.squareThisPreCalc(); - reduceThis(); - } - - /** - * Calculates <i>this</i> to the power of <i>k</i> and returns the result - * in a new GF2nPolynomialElement. - * - * @param k the power - * @return <i>this</i>^<i>k</i> in a new GF2nPolynomialElement - */ - public GF2nPolynomialElement power(int k) - { - if (k == 1) - { - return new GF2nPolynomialElement(this); - } - - GF2nPolynomialElement result = GF2nPolynomialElement - .ONE((GF2nPolynomialField)mField); - if (k == 0) - { - return result; - } - - GF2nPolynomialElement x = new GF2nPolynomialElement(this); - x.polynomial.expandN((x.mDegree << 1) + 32); // increase performance - x.polynomial.reduceN(); - - for (int i = 0; i < mDegree; i++) - { - if ((k & (1 << i)) != 0) - { - result.multiplyThisBy(x); - } - x.square(); - } - - return result; - } - - /** - * Compute the square root of this element and return the result in a new - * {@link GF2nPolynomialElement}. - * - * @return <tt>this<sup>1/2</sup></tt> (newly created) - */ - public GF2nElement squareRoot() - { - GF2nPolynomialElement result = new GF2nPolynomialElement(this); - result.squareRootThis(); - return result; - } - - /** - * Compute the square root of this element. - */ - public void squareRootThis() - { - // increase performance - polynomial.expandN((mDegree << 1) + 32); - polynomial.reduceN(); - for (int i = 0; i < mField.getDegree() - 1; i++) - { - squareThis(); - } - } - - /** - * Solves the quadratic equation <tt>z<sup>2</sup> + z = this</tt> if - * such a solution exists. This method returns one of the two possible - * solutions. The other solution is <tt>z + 1</tt>. Use z.increase() to - * compute this solution. - * - * @return a GF2nPolynomialElement representing one z satisfying the - * equation <tt>z<sup>2</sup> + z = this</tt> - * @throws NoSolutionException if no solution exists - * @see "IEEE 1363, Annex A.4.7" - */ - public GF2nElement solveQuadraticEquation() - throws RuntimeException - { - if (isZero()) - { - return ZERO((GF2nPolynomialField)mField); - } - - if ((mDegree & 1) == 1) - { - return halfTrace(); - } - - // TODO this can be sped-up by precomputation of p and w's - GF2nPolynomialElement z, w; - do - { - // step 1. - GF2nPolynomialElement p = new GF2nPolynomialElement( - (GF2nPolynomialField)mField, new Random()); - // step 2. - z = ZERO((GF2nPolynomialField)mField); - w = (GF2nPolynomialElement)p.clone(); - // step 3. - for (int i = 1; i < mDegree; i++) - { - // compute z = z^2 + w^2 * this - // and w = w^2 + p - z.squareThis(); - w.squareThis(); - z.addToThis(w.multiply(this)); - w.addToThis(p); - } - } - while (w.isZero()); // step 4. - - if (!equals(z.square().add(z))) - { - throw new RuntimeException(); - } - - // step 5. - return z; - } - - /** - * Returns the trace of this GF2nPolynomialElement. - * - * @return the trace of this GF2nPolynomialElement - */ - public int trace() - { - GF2nPolynomialElement t = new GF2nPolynomialElement(this); - int i; - - for (i = 1; i < mDegree; i++) - { - t.squareThis(); - t.addToThis(this); - } - - if (t.isOne()) - { - return 1; - } - return 0; - } - - /** - * Returns the half-trace of this GF2nPolynomialElement. - * - * @return a GF2nPolynomialElement representing the half-trace of this - * GF2nPolynomialElement. - * @throws DegreeIsEvenException if the degree of this GF2nPolynomialElement is even. - */ - private GF2nPolynomialElement halfTrace() - throws RuntimeException - { - if ((mDegree & 0x01) == 0) - { - throw new RuntimeException(); - } - int i; - GF2nPolynomialElement h = new GF2nPolynomialElement(this); - - for (i = 1; i <= ((mDegree - 1) >> 1); i++) - { - h.squareThis(); - h.squareThis(); - h.addToThis(this); - } - - return h; - } - - /** - * Reduces this GF2nPolynomialElement modulo the field-polynomial. - * - * @see GF2Polynomial#reduceTrinomial - * @see GF2Polynomial#reducePentanomial - */ - private void reduceThis() - { - if (polynomial.getLength() > mDegree) - { // really reduce ? - if (((GF2nPolynomialField)mField).isTrinomial()) - { // fieldpolonomial - // is trinomial - int tc; - try - { - tc = ((GF2nPolynomialField)mField).getTc(); - } - catch (RuntimeException NATExc) - { - throw new RuntimeException( - "GF2nPolynomialElement.reduce: the field" - + " polynomial is not a trinomial"); - } - if (((mDegree - tc) <= 32) // do we have to use slow - // bitwise reduction ? - || (polynomial.getLength() > (mDegree << 1))) - { - reduceTrinomialBitwise(tc); - return; - } - polynomial.reduceTrinomial(mDegree, tc); - return; - } - else if (((GF2nPolynomialField)mField).isPentanomial()) - { // fieldpolynomial - // is - // pentanomial - int[] pc; - try - { - pc = ((GF2nPolynomialField)mField).getPc(); - } - catch (RuntimeException NATExc) - { - throw new RuntimeException( - "GF2nPolynomialElement.reduce: the field" - + " polynomial is not a pentanomial"); - } - if (((mDegree - pc[2]) <= 32) // do we have to use slow - // bitwise reduction ? - || (polynomial.getLength() > (mDegree << 1))) - { - reducePentanomialBitwise(pc); - return; - } - polynomial.reducePentanomial(mDegree, pc); - return; - } - else - { // fieldpolynomial is something else - polynomial = polynomial.remainder(mField.getFieldPolynomial()); - polynomial.expandN(mDegree); - return; - } - } - if (polynomial.getLength() < mDegree) - { - polynomial.expandN(mDegree); - } - } - - /** - * Reduce this GF2nPolynomialElement using the trinomial x^n + x^tc + 1 as - * fieldpolynomial. The coefficients are reduced bit by bit. - */ - private void reduceTrinomialBitwise(int tc) - { - int i; - int k = mDegree - tc; - for (i = polynomial.getLength() - 1; i >= mDegree; i--) - { - if (polynomial.testBit(i)) - { - - polynomial.xorBit(i); - polynomial.xorBit(i - k); - polynomial.xorBit(i - mDegree); - - } - } - polynomial.reduceN(); - polynomial.expandN(mDegree); - } - - /** - * Reduce this GF2nPolynomialElement using the pentanomial x^n + x^pc[2] + - * x^pc[1] + x^pc[0] + 1 as fieldpolynomial. The coefficients are reduced - * bit by bit. - */ - private void reducePentanomialBitwise(int[] pc) - { - int i; - int k = mDegree - pc[2]; - int l = mDegree - pc[1]; - int m = mDegree - pc[0]; - for (i = polynomial.getLength() - 1; i >= mDegree; i--) - { - if (polynomial.testBit(i)) - { - polynomial.xorBit(i); - polynomial.xorBit(i - k); - polynomial.xorBit(i - l); - polynomial.xorBit(i - m); - polynomial.xorBit(i - mDegree); - - } - } - polynomial.reduceN(); - polynomial.expandN(mDegree); - } - - // ///////////////////////////////////////////////////////////////////// - // conversion - // ///////////////////////////////////////////////////////////////////// - - /** - * Returns a string representing this Bitstrings value using hexadecimal - * radix in MSB-first order. - * - * @return a String representing this Bitstrings value. - */ - public String toString() - { - return polynomial.toString(16); - } - - /** - * Returns a string representing this Bitstrings value using hexadecimal or - * binary radix in MSB-first order. - * - * @param radix the radix to use (2 or 16, otherwise 2 is used) - * @return a String representing this Bitstrings value. - */ - public String toString(int radix) - { - return polynomial.toString(radix); - } - - /** - * Converts this GF2nPolynomialElement to a byte[] according to 1363. - * - * @return a byte[] representing the value of this GF2nPolynomialElement - * @see "P1363 5.5.2 p22f BS2OSP, FE2OSP" - */ - public byte[] toByteArray() - { - return polynomial.toByteArray(); - } - - /** - * Converts this GF2nPolynomialElement to an integer according to 1363. - * - * @return a BigInteger representing the value of this - * GF2nPolynomialElement - * @see "P1363 5.5.1 p22 BS2IP" - */ - public BigInteger toFlexiBigInt() - { - return polynomial.toFlexiBigInt(); - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nPolynomialField.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nPolynomialField.java deleted file mode 100644 index f66ec20a..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GF2nPolynomialField.java +++ /dev/null @@ -1,553 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - - -import java.util.Random; -import java.util.Vector; - - -/** - * This class implements the abstract class <tt>GF2nField</tt> for polynomial - * representation. It computes the field polynomial and the squaring matrix. - * GF2nField is used by GF2nPolynomialElement which implements the elements of - * this field. - * - * @see GF2nField - * @see GF2nPolynomialElement - */ -public class GF2nPolynomialField - extends GF2nField -{ - - /** - * Matrix used for fast squaring - */ - GF2Polynomial[] squaringMatrix; - - // field polynomial is a trinomial - private boolean isTrinomial = false; - - // field polynomial is a pentanomial - private boolean isPentanomial = false; - - // middle coefficient of the field polynomial in case it is a trinomial - private int tc; - - // middle 3 coefficients of the field polynomial in case it is a pentanomial - private int[] pc = new int[3]; - - /** - * constructs an instance of the finite field with 2<sup>deg</sup> - * elements and characteristic 2. - * - * @param deg the extention degree of this field - */ - public GF2nPolynomialField(int deg) - { - if (deg < 3) - { - throw new IllegalArgumentException("k must be at least 3"); - } - mDegree = deg; - computeFieldPolynomial(); - computeSquaringMatrix(); - fields = new Vector(); - matrices = new Vector(); - } - - /** - * constructs an instance of the finite field with 2<sup>deg</sup> - * elements and characteristic 2. - * - * @param deg the degree of this field - * @param file true if you want to read the field polynomial from the - * file false if you want to use a random fielpolynomial - * (this can take very long for huge degrees) - */ - public GF2nPolynomialField(int deg, boolean file) - { - if (deg < 3) - { - throw new IllegalArgumentException("k must be at least 3"); - } - mDegree = deg; - if (file) - { - computeFieldPolynomial(); - } - else - { - computeFieldPolynomial2(); - } - computeSquaringMatrix(); - fields = new Vector(); - matrices = new Vector(); - } - - /** - * Creates a new GF2nField of degree <i>i</i> and uses the given - * <i>polynomial</i> as field polynomial. The <i>polynomial</i> is checked - * whether it is irreducible. This can take some time if <i>i</i> is huge! - * - * @param deg degree of the GF2nField - * @param polynomial the field polynomial to use - * @throws PolynomialIsNotIrreducibleException if the given polynomial is not irreducible in GF(2^<i>i</i>) - */ - public GF2nPolynomialField(int deg, GF2Polynomial polynomial) - throws RuntimeException - { - if (deg < 3) - { - throw new IllegalArgumentException("degree must be at least 3"); - } - if (polynomial.getLength() != deg + 1) - { - throw new RuntimeException(); - } - if (!polynomial.isIrreducible()) - { - throw new RuntimeException(); - } - mDegree = deg; - // fieldPolynomial = new Bitstring(polynomial); - fieldPolynomial = polynomial; - computeSquaringMatrix(); - int k = 2; // check if the polynomial is a trinomial or pentanomial - for (int j = 1; j < fieldPolynomial.getLength() - 1; j++) - { - if (fieldPolynomial.testBit(j)) - { - k++; - if (k == 3) - { - tc = j; - } - if (k <= 5) - { - pc[k - 3] = j; - } - } - } - if (k == 3) - { - isTrinomial = true; - } - if (k == 5) - { - isPentanomial = true; - } - fields = new Vector(); - matrices = new Vector(); - } - - /** - * Returns true if the field polynomial is a trinomial. The coefficient can - * be retrieved using getTc(). - * - * @return true if the field polynomial is a trinomial - */ - public boolean isTrinomial() - { - return isTrinomial; - } - - /** - * Returns true if the field polynomial is a pentanomial. The coefficients - * can be retrieved using getPc(). - * - * @return true if the field polynomial is a pentanomial - */ - public boolean isPentanomial() - { - return isPentanomial; - } - - /** - * Returns the degree of the middle coefficient of the used field trinomial - * (x^n + x^(getTc()) + 1). - * - * @return the middle coefficient of the used field trinomial - * @throws GFException if the field polynomial is not a trinomial - */ - public int getTc() - throws RuntimeException - { - if (!isTrinomial) - { - throw new RuntimeException(); - } - return tc; - } - - /** - * Returns the degree of the middle coefficients of the used field - * pentanomial (x^n + x^(getPc()[2]) + x^(getPc()[1]) + x^(getPc()[0]) + 1). - * - * @return the middle coefficients of the used field pentanomial - * @throws GFException if the field polynomial is not a pentanomial - */ - public int[] getPc() - throws RuntimeException - { - if (!isPentanomial) - { - throw new RuntimeException(); - } - int[] result = new int[3]; - System.arraycopy(pc, 0, result, 0, 3); - return result; - } - - /** - * Return row vector i of the squaring matrix. - * - * @param i the index of the row vector to return - * @return a copy of squaringMatrix[i] - * @see GF2nPolynomialElement#squareMatrix - */ - public GF2Polynomial getSquaringVector(int i) - { - return new GF2Polynomial(squaringMatrix[i]); - } - - /** - * Compute a random root of the given GF2Polynomial. - * - * @param polynomial the polynomial - * @return a random root of <tt>polynomial</tt> - */ - protected GF2nElement getRandomRoot(GF2Polynomial polynomial) - { - // We are in B1!!! - GF2nPolynomial c; - GF2nPolynomial ut; - GF2nElement u; - GF2nPolynomial h; - int hDegree; - // 1. Set g(t) <- f(t) - GF2nPolynomial g = new GF2nPolynomial(polynomial, this); - int gDegree = g.getDegree(); - int i; - - // 2. while deg(g) > 1 - while (gDegree > 1) - { - do - { - // 2.1 choose random u (element of) GF(2^m) - u = new GF2nPolynomialElement(this, new Random()); - ut = new GF2nPolynomial(2, GF2nPolynomialElement.ZERO(this)); - // 2.2 Set c(t) <- ut - ut.set(1, u); - c = new GF2nPolynomial(ut); - // 2.3 For i from 1 to m-1 do - for (i = 1; i <= mDegree - 1; i++) - { - // 2.3.1 c(t) <- (c(t)^2 + ut) mod g(t) - c = c.multiplyAndReduce(c, g); - c = c.add(ut); - } - // 2.4 set h(t) <- GCD(c(t), g(t)) - h = c.gcd(g); - // 2.5 if h(t) is constant or deg(g) = deg(h) then go to - // step 2.1 - hDegree = h.getDegree(); - gDegree = g.getDegree(); - } - while ((hDegree == 0) || (hDegree == gDegree)); - // 2.6 If 2deg(h) > deg(g) then set g(t) <- g(t)/h(t) ... - if ((hDegree << 1) > gDegree) - { - g = g.quotient(h); - } - else - { - // ... else g(t) <- h(t) - g = new GF2nPolynomial(h); - } - gDegree = g.getDegree(); - } - // 3. Output g(0) - return g.at(0); - - } - - /** - * Computes the change-of-basis matrix for basis conversion according to - * 1363. The result is stored in the lists fields and matrices. - * - * @param B1 the GF2nField to convert to - * @see "P1363 A.7.3, p111ff" - */ - protected void computeCOBMatrix(GF2nField B1) - { - // we are in B0 here! - if (mDegree != B1.mDegree) - { - throw new IllegalArgumentException( - "GF2nPolynomialField.computeCOBMatrix: B1 has a different " - + "degree and thus cannot be coverted to!"); - } - if (B1 instanceof GF2nONBField) - { - // speedup (calculation is done in PolynomialElements instead of - // ONB) - B1.computeCOBMatrix(this); - return; - } - int i, j; - GF2nElement[] gamma; - GF2nElement u; - GF2Polynomial[] COBMatrix = new GF2Polynomial[mDegree]; - for (i = 0; i < mDegree; i++) - { - COBMatrix[i] = new GF2Polynomial(mDegree); - } - - // find Random Root - do - { - // u is in representation according to B1 - u = B1.getRandomRoot(fieldPolynomial); - } - while (u.isZero()); - - // build gamma matrix by multiplying by u - if (u instanceof GF2nONBElement) - { - gamma = new GF2nONBElement[mDegree]; - gamma[mDegree - 1] = GF2nONBElement.ONE((GF2nONBField)B1); - } - else - { - gamma = new GF2nPolynomialElement[mDegree]; - gamma[mDegree - 1] = GF2nPolynomialElement - .ONE((GF2nPolynomialField)B1); - } - gamma[mDegree - 2] = u; - for (i = mDegree - 3; i >= 0; i--) - { - gamma[i] = (GF2nElement)gamma[i + 1].multiply(u); - } - if (B1 instanceof GF2nONBField) - { - // convert horizontal gamma matrix by vertical Bitstrings - for (i = 0; i < mDegree; i++) - { - for (j = 0; j < mDegree; j++) - { - // TODO remember: ONB treats its Bits in reverse order !!! - if (gamma[i].testBit(mDegree - j - 1)) - { - COBMatrix[mDegree - j - 1].setBit(mDegree - i - 1); - } - } - } - } - else - { - // convert horizontal gamma matrix by vertical Bitstrings - for (i = 0; i < mDegree; i++) - { - for (j = 0; j < mDegree; j++) - { - if (gamma[i].testBit(j)) - { - COBMatrix[mDegree - j - 1].setBit(mDegree - i - 1); - } - } - } - } - - // store field and matrix for further use - fields.addElement(B1); - matrices.addElement(COBMatrix); - // store field and inverse matrix for further use in B1 - B1.fields.addElement(this); - B1.matrices.addElement(invertMatrix(COBMatrix)); - } - - /** - * Computes a new squaring matrix used for fast squaring. - * - * @see GF2nPolynomialElement#square - */ - private void computeSquaringMatrix() - { - GF2Polynomial[] d = new GF2Polynomial[mDegree - 1]; - int i, j; - squaringMatrix = new GF2Polynomial[mDegree]; - for (i = 0; i < squaringMatrix.length; i++) - { - squaringMatrix[i] = new GF2Polynomial(mDegree, "ZERO"); - } - - for (i = 0; i < mDegree - 1; i++) - { - d[i] = new GF2Polynomial(1, "ONE").shiftLeft(mDegree + i) - .remainder(fieldPolynomial); - } - for (i = 1; i <= Math.abs(mDegree >> 1); i++) - { - for (j = 1; j <= mDegree; j++) - { - if (d[mDegree - (i << 1)].testBit(mDegree - j)) - { - squaringMatrix[j - 1].setBit(mDegree - i); - } - } - } - for (i = Math.abs(mDegree >> 1) + 1; i <= mDegree; i++) - { - squaringMatrix[(i << 1) - mDegree - 1].setBit(mDegree - i); - } - - } - - /** - * Computes the field polynomial. This can take a long time for big degrees. - */ - protected void computeFieldPolynomial() - { - if (testTrinomials()) - { - return; - } - if (testPentanomials()) - { - return; - } - testRandom(); - } - - /** - * Computes the field polynomial. This can take a long time for big degrees. - */ - protected void computeFieldPolynomial2() - { - if (testTrinomials()) - { - return; - } - if (testPentanomials()) - { - return; - } - testRandom(); - } - - /** - * Tests all trinomials of degree (n+1) until a irreducible is found and - * stores the result in <i>field polynomial</i>. Returns false if no - * irreducible trinomial exists in GF(2^n). This can take very long for huge - * degrees. - * - * @return true if an irreducible trinomial is found - */ - private boolean testTrinomials() - { - int i, l; - boolean done = false; - l = 0; - - fieldPolynomial = new GF2Polynomial(mDegree + 1); - fieldPolynomial.setBit(0); - fieldPolynomial.setBit(mDegree); - for (i = 1; (i < mDegree) && !done; i++) - { - fieldPolynomial.setBit(i); - done = fieldPolynomial.isIrreducible(); - l++; - if (done) - { - isTrinomial = true; - tc = i; - return done; - } - fieldPolynomial.resetBit(i); - done = fieldPolynomial.isIrreducible(); - } - - return done; - } - - /** - * Tests all pentanomials of degree (n+1) until a irreducible is found and - * stores the result in <i>field polynomial</i>. Returns false if no - * irreducible pentanomial exists in GF(2^n). This can take very long for - * huge degrees. - * - * @return true if an irreducible pentanomial is found - */ - private boolean testPentanomials() - { - int i, j, k, l; - boolean done = false; - l = 0; - - fieldPolynomial = new GF2Polynomial(mDegree + 1); - fieldPolynomial.setBit(0); - fieldPolynomial.setBit(mDegree); - for (i = 1; (i <= (mDegree - 3)) && !done; i++) - { - fieldPolynomial.setBit(i); - for (j = i + 1; (j <= (mDegree - 2)) && !done; j++) - { - fieldPolynomial.setBit(j); - for (k = j + 1; (k <= (mDegree - 1)) && !done; k++) - { - fieldPolynomial.setBit(k); - if (((mDegree & 1) != 0) | ((i & 1) != 0) | ((j & 1) != 0) - | ((k & 1) != 0)) - { - done = fieldPolynomial.isIrreducible(); - l++; - if (done) - { - isPentanomial = true; - pc[0] = i; - pc[1] = j; - pc[2] = k; - return done; - } - } - fieldPolynomial.resetBit(k); - } - fieldPolynomial.resetBit(j); - } - fieldPolynomial.resetBit(i); - } - - return done; - } - - /** - * Tests random polynomials of degree (n+1) until an irreducible is found - * and stores the result in <i>field polynomial</i>. This can take very - * long for huge degrees. - * - * @return true - */ - private boolean testRandom() - { - int l; - boolean done = false; - - fieldPolynomial = new GF2Polynomial(mDegree + 1); - l = 0; - while (!done) - { - l++; - fieldPolynomial.randomize(); - fieldPolynomial.setBit(mDegree); - fieldPolynomial.setBit(0); - if (fieldPolynomial.isIrreducible()) - { - done = true; - return done; - } - } - - return done; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GFElement.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GFElement.java deleted file mode 100644 index 1e93e158..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GFElement.java +++ /dev/null @@ -1,158 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -import java.math.BigInteger; - - -/** - * This interface defines a finite field element. It is implemented by the - * classes {@link GFPElement} and {@link GF2nElement}. - * - * @see GFPElement - * @see GF2nElement - */ -public interface GFElement -{ - - /** - * @return a copy of this GFElement - */ - Object clone(); - - // ///////////////////////////////////////////////////////////////// - // comparison - // ///////////////////////////////////////////////////////////////// - - /** - * Compare this curve with another object. - * - * @param other the other object - * @return the result of the comparison - */ - boolean equals(Object other); - - /** - * @return the hash code of this element - */ - int hashCode(); - - /** - * Checks whether this element is zero. - * - * @return <tt>true</tt> if <tt>this</tt> is the zero element - */ - boolean isZero(); - - /** - * Checks whether this element is one. - * - * @return <tt>true</tt> if <tt>this</tt> is the one element - */ - boolean isOne(); - - // ///////////////////////////////////////////////////////////////////// - // arithmetic - // ///////////////////////////////////////////////////////////////////// - - /** - * Compute the sum of this element and the addend. - * - * @param addend the addend - * @return <tt>this + other</tt> (newly created) - * @throws DifferentFieldsException if the elements are of different fields. - */ - GFElement add(GFElement addend) - throws RuntimeException; - - /** - * Compute the sum of this element and the addend, overwriting this element. - * - * @param addend the addend - * @throws DifferentFieldsException if the elements are of different fields. - */ - void addToThis(GFElement addend) - throws RuntimeException; - - /** - * Compute the difference of this element and <tt>minuend</tt>. - * - * @param minuend the minuend - * @return <tt>this - minuend</tt> (newly created) - * @throws DifferentFieldsException if the elements are of different fields. - */ - GFElement subtract(GFElement minuend) - throws RuntimeException; - - /** - * Compute the difference of this element and <tt>minuend</tt>, - * overwriting this element. - * - * @param minuend the minuend - * @throws DifferentFieldsException if the elements are of different fields. - */ - void subtractFromThis(GFElement minuend); - - /** - * Compute the product of this element and <tt>factor</tt>. - * - * @param factor the factor - * @return <tt>this * factor</tt> (newly created) - * @throws DifferentFieldsException if the elements are of different fields. - */ - GFElement multiply(GFElement factor) - throws RuntimeException; - - /** - * Compute <tt>this * factor</tt> (overwrite <tt>this</tt>). - * - * @param factor the factor - * @throws DifferentFieldsException if the elements are of different fields. - */ - void multiplyThisBy(GFElement factor) - throws RuntimeException; - - /** - * Compute the multiplicative inverse of this element. - * - * @return <tt>this<sup>-1</sup></tt> (newly created) - * @throws ArithmeticException if <tt>this</tt> is the zero element. - */ - GFElement invert() - throws ArithmeticException; - - // ///////////////////////////////////////////////////////////////////// - // conversion - // ///////////////////////////////////////////////////////////////////// - - /** - * Returns this element as FlexiBigInt. The conversion is <a - * href="http://grouper.ieee.org/groups/1363/">P1363</a>-conform. - * - * @return this element as BigInt - */ - BigInteger toFlexiBigInt(); - - /** - * Returns this element as byte array. The conversion is <a href = - * "http://grouper.ieee.org/groups/1363/">P1363</a>-conform. - * - * @return this element as byte array - */ - byte[] toByteArray(); - - /** - * Return a String representation of this element. - * - * @return String representation of this element - */ - String toString(); - - /** - * Return a String representation of this element. <tt>radix</tt> - * specifies the radix of the String representation. - * - * @param radix specifies the radix of the String representation - * @return String representation of this element with the specified radix - */ - String toString(int radix); - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GoppaCode.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GoppaCode.java deleted file mode 100644 index cf82eaea..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/GoppaCode.java +++ /dev/null @@ -1,310 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -import java.security.SecureRandom; - -/** - * This class describes decoding operations of an irreducible binary Goppa code. - * A check matrix H of the Goppa code and an irreducible Goppa polynomial are - * used the operations are worked over a finite field GF(2^m) - * - * @see GF2mField - * @see PolynomialGF2mSmallM - */ -public final class GoppaCode -{ - - /** - * Default constructor (private). - */ - private GoppaCode() - { - // empty - } - - /** - * This class is a container for two instances of {@link GF2Matrix} and one - * instance of {@link Permutation}. It is used to hold the systematic form - * <tt>S*H*P = (Id|M)</tt> of the check matrix <tt>H</tt> as returned by - * {@link GoppaCode#computeSystematicForm(GF2Matrix, SecureRandom)}. - * - * @see GF2Matrix - * @see Permutation - */ - public static class MaMaPe - { - - private GF2Matrix s, h; - - private Permutation p; - - /** - * Construct a new {@link MaMaPe} container with the given parameters. - * - * @param s the first matrix - * @param h the second matrix - * @param p the permutation - */ - public MaMaPe(GF2Matrix s, GF2Matrix h, Permutation p) - { - this.s = s; - this.h = h; - this.p = p; - } - - /** - * @return the first matrix - */ - public GF2Matrix getFirstMatrix() - { - return s; - } - - /** - * @return the second matrix - */ - public GF2Matrix getSecondMatrix() - { - return h; - } - - /** - * @return the permutation - */ - public Permutation getPermutation() - { - return p; - } - } - - /** - * This class is a container for an instance of {@link GF2Matrix} and one - * int[]. It is used to hold a generator matrix and the set of indices such - * that the submatrix of the generator matrix consisting of the specified - * columns is the identity. - * - * @see GF2Matrix - * @see Permutation - */ - public static class MatrixSet - { - - private GF2Matrix g; - - private int[] setJ; - - /** - * Construct a new {@link MatrixSet} container with the given - * parameters. - * - * @param g the generator matrix - * @param setJ the set of indices such that the submatrix of the - * generator matrix consisting of the specified columns - * is the identity - */ - public MatrixSet(GF2Matrix g, int[] setJ) - { - this.g = g; - this.setJ = setJ; - } - - /** - * @return the generator matrix - */ - public GF2Matrix getG() - { - return g; - } - - /** - * @return the set of indices such that the submatrix of the generator - * matrix consisting of the specified columns is the identity - */ - public int[] getSetJ() - { - return setJ; - } - } - - /** - * Construct the check matrix of a Goppa code in canonical form from the - * irreducible Goppa polynomial over the finite field - * <tt>GF(2<sup>m</sup>)</tt>. - * - * @param field the finite field - * @param gp the irreducible Goppa polynomial - */ - public static GF2Matrix createCanonicalCheckMatrix(GF2mField field, - PolynomialGF2mSmallM gp) - { - int m = field.getDegree(); - int n = 1 << m; - int t = gp.getDegree(); - - /* create matrix H over GF(2^m) */ - - int[][] hArray = new int[t][n]; - - // create matrix YZ - int[][] yz = new int[t][n]; - for (int j = 0; j < n; j++) - { - // here j is used as index and as element of field GF(2^m) - yz[0][j] = field.inverse(gp.evaluateAt(j)); - } - - for (int i = 1; i < t; i++) - { - for (int j = 0; j < n; j++) - { - // here j is used as index and as element of field GF(2^m) - yz[i][j] = field.mult(yz[i - 1][j], j); - } - } - - // create matrix H = XYZ - for (int i = 0; i < t; i++) - { - for (int j = 0; j < n; j++) - { - for (int k = 0; k <= i; k++) - { - hArray[i][j] = field.add(hArray[i][j], field.mult(yz[k][j], - gp.getCoefficient(t + k - i))); - } - } - } - - /* convert to matrix over GF(2) */ - - int[][] result = new int[t * m][(n + 31) >>> 5]; - - for (int j = 0; j < n; j++) - { - int q = j >>> 5; - int r = 1 << (j & 0x1f); - for (int i = 0; i < t; i++) - { - int e = hArray[i][j]; - for (int u = 0; u < m; u++) - { - int b = (e >>> u) & 1; - if (b != 0) - { - int ind = (i + 1) * m - u - 1; - result[ind][q] ^= r; - } - } - } - } - - return new GF2Matrix(n, result); - } - - /** - * Given a check matrix <tt>H</tt>, compute matrices <tt>S</tt>, - * <tt>M</tt>, and a random permutation <tt>P</tt> such that - * <tt>S*H*P = (Id|M)</tt>. Return <tt>S^-1</tt>, <tt>M</tt>, and - * <tt>P</tt> as {@link MaMaPe}. The matrix <tt>(Id | M)</tt> is called - * the systematic form of H. - * - * @param h the check matrix - * @param sr a source of randomness - * @return the tuple <tt>(S^-1, M, P)</tt> - */ - public static MaMaPe computeSystematicForm(GF2Matrix h, SecureRandom sr) - { - int n = h.getNumColumns(); - GF2Matrix hp, sInv; - GF2Matrix s = null; - Permutation p; - boolean found = false; - - do - { - p = new Permutation(n, sr); - hp = (GF2Matrix)h.rightMultiply(p); - sInv = hp.getLeftSubMatrix(); - try - { - found = true; - s = (GF2Matrix)sInv.computeInverse(); - } - catch (ArithmeticException ae) - { - found = false; - } - } - while (!found); - - GF2Matrix shp = (GF2Matrix)s.rightMultiply(hp); - GF2Matrix m = shp.getRightSubMatrix(); - - return new MaMaPe(sInv, m, p); - } - - /** - * Find an error vector <tt>e</tt> over <tt>GF(2)</tt> from an input - * syndrome <tt>s</tt> over <tt>GF(2<sup>m</sup>)</tt>. - * - * @param syndVec the syndrome - * @param field the finite field - * @param gp the irreducible Goppa polynomial - * @param sqRootMatrix the matrix for computing square roots in - * <tt>(GF(2<sup>m</sup>))<sup>t</sup></tt> - * @return the error vector - */ - public static GF2Vector syndromeDecode(GF2Vector syndVec, GF2mField field, - PolynomialGF2mSmallM gp, PolynomialGF2mSmallM[] sqRootMatrix) - { - - int n = 1 << field.getDegree(); - - // the error vector - GF2Vector errors = new GF2Vector(n); - - // if the syndrome vector is zero, the error vector is also zero - if (!syndVec.isZero()) - { - // convert syndrome vector to polynomial over GF(2^m) - PolynomialGF2mSmallM syndrome = new PolynomialGF2mSmallM(syndVec - .toExtensionFieldVector(field)); - - // compute T = syndrome^-1 mod gp - PolynomialGF2mSmallM t = syndrome.modInverse(gp); - - // compute tau = sqRoot(T + X) mod gp - PolynomialGF2mSmallM tau = t.addMonomial(1); - tau = tau.modSquareRootMatrix(sqRootMatrix); - - // compute polynomials a and b satisfying a + b*tau = 0 mod gp - PolynomialGF2mSmallM[] ab = tau.modPolynomialToFracton(gp); - - // compute the polynomial a^2 + X*b^2 - PolynomialGF2mSmallM a2 = ab[0].multiply(ab[0]); - PolynomialGF2mSmallM b2 = ab[1].multiply(ab[1]); - PolynomialGF2mSmallM xb2 = b2.multWithMonomial(1); - PolynomialGF2mSmallM a2plusXb2 = a2.add(xb2); - - // normalize a^2 + X*b^2 to obtain the error locator polynomial - int headCoeff = a2plusXb2.getHeadCoefficient(); - int invHeadCoeff = field.inverse(headCoeff); - PolynomialGF2mSmallM elp = a2plusXb2.multWithElement(invHeadCoeff); - - // for all elements i of GF(2^m) - for (int i = 0; i < n; i++) - { - // evaluate the error locator polynomial at i - int z = elp.evaluateAt(i); - // if polynomial evaluates to zero - if (z == 0) - { - // set the i-th coefficient of the error vector - errors.setBit(i); - } - } - } - - return errors; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/IntUtils.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/IntUtils.java deleted file mode 100644 index 90a3c60d..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/IntUtils.java +++ /dev/null @@ -1,202 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -import java.math.BigInteger; - -/** - * - * - * - */ -public final class IntUtils -{ - - /** - * Default constructor (private). - */ - private IntUtils() - { - // empty - } - - /** - * Compare two int arrays. No null checks are performed. - * - * @param left the first int array - * @param right the second int array - * @return the result of the comparison - */ - public static boolean equals(int[] left, int[] right) - { - if (left.length != right.length) - { - return false; - } - boolean result = true; - for (int i = left.length - 1; i >= 0; i--) - { - result &= left[i] == right[i]; - } - return result; - } - - /** - * Return a clone of the given int array. No null checks are performed. - * - * @param array the array to clone - * @return the clone of the given array - */ - public static int[] clone(int[] array) - { - int[] result = new int[array.length]; - System.arraycopy(array, 0, result, 0, array.length); - return result; - } - - /** - * Fill the given int array with the given value. - * - * @param array the array - * @param value the value - */ - public static void fill(int[] array, int value) - { - for (int i = array.length - 1; i >= 0; i--) - { - array[i] = value; - } - } - - /** - * Sorts this array of integers according to the Quicksort algorithm. After - * calling this method this array is sorted in ascending order with the - * smallest integer taking position 0 in the array. - * <p> - * This implementation is based on the quicksort algorithm as described in - * <code>Data Structures In Java</code> by Thomas A. Standish, Chapter 10, - * ISBN 0-201-30564-X. - * - * @param source the array of integers that needs to be sorted. - */ - public static void quicksort(int[] source) - { - quicksort(source, 0, source.length - 1); - } - - /** - * Sort a subarray of a source array. The subarray is specified by its start - * and end index. - * - * @param source the int array to be sorted - * @param left the start index of the subarray - * @param right the end index of the subarray - */ - public static void quicksort(int[] source, int left, int right) - { - if (right > left) - { - int index = partition(source, left, right, right); - quicksort(source, left, index - 1); - quicksort(source, index + 1, right); - } - } - - /** - * Split a subarray of a source array into two partitions. The left - * partition contains elements that have value less than or equal to the - * pivot element, the right partition contains the elements that have larger - * value. - * - * @param source the int array whose subarray will be splitted - * @param left the start position of the subarray - * @param right the end position of the subarray - * @param pivotIndex the index of the pivot element inside the array - * @return the new index of the pivot element inside the array - */ - private static int partition(int[] source, int left, int right, - int pivotIndex) - { - - int pivot = source[pivotIndex]; - source[pivotIndex] = source[right]; - source[right] = pivot; - - int index = left; - - for (int i = left; i < right; i++) - { - if (source[i] <= pivot) - { - int tmp = source[index]; - source[index] = source[i]; - source[i] = tmp; - index++; - } - } - - int tmp = source[index]; - source[index] = source[right]; - source[right] = tmp; - - return index; - } - - /** - * Generates a subarray of a given int array. - * - * @param input - - * the input int array - * @param start - - * the start index - * @param end - - * the end index - * @return a subarray of <tt>input</tt>, ranging from <tt>start</tt> to - * <tt>end</tt> - */ - public static int[] subArray(final int[] input, final int start, - final int end) - { - int[] result = new int[end - start]; - System.arraycopy(input, start, result, 0, end - start); - return result; - } - - /** - * Convert an int array to a {@link FlexiBigInt} array. - * - * @param input the int array - * @return the {@link FlexiBigInt} array - */ - public static BigInteger[] toFlexiBigIntArray(int[] input) - { - BigInteger[] result = new BigInteger[input.length]; - for (int i = 0; i < input.length; i++) - { - result[i] = BigInteger.valueOf(input[i]); - } - return result; - } - - /** - * @param input an int array - * @return a human readable form of the given int array - */ - public static String toString(int[] input) - { - String result = ""; - for (int i = 0; i < input.length; i++) - { - result += input[i] + " "; - } - return result; - } - - /** - * @param input an int arary - * @return the int array as hex string - */ - public static String toHexString(int[] input) - { - return ByteUtils.toHexString(BigEndianConversions.toByteArray(input)); - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/IntegerFunctions.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/IntegerFunctions.java deleted file mode 100644 index 779f384a..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/IntegerFunctions.java +++ /dev/null @@ -1,1423 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -import java.math.BigInteger; -import java.security.SecureRandom; - -/** - * Class of number-theory related functions for use with integers represented as - * <tt>int</tt>'s or <tt>BigInteger</tt> objects. - */ -public final class IntegerFunctions -{ - - private static final BigInteger ZERO = BigInteger.valueOf(0); - - private static final BigInteger ONE = BigInteger.valueOf(1); - - private static final BigInteger TWO = BigInteger.valueOf(2); - - private static final BigInteger FOUR = BigInteger.valueOf(4); - - private static final int[] SMALL_PRIMES = {3, 5, 7, 11, 13, 17, 19, 23, - 29, 31, 37, 41}; - - private static final long SMALL_PRIME_PRODUCT = 3L * 5 * 7 * 11 * 13 * 17 - * 19 * 23 * 29 * 31 * 37 * 41; - - private static SecureRandom sr = null; - - // the jacobi function uses this lookup table - private static final int[] jacobiTable = {0, 1, 0, -1, 0, -1, 0, 1}; - - private IntegerFunctions() - { - // empty - } - - /** - * Computes the value of the Jacobi symbol (A|B). The following properties - * hold for the Jacobi symbol which makes it a very efficient way to - * evaluate the Legendre symbol - * <p> - * (A|B) = 0 IF gcd(A,B) > 1<br> - * (-1|B) = 1 IF n = 1 (mod 1)<br> - * (-1|B) = -1 IF n = 3 (mod 4)<br> - * (A|B) (C|B) = (AC|B)<br> - * (A|B) (A|C) = (A|CB)<br> - * (A|B) = (C|B) IF A = C (mod B)<br> - * (2|B) = 1 IF N = 1 OR 7 (mod 8)<br> - * (2|B) = 1 IF N = 3 OR 5 (mod 8) - * - * @param A integer value - * @param B integer value - * @return value of the jacobi symbol (A|B) - */ - public static int jacobi(BigInteger A, BigInteger B) - { - BigInteger a, b, v; - long k = 1; - - k = 1; - - // test trivial cases - if (B.equals(ZERO)) - { - a = A.abs(); - return a.equals(ONE) ? 1 : 0; - } - - if (!A.testBit(0) && !B.testBit(0)) - { - return 0; - } - - a = A; - b = B; - - if (b.signum() == -1) - { // b < 0 - b = b.negate(); // b = -b - if (a.signum() == -1) - { - k = -1; - } - } - - v = ZERO; - while (!b.testBit(0)) - { - v = v.add(ONE); // v = v + 1 - b = b.divide(TWO); // b = b/2 - } - - if (v.testBit(0)) - { - k = k * jacobiTable[a.intValue() & 7]; - } - - if (a.signum() < 0) - { // a < 0 - if (b.testBit(1)) - { - k = -k; // k = -k - } - a = a.negate(); // a = -a - } - - // main loop - while (a.signum() != 0) - { - v = ZERO; - while (!a.testBit(0)) - { // a is even - v = v.add(ONE); - a = a.divide(TWO); - } - if (v.testBit(0)) - { - k = k * jacobiTable[b.intValue() & 7]; - } - - if (a.compareTo(b) < 0) - { // a < b - // swap and correct intermediate result - BigInteger x = a; - a = b; - b = x; - if (a.testBit(1) && b.testBit(1)) - { - k = -k; - } - } - a = a.subtract(b); - } - - return b.equals(ONE) ? (int)k : 0; - } - - /** - * Computes the square root of a BigInteger modulo a prime employing the - * Shanks-Tonelli algorithm. - * - * @param a value out of which we extract the square root - * @param p prime modulus that determines the underlying field - * @return a number <tt>b</tt> such that b<sup>2</sup> = a (mod p) if - * <tt>a</tt> is a quadratic residue modulo <tt>p</tt>. - * @throws NoQuadraticResidueException if <tt>a</tt> is a quadratic non-residue modulo <tt>p</tt> - */ - public static BigInteger ressol(BigInteger a, BigInteger p) - throws IllegalArgumentException - { - - BigInteger v = null; - - if (a.compareTo(ZERO) < 0) - { - a = a.add(p); - } - - if (a.equals(ZERO)) - { - return ZERO; - } - - if (p.equals(TWO)) - { - return a; - } - - // p = 3 mod 4 - if (p.testBit(0) && p.testBit(1)) - { - if (jacobi(a, p) == 1) - { // a quadr. residue mod p - v = p.add(ONE); // v = p+1 - v = v.shiftRight(2); // v = v/4 - return a.modPow(v, p); // return a^v mod p - // return --> a^((p+1)/4) mod p - } - throw new IllegalArgumentException("No quadratic residue: " + a + ", " + p); - } - - long t = 0; - - // initialization - // compute k and s, where p = 2^s (2k+1) +1 - - BigInteger k = p.subtract(ONE); // k = p-1 - long s = 0; - while (!k.testBit(0)) - { // while k is even - s++; // s = s+1 - k = k.shiftRight(1); // k = k/2 - } - - k = k.subtract(ONE); // k = k - 1 - k = k.shiftRight(1); // k = k/2 - - // initial values - BigInteger r = a.modPow(k, p); // r = a^k mod p - - BigInteger n = r.multiply(r).remainder(p); // n = r^2 % p - n = n.multiply(a).remainder(p); // n = n * a % p - r = r.multiply(a).remainder(p); // r = r * a %p - - if (n.equals(ONE)) - { - return r; - } - - // non-quadratic residue - BigInteger z = TWO; // z = 2 - while (jacobi(z, p) == 1) - { - // while z quadratic residue - z = z.add(ONE); // z = z + 1 - } - - v = k; - v = v.multiply(TWO); // v = 2k - v = v.add(ONE); // v = 2k + 1 - BigInteger c = z.modPow(v, p); // c = z^v mod p - - // iteration - while (n.compareTo(ONE) == 1) - { // n > 1 - k = n; // k = n - t = s; // t = s - s = 0; - - while (!k.equals(ONE)) - { // k != 1 - k = k.multiply(k).mod(p); // k = k^2 % p - s++; // s = s + 1 - } - - t -= s; // t = t - s - if (t == 0) - { - throw new IllegalArgumentException("No quadratic residue: " + a + ", " + p); - } - - v = ONE; - for (long i = 0; i < t - 1; i++) - { - v = v.shiftLeft(1); // v = 1 * 2^(t - 1) - } - c = c.modPow(v, p); // c = c^v mod p - r = r.multiply(c).remainder(p); // r = r * c % p - c = c.multiply(c).remainder(p); // c = c^2 % p - n = n.multiply(c).mod(p); // n = n * c % p - } - return r; - } - - /** - * Computes the greatest common divisor of the two specified integers - * - * @param u - first integer - * @param v - second integer - * @return gcd(a, b) - */ - public static int gcd(int u, int v) - { - return BigInteger.valueOf(u).gcd(BigInteger.valueOf(v)).intValue(); - } - - /** - * Extended euclidian algorithm (computes gcd and representation). - * - * @param a the first integer - * @param b the second integer - * @return <tt>(g,u,v)</tt>, where <tt>g = gcd(abs(a),abs(b)) = ua + vb</tt> - */ - public static int[] extGCD(int a, int b) - { - BigInteger ba = BigInteger.valueOf(a); - BigInteger bb = BigInteger.valueOf(b); - BigInteger[] bresult = extgcd(ba, bb); - int[] result = new int[3]; - result[0] = bresult[0].intValue(); - result[1] = bresult[1].intValue(); - result[2] = bresult[2].intValue(); - return result; - } - - public static BigInteger divideAndRound(BigInteger a, BigInteger b) - { - if (a.signum() < 0) - { - return divideAndRound(a.negate(), b).negate(); - } - if (b.signum() < 0) - { - return divideAndRound(a, b.negate()).negate(); - } - return a.shiftLeft(1).add(b).divide(b.shiftLeft(1)); - } - - public static BigInteger[] divideAndRound(BigInteger[] a, BigInteger b) - { - BigInteger[] out = new BigInteger[a.length]; - for (int i = 0; i < a.length; i++) - { - out[i] = divideAndRound(a[i], b); - } - return out; - } - - /** - * Compute the smallest integer that is greater than or equal to the - * logarithm to the base 2 of the given BigInteger. - * - * @param a the integer - * @return ceil[log(a)] - */ - public static int ceilLog(BigInteger a) - { - int result = 0; - BigInteger p = ONE; - while (p.compareTo(a) < 0) - { - result++; - p = p.shiftLeft(1); - } - return result; - } - - /** - * Compute the smallest integer that is greater than or equal to the - * logarithm to the base 2 of the given integer. - * - * @param a the integer - * @return ceil[log(a)] - */ - public static int ceilLog(int a) - { - int log = 0; - int i = 1; - while (i < a) - { - i <<= 1; - log++; - } - return log; - } - - /** - * Compute <tt>ceil(log_256 n)</tt>, the number of bytes needed to encode - * the integer <tt>n</tt>. - * - * @param n the integer - * @return the number of bytes needed to encode <tt>n</tt> - */ - public static int ceilLog256(int n) - { - if (n == 0) - { - return 1; - } - int m; - if (n < 0) - { - m = -n; - } - else - { - m = n; - } - - int d = 0; - while (m > 0) - { - d++; - m >>>= 8; - } - return d; - } - - /** - * Compute <tt>ceil(log_256 n)</tt>, the number of bytes needed to encode - * the long integer <tt>n</tt>. - * - * @param n the long integer - * @return the number of bytes needed to encode <tt>n</tt> - */ - public static int ceilLog256(long n) - { - if (n == 0) - { - return 1; - } - long m; - if (n < 0) - { - m = -n; - } - else - { - m = n; - } - - int d = 0; - while (m > 0) - { - d++; - m >>>= 8; - } - return d; - } - - /** - * Compute the integer part of the logarithm to the base 2 of the given - * integer. - * - * @param a the integer - * @return floor[log(a)] - */ - public static int floorLog(BigInteger a) - { - int result = -1; - BigInteger p = ONE; - while (p.compareTo(a) <= 0) - { - result++; - p = p.shiftLeft(1); - } - return result; - } - - /** - * Compute the integer part of the logarithm to the base 2 of the given - * integer. - * - * @param a the integer - * @return floor[log(a)] - */ - public static int floorLog(int a) - { - int h = 0; - if (a <= 0) - { - return -1; - } - int p = a >>> 1; - while (p > 0) - { - h++; - p >>>= 1; - } - - return h; - } - - /** - * Compute the largest <tt>h</tt> with <tt>2^h | a</tt> if <tt>a!=0</tt>. - * - * @param a an integer - * @return the largest <tt>h</tt> with <tt>2^h | a</tt> if <tt>a!=0</tt>, - * <tt>0</tt> otherwise - */ - public static int maxPower(int a) - { - int h = 0; - if (a != 0) - { - int p = 1; - while ((a & p) == 0) - { - h++; - p <<= 1; - } - } - - return h; - } - - /** - * @param a an integer - * @return the number of ones in the binary representation of an integer - * <tt>a</tt> - */ - public static int bitCount(int a) - { - int h = 0; - while (a != 0) - { - h += a & 1; - a >>>= 1; - } - - return h; - } - - /** - * determines the order of g modulo p, p prime and 1 < g < p. This algorithm - * is only efficient for small p (see X9.62-1998, p. 68). - * - * @param g an integer with 1 < g < p - * @param p a prime - * @return the order k of g (that is k is the smallest integer with - * g<sup>k</sup> = 1 mod p - */ - public static int order(int g, int p) - { - int b, j; - - b = g % p; // Reduce g mod p first. - j = 1; - - // Check whether g == 0 mod p (avoiding endless loop). - if (b == 0) - { - throw new IllegalArgumentException(g + " is not an element of Z/(" - + p + "Z)^*; it is not meaningful to compute its order."); - } - - // Compute the order of g mod p: - while (b != 1) - { - b *= g; - b %= p; - if (b < 0) - { - b += p; - } - j++; - } - - return j; - } - - /** - * Reduces an integer into a given interval - * - * @param n - the integer - * @param begin - left bound of the interval - * @param end - right bound of the interval - * @return <tt>n</tt> reduced into <tt>[begin,end]</tt> - */ - public static BigInteger reduceInto(BigInteger n, BigInteger begin, - BigInteger end) - { - return n.subtract(begin).mod(end.subtract(begin)).add(begin); - } - - /** - * Compute <tt>a<sup>e</sup></tt>. - * - * @param a the base - * @param e the exponent - * @return <tt>a<sup>e</sup></tt> - */ - public static int pow(int a, int e) - { - int result = 1; - while (e > 0) - { - if ((e & 1) == 1) - { - result *= a; - } - a *= a; - e >>>= 1; - } - return result; - } - - /** - * Compute <tt>a<sup>e</sup></tt>. - * - * @param a the base - * @param e the exponent - * @return <tt>a<sup>e</sup></tt> - */ - public static long pow(long a, int e) - { - long result = 1; - while (e > 0) - { - if ((e & 1) == 1) - { - result *= a; - } - a *= a; - e >>>= 1; - } - return result; - } - - /** - * Compute <tt>a<sup>e</sup> mod n</tt>. - * - * @param a the base - * @param e the exponent - * @param n the modulus - * @return <tt>a<sup>e</sup> mod n</tt> - */ - public static int modPow(int a, int e, int n) - { - if (n <= 0 || (n * n) > Integer.MAX_VALUE || e < 0) - { - return 0; - } - int result = 1; - a = (a % n + n) % n; - while (e > 0) - { - if ((e & 1) == 1) - { - result = (result * a) % n; - } - a = (a * a) % n; - e >>>= 1; - } - return result; - } - - /** - * Extended euclidian algorithm (computes gcd and representation). - * - * @param a - the first integer - * @param b - the second integer - * @return <tt>(d,u,v)</tt>, where <tt>d = gcd(a,b) = ua + vb</tt> - */ - public static BigInteger[] extgcd(BigInteger a, BigInteger b) - { - BigInteger u = ONE; - BigInteger v = ZERO; - BigInteger d = a; - if (b.signum() != 0) - { - BigInteger v1 = ZERO; - BigInteger v3 = b; - while (v3.signum() != 0) - { - BigInteger[] tmp = d.divideAndRemainder(v3); - BigInteger q = tmp[0]; - BigInteger t3 = tmp[1]; - BigInteger t1 = u.subtract(q.multiply(v1)); - u = v1; - d = v3; - v1 = t1; - v3 = t3; - } - v = d.subtract(a.multiply(u)).divide(b); - } - return new BigInteger[]{d, u, v}; - } - - /** - * Computation of the least common multiple of a set of BigIntegers. - * - * @param numbers - the set of numbers - * @return the lcm(numbers) - */ - public static BigInteger leastCommonMultiple(BigInteger[] numbers) - { - int n = numbers.length; - BigInteger result = numbers[0]; - for (int i = 1; i < n; i++) - { - BigInteger gcd = result.gcd(numbers[i]); - result = result.multiply(numbers[i]).divide(gcd); - } - return result; - } - - /** - * Returns a long integer whose value is <tt>(a mod m</tt>). This method - * differs from <tt>%</tt> in that it always returns a <i>non-negative</i> - * integer. - * - * @param a value on which the modulo operation has to be performed. - * @param m the modulus. - * @return <tt>a mod m</tt> - */ - public static long mod(long a, long m) - { - long result = a % m; - if (result < 0) - { - result += m; - } - return result; - } - - /** - * Computes the modular inverse of an integer a - * - * @param a - the integer to invert - * @param mod - the modulus - * @return <tt>a<sup>-1</sup> mod n</tt> - */ - public static int modInverse(int a, int mod) - { - return BigInteger.valueOf(a).modInverse(BigInteger.valueOf(mod)) - .intValue(); - } - - /** - * Computes the modular inverse of an integer a - * - * @param a - the integer to invert - * @param mod - the modulus - * @return <tt>a<sup>-1</sup> mod n</tt> - */ - public static long modInverse(long a, long mod) - { - return BigInteger.valueOf(a).modInverse(BigInteger.valueOf(mod)) - .longValue(); - } - - /** - * Tests whether an integer <tt>a</tt> is power of another integer - * <tt>p</tt>. - * - * @param a - the first integer - * @param p - the second integer - * @return n if a = p^n or -1 otherwise - */ - public static int isPower(int a, int p) - { - if (a <= 0) - { - return -1; - } - int n = 0; - int d = a; - while (d > 1) - { - if (d % p != 0) - { - return -1; - } - d /= p; - n++; - } - return n; - } - - /** - * Find and return the least non-trivial divisor of an integer <tt>a</tt>. - * - * @param a - the integer - * @return divisor p >1 or 1 if a = -1,0,1 - */ - public static int leastDiv(int a) - { - if (a < 0) - { - a = -a; - } - if (a == 0) - { - return 1; - } - if ((a & 1) == 0) - { - return 2; - } - int p = 3; - while (p <= (a / p)) - { - if ((a % p) == 0) - { - return p; - } - p += 2; - } - - return a; - } - - /** - * Miller-Rabin-Test, determines wether the given integer is probably prime - * or composite. This method returns <tt>true</tt> if the given integer is - * prime with probability <tt>1 - 2<sup>-20</sup></tt>. - * - * @param n the integer to test for primality - * @return <tt>true</tt> if the given integer is prime with probability - * 2<sup>-100</sup>, <tt>false</tt> otherwise - */ - public static boolean isPrime(int n) - { - if (n < 2) - { - return false; - } - if (n == 2) - { - return true; - } - if ((n & 1) == 0) - { - return false; - } - if (n < 42) - { - for (int i = 0; i < SMALL_PRIMES.length; i++) - { - if (n == SMALL_PRIMES[i]) - { - return true; - } - } - } - - if ((n % 3 == 0) || (n % 5 == 0) || (n % 7 == 0) || (n % 11 == 0) - || (n % 13 == 0) || (n % 17 == 0) || (n % 19 == 0) - || (n % 23 == 0) || (n % 29 == 0) || (n % 31 == 0) - || (n % 37 == 0) || (n % 41 == 0)) - { - return false; - } - - return BigInteger.valueOf(n).isProbablePrime(20); - } - - /** - * Short trial-division test to find out whether a number is not prime. This - * test is usually used before a Miller-Rabin primality test. - * - * @param candidate the number to test - * @return <tt>true</tt> if the number has no factor of the tested primes, - * <tt>false</tt> if the number is definitely composite - */ - public static boolean passesSmallPrimeTest(BigInteger candidate) - { - final int[] smallPrime = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, - 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, - 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, - 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, - 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, - 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, - 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, - 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, - 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, - 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, - 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, - 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, - 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, - 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, - 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, - 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, - 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, - 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, - 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, - 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, - 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499}; - - for (int i = 0; i < smallPrime.length; i++) - { - if (candidate.mod(BigInteger.valueOf(smallPrime[i])).equals( - ZERO)) - { - return false; - } - } - return true; - } - - /** - * Returns the largest prime smaller than the given integer - * - * @param n - upper bound - * @return the largest prime smaller than <tt>n</tt>, or <tt>1</tt> if - * <tt>n <= 2</tt> - */ - public static int nextSmallerPrime(int n) - { - if (n <= 2) - { - return 1; - } - - if (n == 3) - { - return 2; - } - - if ((n & 1) == 0) - { - n--; - } - else - { - n -= 2; - } - - while (n > 3 & !isPrime(n)) - { - n -= 2; - } - return n; - } - - /** - * Compute the next probable prime greater than <tt>n</tt> with the - * specified certainty. - * - * @param n a integer number - * @param certainty the certainty that the generated number is prime - * @return the next prime greater than <tt>n</tt> - */ - public static BigInteger nextProbablePrime(BigInteger n, int certainty) - { - - if (n.signum() < 0 || n.signum() == 0 || n.equals(ONE)) - { - return TWO; - } - - BigInteger result = n.add(ONE); - - // Ensure an odd number - if (!result.testBit(0)) - { - result = result.add(ONE); - } - - while (true) - { - // Do cheap "pre-test" if applicable - if (result.bitLength() > 6) - { - long r = result.remainder( - BigInteger.valueOf(SMALL_PRIME_PRODUCT)).longValue(); - if ((r % 3 == 0) || (r % 5 == 0) || (r % 7 == 0) - || (r % 11 == 0) || (r % 13 == 0) || (r % 17 == 0) - || (r % 19 == 0) || (r % 23 == 0) || (r % 29 == 0) - || (r % 31 == 0) || (r % 37 == 0) || (r % 41 == 0)) - { - result = result.add(TWO); - continue; // Candidate is composite; try another - } - } - - // All candidates of bitLength 2 and 3 are prime by this point - if (result.bitLength() < 4) - { - return result; - } - - // The expensive test - if (result.isProbablePrime(certainty)) - { - return result; - } - - result = result.add(TWO); - } - } - - /** - * Compute the next probable prime greater than <tt>n</tt> with the default - * certainty (20). - * - * @param n a integer number - * @return the next prime greater than <tt>n</tt> - */ - public static BigInteger nextProbablePrime(BigInteger n) - { - return nextProbablePrime(n, 20); - } - - /** - * Computes the next prime greater than n. - * - * @param n a integer number - * @return the next prime greater than n - */ - public static BigInteger nextPrime(long n) - { - long i; - boolean found = false; - long result = 0; - - if (n <= 1) - { - return BigInteger.valueOf(2); - } - if (n == 2) - { - return BigInteger.valueOf(3); - } - - for (i = n + 1 + (n & 1); (i <= n << 1) && !found; i += 2) - { - for (long j = 3; (j <= i >> 1) && !found; j += 2) - { - if (i % j == 0) - { - found = true; - } - } - if (found) - { - found = false; - } - else - { - result = i; - found = true; - } - } - return BigInteger.valueOf(result); - } - - /** - * Computes the binomial coefficient (n|t) ("n over t"). Formula: - * <ul> - * <li>if n !=0 and t != 0 then (n|t) = Mult(i=1, t): (n-(i-1))/i</li> - * <li>if t = 0 then (n|t) = 1</li> - * <li>if n = 0 and t > 0 then (n|t) = 0</li> - * </ul> - * - * @param n - the "upper" integer - * @param t - the "lower" integer - * @return the binomialcoefficient "n over t" as BigInteger - */ - public static BigInteger binomial(int n, int t) - { - - BigInteger result = ONE; - - if (n == 0) - { - if (t == 0) - { - return result; - } - return ZERO; - } - - // the property (n|t) = (n|n-t) be used to reduce numbers of operations - if (t > (n >>> 1)) - { - t = n - t; - } - - for (int i = 1; i <= t; i++) - { - result = (result.multiply(BigInteger.valueOf(n - (i - 1)))) - .divide(BigInteger.valueOf(i)); - } - - return result; - } - - public static BigInteger randomize(BigInteger upperBound) - { - if (sr == null) - { - sr = new SecureRandom(); - } - return randomize(upperBound, sr); - } - - public static BigInteger randomize(BigInteger upperBound, - SecureRandom prng) - { - int blen = upperBound.bitLength(); - BigInteger randomNum = BigInteger.valueOf(0); - - if (prng == null) - { - prng = sr != null ? sr : new SecureRandom(); - } - - for (int i = 0; i < 20; i++) - { - randomNum = new BigInteger(blen, prng); - if (randomNum.compareTo(upperBound) < 0) - { - return randomNum; - } - } - return randomNum.mod(upperBound); - } - - /** - * Extract the truncated square root of a BigInteger. - * - * @param a - value out of which we extract the square root - * @return the truncated square root of <tt>a</tt> - */ - public static BigInteger squareRoot(BigInteger a) - { - int bl; - BigInteger result, remainder, b; - - if (a.compareTo(ZERO) < 0) - { - throw new ArithmeticException( - "cannot extract root of negative number" + a + "."); - } - - bl = a.bitLength(); - result = ZERO; - remainder = ZERO; - - // if the bit length is odd then extra step - if ((bl & 1) != 0) - { - result = result.add(ONE); - bl--; - } - - while (bl > 0) - { - remainder = remainder.multiply(FOUR); - remainder = remainder.add(BigInteger.valueOf((a.testBit(--bl) ? 2 - : 0) - + (a.testBit(--bl) ? 1 : 0))); - b = result.multiply(FOUR).add(ONE); - result = result.multiply(TWO); - if (remainder.compareTo(b) != -1) - { - result = result.add(ONE); - remainder = remainder.subtract(b); - } - } - - return result; - } - - /** - * Takes an approximation of the root from an integer base, using newton's - * algorithm - * - * @param base the base to take the root from - * @param root the root, for example 2 for a square root - */ - public static float intRoot(int base, int root) - { - float gNew = base / root; - float gOld = 0; - int counter = 0; - while (Math.abs(gOld - gNew) > 0.0001) - { - float gPow = floatPow(gNew, root); - while (Float.isInfinite(gPow)) - { - gNew = (gNew + gOld) / 2; - gPow = floatPow(gNew, root); - } - counter += 1; - gOld = gNew; - gNew = gOld - (gPow - base) / (root * floatPow(gOld, root - 1)); - } - return gNew; - } - - /** - * Calculation of a logarithmus of a float param - * - * @param param - * @return - */ - public static float floatLog(float param) - { - double arg = (param - 1) / (param + 1); - double arg2 = arg; - int counter = 1; - float result = (float)arg; - - while (arg2 > 0.001) - { - counter += 2; - arg2 *= arg * arg; - result += (1. / counter) * arg2; - } - return 2 * result; - } - - /** - * int power of a base float, only use for small ints - * - * @param f - * @param i - * @return - */ - public static float floatPow(float f, int i) - { - float g = 1; - for (; i > 0; i--) - { - g *= f; - } - return g; - } - - /** - * calculate the logarithm to the base 2. - * - * @param x any double value - * @return log_2(x) - * @deprecated use MathFunctions.log(double) instead - */ - public static double log(double x) - { - if (x > 0 && x < 1) - { - double d = 1 / x; - double result = -log(d); - return result; - } - - int tmp = 0; - double tmp2 = 1; - double d = x; - - while (d > 2) - { - d = d / 2; - tmp += 1; - tmp2 *= 2; - } - double rem = x / tmp2; - rem = logBKM(rem); - return tmp + rem; - } - - /** - * calculate the logarithm to the base 2. - * - * @param x any long value >=1 - * @return log_2(x) - * @deprecated use MathFunctions.log(long) instead - */ - public static double log(long x) - { - int tmp = floorLog(BigInteger.valueOf(x)); - long tmp2 = 1 << tmp; - double rem = (double)x / (double)tmp2; - rem = logBKM(rem); - return tmp + rem; - } - - /** - * BKM Algorithm to calculate logarithms to the base 2. - * - * @param arg a double value with 1<= arg<= 4.768462058 - * @return log_2(arg) - * @deprecated use MathFunctions.logBKM(double) instead - */ - private static double logBKM(double arg) - { - double ae[] = // A_e[k] = log_2 (1 + 0.5^k) - { - 1.0000000000000000000000000000000000000000000000000000000000000000000000000000, - 0.5849625007211561814537389439478165087598144076924810604557526545410982276485, - 0.3219280948873623478703194294893901758648313930245806120547563958159347765589, - 0.1699250014423123629074778878956330175196288153849621209115053090821964552970, - 0.0874628412503394082540660108104043540112672823448206881266090643866965081686, - 0.0443941193584534376531019906736094674630459333742491317685543002674288465967, - 0.0223678130284545082671320837460849094932677948156179815932199216587899627785, - 0.0112272554232541203378805844158839407281095943600297940811823651462712311786, - 0.0056245491938781069198591026740666017211096815383520359072957784732489771013, - 0.0028150156070540381547362547502839489729507927389771959487826944878598909400, - 0.0014081943928083889066101665016890524233311715793462235597709051792834906001, - 0.0007042690112466432585379340422201964456668872087249334581924550139514213168, - 0.0003521774803010272377989609925281744988670304302127133979341729842842377649, - 0.0001760994864425060348637509459678580940163670081839283659942864068257522373, - 0.0000880524301221769086378699983597183301490534085738474534831071719854721939, - 0.0000440268868273167176441087067175806394819146645511899503059774914593663365, - 0.0000220136113603404964890728830697555571275493801909791504158295359319433723, - 0.0000110068476674814423006223021573490183469930819844945565597452748333526464, - 0.0000055034343306486037230640321058826431606183125807276574241540303833251704, - 0.0000027517197895612831123023958331509538486493412831626219340570294203116559, - 0.0000013758605508411382010566802834037147561973553922354232704569052932922954, - 0.0000006879304394358496786728937442939160483304056131990916985043387874690617, - 0.0000003439652607217645360118314743718005315334062644619363447395987584138324, - 0.0000001719826406118446361936972479533123619972434705828085978955697643547921, - 0.0000000859913228686632156462565208266682841603921494181830811515318381744650, - 0.0000000429956620750168703982940244684787907148132725669106053076409624949917, - 0.0000000214978311976797556164155504126645192380395989504741781512309853438587, - 0.0000000107489156388827085092095702361647949603617203979413516082280717515504, - 0.0000000053744578294520620044408178949217773318785601260677517784797554422804, - 0.0000000026872289172287079490026152352638891824761667284401180026908031182361, - 0.0000000013436144592400232123622589569799954658536700992739887706412976115422, - 0.0000000006718072297764289157920422846078078155859484240808550018085324187007, - 0.0000000003359036149273187853169587152657145221968468364663464125722491530858, - 0.0000000001679518074734354745159899223037458278711244127245990591908996412262, - 0.0000000000839759037391617577226571237484864917411614198675604731728132152582, - 0.0000000000419879518701918839775296677020135040214077417929807824842667285938, - 0.0000000000209939759352486932678195559552767641474249812845414125580747434389, - 0.0000000000104969879676625344536740142096218372850561859495065136990936290929, - 0.0000000000052484939838408141817781356260462777942148580518406975851213868092, - 0.0000000000026242469919227938296243586262369156865545638305682553644113887909, - 0.0000000000013121234959619935994960031017850191710121890821178731821983105443, - 0.0000000000006560617479811459709189576337295395590603644549624717910616347038, - 0.0000000000003280308739906102782522178545328259781415615142931952662153623493, - 0.0000000000001640154369953144623242936888032768768777422997704541618141646683, - 0.0000000000000820077184976595619616930350508356401599552034612281802599177300, - 0.0000000000000410038592488303636807330652208397742314215159774270270147020117, - 0.0000000000000205019296244153275153381695384157073687186580546938331088730952, - 0.0000000000000102509648122077001764119940017243502120046885379813510430378661, - 0.0000000000000051254824061038591928917243090559919209628584150482483994782302, - 0.0000000000000025627412030519318726172939815845367496027046030028595094737777, - 0.0000000000000012813706015259665053515049475574143952543145124550608158430592, - 0.0000000000000006406853007629833949364669629701200556369782295210193569318434, - 0.0000000000000003203426503814917330334121037829290364330169106716787999052925, - 0.0000000000000001601713251907458754080007074659337446341494733882570243497196, - 0.0000000000000000800856625953729399268240176265844257044861248416330071223615, - 0.0000000000000000400428312976864705191179247866966320469710511619971334577509, - 0.0000000000000000200214156488432353984854413866994246781519154793320684126179, - 0.0000000000000000100107078244216177339743404416874899847406043033792202127070, - 0.0000000000000000050053539122108088756700751579281894640362199287591340285355, - 0.0000000000000000025026769561054044400057638132352058574658089256646014899499, - 0.0000000000000000012513384780527022205455634651853807110362316427807660551208, - 0.0000000000000000006256692390263511104084521222346348012116229213309001913762, - 0.0000000000000000003128346195131755552381436585278035120438976487697544916191, - 0.0000000000000000001564173097565877776275512286165232838833090480508502328437, - 0.0000000000000000000782086548782938888158954641464170239072244145219054734086, - 0.0000000000000000000391043274391469444084776945327473574450334092075712154016, - 0.0000000000000000000195521637195734722043713378812583900953755962557525252782, - 0.0000000000000000000097760818597867361022187915943503728909029699365320287407, - 0.0000000000000000000048880409298933680511176764606054809062553340323879609794, - 0.0000000000000000000024440204649466840255609083961603140683286362962192177597, - 0.0000000000000000000012220102324733420127809717395445504379645613448652614939, - 0.0000000000000000000006110051162366710063906152551383735699323415812152114058, - 0.0000000000000000000003055025581183355031953399739107113727036860315024588989, - 0.0000000000000000000001527512790591677515976780735407368332862218276873443537, - 0.0000000000000000000000763756395295838757988410584167137033767056170417508383, - 0.0000000000000000000000381878197647919378994210346199431733717514843471513618, - 0.0000000000000000000000190939098823959689497106436628681671067254111334889005, - 0.0000000000000000000000095469549411979844748553534196582286585751228071408728, - 0.0000000000000000000000047734774705989922374276846068851506055906657137209047, - 0.0000000000000000000000023867387352994961187138442777065843718711089344045782, - 0.0000000000000000000000011933693676497480593569226324192944532044984865894525, - 0.0000000000000000000000005966846838248740296784614396011477934194852481410926, - 0.0000000000000000000000002983423419124370148392307506484490384140516252814304, - 0.0000000000000000000000001491711709562185074196153830361933046331030629430117, - 0.0000000000000000000000000745855854781092537098076934460888486730708440475045, - 0.0000000000000000000000000372927927390546268549038472050424734256652501673274, - 0.0000000000000000000000000186463963695273134274519237230207489851150821191330, - 0.0000000000000000000000000093231981847636567137259618916352525606281553180093, - 0.0000000000000000000000000046615990923818283568629809533488457973317312233323, - 0.0000000000000000000000000023307995461909141784314904785572277779202790023236, - 0.0000000000000000000000000011653997730954570892157452397493151087737428485431, - 0.0000000000000000000000000005826998865477285446078726199923328593402722606924, - 0.0000000000000000000000000002913499432738642723039363100255852559084863397344, - 0.0000000000000000000000000001456749716369321361519681550201473345138307215067, - 0.0000000000000000000000000000728374858184660680759840775119123438968122488047, - 0.0000000000000000000000000000364187429092330340379920387564158411083803465567, - 0.0000000000000000000000000000182093714546165170189960193783228378441837282509, - 0.0000000000000000000000000000091046857273082585094980096891901482445902524441, - 0.0000000000000000000000000000045523428636541292547490048446022564529197237262, - 0.0000000000000000000000000000022761714318270646273745024223029238091160103901}; - int n = 53; - double x = 1; - double y = 0; - double z; - double s = 1; - int k; - - for (k = 0; k < n; k++) - { - z = x + x * s; - if (z <= arg) - { - x = z; - y += ae[k]; - } - s *= 0.5; - } - return y; - } - - public static boolean isIncreasing(int[] a) - { - for (int i = 1; i < a.length; i++) - { - if (a[i - 1] >= a[i]) - { - System.out.println("a[" + (i - 1) + "] = " + a[i - 1] + " >= " - + a[i] + " = a[" + i + "]"); - return false; - } - } - return true; - } - - public static byte[] integerToOctets(BigInteger val) - { - byte[] valBytes = val.abs().toByteArray(); - - // check whether the array includes a sign bit - if ((val.bitLength() & 7) != 0) - { - return valBytes; - } - // get rid of the sign bit (first byte) - byte[] tmp = new byte[val.bitLength() >> 3]; - System.arraycopy(valBytes, 1, tmp, 0, tmp.length); - return tmp; - } - - public static BigInteger octetsToInteger(byte[] data, int offset, - int length) - { - byte[] val = new byte[length + 1]; - - val[0] = 0; - System.arraycopy(data, offset, val, 1, length); - return new BigInteger(val); - } - - public static BigInteger octetsToInteger(byte[] data) - { - return octetsToInteger(data, 0, data.length); - } - - public static void main(String[] args) - { - System.out.println("test"); - // System.out.println(intRoot(37, 5)); - // System.out.println(floatPow((float)2.5, 4)); - System.out.println(floatLog(10)); - System.out.println("test2"); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/LittleEndianConversions.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/LittleEndianConversions.java deleted file mode 100644 index c97fdc58..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/LittleEndianConversions.java +++ /dev/null @@ -1,230 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -/** - * This is a utility class containing data type conversions using little-endian - * byte order. - * - * @see BigEndianConversions - */ -public final class LittleEndianConversions -{ - - /** - * Default constructor (private). - */ - private LittleEndianConversions() - { - // empty - } - - /** - * Convert an octet string of length 4 to an integer. No length checking is - * performed. - * - * @param input the byte array holding the octet string - * @return an integer representing the octet string <tt>input</tt> - * @throws ArithmeticException if the length of the given octet string is larger than 4. - */ - public static int OS2IP(byte[] input) - { - return ((input[0] & 0xff)) | ((input[1] & 0xff) << 8) - | ((input[2] & 0xff) << 16) | ((input[3] & 0xff)) << 24; - } - - /** - * Convert an byte array of length 4 beginning at <tt>offset</tt> into an - * integer. - * - * @param input the byte array - * @param inOff the offset into the byte array - * @return the resulting integer - */ - public static int OS2IP(byte[] input, int inOff) - { - int result = input[inOff++] & 0xff; - result |= (input[inOff++] & 0xff) << 8; - result |= (input[inOff++] & 0xff) << 16; - result |= (input[inOff] & 0xff) << 24; - return result; - } - - /** - * Convert a byte array of the given length beginning at <tt>offset</tt> - * into an integer. - * - * @param input the byte array - * @param inOff the offset into the byte array - * @param inLen the length of the encoding - * @return the resulting integer - */ - public static int OS2IP(byte[] input, int inOff, int inLen) - { - int result = 0; - for (int i = inLen - 1; i >= 0; i--) - { - result |= (input[inOff + i] & 0xff) << (8 * i); - } - return result; - } - - /** - * Convert a byte array of length 8 beginning at <tt>inOff</tt> into a - * long integer. - * - * @param input the byte array - * @param inOff the offset into the byte array - * @return the resulting long integer - */ - public static long OS2LIP(byte[] input, int inOff) - { - long result = input[inOff++] & 0xff; - result |= (input[inOff++] & 0xff) << 8; - result |= (input[inOff++] & 0xff) << 16; - result |= ((long)input[inOff++] & 0xff) << 24; - result |= ((long)input[inOff++] & 0xff) << 32; - result |= ((long)input[inOff++] & 0xff) << 40; - result |= ((long)input[inOff++] & 0xff) << 48; - result |= ((long)input[inOff++] & 0xff) << 56; - return result; - } - - /** - * Convert an integer to an octet string of length 4. - * - * @param x the integer to convert - * @return the converted integer - */ - public static byte[] I2OSP(int x) - { - byte[] result = new byte[4]; - result[0] = (byte)x; - result[1] = (byte)(x >>> 8); - result[2] = (byte)(x >>> 16); - result[3] = (byte)(x >>> 24); - return result; - } - - /** - * Convert an integer into a byte array beginning at the specified offset. - * - * @param value the integer to convert - * @param output the byte array to hold the result - * @param outOff the integer offset into the byte array - */ - public static void I2OSP(int value, byte[] output, int outOff) - { - output[outOff++] = (byte)value; - output[outOff++] = (byte)(value >>> 8); - output[outOff++] = (byte)(value >>> 16); - output[outOff++] = (byte)(value >>> 24); - } - - /** - * Convert an integer to a byte array beginning at the specified offset. No - * length checking is performed (i.e., if the integer cannot be encoded with - * <tt>length</tt> octets, it is truncated). - * - * @param value the integer to convert - * @param output the byte array to hold the result - * @param outOff the integer offset into the byte array - * @param outLen the length of the encoding - */ - public static void I2OSP(int value, byte[] output, int outOff, int outLen) - { - for (int i = outLen - 1; i >= 0; i--) - { - output[outOff + i] = (byte)(value >>> (8 * i)); - } - } - - /** - * Convert an integer to a byte array of length 8. - * - * @param input the integer to convert - * @return the converted integer - */ - public static byte[] I2OSP(long input) - { - byte[] output = new byte[8]; - output[0] = (byte)input; - output[1] = (byte)(input >>> 8); - output[2] = (byte)(input >>> 16); - output[3] = (byte)(input >>> 24); - output[4] = (byte)(input >>> 32); - output[5] = (byte)(input >>> 40); - output[6] = (byte)(input >>> 48); - output[7] = (byte)(input >>> 56); - return output; - } - - /** - * Convert an integer to a byte array of length 8. - * - * @param input the integer to convert - * @param output byte array holding the output - * @param outOff offset in output array where the result is stored - */ - public static void I2OSP(long input, byte[] output, int outOff) - { - output[outOff++] = (byte)input; - output[outOff++] = (byte)(input >>> 8); - output[outOff++] = (byte)(input >>> 16); - output[outOff++] = (byte)(input >>> 24); - output[outOff++] = (byte)(input >>> 32); - output[outOff++] = (byte)(input >>> 40); - output[outOff++] = (byte)(input >>> 48); - output[outOff] = (byte)(input >>> 56); - } - - /** - * Convert an int array to a byte array of the specified length. No length - * checking is performed (i.e., if the last integer cannot be encoded with - * <tt>length % 4</tt> octets, it is truncated). - * - * @param input the int array - * @param outLen the length of the converted array - * @return the converted array - */ - public static byte[] toByteArray(int[] input, int outLen) - { - int intLen = input.length; - byte[] result = new byte[outLen]; - int index = 0; - for (int i = 0; i <= intLen - 2; i++, index += 4) - { - I2OSP(input[i], result, index); - } - I2OSP(input[intLen - 1], result, index, outLen - index); - return result; - } - - /** - * Convert a byte array to an int array. - * - * @param input the byte array - * @return the converted array - */ - public static int[] toIntArray(byte[] input) - { - int intLen = (input.length + 3) / 4; - int lastLen = input.length & 0x03; - int[] result = new int[intLen]; - - int index = 0; - for (int i = 0; i <= intLen - 2; i++, index += 4) - { - result[i] = OS2IP(input, index); - } - if (lastLen != 0) - { - result[intLen - 1] = OS2IP(input, index, lastLen); - } - else - { - result[intLen - 1] = OS2IP(input, index); - } - - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/Matrix.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/Matrix.java deleted file mode 100644 index 2c9a0eb6..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/Matrix.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -/** - * This abstract class defines matrices. It holds the number of rows and the - * number of columns of the matrix and defines some basic methods. - */ -public abstract class Matrix -{ - - /** - * number of rows - */ - protected int numRows; - - /** - * number of columns - */ - protected int numColumns; - - // ---------------------------------------------------- - // some constants (matrix types) - // ---------------------------------------------------- - - /** - * zero matrix - */ - public static final char MATRIX_TYPE_ZERO = 'Z'; - - /** - * unit matrix - */ - public static final char MATRIX_TYPE_UNIT = 'I'; - - /** - * random lower triangular matrix - */ - public static final char MATRIX_TYPE_RANDOM_LT = 'L'; - - /** - * random upper triangular matrix - */ - public static final char MATRIX_TYPE_RANDOM_UT = 'U'; - - /** - * random regular matrix - */ - public static final char MATRIX_TYPE_RANDOM_REGULAR = 'R'; - - // ---------------------------------------------------- - // getters - // ---------------------------------------------------- - - /** - * @return the number of rows in the matrix - */ - public int getNumRows() - { - return numRows; - } - - /** - * @return the number of columns in the binary matrix - */ - public int getNumColumns() - { - return numColumns; - } - - /** - * @return the encoded matrix, i.e., this matrix in byte array form. - */ - public abstract byte[] getEncoded(); - - // ---------------------------------------------------- - // arithmetic - // ---------------------------------------------------- - - /** - * Compute the inverse of this matrix. - * - * @return the inverse of this matrix (newly created). - */ - public abstract Matrix computeInverse(); - - /** - * Check if this is the zero matrix (i.e., all entries are zero). - * - * @return <tt>true</tt> if this is the zero matrix - */ - public abstract boolean isZero(); - - /** - * Compute the product of this matrix and another matrix. - * - * @param a the other matrix - * @return <tt>this * a</tt> (newly created) - */ - public abstract Matrix rightMultiply(Matrix a); - - /** - * Compute the product of this matrix and a permutation. - * - * @param p the permutation - * @return <tt>this * p</tt> (newly created) - */ - public abstract Matrix rightMultiply(Permutation p); - - /** - * Compute the product of a vector and this matrix. If the length of the - * vector is greater than the number of rows of this matrix, the matrix is - * multiplied by each m-bit part of the vector. - * - * @param vector a vector - * @return <tt>vector * this</tt> (newly created) - */ - public abstract Vector leftMultiply(Vector vector); - - /** - * Compute the product of this matrix and a vector. - * - * @param vector a vector - * @return <tt>this * vector</tt> (newly created) - */ - public abstract Vector rightMultiply(Vector vector); - - /** - * @return a human readable form of the matrix. - */ - public abstract String toString(); - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/Permutation.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/Permutation.java deleted file mode 100644 index 28b58d34..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/Permutation.java +++ /dev/null @@ -1,247 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -import java.security.SecureRandom; - -/** - * This class implements permutations of the set {0,1,...,n-1} for some given n - * > 0, i.e., ordered sequences containing each number <tt>m</tt> (<tt>0 <= - * m < n</tt>) - * once and only once. - */ -public class Permutation -{ - - /** - * perm holds the elements of the permutation vector, i.e. <tt>[perm(0), - * perm(1), ..., perm(n-1)]</tt> - */ - private int[] perm; - - /** - * Create the identity permutation of the given size. - * - * @param n the size of the permutation - */ - public Permutation(int n) - { - if (n <= 0) - { - throw new IllegalArgumentException("invalid length"); - } - - perm = new int[n]; - for (int i = n - 1; i >= 0; i--) - { - perm[i] = i; - } - } - - /** - * Create a permutation using the given permutation vector. - * - * @param perm the permutation vector - */ - public Permutation(int[] perm) - { - if (!isPermutation(perm)) - { - throw new IllegalArgumentException( - "array is not a permutation vector"); - } - - this.perm = IntUtils.clone(perm); - } - - /** - * Create a permutation from an encoded permutation. - * - * @param enc the encoded permutation - */ - public Permutation(byte[] enc) - { - if (enc.length <= 4) - { - throw new IllegalArgumentException("invalid encoding"); - } - - int n = LittleEndianConversions.OS2IP(enc, 0); - int size = IntegerFunctions.ceilLog256(n - 1); - - if (enc.length != 4 + n * size) - { - throw new IllegalArgumentException("invalid encoding"); - } - - perm = new int[n]; - for (int i = 0; i < n; i++) - { - perm[i] = LittleEndianConversions.OS2IP(enc, 4 + i * size, size); - } - - if (!isPermutation(perm)) - { - throw new IllegalArgumentException("invalid encoding"); - } - - } - - /** - * Create a random permutation of the given size. - * - * @param n the size of the permutation - * @param sr the source of randomness - */ - public Permutation(int n, SecureRandom sr) - { - if (n <= 0) - { - throw new IllegalArgumentException("invalid length"); - } - - perm = new int[n]; - - int[] help = new int[n]; - for (int i = 0; i < n; i++) - { - help[i] = i; - } - - int k = n; - for (int j = 0; j < n; j++) - { - int i = RandUtils.nextInt(sr, k); - k--; - perm[j] = help[i]; - help[i] = help[k]; - } - } - - /** - * Encode this permutation as byte array. - * - * @return the encoded permutation - */ - public byte[] getEncoded() - { - int n = perm.length; - int size = IntegerFunctions.ceilLog256(n - 1); - byte[] result = new byte[4 + n * size]; - LittleEndianConversions.I2OSP(n, result, 0); - for (int i = 0; i < n; i++) - { - LittleEndianConversions.I2OSP(perm[i], result, 4 + i * size, size); - } - return result; - } - - /** - * @return the permutation vector <tt>(perm(0),perm(1),...,perm(n-1))</tt> - */ - public int[] getVector() - { - return IntUtils.clone(perm); - } - - /** - * Compute the inverse permutation <tt>P<sup>-1</sup></tt>. - * - * @return <tt>this<sup>-1</sup></tt> - */ - public Permutation computeInverse() - { - Permutation result = new Permutation(perm.length); - for (int i = perm.length - 1; i >= 0; i--) - { - result.perm[perm[i]] = i; - } - return result; - } - - /** - * Compute the product of this permutation and another permutation. - * - * @param p the other permutation - * @return <tt>this * p</tt> - */ - public Permutation rightMultiply(Permutation p) - { - if (p.perm.length != perm.length) - { - throw new IllegalArgumentException("length mismatch"); - } - Permutation result = new Permutation(perm.length); - for (int i = perm.length - 1; i >= 0; i--) - { - result.perm[i] = perm[p.perm[i]]; - } - return result; - } - - /** - * checks if given object is equal to this permutation. - * <p> - * The method returns false whenever the given object is not permutation. - * - * @param other - - * permutation - * @return true or false - */ - public boolean equals(Object other) - { - - if (!(other instanceof Permutation)) - { - return false; - } - Permutation otherPerm = (Permutation)other; - - return IntUtils.equals(perm, otherPerm.perm); - } - - /** - * @return a human readable form of the permutation - */ - public String toString() - { - String result = "[" + perm[0]; - for (int i = 1; i < perm.length; i++) - { - result += ", " + perm[i]; - } - result += "]"; - return result; - } - - /** - * @return the hash code of this permutation - */ - public int hashCode() - { - return perm.hashCode(); - } - - /** - * Check that the given array corresponds to a permutation of the set - * <tt>{0, 1, ..., n-1}</tt>. - * - * @param perm permutation vector - * @return true if perm represents an n-permutation and false otherwise - */ - private boolean isPermutation(int[] perm) - { - int n = perm.length; - boolean[] onlyOnce = new boolean[n]; - - for (int i = 0; i < n; i++) - { - if ((perm[i] < 0) || (perm[i] >= n) || onlyOnce[perm[i]]) - { - return false; - } - onlyOnce[perm[i]] = true; - } - - return true; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/PolynomialGF2mSmallM.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/PolynomialGF2mSmallM.java deleted file mode 100644 index 866b6f7c..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/PolynomialGF2mSmallM.java +++ /dev/null @@ -1,1124 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -import java.security.SecureRandom; - -/** - * This class describes operations with polynomials from the ring R = - * GF(2^m)[X], where 2 <= m <=31. - * - * @see GF2mField - * @see PolynomialRingGF2m - */ -public class PolynomialGF2mSmallM -{ - - /** - * the finite field GF(2^m) - */ - private GF2mField field; - - /** - * the degree of this polynomial - */ - private int degree; - - /** - * For the polynomial representation the map f: R->Z*, - * <tt>poly(X) -> [coef_0, coef_1, ...]</tt> is used, where - * <tt>coef_i</tt> is the <tt>i</tt>th coefficient of the polynomial - * represented as int (see {@link GF2mField}). The polynomials are stored - * as int arrays. - */ - private int[] coefficients; - - /* - * some types of polynomials - */ - - /** - * Constant used for polynomial construction (see constructor - * {@link #PolynomialGF2mSmallM(GF2mField, int, char, SecureRandom)}). - */ - public static final char RANDOM_IRREDUCIBLE_POLYNOMIAL = 'I'; - - /** - * Construct the zero polynomial over the finite field GF(2^m). - * - * @param field the finite field GF(2^m) - */ - public PolynomialGF2mSmallM(GF2mField field) - { - this.field = field; - degree = -1; - coefficients = new int[1]; - } - - /** - * Construct a polynomial over the finite field GF(2^m). - * - * @param field the finite field GF(2^m) - * @param deg degree of polynomial - * @param typeOfPolynomial type of polynomial - * @param sr PRNG - */ - public PolynomialGF2mSmallM(GF2mField field, int deg, - char typeOfPolynomial, SecureRandom sr) - { - this.field = field; - - switch (typeOfPolynomial) - { - case PolynomialGF2mSmallM.RANDOM_IRREDUCIBLE_POLYNOMIAL: - coefficients = createRandomIrreduciblePolynomial(deg, sr); - break; - default: - throw new IllegalArgumentException(" Error: type " - + typeOfPolynomial - + " is not defined for GF2smallmPolynomial"); - } - computeDegree(); - } - - /** - * Create an irreducible polynomial with the given degree over the field - * <tt>GF(2^m)</tt>. - * - * @param deg polynomial degree - * @param sr source of randomness - * @return the generated irreducible polynomial - */ - private int[] createRandomIrreduciblePolynomial(int deg, SecureRandom sr) - { - int[] resCoeff = new int[deg + 1]; - resCoeff[deg] = 1; - resCoeff[0] = field.getRandomNonZeroElement(sr); - for (int i = 1; i < deg; i++) - { - resCoeff[i] = field.getRandomElement(sr); - } - while (!isIrreducible(resCoeff)) - { - int n = RandUtils.nextInt(sr, deg); - if (n == 0) - { - resCoeff[0] = field.getRandomNonZeroElement(sr); - } - else - { - resCoeff[n] = field.getRandomElement(sr); - } - } - return resCoeff; - } - - /** - * Construct a monomial of the given degree over the finite field GF(2^m). - * - * @param field the finite field GF(2^m) - * @param degree the degree of the monomial - */ - public PolynomialGF2mSmallM(GF2mField field, int degree) - { - this.field = field; - this.degree = degree; - coefficients = new int[degree + 1]; - coefficients[degree] = 1; - } - - /** - * Construct the polynomial over the given finite field GF(2^m) from the - * given coefficient vector. - * - * @param field finite field GF2m - * @param coeffs the coefficient vector - */ - public PolynomialGF2mSmallM(GF2mField field, int[] coeffs) - { - this.field = field; - coefficients = normalForm(coeffs); - computeDegree(); - } - - /** - * Create a polynomial over the finite field GF(2^m). - * - * @param field the finite field GF(2^m) - * @param enc byte[] polynomial in byte array form - */ - public PolynomialGF2mSmallM(GF2mField field, byte[] enc) - { - this.field = field; - - // decodes polynomial - int d = 8; - int count = 1; - while (field.getDegree() > d) - { - count++; - d += 8; - } - - if ((enc.length % count) != 0) - { - throw new IllegalArgumentException( - " Error: byte array is not encoded polynomial over given finite field GF2m"); - } - - coefficients = new int[enc.length / count]; - count = 0; - for (int i = 0; i < coefficients.length; i++) - { - for (int j = 0; j < d; j += 8) - { - coefficients[i] ^= (enc[count++] & 0x000000ff) << j; - } - if (!this.field.isElementOfThisField(coefficients[i])) - { - throw new IllegalArgumentException( - " Error: byte array is not encoded polynomial over given finite field GF2m"); - } - } - // if HC = 0 for non-zero polynomial, returns error - if ((coefficients.length != 1) - && (coefficients[coefficients.length - 1] == 0)) - { - throw new IllegalArgumentException( - " Error: byte array is not encoded polynomial over given finite field GF2m"); - } - computeDegree(); - } - - /** - * Copy constructor. - * - * @param other another {@link PolynomialGF2mSmallM} - */ - public PolynomialGF2mSmallM(PolynomialGF2mSmallM other) - { - // field needs not to be cloned since it is immutable - field = other.field; - degree = other.degree; - coefficients = IntUtils.clone(other.coefficients); - } - - /** - * Create a polynomial over the finite field GF(2^m) out of the given - * coefficient vector. The finite field is also obtained from the - * {@link GF2mVector}. - * - * @param vect the coefficient vector - */ - public PolynomialGF2mSmallM(GF2mVector vect) - { - this(vect.getField(), vect.getIntArrayForm()); - } - - /* - * ------------------------ - */ - - /** - * Return the degree of this polynomial - * - * @return int degree of this polynomial if this is zero polynomial return - * -1 - */ - public int getDegree() - { - int d = coefficients.length - 1; - if (coefficients[d] == 0) - { - return -1; - } - return d; - } - - /** - * @return the head coefficient of this polynomial - */ - public int getHeadCoefficient() - { - if (degree == -1) - { - return 0; - } - return coefficients[degree]; - } - - /** - * Return the head coefficient of a polynomial. - * - * @param a the polynomial - * @return the head coefficient of <tt>a</tt> - */ - private static int headCoefficient(int[] a) - { - int degree = computeDegree(a); - if (degree == -1) - { - return 0; - } - return a[degree]; - } - - /** - * Return the coefficient with the given index. - * - * @param index the index - * @return the coefficient with the given index - */ - public int getCoefficient(int index) - { - if ((index < 0) || (index > degree)) - { - return 0; - } - return coefficients[index]; - } - - /** - * Returns encoded polynomial, i.e., this polynomial in byte array form - * - * @return the encoded polynomial - */ - public byte[] getEncoded() - { - int d = 8; - int count = 1; - while (field.getDegree() > d) - { - count++; - d += 8; - } - - byte[] res = new byte[coefficients.length * count]; - count = 0; - for (int i = 0; i < coefficients.length; i++) - { - for (int j = 0; j < d; j += 8) - { - res[count++] = (byte)(coefficients[i] >>> j); - } - } - - return res; - } - - /** - * Evaluate this polynomial <tt>p</tt> at a value <tt>e</tt> (in - * <tt>GF(2^m)</tt>) with the Horner scheme. - * - * @param e the element of the finite field GF(2^m) - * @return <tt>this(e)</tt> - */ - public int evaluateAt(int e) - { - int result = coefficients[degree]; - for (int i = degree - 1; i >= 0; i--) - { - result = field.mult(result, e) ^ coefficients[i]; - } - return result; - } - - /** - * Compute the sum of this polynomial and the given polynomial. - * - * @param addend the addend - * @return <tt>this + a</tt> (newly created) - */ - public PolynomialGF2mSmallM add(PolynomialGF2mSmallM addend) - { - int[] resultCoeff = add(coefficients, addend.coefficients); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Add the given polynomial to this polynomial (overwrite this). - * - * @param addend the addend - */ - public void addToThis(PolynomialGF2mSmallM addend) - { - coefficients = add(coefficients, addend.coefficients); - computeDegree(); - } - - /** - * Compute the sum of two polynomials a and b over the finite field - * <tt>GF(2^m)</tt>. - * - * @param a the first polynomial - * @param b the second polynomial - * @return a + b - */ - private int[] add(int[] a, int[] b) - { - int[] result, addend; - if (a.length < b.length) - { - result = new int[b.length]; - System.arraycopy(b, 0, result, 0, b.length); - addend = a; - } - else - { - result = new int[a.length]; - System.arraycopy(a, 0, result, 0, a.length); - addend = b; - } - - for (int i = addend.length - 1; i >= 0; i--) - { - result[i] = field.add(result[i], addend[i]); - } - - return result; - } - - /** - * Compute the sum of this polynomial and the monomial of the given degree. - * - * @param degree the degree of the monomial - * @return <tt>this + X^k</tt> - */ - public PolynomialGF2mSmallM addMonomial(int degree) - { - int[] monomial = new int[degree + 1]; - monomial[degree] = 1; - int[] resultCoeff = add(coefficients, monomial); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Compute the product of this polynomial with an element from GF(2^m). - * - * @param element an element of the finite field GF(2^m) - * @return <tt>this * element</tt> (newly created) - * @throws ArithmeticException if <tt>element</tt> is not an element of the finite - * field this polynomial is defined over. - */ - public PolynomialGF2mSmallM multWithElement(int element) - { - if (!field.isElementOfThisField(element)) - { - throw new ArithmeticException( - "Not an element of the finite field this polynomial is defined over."); - } - int[] resultCoeff = multWithElement(coefficients, element); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Multiply this polynomial with an element from GF(2^m). - * - * @param element an element of the finite field GF(2^m) - * @throws ArithmeticException if <tt>element</tt> is not an element of the finite - * field this polynomial is defined over. - */ - public void multThisWithElement(int element) - { - if (!field.isElementOfThisField(element)) - { - throw new ArithmeticException( - "Not an element of the finite field this polynomial is defined over."); - } - coefficients = multWithElement(coefficients, element); - computeDegree(); - } - - /** - * Compute the product of a polynomial a with an element from the finite - * field <tt>GF(2^m)</tt>. - * - * @param a the polynomial - * @param element an element of the finite field GF(2^m) - * @return <tt>a * element</tt> - */ - private int[] multWithElement(int[] a, int element) - { - int degree = computeDegree(a); - if (degree == -1 || element == 0) - { - return new int[1]; - } - - if (element == 1) - { - return IntUtils.clone(a); - } - - int[] result = new int[degree + 1]; - for (int i = degree; i >= 0; i--) - { - result[i] = field.mult(a[i], element); - } - - return result; - } - - /** - * Compute the product of this polynomial with a monomial X^k. - * - * @param k the degree of the monomial - * @return <tt>this * X^k</tt> - */ - public PolynomialGF2mSmallM multWithMonomial(int k) - { - int[] resultCoeff = multWithMonomial(coefficients, k); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Compute the product of a polynomial with a monomial X^k. - * - * @param a the polynomial - * @param k the degree of the monomial - * @return <tt>a * X^k</tt> - */ - private static int[] multWithMonomial(int[] a, int k) - { - int d = computeDegree(a); - if (d == -1) - { - return new int[1]; - } - int[] result = new int[d + k + 1]; - System.arraycopy(a, 0, result, k, d + 1); - return result; - } - - /** - * Divide this polynomial by the given polynomial. - * - * @param f a polynomial - * @return polynomial pair = {q,r} where this = q*f+r and deg(r) < - * deg(f); - */ - public PolynomialGF2mSmallM[] div(PolynomialGF2mSmallM f) - { - int[][] resultCoeffs = div(coefficients, f.coefficients); - return new PolynomialGF2mSmallM[]{ - new PolynomialGF2mSmallM(field, resultCoeffs[0]), - new PolynomialGF2mSmallM(field, resultCoeffs[1])}; - } - - /** - * Compute the result of the division of two polynomials over the field - * <tt>GF(2^m)</tt>. - * - * @param a the first polynomial - * @param f the second polynomial - * @return int[][] {q,r}, where a = q*f+r and deg(r) < deg(f); - */ - private int[][] div(int[] a, int[] f) - { - int df = computeDegree(f); - int da = computeDegree(a) + 1; - if (df == -1) - { - throw new ArithmeticException("Division by zero."); - } - int[][] result = new int[2][]; - result[0] = new int[1]; - result[1] = new int[da]; - int hc = headCoefficient(f); - hc = field.inverse(hc); - result[0][0] = 0; - System.arraycopy(a, 0, result[1], 0, result[1].length); - while (df <= computeDegree(result[1])) - { - int[] q; - int[] coeff = new int[1]; - coeff[0] = field.mult(headCoefficient(result[1]), hc); - q = multWithElement(f, coeff[0]); - int n = computeDegree(result[1]) - df; - q = multWithMonomial(q, n); - coeff = multWithMonomial(coeff, n); - result[0] = add(coeff, result[0]); - result[1] = add(q, result[1]); - } - return result; - } - - /** - * Return the greatest common divisor of this and a polynomial <i>f</i> - * - * @param f polynomial - * @return GCD(this, f) - */ - public PolynomialGF2mSmallM gcd(PolynomialGF2mSmallM f) - { - int[] resultCoeff = gcd(coefficients, f.coefficients); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Return the greatest common divisor of two polynomials over the field - * <tt>GF(2^m)</tt>. - * - * @param f the first polynomial - * @param g the second polynomial - * @return <tt>gcd(f, g)</tt> - */ - private int[] gcd(int[] f, int[] g) - { - int[] a = f; - int[] b = g; - if (computeDegree(a) == -1) - { - return b; - } - while (computeDegree(b) != -1) - { - int[] c = mod(a, b); - a = new int[b.length]; - System.arraycopy(b, 0, a, 0, a.length); - b = new int[c.length]; - System.arraycopy(c, 0, b, 0, b.length); - } - int coeff = field.inverse(headCoefficient(a)); - return multWithElement(a, coeff); - } - - /** - * Compute the product of this polynomial and the given factor using a - * Karatzuba like scheme. - * - * @param factor the polynomial - * @return <tt>this * factor</tt> - */ - public PolynomialGF2mSmallM multiply(PolynomialGF2mSmallM factor) - { - int[] resultCoeff = multiply(coefficients, factor.coefficients); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Compute the product of two polynomials over the field <tt>GF(2^m)</tt> - * using a Karatzuba like multiplication. - * - * @param a the first polynomial - * @param b the second polynomial - * @return a * b - */ - private int[] multiply(int[] a, int[] b) - { - int[] mult1, mult2; - if (computeDegree(a) < computeDegree(b)) - { - mult1 = b; - mult2 = a; - } - else - { - mult1 = a; - mult2 = b; - } - - mult1 = normalForm(mult1); - mult2 = normalForm(mult2); - - if (mult2.length == 1) - { - return multWithElement(mult1, mult2[0]); - } - - int d1 = mult1.length; - int d2 = mult2.length; - int[] result = new int[d1 + d2 - 1]; - - if (d2 != d1) - { - int[] res1 = new int[d2]; - int[] res2 = new int[d1 - d2]; - System.arraycopy(mult1, 0, res1, 0, res1.length); - System.arraycopy(mult1, d2, res2, 0, res2.length); - res1 = multiply(res1, mult2); - res2 = multiply(res2, mult2); - res2 = multWithMonomial(res2, d2); - result = add(res1, res2); - } - else - { - d2 = (d1 + 1) >>> 1; - int d = d1 - d2; - int[] firstPartMult1 = new int[d2]; - int[] firstPartMult2 = new int[d2]; - int[] secondPartMult1 = new int[d]; - int[] secondPartMult2 = new int[d]; - System - .arraycopy(mult1, 0, firstPartMult1, 0, - firstPartMult1.length); - System.arraycopy(mult1, d2, secondPartMult1, 0, - secondPartMult1.length); - System - .arraycopy(mult2, 0, firstPartMult2, 0, - firstPartMult2.length); - System.arraycopy(mult2, d2, secondPartMult2, 0, - secondPartMult2.length); - int[] helpPoly1 = add(firstPartMult1, secondPartMult1); - int[] helpPoly2 = add(firstPartMult2, secondPartMult2); - int[] res1 = multiply(firstPartMult1, firstPartMult2); - int[] res2 = multiply(helpPoly1, helpPoly2); - int[] res3 = multiply(secondPartMult1, secondPartMult2); - res2 = add(res2, res1); - res2 = add(res2, res3); - res3 = multWithMonomial(res3, d2); - result = add(res2, res3); - result = multWithMonomial(result, d2); - result = add(result, res1); - } - - return result; - } - - /* - * ---------------- PART II ---------------- - * - */ - - /** - * Check a polynomial for irreducibility over the field <tt>GF(2^m)</tt>. - * - * @param a the polynomial to check - * @return true if a is irreducible, false otherwise - */ - private boolean isIrreducible(int[] a) - { - if (a[0] == 0) - { - return false; - } - int d = computeDegree(a) >> 1; - int[] u = {0, 1}; - final int[] Y = {0, 1}; - int fieldDegree = field.getDegree(); - for (int i = 0; i < d; i++) - { - for (int j = fieldDegree - 1; j >= 0; j--) - { - u = modMultiply(u, u, a); - } - u = normalForm(u); - int[] g = gcd(add(u, Y), a); - if (computeDegree(g) != 0) - { - return false; - } - } - return true; - } - - /** - * Reduce this polynomial modulo another polynomial. - * - * @param f the reduction polynomial - * @return <tt>this mod f</tt> - */ - public PolynomialGF2mSmallM mod(PolynomialGF2mSmallM f) - { - int[] resultCoeff = mod(coefficients, f.coefficients); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Reduce a polynomial modulo another polynomial. - * - * @param a the polynomial - * @param f the reduction polynomial - * @return <tt>a mod f</tt> - */ - private int[] mod(int[] a, int[] f) - { - int df = computeDegree(f); - if (df == -1) - { - throw new ArithmeticException("Division by zero"); - } - int[] result = new int[a.length]; - int hc = headCoefficient(f); - hc = field.inverse(hc); - System.arraycopy(a, 0, result, 0, result.length); - while (df <= computeDegree(result)) - { - int[] q; - int coeff = field.mult(headCoefficient(result), hc); - q = multWithMonomial(f, computeDegree(result) - df); - q = multWithElement(q, coeff); - result = add(q, result); - } - return result; - } - - /** - * Compute the product of this polynomial and another polynomial modulo a - * third polynomial. - * - * @param a another polynomial - * @param b the reduction polynomial - * @return <tt>this * a mod b</tt> - */ - public PolynomialGF2mSmallM modMultiply(PolynomialGF2mSmallM a, - PolynomialGF2mSmallM b) - { - int[] resultCoeff = modMultiply(coefficients, a.coefficients, - b.coefficients); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Square this polynomial using a squaring matrix. - * - * @param matrix the squaring matrix - * @return <tt>this^2</tt> modulo the reduction polynomial implicitly - * given via the squaring matrix - */ - public PolynomialGF2mSmallM modSquareMatrix(PolynomialGF2mSmallM[] matrix) - { - - int length = matrix.length; - - int[] resultCoeff = new int[length]; - int[] thisSquare = new int[length]; - - // square each entry of this polynomial - for (int i = 0; i < coefficients.length; i++) - { - thisSquare[i] = field.mult(coefficients[i], coefficients[i]); - } - - // do matrix-vector multiplication - for (int i = 0; i < length; i++) - { - // compute scalar product of i-th row and coefficient vector - for (int j = 0; j < length; j++) - { - if (i >= matrix[j].coefficients.length) - { - continue; - } - int scalarTerm = field.mult(matrix[j].coefficients[i], - thisSquare[j]); - resultCoeff[i] = field.add(resultCoeff[i], scalarTerm); - } - } - - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Compute the product of two polynomials modulo a third polynomial over the - * finite field <tt>GF(2^m)</tt>. - * - * @param a the first polynomial - * @param b the second polynomial - * @param g the reduction polynomial - * @return <tt>a * b mod g</tt> - */ - private int[] modMultiply(int[] a, int[] b, int[] g) - { - return mod(multiply(a, b), g); - } - - /** - * Compute the square root of this polynomial modulo the given polynomial. - * - * @param a the reduction polynomial - * @return <tt>this^(1/2) mod a</tt> - */ - public PolynomialGF2mSmallM modSquareRoot(PolynomialGF2mSmallM a) - { - int[] resultCoeff = IntUtils.clone(coefficients); - int[] help = modMultiply(resultCoeff, resultCoeff, a.coefficients); - while (!isEqual(help, coefficients)) - { - resultCoeff = normalForm(help); - help = modMultiply(resultCoeff, resultCoeff, a.coefficients); - } - - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Compute the square root of this polynomial using a square root matrix. - * - * @param matrix the matrix for computing square roots in - * <tt>(GF(2^m))^t</tt> the polynomial ring defining the - * square root matrix - * @return <tt>this^(1/2)</tt> modulo the reduction polynomial implicitly - * given via the square root matrix - */ - public PolynomialGF2mSmallM modSquareRootMatrix( - PolynomialGF2mSmallM[] matrix) - { - - int length = matrix.length; - - int[] resultCoeff = new int[length]; - - // do matrix multiplication - for (int i = 0; i < length; i++) - { - // compute scalar product of i-th row and j-th column - for (int j = 0; j < length; j++) - { - if (i >= matrix[j].coefficients.length) - { - continue; - } - if (j < coefficients.length) - { - int scalarTerm = field.mult(matrix[j].coefficients[i], - coefficients[j]); - resultCoeff[i] = field.add(resultCoeff[i], scalarTerm); - } - } - } - - // compute the square root of each entry of the result coefficients - for (int i = 0; i < length; i++) - { - resultCoeff[i] = field.sqRoot(resultCoeff[i]); - } - - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Compute the result of the division of this polynomial by another - * polynomial modulo a third polynomial. - * - * @param divisor the divisor - * @param modulus the reduction polynomial - * @return <tt>this * divisor^(-1) mod modulus</tt> - */ - public PolynomialGF2mSmallM modDiv(PolynomialGF2mSmallM divisor, - PolynomialGF2mSmallM modulus) - { - int[] resultCoeff = modDiv(coefficients, divisor.coefficients, - modulus.coefficients); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Compute the result of the division of two polynomials modulo a third - * polynomial over the field <tt>GF(2^m)</tt>. - * - * @param a the first polynomial - * @param b the second polynomial - * @param g the reduction polynomial - * @return <tt>a * b^(-1) mod g</tt> - */ - private int[] modDiv(int[] a, int[] b, int[] g) - { - int[] r0 = normalForm(g); - int[] r1 = mod(b, g); - int[] s0 = {0}; - int[] s1 = mod(a, g); - int[] s2; - int[][] q; - while (computeDegree(r1) != -1) - { - q = div(r0, r1); - r0 = normalForm(r1); - r1 = normalForm(q[1]); - s2 = add(s0, modMultiply(q[0], s1, g)); - s0 = normalForm(s1); - s1 = normalForm(s2); - - } - int hc = headCoefficient(r0); - s0 = multWithElement(s0, field.inverse(hc)); - return s0; - } - - /** - * Compute the inverse of this polynomial modulo the given polynomial. - * - * @param a the reduction polynomial - * @return <tt>this^(-1) mod a</tt> - */ - public PolynomialGF2mSmallM modInverse(PolynomialGF2mSmallM a) - { - int[] unit = {1}; - int[] resultCoeff = modDiv(unit, coefficients, a.coefficients); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Compute a polynomial pair (a,b) from this polynomial and the given - * polynomial g with the property b*this = a mod g and deg(a)<=deg(g)/2. - * - * @param g the reduction polynomial - * @return PolynomialGF2mSmallM[] {a,b} with b*this = a mod g and deg(a)<= - * deg(g)/2 - */ - public PolynomialGF2mSmallM[] modPolynomialToFracton(PolynomialGF2mSmallM g) - { - int dg = g.degree >> 1; - int[] a0 = normalForm(g.coefficients); - int[] a1 = mod(coefficients, g.coefficients); - int[] b0 = {0}; - int[] b1 = {1}; - while (computeDegree(a1) > dg) - { - int[][] q = div(a0, a1); - a0 = a1; - a1 = q[1]; - int[] b2 = add(b0, modMultiply(q[0], b1, g.coefficients)); - b0 = b1; - b1 = b2; - } - - return new PolynomialGF2mSmallM[]{ - new PolynomialGF2mSmallM(field, a1), - new PolynomialGF2mSmallM(field, b1)}; - } - - /** - * checks if given object is equal to this polynomial. - * <p> - * The method returns false whenever the given object is not polynomial over - * GF(2^m). - * - * @param other object - * @return true or false - */ - public boolean equals(Object other) - { - - if (other == null || !(other instanceof PolynomialGF2mSmallM)) - { - return false; - } - - PolynomialGF2mSmallM p = (PolynomialGF2mSmallM)other; - - if ((field.equals(p.field)) && (degree == p.degree) - && (isEqual(coefficients, p.coefficients))) - { - return true; - } - - return false; - } - - /** - * Compare two polynomials given as int arrays. - * - * @param a the first polynomial - * @param b the second polynomial - * @return <tt>true</tt> if <tt>a</tt> and <tt>b</tt> represent the - * same polynomials, <tt>false</tt> otherwise - */ - private static boolean isEqual(int[] a, int[] b) - { - int da = computeDegree(a); - int db = computeDegree(b); - if (da != db) - { - return false; - } - for (int i = 0; i <= da; i++) - { - if (a[i] != b[i]) - { - return false; - } - } - return true; - } - - /** - * @return the hash code of this polynomial - */ - public int hashCode() - { - int hash = field.hashCode(); - for (int j = 0; j < coefficients.length; j++) - { - hash = hash * 31 + coefficients[j]; - } - return hash; - } - - /** - * Returns a human readable form of the polynomial. - * - * @return a human readable form of the polynomial. - */ - public String toString() - { - String str = " Polynomial over " + field.toString() + ": \n"; - - for (int i = 0; i < coefficients.length; i++) - { - str = str + field.elementToStr(coefficients[i]) + "Y^" + i + "+"; - } - str = str + ";"; - - return str; - } - - /** - * Compute the degree of this polynomial. If this is the zero polynomial, - * the degree is -1. - */ - private void computeDegree() - { - for (degree = coefficients.length - 1; degree >= 0 - && coefficients[degree] == 0; degree--) - { - ; - } - } - - /** - * Compute the degree of a polynomial. - * - * @param a the polynomial - * @return the degree of the polynomial <tt>a</tt>. If <tt>a</tt> is - * the zero polynomial, return -1. - */ - private static int computeDegree(int[] a) - { - int degree; - for (degree = a.length - 1; degree >= 0 && a[degree] == 0; degree--) - { - ; - } - return degree; - } - - /** - * Strip leading zero coefficients from the given polynomial. - * - * @param a the polynomial - * @return the reduced polynomial - */ - private static int[] normalForm(int[] a) - { - int d = computeDegree(a); - - // if a is the zero polynomial - if (d == -1) - { - // return new zero polynomial - return new int[1]; - } - - // if a already is in normal form - if (a.length == d + 1) - { - // return a clone of a - return IntUtils.clone(a); - } - - // else, reduce a - int[] result = new int[d + 1]; - System.arraycopy(a, 0, result, 0, d + 1); - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/PolynomialRingGF2.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/PolynomialRingGF2.java deleted file mode 100644 index a0e2bacc..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/PolynomialRingGF2.java +++ /dev/null @@ -1,278 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -/** - * This class describes operations with polynomials over finite field GF(2), i e - * polynomial ring R = GF(2)[X]. All operations are defined only for polynomials - * with degree <=32. For the polynomial representation the map f: R->Z, - * poly(X)->poly(2) is used, where integers have the binary representation. For - * example: X^7+X^3+X+1 -> (00...0010001011)=139 Also for polynomials type - * Integer is used. - * - * @see GF2mField - */ -public final class PolynomialRingGF2 -{ - - /** - * Default constructor (private). - */ - private PolynomialRingGF2() - { - // empty - } - - /** - * Return sum of two polyomials - * - * @param p polynomial - * @param q polynomial - * @return p+q - */ - - public static int add(int p, int q) - { - return p ^ q; - } - - /** - * Return product of two polynomials - * - * @param p polynomial - * @param q polynomial - * @return p*q - */ - - public static long multiply(int p, int q) - { - long result = 0; - if (q != 0) - { - long q1 = q & 0x00000000ffffffffL; - - while (p != 0) - { - byte b = (byte)(p & 0x01); - if (b == 1) - { - result ^= q1; - } - p >>>= 1; - q1 <<= 1; - - } - } - return result; - } - - /** - * Compute the product of two polynomials modulo a third polynomial. - * - * @param a the first polynomial - * @param b the second polynomial - * @param r the reduction polynomial - * @return <tt>a * b mod r</tt> - */ - public static int modMultiply(int a, int b, int r) - { - int result = 0; - int p = remainder(a, r); - int q = remainder(b, r); - if (q != 0) - { - int d = 1 << degree(r); - - while (p != 0) - { - byte pMod2 = (byte)(p & 0x01); - if (pMod2 == 1) - { - result ^= q; - } - p >>>= 1; - q <<= 1; - if (q >= d) - { - q ^= r; - } - } - } - return result; - } - - /** - * Return the degree of a polynomial - * - * @param p polynomial p - * @return degree(p) - */ - - public static int degree(int p) - { - int result = -1; - while (p != 0) - { - result++; - p >>>= 1; - } - return result; - } - - /** - * Return the degree of a polynomial - * - * @param p polynomial p - * @return degree(p) - */ - - public static int degree(long p) - { - int result = 0; - while (p != 0) - { - result++; - p >>>= 1; - } - return result - 1; - } - - /** - * Return the remainder of a polynomial division of two polynomials. - * - * @param p dividend - * @param q divisor - * @return <tt>p mod q</tt> - */ - public static int remainder(int p, int q) - { - int result = p; - - if (q == 0) - { - System.err.println("Error: to be divided by 0"); - return 0; - } - - while (degree(result) >= degree(q)) - { - result ^= q << (degree(result) - degree(q)); - } - - return result; - } - - /** - * Return the rest of devision two polynomials - * - * @param p polinomial - * @param q polinomial - * @return p mod q - */ - - public static int rest(long p, int q) - { - long p1 = p; - if (q == 0) - { - System.err.println("Error: to be divided by 0"); - return 0; - } - long q1 = q & 0x00000000ffffffffL; - while ((p1 >>> 32) != 0) - { - p1 ^= q1 << (degree(p1) - degree(q1)); - } - - int result = (int)(p1 & 0xffffffff); - while (degree(result) >= degree(q)) - { - result ^= q << (degree(result) - degree(q)); - } - - return result; - } - - /** - * Return the greatest common divisor of two polynomials - * - * @param p polinomial - * @param q polinomial - * @return GCD(p, q) - */ - - public static int gcd(int p, int q) - { - int a, b, c; - a = p; - b = q; - while (b != 0) - { - c = remainder(a, b); - a = b; - b = c; - - } - return a; - } - - /** - * Checking polynomial for irreducibility - * - * @param p polinomial - * @return true if p is irreducible and false otherwise - */ - - public static boolean isIrreducible(int p) - { - if (p == 0) - { - return false; - } - int d = degree(p) >>> 1; - int u = 2; - for (int i = 0; i < d; i++) - { - u = modMultiply(u, u, p); - if (gcd(u ^ 2, p) != 1) - { - return false; - } - } - return true; - } - - /** - * Creates irreducible polynomial with degree d - * - * @param deg polynomial degree - * @return irreducible polynomial p - */ - public static int getIrreduciblePolynomial(int deg) - { - if (deg < 0) - { - System.err.println("The Degree is negative"); - return 0; - } - if (deg > 31) - { - System.err.println("The Degree is more then 31"); - return 0; - } - if (deg == 0) - { - return 1; - } - int a = 1 << deg; - a++; - int b = 1 << (deg + 1); - for (int i = a; i < b; i += 2) - { - if (isIrreducible(i)) - { - return i; - } - } - return 0; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/PolynomialRingGF2m.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/PolynomialRingGF2m.java deleted file mode 100644 index 9e5d4139..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/PolynomialRingGF2m.java +++ /dev/null @@ -1,175 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -/** - * This class represents polynomial rings <tt>GF(2^m)[X]/p(X)</tt> for - * <tt>m<32</tt>. If <tt>p(X)</tt> is irreducible, the polynomial ring - * is in fact an extension field of <tt>GF(2^m)</tt>. - */ -public class PolynomialRingGF2m -{ - - /** - * the finite field this polynomial ring is defined over - */ - private GF2mField field; - - /** - * the reduction polynomial - */ - private PolynomialGF2mSmallM p; - - /** - * the squaring matrix for this polynomial ring (given as the array of its - * row vectors) - */ - protected PolynomialGF2mSmallM[] sqMatrix; - - /** - * the matrix for computing square roots in this polynomial ring (given as - * the array of its row vectors). This matrix is computed as the inverse of - * the squaring matrix. - */ - protected PolynomialGF2mSmallM[] sqRootMatrix; - - /** - * Constructor. - * - * @param field the finite field - * @param p the reduction polynomial - */ - public PolynomialRingGF2m(GF2mField field, PolynomialGF2mSmallM p) - { - this.field = field; - this.p = p; - computeSquaringMatrix(); - computeSquareRootMatrix(); - } - - /** - * @return the squaring matrix for this polynomial ring - */ - public PolynomialGF2mSmallM[] getSquaringMatrix() - { - return sqMatrix; - } - - /** - * @return the matrix for computing square roots for this polynomial ring - */ - public PolynomialGF2mSmallM[] getSquareRootMatrix() - { - return sqRootMatrix; - } - - /** - * Compute the squaring matrix for this polynomial ring, using the base - * field and the reduction polynomial. - */ - private void computeSquaringMatrix() - { - int numColumns = p.getDegree(); - sqMatrix = new PolynomialGF2mSmallM[numColumns]; - for (int i = 0; i < numColumns >> 1; i++) - { - int[] monomCoeffs = new int[(i << 1) + 1]; - monomCoeffs[i << 1] = 1; - sqMatrix[i] = new PolynomialGF2mSmallM(field, monomCoeffs); - } - for (int i = numColumns >> 1; i < numColumns; i++) - { - int[] monomCoeffs = new int[(i << 1) + 1]; - monomCoeffs[i << 1] = 1; - PolynomialGF2mSmallM monomial = new PolynomialGF2mSmallM(field, - monomCoeffs); - sqMatrix[i] = monomial.mod(p); - } - } - - /** - * Compute the matrix for computing square roots in this polynomial ring by - * inverting the squaring matrix. - */ - private void computeSquareRootMatrix() - { - int numColumns = p.getDegree(); - - // clone squaring matrix - PolynomialGF2mSmallM[] tmpMatrix = new PolynomialGF2mSmallM[numColumns]; - for (int i = numColumns - 1; i >= 0; i--) - { - tmpMatrix[i] = new PolynomialGF2mSmallM(sqMatrix[i]); - } - - // initialize square root matrix as unit matrix - sqRootMatrix = new PolynomialGF2mSmallM[numColumns]; - for (int i = numColumns - 1; i >= 0; i--) - { - sqRootMatrix[i] = new PolynomialGF2mSmallM(field, i); - } - - // simultaneously compute Gaussian reduction of squaring matrix and unit - // matrix - for (int i = 0; i < numColumns; i++) - { - // if diagonal element is zero - if (tmpMatrix[i].getCoefficient(i) == 0) - { - boolean foundNonZero = false; - // find a non-zero element in the same row - for (int j = i + 1; j < numColumns; j++) - { - if (tmpMatrix[j].getCoefficient(i) != 0) - { - // found it, swap columns ... - foundNonZero = true; - swapColumns(tmpMatrix, i, j); - swapColumns(sqRootMatrix, i, j); - // ... and quit searching - j = numColumns; - continue; - } - } - // if no non-zero element was found - if (!foundNonZero) - { - // the matrix is not invertible - throw new ArithmeticException( - "Squaring matrix is not invertible."); - } - } - - // normalize i-th column - int coef = tmpMatrix[i].getCoefficient(i); - int invCoef = field.inverse(coef); - tmpMatrix[i].multThisWithElement(invCoef); - sqRootMatrix[i].multThisWithElement(invCoef); - - // normalize all other columns - for (int j = 0; j < numColumns; j++) - { - if (j != i) - { - coef = tmpMatrix[j].getCoefficient(i); - if (coef != 0) - { - PolynomialGF2mSmallM tmpSqColumn = tmpMatrix[i] - .multWithElement(coef); - PolynomialGF2mSmallM tmpInvColumn = sqRootMatrix[i] - .multWithElement(coef); - tmpMatrix[j].addToThis(tmpSqColumn); - sqRootMatrix[j].addToThis(tmpInvColumn); - } - } - } - } - } - - private static void swapColumns(PolynomialGF2mSmallM[] matrix, int first, - int second) - { - PolynomialGF2mSmallM tmp = matrix[first]; - matrix[first] = matrix[second]; - matrix[second] = tmp; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/RandUtils.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/RandUtils.java deleted file mode 100644 index dbb1d4a8..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/RandUtils.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -import java.security.SecureRandom; - -public class RandUtils -{ - static int nextInt(SecureRandom rand, int n) - { - - if ((n & -n) == n) // i.e., n is a power of 2 - { - return (int)((n * (long)(rand.nextInt() >>> 1)) >> 31); - } - - int bits, value; - do - { - bits = rand.nextInt() >>> 1; - value = bits % n; - } - while (bits - value + (n - 1) < 0); - - return value; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/Vector.java b/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/Vector.java deleted file mode 100644 index 7e171643..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/linearalgebra/Vector.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.bouncycastle.pqc.math.linearalgebra; - -/** - * This abstract class defines vectors. It holds the length of vector. - */ -public abstract class Vector -{ - - /** - * the length of this vector - */ - protected int length; - - /** - * @return the length of this vector - */ - public final int getLength() - { - return length; - } - - /** - * @return this vector as byte array - */ - public abstract byte[] getEncoded(); - - /** - * Return whether this is the zero vector (i.e., all elements are zero). - * - * @return <tt>true</tt> if this is the zero vector, <tt>false</tt> - * otherwise - */ - public abstract boolean isZero(); - - /** - * Add another vector to this vector. - * - * @param addend the other vector - * @return <tt>this + addend</tt> - */ - public abstract Vector add(Vector addend); - - /** - * Multiply this vector with a permutation. - * - * @param p the permutation - * @return <tt>this*p = p*this</tt> - */ - public abstract Vector multiply(Permutation p); - - /** - * Check if the given object is equal to this vector. - * - * @param other vector - * @return the result of the comparison - */ - public abstract boolean equals(Object other); - - /** - * @return the hash code of this vector - */ - public abstract int hashCode(); - - /** - * @return a human readable form of this vector - */ - public abstract String toString(); - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/euclid/BigIntEuclidean.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/euclid/BigIntEuclidean.java deleted file mode 100644 index 5fb30584..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/euclid/BigIntEuclidean.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.euclid; - -import java.math.BigInteger; - -/** - * Extended Euclidean Algorithm in <code>BigInteger</code>s - */ -public class BigIntEuclidean -{ - public BigInteger x, y, gcd; - - private BigIntEuclidean() - { - } - - /** - * Runs the EEA on two <code>BigInteger</code>s<br> - * Implemented from pseudocode on <a href="http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm">Wikipedia</a>. - * - * @param a - * @param b - * @return a <code>BigIntEuclidean</code> object that contains the result in the variables <code>x</code>, <code>y</code>, and <code>gcd</code> - */ - public static BigIntEuclidean calculate(BigInteger a, BigInteger b) - { - BigInteger x = BigInteger.ZERO; - BigInteger lastx = BigInteger.ONE; - BigInteger y = BigInteger.ONE; - BigInteger lasty = BigInteger.ZERO; - while (!b.equals(BigInteger.ZERO)) - { - BigInteger[] quotientAndRemainder = a.divideAndRemainder(b); - BigInteger quotient = quotientAndRemainder[0]; - - BigInteger temp = a; - a = b; - b = quotientAndRemainder[1]; - - temp = x; - x = lastx.subtract(quotient.multiply(x)); - lastx = temp; - - temp = y; - y = lasty.subtract(quotient.multiply(y)); - lasty = temp; - } - - BigIntEuclidean result = new BigIntEuclidean(); - result.x = lastx; - result.y = lasty; - result.gcd = a; - return result; - } -}
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/euclid/IntEuclidean.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/euclid/IntEuclidean.java deleted file mode 100644 index c959a26d..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/euclid/IntEuclidean.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.euclid; - -/** - * Extended Euclidean Algorithm in <code>int</code>s - */ -public class IntEuclidean -{ - public int x, y, gcd; - - private IntEuclidean() - { - } - - /** - * Runs the EEA on two <code>int</code>s<br> - * Implemented from pseudocode on <a href="http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm">Wikipedia</a>. - * - * @param a - * @param b - * @return a <code>IntEuclidean</code> object that contains the result in the variables <code>x</code>, <code>y</code>, and <code>gcd</code> - */ - public static IntEuclidean calculate(int a, int b) - { - int x = 0; - int lastx = 1; - int y = 1; - int lasty = 0; - while (b != 0) - { - int quotient = a / b; - - int temp = a; - a = b; - b = temp % b; - - temp = x; - x = lastx - quotient * x; - lastx = temp; - - temp = y; - y = lasty - quotient * y; - lasty = temp; - } - - IntEuclidean result = new IntEuclidean(); - result.x = lastx; - result.y = lasty; - result.gcd = a; - return result; - } -}
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/BigDecimalPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/BigDecimalPolynomial.java deleted file mode 100644 index 697f51a6..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/BigDecimalPolynomial.java +++ /dev/null @@ -1,258 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.polynomial; - -import java.math.BigDecimal; - -/** - * A polynomial with {@link BigDecimal} coefficients. - * Some methods (like <code>add</code>) change the polynomial, others (like <code>mult</code>) do - * not but return the result as a new polynomial. - */ -public class BigDecimalPolynomial -{ - private static final BigDecimal ZERO = new BigDecimal("0"); - private static final BigDecimal ONE_HALF = new BigDecimal("0.5"); - - BigDecimal[] coeffs; - - /** - * Constructs a new polynomial with <code>N</code> coefficients initialized to 0. - * - * @param N the number of coefficients - */ - BigDecimalPolynomial(int N) - { - coeffs = new BigDecimal[N]; - for (int i = 0; i < N; i++) - { - coeffs[i] = ZERO; - } - } - - /** - * Constructs a new polynomial with a given set of coefficients. - * - * @param coeffs the coefficients - */ - BigDecimalPolynomial(BigDecimal[] coeffs) - { - this.coeffs = coeffs; - } - - /** - * Constructs a <code>BigDecimalPolynomial</code> from a <code>BigIntPolynomial</code>. The two polynomials are independent of each other. - * - * @param p the original polynomial - */ - public BigDecimalPolynomial(BigIntPolynomial p) - { - int N = p.coeffs.length; - coeffs = new BigDecimal[N]; - for (int i = 0; i < N; i++) - { - coeffs[i] = new BigDecimal(p.coeffs[i]); - } - } - - /** - * Divides all coefficients by 2. - */ - public void halve() - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] = coeffs[i].multiply(ONE_HALF); - } - } - - /** - * Multiplies the polynomial by another. Does not change this polynomial - * but returns the result as a new polynomial. - * - * @param poly2 the polynomial to multiply by - * @return a new polynomial - */ - public BigDecimalPolynomial mult(BigIntPolynomial poly2) - { - return mult(new BigDecimalPolynomial(poly2)); - } - - /** - * Multiplies the polynomial by another, taking the indices mod N. Does not - * change this polynomial but returns the result as a new polynomial. - * - * @param poly2 the polynomial to multiply by - * @return a new polynomial - */ - public BigDecimalPolynomial mult(BigDecimalPolynomial poly2) - { - int N = coeffs.length; - if (poly2.coeffs.length != N) - { - throw new IllegalArgumentException("Number of coefficients must be the same"); - } - - BigDecimalPolynomial c = multRecursive(poly2); - - if (c.coeffs.length > N) - { - for (int k = N; k < c.coeffs.length; k++) - { - c.coeffs[k - N] = c.coeffs[k - N].add(c.coeffs[k]); - } - c.coeffs = copyOf(c.coeffs, N); - } - return c; - } - - /** - * Karazuba multiplication - */ - private BigDecimalPolynomial multRecursive(BigDecimalPolynomial poly2) - { - BigDecimal[] a = coeffs; - BigDecimal[] b = poly2.coeffs; - - int n = poly2.coeffs.length; - if (n <= 1) - { - BigDecimal[] c = coeffs.clone(); - for (int i = 0; i < coeffs.length; i++) - { - c[i] = c[i].multiply(poly2.coeffs[0]); - } - return new BigDecimalPolynomial(c); - } - else - { - int n1 = n / 2; - - BigDecimalPolynomial a1 = new BigDecimalPolynomial(copyOf(a, n1)); - BigDecimalPolynomial a2 = new BigDecimalPolynomial(copyOfRange(a, n1, n)); - BigDecimalPolynomial b1 = new BigDecimalPolynomial(copyOf(b, n1)); - BigDecimalPolynomial b2 = new BigDecimalPolynomial(copyOfRange(b, n1, n)); - - BigDecimalPolynomial A = (BigDecimalPolynomial)a1.clone(); - A.add(a2); - BigDecimalPolynomial B = (BigDecimalPolynomial)b1.clone(); - B.add(b2); - - BigDecimalPolynomial c1 = a1.multRecursive(b1); - BigDecimalPolynomial c2 = a2.multRecursive(b2); - BigDecimalPolynomial c3 = A.multRecursive(B); - c3.sub(c1); - c3.sub(c2); - - BigDecimalPolynomial c = new BigDecimalPolynomial(2 * n - 1); - for (int i = 0; i < c1.coeffs.length; i++) - { - c.coeffs[i] = c1.coeffs[i]; - } - for (int i = 0; i < c3.coeffs.length; i++) - { - c.coeffs[n1 + i] = c.coeffs[n1 + i].add(c3.coeffs[i]); - } - for (int i = 0; i < c2.coeffs.length; i++) - { - c.coeffs[2 * n1 + i] = c.coeffs[2 * n1 + i].add(c2.coeffs[i]); - } - return c; - } - } - - /** - * Adds another polynomial which can have a different number of coefficients. - * - * @param b another polynomial - */ - public void add(BigDecimalPolynomial b) - { - if (b.coeffs.length > coeffs.length) - { - int N = coeffs.length; - coeffs = copyOf(coeffs, b.coeffs.length); - for (int i = N; i < coeffs.length; i++) - { - coeffs[i] = ZERO; - } - } - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] = coeffs[i].add(b.coeffs[i]); - } - } - - /** - * Subtracts another polynomial which can have a different number of coefficients. - * - * @param b - */ - void sub(BigDecimalPolynomial b) - { - if (b.coeffs.length > coeffs.length) - { - int N = coeffs.length; - coeffs = copyOf(coeffs, b.coeffs.length); - for (int i = N; i < coeffs.length; i++) - { - coeffs[i] = ZERO; - } - } - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] = coeffs[i].subtract(b.coeffs[i]); - } - } - - /** - * Rounds all coefficients to the nearest integer. - * - * @return a new polynomial with <code>BigInteger</code> coefficients - */ - public BigIntPolynomial round() - { - int N = coeffs.length; - BigIntPolynomial p = new BigIntPolynomial(N); - for (int i = 0; i < N; i++) - { - p.coeffs[i] = coeffs[i].setScale(0, BigDecimal.ROUND_HALF_EVEN).toBigInteger(); - } - return p; - } - - /** - * Makes a copy of the polynomial that is independent of the original. - */ - public Object clone() - { - return new BigDecimalPolynomial(coeffs.clone()); - } - - private BigDecimal[] copyOf(BigDecimal[] a, int length) - { - BigDecimal[] tmp = new BigDecimal[length]; - - System.arraycopy(a, 0, tmp, 0, a.length < length ? a.length : length); - - return tmp; - } - - private BigDecimal[] copyOfRange(BigDecimal[] a, int from, int to) - { - int newLength = to - from; - BigDecimal[] tmp = new BigDecimal[to - from]; - - System.arraycopy(a, from, tmp, 0, (a.length - from) < newLength ? (a.length - from) : newLength); - - return tmp; - } - - public BigDecimal[] getCoeffs() - { - BigDecimal[] tmp = new BigDecimal[coeffs.length]; - - System.arraycopy(coeffs, 0, tmp, 0, coeffs.length); - - return tmp; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/BigIntPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/BigIntPolynomial.java deleted file mode 100644 index 3c79b2e9..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/BigIntPolynomial.java +++ /dev/null @@ -1,394 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.polynomial; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.bouncycastle.util.Arrays; - -/** - * A polynomial with {@link BigInteger} coefficients.<br> - * Some methods (like <code>add</code>) change the polynomial, others (like <code>mult</code>) do - * not but return the result as a new polynomial. - */ -public class BigIntPolynomial -{ - private final static double LOG_10_2 = Math.log10(2); - - BigInteger[] coeffs; - - /** - * Constructs a new polynomial with <code>N</code> coefficients initialized to 0. - * - * @param N the number of coefficients - */ - BigIntPolynomial(int N) - { - coeffs = new BigInteger[N]; - for (int i = 0; i < N; i++) - { - coeffs[i] = Constants.BIGINT_ZERO; - } - } - - /** - * Constructs a new polynomial with a given set of coefficients. - * - * @param coeffs the coefficients - */ - BigIntPolynomial(BigInteger[] coeffs) - { - this.coeffs = coeffs; - } - - /** - * Constructs a <code>BigIntPolynomial</code> from a <code>IntegerPolynomial</code>. The two polynomials are - * independent of each other. - * - * @param p the original polynomial - */ - public BigIntPolynomial(IntegerPolynomial p) - { - coeffs = new BigInteger[p.coeffs.length]; - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] = BigInteger.valueOf(p.coeffs[i]); - } - } - - /** - * Generates a random polynomial with <code>numOnes</code> coefficients equal to 1, - * <code>numNegOnes</code> coefficients equal to -1, and the rest equal to 0. - * - * @param N number of coefficients - * @param numOnes number of 1's - * @param numNegOnes number of -1's - * @return - */ - static BigIntPolynomial generateRandomSmall(int N, int numOnes, int numNegOnes) - { - List coeffs = new ArrayList(); - for (int i = 0; i < numOnes; i++) - { - coeffs.add(Constants.BIGINT_ONE); - } - for (int i = 0; i < numNegOnes; i++) - { - coeffs.add(BigInteger.valueOf(-1)); - } - while (coeffs.size() < N) - { - coeffs.add(Constants.BIGINT_ZERO); - } - Collections.shuffle(coeffs, new SecureRandom()); - - BigIntPolynomial poly = new BigIntPolynomial(N); - for (int i = 0; i < coeffs.size(); i++) - { - poly.coeffs[i] = (BigInteger)coeffs.get(i); - } - return poly; - } - - /** - * Multiplies the polynomial by another, taking the indices mod N. Does not - * change this polynomial but returns the result as a new polynomial.<br> - * Both polynomials must have the same number of coefficients. - * - * @param poly2 the polynomial to multiply by - * @return a new polynomial - */ - public BigIntPolynomial mult(BigIntPolynomial poly2) - { - int N = coeffs.length; - if (poly2.coeffs.length != N) - { - throw new IllegalArgumentException("Number of coefficients must be the same"); - } - - BigIntPolynomial c = multRecursive(poly2); - - if (c.coeffs.length > N) - { - for (int k = N; k < c.coeffs.length; k++) - { - c.coeffs[k - N] = c.coeffs[k - N].add(c.coeffs[k]); - } - c.coeffs = Arrays.copyOf(c.coeffs, N); - } - return c; - } - - /** - * Karazuba multiplication - */ - private BigIntPolynomial multRecursive(BigIntPolynomial poly2) - { - BigInteger[] a = coeffs; - BigInteger[] b = poly2.coeffs; - - int n = poly2.coeffs.length; - if (n <= 1) - { - BigInteger[] c = Arrays.clone(coeffs); - for (int i = 0; i < coeffs.length; i++) - { - c[i] = c[i].multiply(poly2.coeffs[0]); - } - return new BigIntPolynomial(c); - } - else - { - int n1 = n / 2; - - BigIntPolynomial a1 = new BigIntPolynomial(Arrays.copyOf(a, n1)); - BigIntPolynomial a2 = new BigIntPolynomial(Arrays.copyOfRange(a, n1, n)); - BigIntPolynomial b1 = new BigIntPolynomial(Arrays.copyOf(b, n1)); - BigIntPolynomial b2 = new BigIntPolynomial(Arrays.copyOfRange(b, n1, n)); - - BigIntPolynomial A = (BigIntPolynomial)a1.clone(); - A.add(a2); - BigIntPolynomial B = (BigIntPolynomial)b1.clone(); - B.add(b2); - - BigIntPolynomial c1 = a1.multRecursive(b1); - BigIntPolynomial c2 = a2.multRecursive(b2); - BigIntPolynomial c3 = A.multRecursive(B); - c3.sub(c1); - c3.sub(c2); - - BigIntPolynomial c = new BigIntPolynomial(2 * n - 1); - for (int i = 0; i < c1.coeffs.length; i++) - { - c.coeffs[i] = c1.coeffs[i]; - } - for (int i = 0; i < c3.coeffs.length; i++) - { - c.coeffs[n1 + i] = c.coeffs[n1 + i].add(c3.coeffs[i]); - } - for (int i = 0; i < c2.coeffs.length; i++) - { - c.coeffs[2 * n1 + i] = c.coeffs[2 * n1 + i].add(c2.coeffs[i]); - } - return c; - } - } - - /** - * Adds another polynomial which can have a different number of coefficients, - * and takes the coefficient values mod <code>modulus</code>. - * - * @param b another polynomial - */ - void add(BigIntPolynomial b, BigInteger modulus) - { - add(b); - mod(modulus); - } - - /** - * Adds another polynomial which can have a different number of coefficients. - * - * @param b another polynomial - */ - public void add(BigIntPolynomial b) - { - if (b.coeffs.length > coeffs.length) - { - int N = coeffs.length; - coeffs = Arrays.copyOf(coeffs, b.coeffs.length); - for (int i = N; i < coeffs.length; i++) - { - coeffs[i] = Constants.BIGINT_ZERO; - } - } - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] = coeffs[i].add(b.coeffs[i]); - } - } - - /** - * Subtracts another polynomial which can have a different number of coefficients. - * - * @param b another polynomial - */ - public void sub(BigIntPolynomial b) - { - if (b.coeffs.length > coeffs.length) - { - int N = coeffs.length; - coeffs = Arrays.copyOf(coeffs, b.coeffs.length); - for (int i = N; i < coeffs.length; i++) - { - coeffs[i] = Constants.BIGINT_ZERO; - } - } - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] = coeffs[i].subtract(b.coeffs[i]); - } - } - - /** - * Multiplies each coefficient by a <code>BigInteger</code>. Does not return a new polynomial but modifies this polynomial. - * - * @param factor - */ - public void mult(BigInteger factor) - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] = coeffs[i].multiply(factor); - } - } - - /** - * Multiplies each coefficient by a <code>int</code>. Does not return a new polynomial but modifies this polynomial. - * - * @param factor - */ - void mult(int factor) - { - mult(BigInteger.valueOf(factor)); - } - - /** - * Divides each coefficient by a <code>BigInteger</code> and rounds the result to the nearest whole number.<br> - * Does not return a new polynomial but modifies this polynomial. - * - * @param divisor the number to divide by - */ - public void div(BigInteger divisor) - { - BigInteger d = divisor.add(Constants.BIGINT_ONE).divide(BigInteger.valueOf(2)); - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] = coeffs[i].compareTo(Constants.BIGINT_ZERO) > 0 ? coeffs[i].add(d) : coeffs[i].add(d.negate()); - coeffs[i] = coeffs[i].divide(divisor); - } - } - - /** - * Divides each coefficient by a <code>BigDecimal</code> and rounds the result to <code>decimalPlaces</code> places. - * - * @param divisor the number to divide by - * @param decimalPlaces the number of fractional digits to round the result to - * @return a new <code>BigDecimalPolynomial</code> - */ - public BigDecimalPolynomial div(BigDecimal divisor, int decimalPlaces) - { - BigInteger max = maxCoeffAbs(); - int coeffLength = (int)(max.bitLength() * LOG_10_2) + 1; - // factor = 1/divisor - BigDecimal factor = Constants.BIGDEC_ONE.divide(divisor, coeffLength + decimalPlaces + 1, BigDecimal.ROUND_HALF_EVEN); - - // multiply each coefficient by factor - BigDecimalPolynomial p = new BigDecimalPolynomial(coeffs.length); - for (int i = 0; i < coeffs.length; i++) - // multiply, then truncate after decimalPlaces so subsequent operations aren't slowed down - { - p.coeffs[i] = new BigDecimal(coeffs[i]).multiply(factor).setScale(decimalPlaces, BigDecimal.ROUND_HALF_EVEN); - } - - return p; - } - - /** - * Returns the base10 length of the largest coefficient. - * - * @return length of the longest coefficient - */ - public int getMaxCoeffLength() - { - return (int)(maxCoeffAbs().bitLength() * LOG_10_2) + 1; - } - - private BigInteger maxCoeffAbs() - { - BigInteger max = coeffs[0].abs(); - for (int i = 1; i < coeffs.length; i++) - { - BigInteger coeff = coeffs[i].abs(); - if (coeff.compareTo(max) > 0) - { - max = coeff; - } - } - return max; - } - - /** - * Takes each coefficient modulo a number. - * - * @param modulus - */ - public void mod(BigInteger modulus) - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] = coeffs[i].mod(modulus); - } - } - - /** - * Returns the sum of all coefficients, i.e. evaluates the polynomial at 0. - * - * @return the sum of all coefficients - */ - BigInteger sumCoeffs() - { - BigInteger sum = Constants.BIGINT_ZERO; - for (int i = 0; i < coeffs.length; i++) - { - sum = sum.add(coeffs[i]); - } - return sum; - } - - /** - * Makes a copy of the polynomial that is independent of the original. - */ - public Object clone() - { - return new BigIntPolynomial(coeffs.clone()); - } - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + Arrays.hashCode(coeffs); - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - BigIntPolynomial other = (BigIntPolynomial)obj; - if (!Arrays.areEqual(coeffs, other.coeffs)) - { - return false; - } - return true; - } - - public BigInteger[] getCoeffs() - { - return Arrays.clone(coeffs); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/Constants.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/Constants.java deleted file mode 100644 index 2b41b19a..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/Constants.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.polynomial; - -import java.math.BigDecimal; -import java.math.BigInteger; - -public class Constants -{ - static final BigInteger BIGINT_ZERO = BigInteger.valueOf(0); - static final BigInteger BIGINT_ONE = BigInteger.valueOf(1); - - static final BigDecimal BIGDEC_ONE = BigDecimal.valueOf(1); -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/DenseTernaryPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/DenseTernaryPolynomial.java deleted file mode 100644 index 85730dab..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/DenseTernaryPolynomial.java +++ /dev/null @@ -1,142 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.polynomial; - -import java.security.SecureRandom; - -import org.bouncycastle.pqc.math.ntru.util.Util; -import org.bouncycastle.util.Arrays; - -/** - * A <code>TernaryPolynomial</code> with a "high" number of nonzero coefficients. - */ -public class DenseTernaryPolynomial - extends IntegerPolynomial - implements TernaryPolynomial -{ - - /** - * Constructs a new <code>DenseTernaryPolynomial</code> with <code>N</code> coefficients. - * - * @param N the number of coefficients - */ - DenseTernaryPolynomial(int N) - { - super(N); - checkTernarity(); - } - - /** - * Constructs a <code>DenseTernaryPolynomial</code> from a <code>IntegerPolynomial</code>. The two polynomials are - * independent of each other. - * - * @param intPoly the original polynomial - */ - public DenseTernaryPolynomial(IntegerPolynomial intPoly) - { - this(intPoly.coeffs); - } - - /** - * Constructs a new <code>DenseTernaryPolynomial</code> with a given set of coefficients. - * - * @param coeffs the coefficients - */ - public DenseTernaryPolynomial(int[] coeffs) - { - super(coeffs); - checkTernarity(); - } - - private void checkTernarity() - { - for (int i = 0; i != coeffs.length; i++) - { - int c = coeffs[i]; - if (c < -1 || c > 1) - { - throw new IllegalStateException("Illegal value: " + c + ", must be one of {-1, 0, 1}"); - } - } - } - - /** - * Generates a random polynomial with <code>numOnes</code> coefficients equal to 1, - * <code>numNegOnes</code> coefficients equal to -1, and the rest equal to 0. - * - * @param N number of coefficients - * @param numOnes number of 1's - * @param numNegOnes number of -1's - */ - public static DenseTernaryPolynomial generateRandom(int N, int numOnes, int numNegOnes, SecureRandom random) - { - int[] coeffs = Util.generateRandomTernary(N, numOnes, numNegOnes, random); - return new DenseTernaryPolynomial(coeffs); - } - - /** - * Generates a polynomial with coefficients randomly selected from <code>{-1, 0, 1}</code>. - * - * @param N number of coefficients - */ - public static DenseTernaryPolynomial generateRandom(int N, SecureRandom random) - { - DenseTernaryPolynomial poly = new DenseTernaryPolynomial(N); - for (int i = 0; i < N; i++) - { - poly.coeffs[i] = random.nextInt(3) - 1; - } - return poly; - } - - public IntegerPolynomial mult(IntegerPolynomial poly2, int modulus) - { - // even on 32-bit systems, LongPolynomial5 multiplies faster than IntegerPolynomial - if (modulus == 2048) - { - IntegerPolynomial poly2Pos = (IntegerPolynomial)poly2.clone(); - poly2Pos.modPositive(2048); - LongPolynomial5 poly5 = new LongPolynomial5(poly2Pos); - return poly5.mult(this).toIntegerPolynomial(); - } - else - { - return super.mult(poly2, modulus); - } - } - - public int[] getOnes() - { - int N = coeffs.length; - int[] ones = new int[N]; - int onesIdx = 0; - for (int i = 0; i < N; i++) - { - int c = coeffs[i]; - if (c == 1) - { - ones[onesIdx++] = i; - } - } - return Arrays.copyOf(ones, onesIdx); - } - - public int[] getNegOnes() - { - int N = coeffs.length; - int[] negOnes = new int[N]; - int negOnesIdx = 0; - for (int i = 0; i < N; i++) - { - int c = coeffs[i]; - if (c == -1) - { - negOnes[negOnesIdx++] = i; - } - } - return Arrays.copyOf(negOnes, negOnesIdx); - } - - public int size() - { - return coeffs.length; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/IntegerPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/IntegerPolynomial.java deleted file mode 100644 index c6bd7fbc..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/IntegerPolynomial.java +++ /dev/null @@ -1,1358 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.polynomial; - -import java.io.IOException; -import java.io.InputStream; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.LinkedBlockingQueue; - -import org.bouncycastle.pqc.math.ntru.euclid.BigIntEuclidean; -import org.bouncycastle.pqc.math.ntru.util.ArrayEncoder; -import org.bouncycastle.pqc.math.ntru.util.Util; -import org.bouncycastle.util.Arrays; - -/** - * A polynomial with <code>int</code> coefficients.<br> - * Some methods (like <code>add</code>) change the polynomial, others (like <code>mult</code>) do - * not but return the result as a new polynomial. - */ -public class IntegerPolynomial - implements Polynomial -{ - private static final int NUM_EQUAL_RESULTANTS = 3; - /** - * Prime numbers > 4500 for resultant computation. Starting them below ~4400 causes incorrect results occasionally. - * Fortunately, 4500 is about the optimum number for performance.<br/> - * This array contains enough prime numbers so primes never have to be computed on-line for any standard {@link org.bouncycastle.pqc.crypto.ntru.NTRUSigningParameters}. - */ - private static final int[] PRIMES = new int[]{ - 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, - 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, - 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, - 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, - 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, - 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, - 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, - 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, - 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, - 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, - 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, - 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, - 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, - 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, - 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, - 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, - 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, - 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, - 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, - 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, - 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, - 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, - 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, - 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, - 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, - 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, - 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, - 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, - 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, - 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, - 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, - 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, - 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, - 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, - 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, - 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, - 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, - 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, - 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, - 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, - 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, - 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, - 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, - 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, - 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, - 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, - 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, - 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, - 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, - 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, - 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, - 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, - 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, - 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283, - 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, - 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, - 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, - 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, - 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, - 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, - 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, - 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973}; - private static final List BIGINT_PRIMES; - - static - { - BIGINT_PRIMES = new ArrayList(); - for (int i = 0; i != PRIMES.length; i++) - { - BIGINT_PRIMES.add(BigInteger.valueOf(PRIMES[i])); - } - } - - public int[] coeffs; - - /** - * Constructs a new polynomial with <code>N</code> coefficients initialized to 0. - * - * @param N the number of coefficients - */ - public IntegerPolynomial(int N) - { - coeffs = new int[N]; - } - - /** - * Constructs a new polynomial with a given set of coefficients. - * - * @param coeffs the coefficients - */ - public IntegerPolynomial(int[] coeffs) - { - this.coeffs = coeffs; - } - - /** - * Constructs a <code>IntegerPolynomial</code> from a <code>BigIntPolynomial</code>. The two polynomials are independent of each other. - * - * @param p the original polynomial - */ - public IntegerPolynomial(BigIntPolynomial p) - { - coeffs = new int[p.coeffs.length]; - for (int i = 0; i < p.coeffs.length; i++) - { - coeffs[i] = p.coeffs[i].intValue(); - } - } - - /** - * Decodes a byte array to a polynomial with <code>N</code> ternary coefficients<br> - * Ignores any excess bytes. - * - * @param data an encoded ternary polynomial - * @param N number of coefficients - * @return the decoded polynomial - */ - public static IntegerPolynomial fromBinary3Sves(byte[] data, int N) - { - return new IntegerPolynomial(ArrayEncoder.decodeMod3Sves(data, N)); - } - - /** - * Converts a byte array produced by {@link #toBinary3Tight()} to a polynomial. - * - * @param b a byte array - * @param N number of coefficients - * @return the decoded polynomial - */ - public static IntegerPolynomial fromBinary3Tight(byte[] b, int N) - { - return new IntegerPolynomial(ArrayEncoder.decodeMod3Tight(b, N)); - } - - /** - * Reads data produced by {@link #toBinary3Tight()} from an input stream and converts it to a polynomial. - * - * @param is an input stream - * @param N number of coefficients - * @return the decoded polynomial - */ - public static IntegerPolynomial fromBinary3Tight(InputStream is, int N) - throws IOException - { - return new IntegerPolynomial(ArrayEncoder.decodeMod3Tight(is, N)); - } - - /** - * Returns a polynomial with N coefficients between <code>0</code> and <code>q-1</code>.<br> - * <code>q</code> must be a power of 2.<br> - * Ignores any excess bytes. - * - * @param data an encoded ternary polynomial - * @param N number of coefficients - * @param q - * @return the decoded polynomial - */ - public static IntegerPolynomial fromBinary(byte[] data, int N, int q) - { - return new IntegerPolynomial(ArrayEncoder.decodeModQ(data, N, q)); - } - - /** - * Returns a polynomial with N coefficients between <code>0</code> and <code>q-1</code>.<br> - * <code>q</code> must be a power of 2.<br> - * Ignores any excess bytes. - * - * @param is an encoded ternary polynomial - * @param N number of coefficients - * @param q - * @return the decoded polynomial - */ - public static IntegerPolynomial fromBinary(InputStream is, int N, int q) - throws IOException - { - return new IntegerPolynomial(ArrayEncoder.decodeModQ(is, N, q)); - } - - /** - * Encodes a polynomial with ternary coefficients to binary. - * <code>coeffs[2*i]</code> and <code>coeffs[2*i+1]</code> must not both equal -1 for any integer <code>i</code>, - * so this method is only safe to use with polynomials produced by <code>fromBinary3Sves()</code>. - * - * @return the encoded polynomial - */ - public byte[] toBinary3Sves() - { - return ArrayEncoder.encodeMod3Sves(coeffs); - } - - /** - * Converts a polynomial with ternary coefficients to binary. - * - * @return the encoded polynomial - */ - public byte[] toBinary3Tight() - { - BigInteger sum = Constants.BIGINT_ZERO; - for (int i = coeffs.length - 1; i >= 0; i--) - { - sum = sum.multiply(BigInteger.valueOf(3)); - sum = sum.add(BigInteger.valueOf(coeffs[i] + 1)); - } - - int size = (BigInteger.valueOf(3).pow(coeffs.length).bitLength() + 7) / 8; - byte[] arr = sum.toByteArray(); - - if (arr.length < size) - { - // pad with leading zeros so arr.length==size - byte[] arr2 = new byte[size]; - System.arraycopy(arr, 0, arr2, size - arr.length, arr.length); - return arr2; - } - - if (arr.length > size) - // drop sign bit - { - arr = Arrays.copyOfRange(arr, 1, arr.length); - } - return arr; - } - - /** - * Encodes a polynomial whose coefficients are between 0 and q, to binary. q must be a power of 2. - * - * @param q - * @return the encoded polynomial - */ - public byte[] toBinary(int q) - { - return ArrayEncoder.encodeModQ(coeffs, q); - } - - /** - * Multiplies the polynomial with another, taking the values mod modulus and the indices mod N - */ - public IntegerPolynomial mult(IntegerPolynomial poly2, int modulus) - { - IntegerPolynomial c = mult(poly2); - c.mod(modulus); - return c; - } - - /** - * Multiplies the polynomial with another, taking the indices mod N - */ - public IntegerPolynomial mult(IntegerPolynomial poly2) - { - int N = coeffs.length; - if (poly2.coeffs.length != N) - { - throw new IllegalArgumentException("Number of coefficients must be the same"); - } - - IntegerPolynomial c = multRecursive(poly2); - - if (c.coeffs.length > N) - { - for (int k = N; k < c.coeffs.length; k++) - { - c.coeffs[k - N] += c.coeffs[k]; - } - c.coeffs = Arrays.copyOf(c.coeffs, N); - } - return c; - } - - public BigIntPolynomial mult(BigIntPolynomial poly2) - { - return new BigIntPolynomial(this).mult(poly2); - } - - /** - * Karazuba multiplication - */ - private IntegerPolynomial multRecursive(IntegerPolynomial poly2) - { - int[] a = coeffs; - int[] b = poly2.coeffs; - - int n = poly2.coeffs.length; - if (n <= 32) - { - int cn = 2 * n - 1; - IntegerPolynomial c = new IntegerPolynomial(new int[cn]); - for (int k = 0; k < cn; k++) - { - for (int i = Math.max(0, k - n + 1); i <= Math.min(k, n - 1); i++) - { - c.coeffs[k] += b[i] * a[k - i]; - } - } - return c; - } - else - { - int n1 = n / 2; - - IntegerPolynomial a1 = new IntegerPolynomial(Arrays.copyOf(a, n1)); - IntegerPolynomial a2 = new IntegerPolynomial(Arrays.copyOfRange(a, n1, n)); - IntegerPolynomial b1 = new IntegerPolynomial(Arrays.copyOf(b, n1)); - IntegerPolynomial b2 = new IntegerPolynomial(Arrays.copyOfRange(b, n1, n)); - - IntegerPolynomial A = (IntegerPolynomial)a1.clone(); - A.add(a2); - IntegerPolynomial B = (IntegerPolynomial)b1.clone(); - B.add(b2); - - IntegerPolynomial c1 = a1.multRecursive(b1); - IntegerPolynomial c2 = a2.multRecursive(b2); - IntegerPolynomial c3 = A.multRecursive(B); - c3.sub(c1); - c3.sub(c2); - - IntegerPolynomial c = new IntegerPolynomial(2 * n - 1); - for (int i = 0; i < c1.coeffs.length; i++) - { - c.coeffs[i] = c1.coeffs[i]; - } - for (int i = 0; i < c3.coeffs.length; i++) - { - c.coeffs[n1 + i] += c3.coeffs[i]; - } - for (int i = 0; i < c2.coeffs.length; i++) - { - c.coeffs[2 * n1 + i] += c2.coeffs[i]; - } - return c; - } - } - - /** - * Computes the inverse mod <code>q; q</code> must be a power of 2.<br> - * Returns <code>null</code> if the polynomial is not invertible. - * - * @param q the modulus - * @return a new polynomial - */ - public IntegerPolynomial invertFq(int q) - { - int N = coeffs.length; - int k = 0; - IntegerPolynomial b = new IntegerPolynomial(N + 1); - b.coeffs[0] = 1; - IntegerPolynomial c = new IntegerPolynomial(N + 1); - IntegerPolynomial f = new IntegerPolynomial(N + 1); - f.coeffs = Arrays.copyOf(coeffs, N + 1); - f.modPositive(2); - // set g(x) = x^N − 1 - IntegerPolynomial g = new IntegerPolynomial(N + 1); - g.coeffs[0] = 1; - g.coeffs[N] = 1; - while (true) - { - while (f.coeffs[0] == 0) - { - for (int i = 1; i <= N; i++) - { - f.coeffs[i - 1] = f.coeffs[i]; // f(x) = f(x) / x - c.coeffs[N + 1 - i] = c.coeffs[N - i]; // c(x) = c(x) * x - } - f.coeffs[N] = 0; - c.coeffs[0] = 0; - k++; - if (f.equalsZero()) - { - return null; // not invertible - } - } - if (f.equalsOne()) - { - break; - } - if (f.degree() < g.degree()) - { - // exchange f and g - IntegerPolynomial temp = f; - f = g; - g = temp; - // exchange b and c - temp = b; - b = c; - c = temp; - } - f.add(g, 2); - b.add(c, 2); - } - - if (b.coeffs[N] != 0) - { - return null; - } - // Fq(x) = x^(N-k) * b(x) - IntegerPolynomial Fq = new IntegerPolynomial(N); - int j = 0; - k %= N; - for (int i = N - 1; i >= 0; i--) - { - j = i - k; - if (j < 0) - { - j += N; - } - Fq.coeffs[j] = b.coeffs[i]; - } - - return mod2ToModq(Fq, q); - } - - /** - * Computes the inverse mod q from the inverse mod 2 - * - * @param Fq - * @param q - * @return The inverse of this polynomial mod q - */ - private IntegerPolynomial mod2ToModq(IntegerPolynomial Fq, int q) - { - if (Util.is64BitJVM() && q == 2048) - { - LongPolynomial2 thisLong = new LongPolynomial2(this); - LongPolynomial2 FqLong = new LongPolynomial2(Fq); - int v = 2; - while (v < q) - { - v *= 2; - LongPolynomial2 temp = (LongPolynomial2)FqLong.clone(); - temp.mult2And(v - 1); - FqLong = thisLong.mult(FqLong).mult(FqLong); - temp.subAnd(FqLong, v - 1); - FqLong = temp; - } - return FqLong.toIntegerPolynomial(); - } - else - { - int v = 2; - while (v < q) - { - v *= 2; - IntegerPolynomial temp = new IntegerPolynomial(Arrays.copyOf(Fq.coeffs, Fq.coeffs.length)); - temp.mult2(v); - Fq = mult(Fq, v).mult(Fq, v); - temp.sub(Fq, v); - Fq = temp; - } - return Fq; - } - } - - /** - * Computes the inverse mod 3. - * Returns <code>null</code> if the polynomial is not invertible. - * - * @return a new polynomial - */ - public IntegerPolynomial invertF3() - { - int N = coeffs.length; - int k = 0; - IntegerPolynomial b = new IntegerPolynomial(N + 1); - b.coeffs[0] = 1; - IntegerPolynomial c = new IntegerPolynomial(N + 1); - IntegerPolynomial f = new IntegerPolynomial(N + 1); - f.coeffs = Arrays.copyOf(coeffs, N + 1); - f.modPositive(3); - // set g(x) = x^N − 1 - IntegerPolynomial g = new IntegerPolynomial(N + 1); - g.coeffs[0] = -1; - g.coeffs[N] = 1; - while (true) - { - while (f.coeffs[0] == 0) - { - for (int i = 1; i <= N; i++) - { - f.coeffs[i - 1] = f.coeffs[i]; // f(x) = f(x) / x - c.coeffs[N + 1 - i] = c.coeffs[N - i]; // c(x) = c(x) * x - } - f.coeffs[N] = 0; - c.coeffs[0] = 0; - k++; - if (f.equalsZero()) - { - return null; // not invertible - } - } - if (f.equalsAbsOne()) - { - break; - } - if (f.degree() < g.degree()) - { - // exchange f and g - IntegerPolynomial temp = f; - f = g; - g = temp; - // exchange b and c - temp = b; - b = c; - c = temp; - } - if (f.coeffs[0] == g.coeffs[0]) - { - f.sub(g, 3); - b.sub(c, 3); - } - else - { - f.add(g, 3); - b.add(c, 3); - } - } - - if (b.coeffs[N] != 0) - { - return null; - } - // Fp(x) = [+-] x^(N-k) * b(x) - IntegerPolynomial Fp = new IntegerPolynomial(N); - int j = 0; - k %= N; - for (int i = N - 1; i >= 0; i--) - { - j = i - k; - if (j < 0) - { - j += N; - } - Fp.coeffs[j] = f.coeffs[0] * b.coeffs[i]; - } - - Fp.ensurePositive(3); - return Fp; - } - - /** - * Resultant of this polynomial with <code>x^n-1</code> using a probabilistic algorithm. - * <p> - * Unlike EESS, this implementation does not compute all resultants modulo primes - * such that their product exceeds the maximum possible resultant, but rather stops - * when <code>NUM_EQUAL_RESULTANTS</code> consecutive modular resultants are equal.<br> - * This means the return value may be incorrect. Experiments show this happens in - * about 1 out of 100 cases when <code>N=439</code> and <code>NUM_EQUAL_RESULTANTS=2</code>, - * so the likelyhood of leaving the loop too early is <code>(1/100)^(NUM_EQUAL_RESULTANTS-1)</code>. - * <p> - * Because of the above, callers must verify the output and try a different polynomial if necessary. - * - * @return <code>(rho, res)</code> satisfying <code>res = rho*this + t*(x^n-1)</code> for some integer <code>t</code>. - */ - public Resultant resultant() - { - int N = coeffs.length; - - // Compute resultants modulo prime numbers. Continue until NUM_EQUAL_RESULTANTS consecutive modular resultants are equal. - LinkedList<ModularResultant> modResultants = new LinkedList<ModularResultant>(); - BigInteger prime = null; - BigInteger pProd = Constants.BIGINT_ONE; - BigInteger res = Constants.BIGINT_ONE; - int numEqual = 1; // number of consecutive modular resultants equal to each other - Iterator<BigInteger> primes = BIGINT_PRIMES.iterator(); - while (true) - { - prime = primes.hasNext() ? primes.next() : prime.nextProbablePrime(); - ModularResultant crr = resultant(prime.intValue()); - modResultants.add(crr); - - BigInteger temp = pProd.multiply(prime); - BigIntEuclidean er = BigIntEuclidean.calculate(prime, pProd); - BigInteger resPrev = res; - res = res.multiply(er.x.multiply(prime)); - BigInteger res2 = crr.res.multiply(er.y.multiply(pProd)); - res = res.add(res2).mod(temp); - pProd = temp; - - BigInteger pProd2 = pProd.divide(BigInteger.valueOf(2)); - BigInteger pProd2n = pProd2.negate(); - if (res.compareTo(pProd2) > 0) - { - res = res.subtract(pProd); - } - else if (res.compareTo(pProd2n) < 0) - { - res = res.add(pProd); - } - - if (res.equals(resPrev)) - { - numEqual++; - if (numEqual >= NUM_EQUAL_RESULTANTS) - { - break; - } - } - else - { - numEqual = 1; - } - } - - // Combine modular rho's to obtain the final rho. - // For efficiency, first combine all pairs of small resultants to bigger resultants, - // then combine pairs of those, etc. until only one is left. - while (modResultants.size() > 1) - { - ModularResultant modRes1 = modResultants.removeFirst(); - ModularResultant modRes2 = modResultants.removeFirst(); - ModularResultant modRes3 = ModularResultant.combineRho(modRes1, modRes2); - modResultants.addLast(modRes3); - } - BigIntPolynomial rhoP = modResultants.getFirst().rho; - - BigInteger pProd2 = pProd.divide(BigInteger.valueOf(2)); - BigInteger pProd2n = pProd2.negate(); - if (res.compareTo(pProd2) > 0) - { - res = res.subtract(pProd); - } - if (res.compareTo(pProd2n) < 0) - { - res = res.add(pProd); - } - - for (int i = 0; i < N; i++) - { - BigInteger c = rhoP.coeffs[i]; - if (c.compareTo(pProd2) > 0) - { - rhoP.coeffs[i] = c.subtract(pProd); - } - if (c.compareTo(pProd2n) < 0) - { - rhoP.coeffs[i] = c.add(pProd); - } - } - - return new Resultant(rhoP, res); - } - - /** - * Multithreaded version of {@link #resultant()}. - * - * @return <code>(rho, res)</code> satisfying <code>res = rho*this + t*(x^n-1)</code> for some integer <code>t</code>. - */ - public Resultant resultantMultiThread() - { - int N = coeffs.length; - - // upper bound for resultant(f, g) = ||f, 2||^deg(g) * ||g, 2||^deg(f) = squaresum(f)^(N/2) * 2^(deg(f)/2) because g(x)=x^N-1 - // see http://jondalon.mathematik.uni-osnabrueck.de/staff/phpages/brunsw/CompAlg.pdf chapter 3 - BigInteger max = squareSum().pow((N + 1) / 2); - max = max.multiply(BigInteger.valueOf(2).pow((degree() + 1) / 2)); - BigInteger max2 = max.multiply(BigInteger.valueOf(2)); - - // compute resultants modulo prime numbers - BigInteger prime = BigInteger.valueOf(10000); - BigInteger pProd = Constants.BIGINT_ONE; - LinkedBlockingQueue<Future<ModularResultant>> resultantTasks = new LinkedBlockingQueue<Future<ModularResultant>>(); - Iterator<BigInteger> primes = BIGINT_PRIMES.iterator(); - ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); - while (pProd.compareTo(max2) < 0) - { - if (primes.hasNext()) - { - prime = primes.next(); - } - else - { - prime = prime.nextProbablePrime(); - } - Future<ModularResultant> task = executor.submit(new ModResultantTask(prime.intValue())); - resultantTasks.add(task); - pProd = pProd.multiply(prime); - } - - // Combine modular resultants to obtain the resultant. - // For efficiency, first combine all pairs of small resultants to bigger resultants, - // then combine pairs of those, etc. until only one is left. - ModularResultant overallResultant = null; - while (!resultantTasks.isEmpty()) - { - try - { - Future<ModularResultant> modRes1 = resultantTasks.take(); - Future<ModularResultant> modRes2 = resultantTasks.poll(); - if (modRes2 == null) - { - // modRes1 is the only one left - overallResultant = modRes1.get(); - break; - } - Future<ModularResultant> newTask = executor.submit(new CombineTask(modRes1.get(), modRes2.get())); - resultantTasks.add(newTask); - } - catch (Exception e) - { - throw new IllegalStateException(e.toString()); - } - } - executor.shutdown(); - BigInteger res = overallResultant.res; - BigIntPolynomial rhoP = overallResultant.rho; - - BigInteger pProd2 = pProd.divide(BigInteger.valueOf(2)); - BigInteger pProd2n = pProd2.negate(); - - if (res.compareTo(pProd2) > 0) - { - res = res.subtract(pProd); - } - if (res.compareTo(pProd2n) < 0) - { - res = res.add(pProd); - } - - for (int i = 0; i < N; i++) - { - BigInteger c = rhoP.coeffs[i]; - if (c.compareTo(pProd2) > 0) - { - rhoP.coeffs[i] = c.subtract(pProd); - } - if (c.compareTo(pProd2n) < 0) - { - rhoP.coeffs[i] = c.add(pProd); - } - } - - return new Resultant(rhoP, res); - } - - /** - * Resultant of this polynomial with <code>x^n-1 mod p</code>. - * - * @return <code>(rho, res)</code> satisfying <code>res = rho*this + t*(x^n-1) mod p</code> for some integer <code>t</code>. - */ - public ModularResultant resultant(int p) - { - // Add a coefficient as the following operations involve polynomials of degree deg(f)+1 - int[] fcoeffs = Arrays.copyOf(coeffs, coeffs.length + 1); - IntegerPolynomial f = new IntegerPolynomial(fcoeffs); - int N = fcoeffs.length; - - IntegerPolynomial a = new IntegerPolynomial(N); - a.coeffs[0] = -1; - a.coeffs[N - 1] = 1; - IntegerPolynomial b = new IntegerPolynomial(f.coeffs); - IntegerPolynomial v1 = new IntegerPolynomial(N); - IntegerPolynomial v2 = new IntegerPolynomial(N); - v2.coeffs[0] = 1; - int da = N - 1; - int db = b.degree(); - int ta = da; - int c = 0; - int r = 1; - while (db > 0) - { - c = Util.invert(b.coeffs[db], p); - c = (c * a.coeffs[da]) % p; - a.multShiftSub(b, c, da - db, p); - v1.multShiftSub(v2, c, da - db, p); - - da = a.degree(); - if (da < db) - { - r *= Util.pow(b.coeffs[db], ta - da, p); - r %= p; - if (ta % 2 == 1 && db % 2 == 1) - { - r = (-r) % p; - } - IntegerPolynomial temp = a; - a = b; - b = temp; - int tempdeg = da; - da = db; - temp = v1; - v1 = v2; - v2 = temp; - ta = db; - db = tempdeg; - } - } - r *= Util.pow(b.coeffs[0], da, p); - r %= p; - c = Util.invert(b.coeffs[0], p); - v2.mult(c); - v2.mod(p); - v2.mult(r); - v2.mod(p); - - // drop the highest coefficient so #coeffs matches the original input - v2.coeffs = Arrays.copyOf(v2.coeffs, v2.coeffs.length - 1); - return new ModularResultant(new BigIntPolynomial(v2), BigInteger.valueOf(r), BigInteger.valueOf(p)); - } - - /** - * Computes <code>this-b*c*(x^k) mod p</code> and stores the result in this polynomial.<br/> - * See steps 4a,4b in EESS algorithm 2.2.7.1. - * - * @param b - * @param c - * @param k - * @param p - */ - private void multShiftSub(IntegerPolynomial b, int c, int k, int p) - { - int N = coeffs.length; - for (int i = k; i < N; i++) - { - coeffs[i] = (coeffs[i] - b.coeffs[i - k] * c) % p; - } - } - - /** - * Adds the squares of all coefficients. - * - * @return the sum of squares - */ - private BigInteger squareSum() - { - BigInteger sum = Constants.BIGINT_ZERO; - for (int i = 0; i < coeffs.length; i++) - { - sum = sum.add(BigInteger.valueOf(coeffs[i] * coeffs[i])); - } - return sum; - } - - /** - * Returns the degree of the polynomial - * - * @return the degree - */ - int degree() - { - int degree = coeffs.length - 1; - while (degree > 0 && coeffs[degree] == 0) - { - degree--; - } - return degree; - } - - /** - * Adds another polynomial which can have a different number of coefficients, - * and takes the coefficient values mod <code>modulus</code>. - * - * @param b another polynomial - */ - public void add(IntegerPolynomial b, int modulus) - { - add(b); - mod(modulus); - } - - /** - * Adds another polynomial which can have a different number of coefficients. - * - * @param b another polynomial - */ - public void add(IntegerPolynomial b) - { - if (b.coeffs.length > coeffs.length) - { - coeffs = Arrays.copyOf(coeffs, b.coeffs.length); - } - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] += b.coeffs[i]; - } - } - - /** - * Subtracts another polynomial which can have a different number of coefficients, - * and takes the coefficient values mod <code>modulus</code>. - * - * @param b another polynomial - */ - public void sub(IntegerPolynomial b, int modulus) - { - sub(b); - mod(modulus); - } - - /** - * Subtracts another polynomial which can have a different number of coefficients. - * - * @param b another polynomial - */ - public void sub(IntegerPolynomial b) - { - if (b.coeffs.length > coeffs.length) - { - coeffs = Arrays.copyOf(coeffs, b.coeffs.length); - } - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] -= b.coeffs[i]; - } - } - - /** - * Subtracts a <code>int</code> from each coefficient. Does not return a new polynomial but modifies this polynomial. - * - * @param b - */ - void sub(int b) - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] -= b; - } - } - - /** - * Multiplies each coefficient by a <code>int</code>. Does not return a new polynomial but modifies this polynomial. - * - * @param factor - */ - public void mult(int factor) - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] *= factor; - } - } - - /** - * Multiplies each coefficient by a 2 and applies a modulus. Does not return a new polynomial but modifies this polynomial. - * - * @param modulus a modulus - */ - private void mult2(int modulus) - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] *= 2; - coeffs[i] %= modulus; - } - } - - /** - * Multiplies each coefficient by a 2 and applies a modulus. Does not return a new polynomial but modifies this polynomial. - * - * @param modulus a modulus - */ - public void mult3(int modulus) - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] *= 3; - coeffs[i] %= modulus; - } - } - - /** - * Divides each coefficient by <code>k</code> and rounds to the nearest integer. Does not return a new polynomial but modifies this polynomial. - * - * @param k the divisor - */ - public void div(int k) - { - int k2 = (k + 1) / 2; - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] += coeffs[i] > 0 ? k2 : -k2; - coeffs[i] /= k; - } - } - - /** - * Takes each coefficient modulo 3 such that all coefficients are ternary. - */ - public void mod3() - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] %= 3; - if (coeffs[i] > 1) - { - coeffs[i] -= 3; - } - if (coeffs[i] < -1) - { - coeffs[i] += 3; - } - } - } - - /** - * Ensures all coefficients are between 0 and <code>modulus-1</code> - * - * @param modulus a modulus - */ - public void modPositive(int modulus) - { - mod(modulus); - ensurePositive(modulus); - } - - /** - * Reduces all coefficients to the interval [-modulus/2, modulus/2) - */ - void modCenter(int modulus) - { - mod(modulus); - for (int j = 0; j < coeffs.length; j++) - { - while (coeffs[j] < modulus / 2) - { - coeffs[j] += modulus; - } - while (coeffs[j] >= modulus / 2) - { - coeffs[j] -= modulus; - } - } - } - - /** - * Takes each coefficient modulo <code>modulus</code>. - */ - public void mod(int modulus) - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] %= modulus; - } - } - - /** - * Adds <code>modulus</code> until all coefficients are above 0. - * - * @param modulus a modulus - */ - public void ensurePositive(int modulus) - { - for (int i = 0; i < coeffs.length; i++) - { - while (coeffs[i] < 0) - { - coeffs[i] += modulus; - } - } - } - - /** - * Computes the centered euclidean norm of the polynomial. - * - * @param q a modulus - * @return the centered norm - */ - public long centeredNormSq(int q) - { - int N = coeffs.length; - IntegerPolynomial p = (IntegerPolynomial)clone(); - p.shiftGap(q); - - long sum = 0; - long sqSum = 0; - for (int i = 0; i != p.coeffs.length; i++) - { - int c = p.coeffs[i]; - sum += c; - sqSum += c * c; - } - - long centeredNormSq = sqSum - sum * sum / N; - return centeredNormSq; - } - - /** - * Shifts all coefficients so the largest gap is centered around <code>-q/2</code>. - * - * @param q a modulus - */ - void shiftGap(int q) - { - modCenter(q); - - int[] sorted = Arrays.clone(coeffs); - - sort(sorted); - - int maxrange = 0; - int maxrangeStart = 0; - for (int i = 0; i < sorted.length - 1; i++) - { - int range = sorted[i + 1] - sorted[i]; - if (range > maxrange) - { - maxrange = range; - maxrangeStart = sorted[i]; - } - } - - int pmin = sorted[0]; - int pmax = sorted[sorted.length - 1]; - - int j = q - pmax + pmin; - int shift; - if (j > maxrange) - { - shift = (pmax + pmin) / 2; - } - else - { - shift = maxrangeStart + maxrange / 2 + q / 2; - } - - sub(shift); - } - - private void sort(int[] ints) - { - boolean swap = true; - - while (swap) - { - swap = false; - for (int i = 0; i != ints.length - 1; i++) - { - if (ints[i] > ints[i+1]) - { - int tmp = ints[i]; - ints[i] = ints[i+1]; - ints[i+1] = tmp; - swap = true; - } - } - } - } - - /** - * Shifts the values of all coefficients to the interval <code>[-q/2, q/2]</code>. - * - * @param q a modulus - */ - public void center0(int q) - { - for (int i = 0; i < coeffs.length; i++) - { - while (coeffs[i] < -q / 2) - { - coeffs[i] += q; - } - while (coeffs[i] > q / 2) - { - coeffs[i] -= q; - } - } - } - - /** - * Returns the sum of all coefficients, i.e. evaluates the polynomial at 0. - * - * @return the sum of all coefficients - */ - public int sumCoeffs() - { - int sum = 0; - for (int i = 0; i < coeffs.length; i++) - { - sum += coeffs[i]; - } - return sum; - } - - /** - * Tests if <code>p(x) = 0</code>. - * - * @return true iff all coefficients are zeros - */ - private boolean equalsZero() - { - for (int i = 0; i < coeffs.length; i++) - { - if (coeffs[i] != 0) - { - return false; - } - } - return true; - } - - /** - * Tests if <code>p(x) = 1</code>. - * - * @return true iff all coefficients are equal to zero, except for the lowest coefficient which must equal 1 - */ - public boolean equalsOne() - { - for (int i = 1; i < coeffs.length; i++) - { - if (coeffs[i] != 0) - { - return false; - } - } - return coeffs[0] == 1; - } - - /** - * Tests if <code>|p(x)| = 1</code>. - * - * @return true iff all coefficients are equal to zero, except for the lowest coefficient which must equal 1 or -1 - */ - private boolean equalsAbsOne() - { - for (int i = 1; i < coeffs.length; i++) - { - if (coeffs[i] != 0) - { - return false; - } - } - return Math.abs(coeffs[0]) == 1; - } - - /** - * Counts the number of coefficients equal to an integer - * - * @param value an integer - * @return the number of coefficients equal to <code>value</code> - */ - public int count(int value) - { - int count = 0; - for (int i = 0; i != coeffs.length; i++) - { - if (coeffs[i] == value) - { - count++; - } - } - return count; - } - - /** - * Multiplication by <code>X</code> in <code>Z[X]/Z[X^n-1]</code>. - */ - public void rotate1() - { - int clast = coeffs[coeffs.length - 1]; - for (int i = coeffs.length - 1; i > 0; i--) - { - coeffs[i] = coeffs[i - 1]; - } - coeffs[0] = clast; - } - - public void clear() - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] = 0; - } - } - - public IntegerPolynomial toIntegerPolynomial() - { - return (IntegerPolynomial)clone(); - } - - public Object clone() - { - return new IntegerPolynomial(coeffs.clone()); - } - - public boolean equals(Object obj) - { - if (obj instanceof IntegerPolynomial) - { - return Arrays.areEqual(coeffs, ((IntegerPolynomial)obj).coeffs); - } - else - { - return false; - } - } - - /** - * Calls {@link IntegerPolynomial#resultant(int) - */ - private class ModResultantTask - implements Callable<ModularResultant> - { - private int modulus; - - private ModResultantTask(int modulus) - { - this.modulus = modulus; - } - - public ModularResultant call() - { - return resultant(modulus); - } - } - - /** - * Calls {@link ModularResultant#combineRho(ModularResultant, ModularResultant) - */ - private class CombineTask - implements Callable<ModularResultant> - { - private ModularResultant modRes1; - private ModularResultant modRes2; - - private CombineTask(ModularResultant modRes1, ModularResultant modRes2) - { - this.modRes1 = modRes1; - this.modRes2 = modRes2; - } - - public ModularResultant call() - { - return ModularResultant.combineRho(modRes1, modRes2); - } - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/LongPolynomial2.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/LongPolynomial2.java deleted file mode 100644 index d71615a3..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/LongPolynomial2.java +++ /dev/null @@ -1,255 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.polynomial; - -import org.bouncycastle.util.Arrays; - -/** - * A polynomial class that combines two coefficients into one <code>long</code> value for - * faster multiplication in 64 bit environments.<br> - * Coefficients can be between 0 and 2047 and are stored in pairs in the bits 0..10 and 24..34 of a <code>long</code> number. - */ -public class LongPolynomial2 -{ - private long[] coeffs; // each representing two coefficients in the original IntegerPolynomial - private int numCoeffs; - - /** - * Constructs a <code>LongPolynomial2</code> from a <code>IntegerPolynomial</code>. The two polynomials are independent of each other. - * - * @param p the original polynomial. Coefficients must be between 0 and 2047. - */ - public LongPolynomial2(IntegerPolynomial p) - { - numCoeffs = p.coeffs.length; - coeffs = new long[(numCoeffs + 1) / 2]; - int idx = 0; - for (int pIdx = 0; pIdx < numCoeffs; ) - { - int c0 = p.coeffs[pIdx++]; - while (c0 < 0) - { - c0 += 2048; - } - long c1 = pIdx < numCoeffs ? p.coeffs[pIdx++] : 0; - while (c1 < 0) - { - c1 += 2048; - } - coeffs[idx] = c0 + (c1 << 24); - idx++; - } - } - - private LongPolynomial2(long[] coeffs) - { - this.coeffs = coeffs; - } - - private LongPolynomial2(int N) - { - coeffs = new long[N]; - } - - /** - * Multiplies the polynomial with another, taking the indices mod N and the values mod 2048. - */ - public LongPolynomial2 mult(LongPolynomial2 poly2) - { - int N = coeffs.length; - if (poly2.coeffs.length != N || numCoeffs != poly2.numCoeffs) - { - throw new IllegalArgumentException("Number of coefficients must be the same"); - } - - LongPolynomial2 c = multRecursive(poly2); - - if (c.coeffs.length > N) - { - if (numCoeffs % 2 == 0) - { - for (int k = N; k < c.coeffs.length; k++) - { - c.coeffs[k - N] = (c.coeffs[k - N] + c.coeffs[k]) & 0x7FF0007FFL; - } - c.coeffs = Arrays.copyOf(c.coeffs, N); - } - else - { - for (int k = N; k < c.coeffs.length; k++) - { - c.coeffs[k - N] = c.coeffs[k - N] + (c.coeffs[k - 1] >> 24); - c.coeffs[k - N] = c.coeffs[k - N] + ((c.coeffs[k] & 2047) << 24); - c.coeffs[k - N] &= 0x7FF0007FFL; - } - c.coeffs = Arrays.copyOf(c.coeffs, N); - c.coeffs[c.coeffs.length - 1] &= 2047; - } - } - - c = new LongPolynomial2(c.coeffs); - c.numCoeffs = numCoeffs; - return c; - } - - public IntegerPolynomial toIntegerPolynomial() - { - int[] intCoeffs = new int[numCoeffs]; - int uIdx = 0; - for (int i = 0; i < coeffs.length; i++) - { - intCoeffs[uIdx++] = (int)(coeffs[i] & 2047); - if (uIdx < numCoeffs) - { - intCoeffs[uIdx++] = (int)((coeffs[i] >> 24) & 2047); - } - } - return new IntegerPolynomial(intCoeffs); - } - - /** - * Karazuba multiplication - */ - private LongPolynomial2 multRecursive(LongPolynomial2 poly2) - { - long[] a = coeffs; - long[] b = poly2.coeffs; - - int n = poly2.coeffs.length; - if (n <= 32) - { - int cn = 2 * n; - LongPolynomial2 c = new LongPolynomial2(new long[cn]); - for (int k = 0; k < cn; k++) - { - for (int i = Math.max(0, k - n + 1); i <= Math.min(k, n - 1); i++) - { - long c0 = a[k - i] * b[i]; - long cu = c0 & 0x7FF000000L + (c0 & 2047); - long co = (c0 >>> 48) & 2047; - - c.coeffs[k] = (c.coeffs[k] + cu) & 0x7FF0007FFL; - c.coeffs[k + 1] = (c.coeffs[k + 1] + co) & 0x7FF0007FFL; - } - } - return c; - } - else - { - int n1 = n / 2; - - LongPolynomial2 a1 = new LongPolynomial2(Arrays.copyOf(a, n1)); - LongPolynomial2 a2 = new LongPolynomial2(Arrays.copyOfRange(a, n1, n)); - LongPolynomial2 b1 = new LongPolynomial2(Arrays.copyOf(b, n1)); - LongPolynomial2 b2 = new LongPolynomial2(Arrays.copyOfRange(b, n1, n)); - - LongPolynomial2 A = (LongPolynomial2)a1.clone(); - A.add(a2); - LongPolynomial2 B = (LongPolynomial2)b1.clone(); - B.add(b2); - - LongPolynomial2 c1 = a1.multRecursive(b1); - LongPolynomial2 c2 = a2.multRecursive(b2); - LongPolynomial2 c3 = A.multRecursive(B); - c3.sub(c1); - c3.sub(c2); - - LongPolynomial2 c = new LongPolynomial2(2 * n); - for (int i = 0; i < c1.coeffs.length; i++) - { - c.coeffs[i] = c1.coeffs[i] & 0x7FF0007FFL; - } - for (int i = 0; i < c3.coeffs.length; i++) - { - c.coeffs[n1 + i] = (c.coeffs[n1 + i] + c3.coeffs[i]) & 0x7FF0007FFL; - } - for (int i = 0; i < c2.coeffs.length; i++) - { - c.coeffs[2 * n1 + i] = (c.coeffs[2 * n1 + i] + c2.coeffs[i]) & 0x7FF0007FFL; - } - return c; - } - } - - /** - * Adds another polynomial which can have a different number of coefficients. - * - * @param b another polynomial - */ - private void add(LongPolynomial2 b) - { - if (b.coeffs.length > coeffs.length) - { - coeffs = Arrays.copyOf(coeffs, b.coeffs.length); - } - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] = (coeffs[i] + b.coeffs[i]) & 0x7FF0007FFL; - } - } - - /** - * Subtracts another polynomial which can have a different number of coefficients. - * - * @param b another polynomial - */ - private void sub(LongPolynomial2 b) - { - if (b.coeffs.length > coeffs.length) - { - coeffs = Arrays.copyOf(coeffs, b.coeffs.length); - } - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] = (0x0800000800000L + coeffs[i] - b.coeffs[i]) & 0x7FF0007FFL; - } - } - - /** - * Subtracts another polynomial which must have the same number of coefficients, - * and applies an AND mask to the upper and lower halves of each coefficients. - * - * @param b another polynomial - * @param mask a bit mask less than 2048 to apply to each 11-bit coefficient - */ - public void subAnd(LongPolynomial2 b, int mask) - { - long longMask = (((long)mask) << 24) + mask; - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] = (0x0800000800000L + coeffs[i] - b.coeffs[i]) & longMask; - } - } - - /** - * Multiplies this polynomial by 2 and applies an AND mask to the upper and - * lower halves of each coefficients. - * - * @param mask a bit mask less than 2048 to apply to each 11-bit coefficient - */ - public void mult2And(int mask) - { - long longMask = (((long)mask) << 24) + mask; - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] = (coeffs[i] << 1) & longMask; - } - } - - public Object clone() - { - LongPolynomial2 p = new LongPolynomial2(coeffs.clone()); - p.numCoeffs = numCoeffs; - return p; - } - - public boolean equals(Object obj) - { - if (obj instanceof LongPolynomial2) - { - return Arrays.areEqual(coeffs, ((LongPolynomial2)obj).coeffs); - } - else - { - return false; - } - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/LongPolynomial5.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/LongPolynomial5.java deleted file mode 100644 index c804cc8d..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/LongPolynomial5.java +++ /dev/null @@ -1,149 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.polynomial; - -import org.bouncycastle.util.Arrays; - -/** - * A polynomial class that combines five coefficients into one <code>long</code> value for - * faster multiplication by a ternary polynomial.<br> - * Coefficients can be between 0 and 2047 and are stored in bits 0..11, 12..23, ..., 48..59 of a <code>long</code> number. - */ -public class LongPolynomial5 -{ - private long[] coeffs; // groups of 5 coefficients - private int numCoeffs; - - /** - * Constructs a <code>LongPolynomial5</code> from a <code>IntegerPolynomial</code>. The two polynomials are independent of each other. - * - * @param p the original polynomial. Coefficients must be between 0 and 2047. - */ - public LongPolynomial5(IntegerPolynomial p) - { - numCoeffs = p.coeffs.length; - - coeffs = new long[(numCoeffs + 4) / 5]; - int cIdx = 0; - int shift = 0; - for (int i = 0; i < numCoeffs; i++) - { - coeffs[cIdx] |= ((long)p.coeffs[i]) << shift; - shift += 12; - if (shift >= 60) - { - shift = 0; - cIdx++; - } - } - } - - private LongPolynomial5(long[] coeffs, int numCoeffs) - { - this.coeffs = coeffs; - this.numCoeffs = numCoeffs; - } - - /** - * Multiplies the polynomial with a <code>TernaryPolynomial</code>, taking the indices mod N and the values mod 2048. - */ - public LongPolynomial5 mult(TernaryPolynomial poly2) - { - long[][] prod = new long[5][coeffs.length + (poly2.size() + 4) / 5 - 1]; // intermediate results, the subarrays are shifted by 0,...,4 coefficients - - // multiply ones - int[] ones = poly2.getOnes(); - for (int idx = 0; idx != ones.length; idx++) - { - int pIdx = ones[idx]; - int cIdx = pIdx / 5; - int m = pIdx - cIdx * 5; // m = pIdx % 5 - for (int i = 0; i < coeffs.length; i++) - { - prod[m][cIdx] = (prod[m][cIdx] + coeffs[i]) & 0x7FF7FF7FF7FF7FFL; - cIdx++; - } - } - - // multiply negative ones - int[] negOnes = poly2.getNegOnes(); - for (int idx = 0; idx != negOnes.length; idx++) - { - int pIdx = negOnes[idx]; - int cIdx = pIdx / 5; - int m = pIdx - cIdx * 5; // m = pIdx % 5 - for (int i = 0; i < coeffs.length; i++) - { - prod[m][cIdx] = (0x800800800800800L + prod[m][cIdx] - coeffs[i]) & 0x7FF7FF7FF7FF7FFL; - cIdx++; - } - } - - // combine shifted coefficients (5 arrays) into a single array of length prod[*].length+1 - long[] cCoeffs = Arrays.copyOf(prod[0], prod[0].length + 1); - for (int m = 1; m <= 4; m++) - { - int shift = m * 12; - int shift60 = 60 - shift; - long mask = (1L << shift60) - 1; - int pLen = prod[m].length; - for (int i = 0; i < pLen; i++) - { - long upper, lower; - upper = prod[m][i] >> shift60; - lower = prod[m][i] & mask; - - cCoeffs[i] = (cCoeffs[i] + (lower << shift)) & 0x7FF7FF7FF7FF7FFL; - int nextIdx = i + 1; - cCoeffs[nextIdx] = (cCoeffs[nextIdx] + upper) & 0x7FF7FF7FF7FF7FFL; - } - } - - // reduce indices of cCoeffs modulo numCoeffs - int shift = 12 * (numCoeffs % 5); - for (int cIdx = coeffs.length - 1; cIdx < cCoeffs.length; cIdx++) - { - long iCoeff; // coefficient to shift into the [0..numCoeffs-1] range - int newIdx; - if (cIdx == coeffs.length - 1) - { - iCoeff = numCoeffs == 5 ? 0 : cCoeffs[cIdx] >> shift; - newIdx = 0; - } - else - { - iCoeff = cCoeffs[cIdx]; - newIdx = cIdx * 5 - numCoeffs; - } - - int base = newIdx / 5; - int m = newIdx - base * 5; // m = newIdx % 5 - long lower = iCoeff << (12 * m); - long upper = iCoeff >> (12 * (5 - m)); - cCoeffs[base] = (cCoeffs[base] + lower) & 0x7FF7FF7FF7FF7FFL; - int base1 = base + 1; - if (base1 < coeffs.length) - { - cCoeffs[base1] = (cCoeffs[base1] + upper) & 0x7FF7FF7FF7FF7FFL; - } - } - - return new LongPolynomial5(cCoeffs, numCoeffs); - } - - public IntegerPolynomial toIntegerPolynomial() - { - int[] intCoeffs = new int[numCoeffs]; - int cIdx = 0; - int shift = 0; - for (int i = 0; i < numCoeffs; i++) - { - intCoeffs[i] = (int)((coeffs[cIdx] >> shift) & 2047); - shift += 12; - if (shift >= 60) - { - shift = 0; - cIdx++; - } - } - return new IntegerPolynomial(intCoeffs); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/ModularResultant.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/ModularResultant.java deleted file mode 100644 index 5f77192d..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/ModularResultant.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.polynomial; - -import java.math.BigInteger; - -import org.bouncycastle.pqc.math.ntru.euclid.BigIntEuclidean; - -/** - * A resultant modulo a <code>BigInteger</code> - */ -public class ModularResultant - extends Resultant -{ - BigInteger modulus; - - ModularResultant(BigIntPolynomial rho, BigInteger res, BigInteger modulus) - { - super(rho, res); - this.modulus = modulus; - } - - /** - * Calculates a <code>rho</code> modulo <code>m1*m2</code> from - * two resultants whose <code>rho</code>s are modulo <code>m1</code> and <code>m2</code>.<br/> - * </code>res</code> is set to <code>null</code>. - * - * @param modRes1 - * @param modRes2 - * @return <code>rho</code> modulo <code>modRes1.modulus * modRes2.modulus</code>, and <code>null</code> for </code>res</code>. - */ - static ModularResultant combineRho(ModularResultant modRes1, ModularResultant modRes2) - { - BigInteger mod1 = modRes1.modulus; - BigInteger mod2 = modRes2.modulus; - BigInteger prod = mod1.multiply(mod2); - BigIntEuclidean er = BigIntEuclidean.calculate(mod2, mod1); - - BigIntPolynomial rho1 = (BigIntPolynomial)modRes1.rho.clone(); - rho1.mult(er.x.multiply(mod2)); - BigIntPolynomial rho2 = (BigIntPolynomial)modRes2.rho.clone(); - rho2.mult(er.y.multiply(mod1)); - rho1.add(rho2); - rho1.mod(prod); - - return new ModularResultant(rho1, null, prod); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/Polynomial.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/Polynomial.java deleted file mode 100644 index 69193e39..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/Polynomial.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.polynomial; - -public interface Polynomial -{ - - /** - * Multiplies the polynomial by an <code>IntegerPolynomial</code>, - * taking the indices mod <code>N</code>. - * - * @param poly2 a polynomial - * @return the product of the two polynomials - */ - IntegerPolynomial mult(IntegerPolynomial poly2); - - /** - * Multiplies the polynomial by an <code>IntegerPolynomial</code>, - * taking the coefficient values mod <code>modulus</code> and the indices mod <code>N</code>. - * - * @param poly2 a polynomial - * @param modulus a modulus to apply - * @return the product of the two polynomials - */ - IntegerPolynomial mult(IntegerPolynomial poly2, int modulus); - - /** - * Returns a polynomial that is equal to this polynomial (in the sense that {@link #mult(IntegerPolynomial, int)} - * returns equal <code>IntegerPolynomial</code>s). The new polynomial is guaranteed to be independent of the original. - * - * @return a new <code>IntegerPolynomial</code>. - */ - IntegerPolynomial toIntegerPolynomial(); - - /** - * Multiplies the polynomial by a <code>BigIntPolynomial</code>, taking the indices mod N. Does not - * change this polynomial but returns the result as a new polynomial.<br> - * Both polynomials must have the same number of coefficients. - * - * @param poly2 the polynomial to multiply by - * @return a new polynomial - */ - BigIntPolynomial mult(BigIntPolynomial poly2); -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/ProductFormPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/ProductFormPolynomial.java deleted file mode 100644 index dd18902e..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/ProductFormPolynomial.java +++ /dev/null @@ -1,153 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.polynomial; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.security.SecureRandom; - -import org.bouncycastle.util.Arrays; - -/** - * A polynomial of the form <code>f1*f2+f3</code>, where - * <code>f1,f2,f3</code> are very sparsely populated ternary polynomials. - */ -public class ProductFormPolynomial - implements Polynomial -{ - private SparseTernaryPolynomial f1, f2, f3; - - public ProductFormPolynomial(SparseTernaryPolynomial f1, SparseTernaryPolynomial f2, SparseTernaryPolynomial f3) - { - this.f1 = f1; - this.f2 = f2; - this.f3 = f3; - } - - public static ProductFormPolynomial generateRandom(int N, int df1, int df2, int df3Ones, int df3NegOnes, SecureRandom random) - { - SparseTernaryPolynomial f1 = SparseTernaryPolynomial.generateRandom(N, df1, df1, random); - SparseTernaryPolynomial f2 = SparseTernaryPolynomial.generateRandom(N, df2, df2, random); - SparseTernaryPolynomial f3 = SparseTernaryPolynomial.generateRandom(N, df3Ones, df3NegOnes, random); - return new ProductFormPolynomial(f1, f2, f3); - } - - public static ProductFormPolynomial fromBinary(byte[] data, int N, int df1, int df2, int df3Ones, int df3NegOnes) - throws IOException - { - return fromBinary(new ByteArrayInputStream(data), N, df1, df2, df3Ones, df3NegOnes); - } - - public static ProductFormPolynomial fromBinary(InputStream is, int N, int df1, int df2, int df3Ones, int df3NegOnes) - throws IOException - { - SparseTernaryPolynomial f1; - - f1 = SparseTernaryPolynomial.fromBinary(is, N, df1, df1); - SparseTernaryPolynomial f2 = SparseTernaryPolynomial.fromBinary(is, N, df2, df2); - SparseTernaryPolynomial f3 = SparseTernaryPolynomial.fromBinary(is, N, df3Ones, df3NegOnes); - return new ProductFormPolynomial(f1, f2, f3); - } - - public byte[] toBinary() - { - byte[] f1Bin = f1.toBinary(); - byte[] f2Bin = f2.toBinary(); - byte[] f3Bin = f3.toBinary(); - - byte[] all = Arrays.copyOf(f1Bin, f1Bin.length + f2Bin.length + f3Bin.length); - System.arraycopy(f2Bin, 0, all, f1Bin.length, f2Bin.length); - System.arraycopy(f3Bin, 0, all, f1Bin.length + f2Bin.length, f3Bin.length); - return all; - } - - public IntegerPolynomial mult(IntegerPolynomial b) - { - IntegerPolynomial c = f1.mult(b); - c = f2.mult(c); - c.add(f3.mult(b)); - return c; - } - - public BigIntPolynomial mult(BigIntPolynomial b) - { - BigIntPolynomial c = f1.mult(b); - c = f2.mult(c); - c.add(f3.mult(b)); - return c; - } - - public IntegerPolynomial toIntegerPolynomial() - { - IntegerPolynomial i = f1.mult(f2.toIntegerPolynomial()); - i.add(f3.toIntegerPolynomial()); - return i; - } - - public IntegerPolynomial mult(IntegerPolynomial poly2, int modulus) - { - IntegerPolynomial c = mult(poly2); - c.mod(modulus); - return c; - } - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + ((f1 == null) ? 0 : f1.hashCode()); - result = prime * result + ((f2 == null) ? 0 : f2.hashCode()); - result = prime * result + ((f3 == null) ? 0 : f3.hashCode()); - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - ProductFormPolynomial other = (ProductFormPolynomial)obj; - if (f1 == null) - { - if (other.f1 != null) - { - return false; - } - } - else if (!f1.equals(other.f1)) - { - return false; - } - if (f2 == null) - { - if (other.f2 != null) - { - return false; - } - } - else if (!f2.equals(other.f2)) - { - return false; - } - if (f3 == null) - { - if (other.f3 != null) - { - return false; - } - } - else if (!f3.equals(other.f3)) - { - return false; - } - return true; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/Resultant.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/Resultant.java deleted file mode 100644 index ec585779..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/Resultant.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.polynomial; - -import java.math.BigInteger; - -/** - * Contains a resultant and a polynomial <code>rho</code> such that - * <code>res = rho*this + t*(x^n-1) for some integer t</code>. - * - * @see IntegerPolynomial#resultant() - * @see IntegerPolynomial#resultant(int) - */ -public class Resultant -{ - /** - * A polynomial such that <code>res = rho*this + t*(x^n-1) for some integer t</code> - */ - public BigIntPolynomial rho; - /** - * Resultant of a polynomial with <code>x^n-1</code> - */ - public BigInteger res; - - Resultant(BigIntPolynomial rho, BigInteger res) - { - this.rho = rho; - this.res = res; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/SparseTernaryPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/SparseTernaryPolynomial.java deleted file mode 100644 index 3c913397..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/SparseTernaryPolynomial.java +++ /dev/null @@ -1,320 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.polynomial; - -import java.io.IOException; -import java.io.InputStream; -import java.math.BigInteger; -import java.security.SecureRandom; - -import org.bouncycastle.pqc.math.ntru.util.ArrayEncoder; -import org.bouncycastle.pqc.math.ntru.util.Util; -import org.bouncycastle.util.Arrays; - -/** - * A <code>TernaryPolynomial</code> with a "low" number of nonzero coefficients. - */ -public class SparseTernaryPolynomial - implements TernaryPolynomial -{ - /** - * Number of bits to use for each coefficient. Determines the upper bound for <code>N</code>. - */ - private static final int BITS_PER_INDEX = 11; - - private int N; - private int[] ones; - private int[] negOnes; - - /** - * Constructs a new polynomial. - * - * @param N total number of coefficients including zeros - * @param ones indices of coefficients equal to 1 - * @param negOnes indices of coefficients equal to -1 - */ - SparseTernaryPolynomial(int N, int[] ones, int[] negOnes) - { - this.N = N; - this.ones = ones; - this.negOnes = negOnes; - } - - /** - * Constructs a <code>DenseTernaryPolynomial</code> from a <code>IntegerPolynomial</code>. The two polynomials are - * independent of each other. - * - * @param intPoly the original polynomial - */ - public SparseTernaryPolynomial(IntegerPolynomial intPoly) - { - this(intPoly.coeffs); - } - - /** - * Constructs a new <code>SparseTernaryPolynomial</code> with a given set of coefficients. - * - * @param coeffs the coefficients - */ - public SparseTernaryPolynomial(int[] coeffs) - { - N = coeffs.length; - ones = new int[N]; - negOnes = new int[N]; - int onesIdx = 0; - int negOnesIdx = 0; - for (int i = 0; i < N; i++) - { - int c = coeffs[i]; - switch (c) - { - case 1: - ones[onesIdx++] = i; - break; - case -1: - negOnes[negOnesIdx++] = i; - break; - case 0: - break; - default: - throw new IllegalArgumentException("Illegal value: " + c + ", must be one of {-1, 0, 1}"); - } - } - ones = Arrays.copyOf(ones, onesIdx); - negOnes = Arrays.copyOf(negOnes, negOnesIdx); - } - - /** - * Decodes a byte array encoded with {@link #toBinary()} to a ploynomial. - * - * @param is an input stream containing an encoded polynomial - * @param N number of coefficients including zeros - * @param numOnes number of coefficients equal to 1 - * @param numNegOnes number of coefficients equal to -1 - * @return the decoded polynomial - * @throws IOException - */ - public static SparseTernaryPolynomial fromBinary(InputStream is, int N, int numOnes, int numNegOnes) - throws IOException - { - int maxIndex = 1 << BITS_PER_INDEX; - int bitsPerIndex = 32 - Integer.numberOfLeadingZeros(maxIndex - 1); - - int data1Len = (numOnes * bitsPerIndex + 7) / 8; - byte[] data1 = Util.readFullLength(is, data1Len); - int[] ones = ArrayEncoder.decodeModQ(data1, numOnes, maxIndex); - - int data2Len = (numNegOnes * bitsPerIndex + 7) / 8; - byte[] data2 = Util.readFullLength(is, data2Len); - int[] negOnes = ArrayEncoder.decodeModQ(data2, numNegOnes, maxIndex); - - return new SparseTernaryPolynomial(N, ones, negOnes); - } - - /** - * Generates a random polynomial with <code>numOnes</code> coefficients equal to 1, - * <code>numNegOnes</code> coefficients equal to -1, and the rest equal to 0. - * - * @param N number of coefficients - * @param numOnes number of 1's - * @param numNegOnes number of -1's - */ - public static SparseTernaryPolynomial generateRandom(int N, int numOnes, int numNegOnes, SecureRandom random) - { - int[] coeffs = Util.generateRandomTernary(N, numOnes, numNegOnes, random); - return new SparseTernaryPolynomial(coeffs); - } - - public IntegerPolynomial mult(IntegerPolynomial poly2) - { - int[] b = poly2.coeffs; - if (b.length != N) - { - throw new IllegalArgumentException("Number of coefficients must be the same"); - } - - int[] c = new int[N]; - for (int idx = 0; idx != ones.length; idx++) - { - int i = ones[idx]; - int j = N - 1 - i; - for (int k = N - 1; k >= 0; k--) - { - c[k] += b[j]; - j--; - if (j < 0) - { - j = N - 1; - } - } - } - - for (int idx = 0; idx != negOnes.length; idx++) - { - int i = negOnes[idx]; - int j = N - 1 - i; - for (int k = N - 1; k >= 0; k--) - { - c[k] -= b[j]; - j--; - if (j < 0) - { - j = N - 1; - } - } - } - - return new IntegerPolynomial(c); - } - - public IntegerPolynomial mult(IntegerPolynomial poly2, int modulus) - { - IntegerPolynomial c = mult(poly2); - c.mod(modulus); - return c; - } - - public BigIntPolynomial mult(BigIntPolynomial poly2) - { - BigInteger[] b = poly2.coeffs; - if (b.length != N) - { - throw new IllegalArgumentException("Number of coefficients must be the same"); - } - - BigInteger[] c = new BigInteger[N]; - for (int i = 0; i < N; i++) - { - c[i] = BigInteger.ZERO; - } - - for (int idx = 0; idx != ones.length; idx++) - { - int i = ones[idx]; - int j = N - 1 - i; - for (int k = N - 1; k >= 0; k--) - { - c[k] = c[k].add(b[j]); - j--; - if (j < 0) - { - j = N - 1; - } - } - } - - for (int idx = 0; idx != negOnes.length; idx++) - { - int i = negOnes[idx]; - int j = N - 1 - i; - for (int k = N - 1; k >= 0; k--) - { - c[k] = c[k].subtract(b[j]); - j--; - if (j < 0) - { - j = N - 1; - } - } - } - - return new BigIntPolynomial(c); - } - - public int[] getOnes() - { - return ones; - } - - public int[] getNegOnes() - { - return negOnes; - } - - /** - * Encodes the polynomial to a byte array writing <code>BITS_PER_INDEX</code> bits for each coefficient. - * - * @return the encoded polynomial - */ - public byte[] toBinary() - { - int maxIndex = 1 << BITS_PER_INDEX; - byte[] bin1 = ArrayEncoder.encodeModQ(ones, maxIndex); - byte[] bin2 = ArrayEncoder.encodeModQ(negOnes, maxIndex); - - byte[] bin = Arrays.copyOf(bin1, bin1.length + bin2.length); - System.arraycopy(bin2, 0, bin, bin1.length, bin2.length); - return bin; - } - - public IntegerPolynomial toIntegerPolynomial() - { - int[] coeffs = new int[N]; - for (int idx = 0; idx != ones.length; idx++) - { - int i = ones[idx]; - coeffs[i] = 1; - } - for (int idx = 0; idx != negOnes.length; idx++) - { - int i = negOnes[idx]; - coeffs[i] = -1; - } - return new IntegerPolynomial(coeffs); - } - - public int size() - { - return N; - } - - public void clear() - { - for (int i = 0; i < ones.length; i++) - { - ones[i] = 0; - } - for (int i = 0; i < negOnes.length; i++) - { - negOnes[i] = 0; - } - } - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + N; - result = prime * result + Arrays.hashCode(negOnes); - result = prime * result + Arrays.hashCode(ones); - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - SparseTernaryPolynomial other = (SparseTernaryPolynomial)obj; - if (N != other.N) - { - return false; - } - if (!Arrays.areEqual(negOnes, other.negOnes)) - { - return false; - } - if (!Arrays.areEqual(ones, other.ones)) - { - return false; - } - return true; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/TernaryPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/TernaryPolynomial.java deleted file mode 100644 index 822b64b4..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/polynomial/TernaryPolynomial.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.polynomial; - -/** - * A polynomial whose coefficients are all equal to -1, 0, or 1 - */ -public interface TernaryPolynomial - extends Polynomial -{ - - /** - * Multiplies the polynomial by an <code>IntegerPolynomial</code>, taking the indices mod N - */ - IntegerPolynomial mult(IntegerPolynomial poly2); - - int[] getOnes(); - - int[] getNegOnes(); - - /** - * Returns the maximum number of coefficients the polynomial can have - */ - int size(); - - void clear(); -} diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/util/ArrayEncoder.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/util/ArrayEncoder.java deleted file mode 100644 index a437d48a..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/util/ArrayEncoder.java +++ /dev/null @@ -1,292 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.util; - -import java.io.IOException; -import java.io.InputStream; -import java.math.BigInteger; - -import org.bouncycastle.util.Arrays; - -/** - * Converts a coefficient array to a compact byte array and vice versa. - */ -public class ArrayEncoder -{ - /** - * Bit string to coefficient conversion table from P1363.1. Also found at - * {@link http://stackoverflow.com/questions/1562548/how-to-make-a-message-into-a-polynomial} - * <p/> - * Convert each three-bit quantity to two ternary coefficients as follows, and concatenate the resulting - * ternary quantities to obtain [the output]. - * <p/> - * <code> - * {0, 0, 0} -> {0, 0}<br/> - * {0, 0, 1} -> {0, 1}<br/> - * {0, 1, 0} -> {0, -1}<br/> - * {0, 1, 1} -> {1, 0}<br/> - * {1, 0, 0} -> {1, 1}<br/> - * {1, 0, 1} -> {1, -1}<br/> - * {1, 1, 0} -> {-1, 0}<br/> - * {1, 1, 1} -> {-1, 1}<br/> - * </code> - */ - private static final int[] COEFF1_TABLE = {0, 0, 0, 1, 1, 1, -1, -1}; - private static final int[] COEFF2_TABLE = {0, 1, -1, 0, 1, -1, 0, 1}; - /** - * Coefficient to bit string conversion table from P1363.1. Also found at - * {@link http://stackoverflow.com/questions/1562548/how-to-make-a-message-into-a-polynomial} - * <p/> - * Convert each set of two ternary coefficients to three bits as follows, and concatenate the resulting bit - * quantities to obtain [the output]: - * <p/> - * <code> - * {-1, -1} -> set "fail" to 1 and set bit string to {1, 1, 1} - * {-1, 0} -> {1, 1, 0}<br/> - * {-1, 1} -> {1, 1, 1}<br/> - * {0, -1} -> {0, 1, 0}<br/> - * {0, 0} -> {0, 0, 0}<br/> - * {0, 1} -> {0, 0, 1}<br/> - * {1, -1} -> {1, 0, 1}<br/> - * {1, 0} -> {0, 1, 1}<br/> - * {1, 1} -> {1, 0, 0}<br/> - * </code> - */ - private static final int[] BIT1_TABLE = {1, 1, 1, 0, 0, 0, 1, 0, 1}; - private static final int[] BIT2_TABLE = {1, 1, 1, 1, 0, 0, 0, 1, 0}; - private static final int[] BIT3_TABLE = {1, 0, 1, 0, 0, 1, 1, 1, 0}; - - /** - * Encodes an int array whose elements are between 0 and <code>q</code>, - * to a byte array leaving no gaps between bits.<br> - * <code>q</code> must be a power of 2. - * - * @param a the input array - * @param q the modulus - * @return the encoded array - */ - public static byte[] encodeModQ(int[] a, int q) - { - int bitsPerCoeff = 31 - Integer.numberOfLeadingZeros(q); - int numBits = a.length * bitsPerCoeff; - int numBytes = (numBits + 7) / 8; - byte[] data = new byte[numBytes]; - int bitIndex = 0; - int byteIndex = 0; - for (int i = 0; i < a.length; i++) - { - for (int j = 0; j < bitsPerCoeff; j++) - { - int currentBit = (a[i] >> j) & 1; - data[byteIndex] |= currentBit << bitIndex; - if (bitIndex == 7) - { - bitIndex = 0; - byteIndex++; - } - else - { - bitIndex++; - } - } - } - return data; - } - - /** - * Decodes a <code>byte</code> array encoded with {@link #encodeModQ(int[], int)} back to an <code>int</code> array.<br> - * <code>N</code> is the number of coefficients. <code>q</code> must be a power of <code>2</code>.<br> - * Ignores any excess bytes. - * - * @param data an encoded ternary polynomial - * @param N number of coefficients - * @param q - * @return an array containing <code>N</code> coefficients between <code>0</code> and <code>q-1</code> - */ - public static int[] decodeModQ(byte[] data, int N, int q) - { - int[] coeffs = new int[N]; - int bitsPerCoeff = 31 - Integer.numberOfLeadingZeros(q); - int numBits = N * bitsPerCoeff; - int coeffIndex = 0; - for (int bitIndex = 0; bitIndex < numBits; bitIndex++) - { - if (bitIndex > 0 && bitIndex % bitsPerCoeff == 0) - { - coeffIndex++; - } - int bit = getBit(data, bitIndex); - coeffs[coeffIndex] += bit << (bitIndex % bitsPerCoeff); - } - return coeffs; - } - - /** - * Decodes data encoded with {@link #encodeModQ(int[], int)} back to an <code>int</code> array.<br> - * <code>N</code> is the number of coefficients. <code>q</code> must be a power of <code>2</code>.<br> - * Ignores any excess bytes. - * - * @param is an encoded ternary polynomial - * @param N number of coefficients - * @param q - * @return the decoded polynomial - */ - public static int[] decodeModQ(InputStream is, int N, int q) - throws IOException - { - int qBits = 31 - Integer.numberOfLeadingZeros(q); - int size = (N * qBits + 7) / 8; - byte[] arr = Util.readFullLength(is, size); - return decodeModQ(arr, N, q); - } - - /** - * Decodes a <code>byte</code> array encoded with {@link #encodeMod3Sves(int[])} back to an <code>int</code> array - * with <code>N</code> coefficients between <code>-1</code> and <code>1</code>.<br> - * Ignores any excess bytes.<br> - * See P1363.1 section 9.2.2. - * - * @param data an encoded ternary polynomial - * @param N number of coefficients - * @return the decoded coefficients - */ - public static int[] decodeMod3Sves(byte[] data, int N) - { - int[] coeffs = new int[N]; - int coeffIndex = 0; - for (int bitIndex = 0; bitIndex < data.length * 8; ) - { - int bit1 = getBit(data, bitIndex++); - int bit2 = getBit(data, bitIndex++); - int bit3 = getBit(data, bitIndex++); - int coeffTableIndex = bit1 * 4 + bit2 * 2 + bit3; - coeffs[coeffIndex++] = COEFF1_TABLE[coeffTableIndex]; - coeffs[coeffIndex++] = COEFF2_TABLE[coeffTableIndex]; - // ignore bytes that can't fit - if (coeffIndex > N - 2) - { - break; - } - } - return coeffs; - } - - /** - * Encodes an <code>int</code> array whose elements are between <code>-1</code> and <code>1</code>, to a byte array. - * <code>coeffs[2*i]</code> and <code>coeffs[2*i+1]</code> must not both equal -1 for any integer <code>i</code>, - * so this method is only safe to use with arrays produced by {@link #decodeMod3Sves(byte[], int)}.<br> - * See P1363.1 section 9.2.3. - * - * @param arr - * @return the encoded array - */ - public static byte[] encodeMod3Sves(int[] arr) - { - int numBits = (arr.length * 3 + 1) / 2; - int numBytes = (numBits + 7) / 8; - byte[] data = new byte[numBytes]; - int bitIndex = 0; - int byteIndex = 0; - for (int i = 0; i < arr.length / 2 * 2; ) - { // if length is an odd number, throw away the highest coeff - int coeff1 = arr[i++] + 1; - int coeff2 = arr[i++] + 1; - if (coeff1 == 0 && coeff2 == 0) - { - throw new IllegalStateException("Illegal encoding!"); - } - int bitTableIndex = coeff1 * 3 + coeff2; - int[] bits = new int[]{BIT1_TABLE[bitTableIndex], BIT2_TABLE[bitTableIndex], BIT3_TABLE[bitTableIndex]}; - for (int j = 0; j < 3; j++) - { - data[byteIndex] |= bits[j] << bitIndex; - if (bitIndex == 7) - { - bitIndex = 0; - byteIndex++; - } - else - { - bitIndex++; - } - } - } - return data; - } - - /** - * Encodes an <code>int</code> array whose elements are between <code>-1</code> and <code>1</code>, to a byte array. - * - * @return the encoded array - */ - public static byte[] encodeMod3Tight(int[] intArray) - { - BigInteger sum = BigInteger.ZERO; - for (int i = intArray.length - 1; i >= 0; i--) - { - sum = sum.multiply(BigInteger.valueOf(3)); - sum = sum.add(BigInteger.valueOf(intArray[i] + 1)); - } - - int size = (BigInteger.valueOf(3).pow(intArray.length).bitLength() + 7) / 8; - byte[] arr = sum.toByteArray(); - - if (arr.length < size) - { - // pad with leading zeros so arr.length==size - byte[] arr2 = new byte[size]; - System.arraycopy(arr, 0, arr2, size - arr.length, arr.length); - return arr2; - } - - if (arr.length > size) - // drop sign bit - { - arr = Arrays.copyOfRange(arr, 1, arr.length); - } - return arr; - } - - /** - * Converts a byte array produced by {@link #encodeMod3Tight(int[])} back to an <code>int</code> array. - * - * @param b a byte array - * @param N number of coefficients - * @return the decoded array - */ - public static int[] decodeMod3Tight(byte[] b, int N) - { - BigInteger sum = new BigInteger(1, b); - int[] coeffs = new int[N]; - for (int i = 0; i < N; i++) - { - coeffs[i] = sum.mod(BigInteger.valueOf(3)).intValue() - 1; - if (coeffs[i] > 1) - { - coeffs[i] -= 3; - } - sum = sum.divide(BigInteger.valueOf(3)); - } - return coeffs; - } - - /** - * Converts data produced by {@link #encodeMod3Tight(int[])} back to an <code>int</code> array. - * - * @param is an input stream containing the data to decode - * @param N number of coefficients - * @return the decoded array - */ - public static int[] decodeMod3Tight(InputStream is, int N) - throws IOException - { - int size = (int)Math.ceil(N * Math.log(3) / Math.log(2) / 8); - byte[] arr = Util.readFullLength(is, size); - return decodeMod3Tight(arr, N); - } - - private static int getBit(byte[] arr, int bitIndex) - { - int byteIndex = bitIndex / 8; - int arrElem = arr[byteIndex] & 0xFF; - return (arrElem >> (bitIndex % 8)) & 1; - } -}
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/util/Util.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/util/Util.java deleted file mode 100644 index 92c2ed4d..00000000 --- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/util/Util.java +++ /dev/null @@ -1,158 +0,0 @@ -package org.bouncycastle.pqc.math.ntru.util; - -import java.io.IOException; -import java.io.InputStream; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.bouncycastle.pqc.math.ntru.euclid.IntEuclidean; -import org.bouncycastle.pqc.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.SparseTernaryPolynomial; -import org.bouncycastle.pqc.math.ntru.polynomial.TernaryPolynomial; -import org.bouncycastle.util.Integers; - -public class Util -{ - private static volatile boolean IS_64_BITNESS_KNOWN; - private static volatile boolean IS_64_BIT_JVM; - - /** - * Calculates the inverse of n mod modulus - */ - public static int invert(int n, int modulus) - { - n %= modulus; - if (n < 0) - { - n += modulus; - } - return IntEuclidean.calculate(n, modulus).x; - } - - /** - * Calculates a^b mod modulus - */ - public static int pow(int a, int b, int modulus) - { - int p = 1; - for (int i = 0; i < b; i++) - { - p = (p * a) % modulus; - } - return p; - } - - /** - * Calculates a^b mod modulus - */ - public static long pow(long a, int b, long modulus) - { - long p = 1; - for (int i = 0; i < b; i++) - { - p = (p * a) % modulus; - } - return p; - } - - /** - * Generates a "sparse" or "dense" polynomial containing numOnes ints equal to 1, - * numNegOnes int equal to -1, and the rest equal to 0. - * - * @param N - * @param numOnes - * @param numNegOnes - * @param sparse whether to create a {@link SparseTernaryPolynomial} or {@link DenseTernaryPolynomial} - * @return a ternary polynomial - */ - public static TernaryPolynomial generateRandomTernary(int N, int numOnes, int numNegOnes, boolean sparse, SecureRandom random) - { - if (sparse) - { - return SparseTernaryPolynomial.generateRandom(N, numOnes, numNegOnes, random); - } - else - { - return DenseTernaryPolynomial.generateRandom(N, numOnes, numNegOnes, random); - } - } - - /** - * Generates an array containing numOnes ints equal to 1, - * numNegOnes int equal to -1, and the rest equal to 0. - * - * @param N - * @param numOnes - * @param numNegOnes - * @return an array of integers - */ - public static int[] generateRandomTernary(int N, int numOnes, int numNegOnes, SecureRandom random) - { - Integer one = Integers.valueOf(1); - Integer minusOne = Integers.valueOf(-1); - Integer zero = Integers.valueOf(0); - - List list = new ArrayList(); - for (int i = 0; i < numOnes; i++) - { - list.add(one); - } - for (int i = 0; i < numNegOnes; i++) - { - list.add(minusOne); - } - while (list.size() < N) - { - list.add(zero); - } - - Collections.shuffle(list, random); - - int[] arr = new int[N]; - for (int i = 0; i < N; i++) - { - arr[i] = ((Integer)list.get(i)).intValue(); - } - return arr; - } - - /** - * Takes an educated guess as to whether 64 bits are supported by the JVM. - * - * @return <code>true</code> if 64-bit support detected, <code>false</code> otherwise - */ - public static boolean is64BitJVM() - { - if (!IS_64_BITNESS_KNOWN) - { - String arch = System.getProperty("os.arch"); - String sunModel = System.getProperty("sun.arch.data.model"); - IS_64_BIT_JVM = "amd64".equals(arch) || "x86_64".equals(arch) || "ppc64".equals(arch) || "64".equals(sunModel); - IS_64_BITNESS_KNOWN = true; - } - return IS_64_BIT_JVM; - } - - /** - * Reads a given number of bytes from an <code>InputStream</code>. - * If there are not enough bytes in the stream, an <code>IOException</code> - * is thrown. - * - * @param is - * @param length - * @return an array of length <code>length</code> - * @throws IOException - */ - public static byte[] readFullLength(InputStream is, int length) - throws IOException - { - byte[] arr = new byte[length]; - if (is.read(arr) != arr.length) - { - throw new IOException("Not enough bytes to read."); - } - return arr; - } -}
\ No newline at end of file |