org.bouncycastle.pqc.legacy.crypto.mceliece.Conversions Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bcprov-ext-debug-jdk18on Show documentation
Show all versions of bcprov-ext-debug-jdk18on Show documentation
The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for Java 1.8 and later with debug enabled.
The newest version!
package org.bouncycastle.pqc.legacy.crypto.mceliece;
import java.math.BigInteger;
import org.bouncycastle.pqc.legacy.math.linearalgebra.BigIntUtils;
import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Vector;
import org.bouncycastle.pqc.legacy.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
* n bit and of hamming weight t. The result is a
* byte array of length (s+7)/8, where
* s = floor[log(n|t)].
*
* @param n integer
* @param t integer
* @param m the message vector as a byte array
* @return a message representative for m
*/
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;
}
}