ciphertext.length, expectedCTLength);
boolean fail = false;
// Unpack ciphertext into the polynomial e.
FullPolynomial e = new FullPolynomial(keyParams.N);
int numUnpacked = BitPack.unpack(
keyParams.N, keyParams.q, ciphertext, 0, e.p, 0);
if (numUnpacked != ciphertext.length)
throw new CiphertextBadLengthException(
ciphertext.length, BitPack.pack(keyParams.N, keyParams.q));
// a = f*e with coefficients reduced to range [A..A+q-1], where
// A = lower bound decryption coefficient (-q/2 in all param sets)
FullPolynomial ci = FullPolynomial.convolution(f, e, keyParams.q);
for (int i=0; i<ci.p.length; i++)
if (ci.p[i] >= keyParams.q/2)
ci.p[i] -= keyParams.q;
// Calculate ci = message candidate = a mod p in [-1,0,1]
for (int i=0; i<keyParams.N; i++)
{
ci.p[i] = (byte) (ci.p[i] % keyParams.p);
if (ci.p[i] == 2)
ci.p[i] = -1;
else if (ci.p[i] == -2)
ci.p[i] = 1;
}
// Count the number of 1's, -1's, and 0's in ci. Fail if any
// count is less than dm0.
if (!check_dm0(ci, keyParams.dm0))
fail = true;
// Calculate the candidate for r*h: cR = e - ci;
FullPolynomial cR = FullPolynomial.subtract(e, ci, keyParams.q);
// Calculate cR4 = cR mod 4
// Generate masking polynomial mask by calling the given MGF with
// inputs (cR4, N, minCallsMask
FullPolynomial mask = calcEncryptionMask(cR);
// Form cMtrin by polynomial subtraction of cm' and mask mod p
// Note: cm' is actually called ci everywhere else in the spec.
FullPolynomial cMtrin =
FullPolynomial.subtractAndRecenter(ci, mask, keyParams.p, -1);
// Convert cMtrin to cMbin. Discard trailing bits
byte cM[] = convPolyTrinaryToBinary(cMtrin);
// Parse cMbin as b || l || m || p0. Fail if does not match.
int mOffset = (keyParams.db)/8 + keyParams.lLen;
int mLen = verifyMFormat(cM);
if (mLen < 0)
{
// Set mLen to 1 so that later steps won't have to deal
// with an invalid value.
mLen = 1;
fail = true;
}
// Form sData from OID, m, b, hTrunc
// Note: b is the leading bytes of cM.
byte sData[] = form_sData(cM, mOffset, mLen, cM, 0);
// Calc cr from sData
IGF2 igf = new IGF2(
keyParams.N, keyParams.c, keyParams.igfHash, keyParams.minCallsR,
sData, 0, sData.length);
FullPolynomial cr = BPGM3.genTrinomial(
keyParams.N, keyParams.dr, keyParams.dr, igf);
igf.close();
// Calculate cR' = h * cr mod q
FullPolynomial cRPrime = FullPolynomial.convolution(cr, h, keyParams.q);
// If cR != cR', fail
if (!cR.equals(cRPrime))
fail = true;
if (fail)