Пример #1
0
        /// <summary>
        /// Returns the length of a message after encryption with this parameter set
        /// <para>The length does not depend on the input size.</para>
        /// </summary>
        ///
        /// <returns>The length in bytes</returns>
        public int GetOutputLength()
        {
            // ceil(log q)
            int logq = 32 - IntUtils.NumberOfLeadingZeros(Q - 1);

            return((N * logq + 7) / 8);
        }
Пример #2
0
        /// <summary>
        /// Like EncodeModQ(int[], int) but only returns the first <c>NumBytes</c> bytes of the encoding
        /// </summary>
        ///
        /// <param name="Data">The input array</param>
        /// <param name="Q">The modulus</param>
        /// <param name="NumBytes">The encoded array</param>
        ///
        /// <returns>Returns T</returns>
        public static byte[] EncodeModQTrunc(int[] Data, int Q, int NumBytes)
        {
            int bitsPerCoeff = 31 - IntUtils.NumberOfLeadingZeros(Q);

            byte[] data      = new byte[NumBytes];
            int    bitIndex  = 0;
            int    byteIndex = 0;

            for (int i = 0; i < Data.Length; i++)
            {
                for (int j = 0; j < bitsPerCoeff; j++)
                {
                    int currentBit = (Data[i] >> j) & 1;
                    data[byteIndex] |= (byte)(currentBit << bitIndex);

                    if (bitIndex == 7)
                    {
                        bitIndex = 0;
                        byteIndex++;

                        if (byteIndex >= NumBytes)
                        {
                            return(data);
                        }
                    }
                    else
                    {
                        bitIndex++;
                    }
                }
            }

            return(null);
        }
Пример #3
0
        /// <summary>
        /// Encodes an int array whose elements are between 0 and <c>Q</c>, to a byte array leaving no gaps between bits.
        /// <para><c>Q</c> must be a power of 2.</para>
        /// </summary>
        ///
        /// <param name="A">The input array</param>
        /// <param name="Q">The modulus</param>
        ///
        /// <returns>The encoded array</returns>
        public static byte[] EncodeModQ(int[] A, int Q)
        {
            int bitsPerCoeff = 31 - IntUtils.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] |= (byte)(currentBit << bitIndex);

                    if (bitIndex == 7)
                    {
                        bitIndex = 0;
                        byteIndex++;
                    }
                    else
                    {
                        bitIndex++;
                    }
                }
            }

            return(data);
        }
Пример #4
0
        /// <summary>
        /// Decodes a <c>byte</c> array encoded with EncodeModQ(int[], int)} back to an <c>int</c> array.
        /// <para><c>N</c> is the number of coefficients. <c>Q</c> must be a power of <c>2</c>.
        /// Ignores any excess bytes.</para>
        /// </summary>
        ///
        /// <param name="Data">Data an encoded ternary polynomial</param>
        /// <param name="N">The number of coefficients</param>
        /// <param name="Q">The modulus</param>
        ///
        /// <returns>Returns an array containing <c>N</c> coefficients between <c>0</c> and <c>q-1</c></returns>
        public static int[] DecodeModQ(byte[] Data, int N, int Q)
        {
            int[] coeffs       = new int[N];
            int   bitsPerCoeff = 31 - IntUtils.NumberOfLeadingZeros(Q);
            int   mask         = IntUtils.URShift(-1, (32 - bitsPerCoeff)); // for truncating values to bitsPerCoeff bits
            int   byteIndex    = 0;
            int   bitIndex     = 0;                                         // next bit in data[byteIndex]
            int   coeffBuf     = 0;                                         // contains (bitIndex) bits
            int   coeffBits    = 0;                                         // length of coeffBuf
            int   coeffIndex   = 0;                                         // index into coeffs

            while (coeffIndex < N)
            {
                // copy bitsPerCoeff or more into coeffBuf
                while (coeffBits < bitsPerCoeff)
                {
                    coeffBuf  += (Data[byteIndex] & 0xFF) << coeffBits;
                    coeffBits += 8 - bitIndex;
                    byteIndex++;
                    bitIndex = 0;
                }

                // low bitsPerCoeff bits = next coefficient
                coeffs[coeffIndex] = coeffBuf & mask;
                coeffIndex++;
                coeffBuf   = IntUtils.URShift(coeffBuf, bitsPerCoeff);
                coeffBits -= bitsPerCoeff;
            }

            return(coeffs);
        }
Пример #5
0
        /// <summary>
        /// Performs val &lt;= count, val should have enough place (and one digit more)
        /// </summary>
        ///
        /// <param name="Value">The source BigIntger</param>
        /// <param name="N">Shift distance</param>
        internal static void InplaceShiftLeft(BigInteger Value, int N)
        {
            int intCount = N >> 5; // count of integers

            Value._numberLength += intCount + (IntUtils.NumberOfLeadingZeros(Value._digits[Value._numberLength - 1]) - (N & 31) >= 0 ? 0 : 1);
            ShiftLeft(Value._digits, Value._digits, intCount, N & 31);
            Value.CutOffLeadingZeroes();
            Value.UnCache();
        }
Пример #6
0
        /// <summary>
        /// Decodes data encoded with encodeModQ(int[], int) back to an <c>int</c> array.
        /// <para><c>N</c> is the number of coefficients. <c>q</c> must be a power of <c>2</c>.
        /// Ignores any excess bytes.</para>
        /// </summary>
        ///
        /// <param name="InputStream">An encoded ternary polynomial</param>
        /// <param name="N">The number of coefficients</param>
        /// <param name="Q">The modulus</param>
        ///
        /// <returns>The decoded polynomial</returns>
        public static int[] DecodeModQ(Stream InputStream, int N, int Q)
        {
            int qBits = 31 - IntUtils.NumberOfLeadingZeros(Q);
            int size  = (N * qBits + 7) / 8;

            byte[] arr = ArrayEncoder.ReadFullLength(InputStream, size);

            return(DecodeModQ(arr, N, Q));
        }
Пример #7
0
        /// <summary>
        /// Decodes a polynomial encoded with ToBinary()
        /// </summary>
        ///
        /// <param name="InputStream">An input stream containing an encoded polynomial</param>
        /// <param name="N">Number of coefficients in the polynomial</param>
        ///
        /// <returns>The decoded polynomial</returns>
        public static SparseTernaryPolynomial FromBinary(MemoryStream InputStream, int N)
        {
            BinaryReader br = new BinaryReader(InputStream);
            // number of coefficients equal to 1
            int numOnes = IntUtils.ReadShort(InputStream);
            // number of coefficients equal to -1
            int numNegOnes   = IntUtils.ReadShort(InputStream);
            int maxIndex     = 1 << BITS_PER_INDEX;
            int bitsPerIndex = 32 - IntUtils.NumberOfLeadingZeros(maxIndex - 1);

            int data1Len = (numOnes * bitsPerIndex + 7) / 8;

            byte[] data1 = ArrayEncoder.ReadFullLength(InputStream, data1Len);
            int[]  ones  = ArrayEncoder.DecodeModQ(data1, numOnes, maxIndex);

            int data2Len = (numNegOnes * bitsPerIndex + 7) / 8;

            byte[] data2   = ArrayEncoder.ReadFullLength(InputStream, data2Len);
            int[]  negOnes = ArrayEncoder.DecodeModQ(data2, numNegOnes, maxIndex);

            return(new SparseTernaryPolynomial(N, ones, negOnes));
        }
Пример #8
0
        /// <summary>
        /// Returns the length of the value's two's complement representation without
        /// leading zeros for positive numbers / without leading ones for negative values.
        /// <para>The two's complement representation of this will be at least BitLength() + 1 bits long.
        /// The value will fit into an int if <c>bitLength() &lt; 32</c> or into a long if <c>bitLength() &lt; 64</c>.</para>
        /// </summary>
        internal static int BitLength(BigInteger Value)
        {
            if (Value._sign == 0)
            {
                return(0);
            }

            int bLength   = (Value._numberLength << 5);
            int highDigit = Value._digits[Value._numberLength - 1];

            if (Value._sign < 0)
            {
                int i = Value.FirstNonzeroDigit;
                // We reduce the problem to the positive case.
                if (i == Value._numberLength - 1)
                {
                    highDigit--;
                }
            }
            // Subtracting all sign bits
            bLength -= IntUtils.NumberOfLeadingZeros(highDigit);
            return(bLength);
        }
Пример #9
0
        /// <remarks>
        /// <para>Schönhage-Strassen is used unless the numbers are in a range where
        /// <a href="http://en.wikipedia.org/wiki/Karatsuba_algorithm">Karatsuba</a> is more efficient.</para>
        /// The Schönhage-Strassen algorithm works as follows:
        /// Given numbers a and b, split both numbers into pieces of length 2^(n-1) bits.
        /// Take the low n+2 bits of each piece of a, zero-pad them to 3n+5 bits, and concatenate them to a new number u.
        /// Do the same for b to obtain v.
        /// Calculate all pieces of z' by multiplying u and v (using Schönhage-Strassen or another algorithm). The product will contain all pieces of a*b mod n+2.
        /// Pad the pieces of a and b from step 1 to 2^(n+1) bits.
        /// Perform a <a href="http://en.wikipedia.org/wiki/Discrete_Fourier_transform_%28general%29#Number-theoretic_transform">
        /// Discrete Fourier Transform</a> (DFT) on the padded pieces.
        /// Calculate all pieces of z" by multiplying the i-th piece of a by the i-th piece of b.
        /// Perform an Inverse Discrete Fourier Transform (IDFT) on z". z" will contain all pieces of a*b mod Fn where Fn=2^2^n+1.
        /// Calculate all pieces of z such that each piece is congruent to z' modulo n+2 and congruent to z" modulo Fn. This is done using the
        /// <a href="http://en.wikipedia.org/wiki/Chinese_remainder_theorem">Chinese remainder theorem</a>.
        /// Calculate c by adding z_i * 2^(i*2^(n-1)) for all i, where z_i is the i-th piece of z.
        /// Return c reduced modulo 2^2^m+1.
        /// </remarks>
        private static int[] Multiply(int[] A, int ABitLen, int[] B, int BBitLen)
        {
            if (!ShouldUseSchonhageStrassen(Math.Max(ABitLen, BBitLen)))
            {
                return(MultKaratsuba(A, B));
            }

            // set M to the number of binary digits in a or b, whichever is greater
            int M = Math.Max(ABitLen, BBitLen);
            // find the lowest m such that m>=log2(2M)
            int m = 32 - IntUtils.NumberOfLeadingZeros(2 * M - 1 - 1);
            int n = m / 2 + 1;
            // split a and b into pieces 1<<(n-1) bits long; assume n>=6 so pieces start and end at int boundaries
            bool even      = m % 2 == 0;
            int  numPieces = even ? 1 << n : 1 << (n + 1);
            int  pieceSize = 1 << (n - 1 - 5);  // in ints
            // build u and v from a and b, allocating 3n+5 bits in u and v per n+2 bits from a and b, resp.
            int numPiecesA = (A.Length + pieceSize) / pieceSize;

            int[] u          = new int[(numPiecesA * (3 * n + 5) + 31) / 32];
            int   uBitLength = 0;

            for (int i = 0; i < numPiecesA && i * pieceSize < A.Length; i++)
            {
                AppendBits(u, uBitLength, A, i * pieceSize, n + 2);
                uBitLength += 3 * n + 5;
            }

            int numPiecesB = (B.Length + pieceSize) / pieceSize;

            int[] v          = new int[(numPiecesB * (3 * n + 5) + 31) / 32];
            int   vBitLength = 0;

            for (int i = 0; i < numPiecesB && i * pieceSize < B.Length; i++)
            {
                AppendBits(v, vBitLength, B, i * pieceSize, n + 2);
                vBitLength += 3 * n + 5;
            }

            int[]   gamma      = Multiply(u, uBitLength, v, vBitLength);
            int[][] gammai     = SplitBits(gamma, 3 * n + 5);
            int     halfNumPcs = numPieces / 2;

            int[][] zi = new int[gammai.Length][];

            for (int i = 0; i < gammai.Length; i++)
            {
                zi[i] = gammai[i];
            }
            for (int i = 0; i < gammai.Length - halfNumPcs; i++)
            {
                SubModPow2(zi[i], gammai[i + halfNumPcs], n + 2);
            }
            for (int i = 0; i < gammai.Length - 2 * halfNumPcs; i++)
            {
                AddModPow2(zi[i], gammai[i + 2 * halfNumPcs], n + 2);
            }
            for (int i = 0; i < gammai.Length - 3 * halfNumPcs; i++)
            {
                SubModPow2(zi[i], gammai[i + 3 * halfNumPcs], n + 2);
            }

            // zr mod Fn
            int[][] ai = SplitInts(A, halfNumPcs, pieceSize, 1 << (n + 1 - 5));
            int[][] bi = SplitInts(B, halfNumPcs, pieceSize, 1 << (n + 1 - 5));
            Dft(ai, m, n);
            Dft(bi, m, n);
            ModFn(ai);
            ModFn(bi);
            int[][] c = new int[halfNumPcs][];

            for (int i = 0; i < c.Length; i++)
            {
                c[i] = MultModFn(ai[i], bi[i]);
            }

            Idft(c, m, n);
            ModFn(c);

            int[] z = new int[1 << (m + 1 - 5)];
            // calculate zr mod Fm from zr mod Fn and zr mod 2^(n+2), then add to z
            for (int i = 0; i < halfNumPcs; i++)
            {
                int[] eta = i >= zi.Length ? new int[(n + 2 + 31) / 32] : zi[i];
                // zi = delta = (zi-c[i]) % 2^(n+2)
                SubModPow2(eta, c[i], n + 2);
                // z += zr<<shift = [ci + delta*(2^2^n+1)] << [i*2^(n-1)]
                int shift = i * (1 << (n - 1 - 5));   // assume n>=6
                AddShifted(z, c[i], shift);
                AddShifted(z, eta, shift);
                AddShifted(z, eta, shift + (1 << (n - 5)));
            }

            // assume m>=5
            ModFn(z);

            return(z);
        }
Пример #10
0
        /// <summary>
        /// Multiplies the polynomial by another, taking the indices mod N.
        /// <para>Does not change this polynomial but returns the result as a new polynomial.
        /// Both polynomials must have the same number of coefficients.
        /// This method is designed for large polynomials and uses Schönhage-Strassen multiplication
        /// in combination with <a href="http://en.wikipedia.org/wiki/Kronecker_substitution">Kronecker substitution</a>.
        /// See <a href="http://math.stackexchange.com/questions/58946/karatsuba-vs-schonhage-strassen-for-multiplication-of-polynomials#58955">here</a> for details.</para>
        /// </summary>
        ///
        /// <param name="Factor">The polynomial to multiply by</param>
        ///
        /// <returns>The product polynomial</returns>
        public BigIntPolynomial MultBig(BigIntPolynomial Factor)
        {
            int N = Coeffs.Length;

            // determine #bits needed per coefficient
            int logMinDigits = 32 - IntUtils.NumberOfLeadingZeros(N - 1);
            int maxLengthA   = 0;

            for (int i = 0; i < Coeffs.Length; i++)
            {
                BigInteger coeff = Coeffs[i];
                maxLengthA = Math.Max(maxLengthA, coeff.BitLength);
            }

            int maxLengthB = 0;

            for (int i = 0; i < Factor.Coeffs.Length; i++)
            {
                BigInteger coeff = Factor.Coeffs[i];
                maxLengthB = Math.Max(maxLengthB, coeff.BitLength);
            }

            int k = logMinDigits + maxLengthA + maxLengthB + 1; // in bits

            k = (k + 31) / 32;                                  // in ints

            // encode each polynomial into an int[]
            int aDeg = Degree();
            int bDeg = Factor.Degree();

            if (aDeg < 0 || bDeg < 0)
            {
                return(new BigIntPolynomial(N));   // return zero
            }
            int[] aInt = ToIntArray(this, k);
            int[] bInt = ToIntArray(Factor, k);
            int[] cInt = SchonhageStrassen.Multiply(aInt, bInt);
            // decode poly coefficients from the product
            BigInteger       _2k   = BigInteger.One.ShiftLeft(k * 32);
            BigIntPolynomial cPoly = new BigIntPolynomial(N);

            for (int i = 0; i < 2 * N - 1; i++)
            {
                int[]      coeffInt = cInt.CopyOfRange(i * k, (i + 1) * k);
                BigInteger coeff    = SchonhageStrassen.ToBigInteger(coeffInt);
                if (coeffInt[k - 1] < 0)
                {   // if coeff > 2^(k-1)
                    coeff = coeff.Subtract(_2k);
                    // add 2^k to cInt which is the same as subtracting coeff
                    bool carry = false;
                    int  cIdx  = (i + 1) * k;

                    do
                    {
                        cInt[cIdx]++;
                        carry = cInt[cIdx] == 0;
                        cIdx++;
                    } while (carry);
                }
                cPoly.Coeffs[i % N] = cPoly.Coeffs[i % N].Add(coeff);
            }

            int aSign = Coeffs[aDeg].Signum();
            int bSign = Factor.Coeffs[bDeg].Signum();

            if (aSign * bSign < 0)
            {
                for (int i = 0; i < N; i++)
                {
                    cPoly.Coeffs[i] = cPoly.Coeffs[i].Negate();
                }
            }

            return(cPoly);
        }
Пример #11
0
        /// <summary>
        /// Divides the array 'a' by the array 'b' and gets the quotient and the remainder.
        /// <para>Implements the Knuth's division algorithm. See D. Knuth, The Art of Computer Programming,
        /// vol. 2. Steps D1-D8 correspond the steps in the algorithm description.</para>
        /// </summary>
        ///
        /// <param name="Quotient">The quotient</param>
        /// <param name="QuotientLen">The quotient's length</param>
        /// <param name="X">The dividend</param>
        /// <param name="XLen">The dividend's length</param>
        /// <param name="Y">The divisor</param>
        /// <param name="YLength">The divisor's length</param>
        ///
        /// <returns>eturn the remainder</returns>
        internal static int[] Divide(int[] Quotient, int QuotientLen, int[] X, int XLen, int[] Y, int YLength)
        {
            int[] normA = new int[XLen + 1];          // the normalized dividend
            // an extra byte is needed for correct shift
            int[] normB       = new int[YLength + 1]; // the normalized divisor;
            int   normBLength = YLength;

            // Step D1: normalize a and b and put the results to a1 and b1 the
            // normalized divisor's first digit must be >= 2^31
            int divisorShift = IntUtils.NumberOfLeadingZeros(Y[YLength - 1]);

            if (divisorShift != 0)
            {
                BitLevel.ShiftLeft(normB, Y, 0, divisorShift);
                BitLevel.ShiftLeft(normA, X, 0, divisorShift);
            }
            else
            {
                Array.Copy(X, 0, normA, 0, XLen);
                Array.Copy(Y, 0, normB, 0, YLength);
            }
            int firstDivisorDigit = normB[normBLength - 1];
            // Step D2: set the quotient index
            int i = QuotientLen - 1;
            int j = XLen;

            while (i >= 0)
            {
                // Step D3: calculate a guess digit guessDigit
                int guessDigit = 0;

                if (normA[j] == firstDivisorDigit)
                {
                    // set guessDigit to the largest unsigned int value
                    guessDigit = -1;
                }
                else
                {
                    long product = (((normA[j] & 0xffffffffL) << 32) + (normA[j - 1] & 0xffffffffL));
                    long res     = Division.DivideLongByInt(product, firstDivisorDigit);
                    guessDigit = (int)res;      // the quotient of divideLongByInt
                    int rem = (int)(res >> 32); // the remainder of
                    // divideLongByInt
                    // decrease guessDigit by 1 while leftHand > rightHand
                    if (guessDigit != 0)
                    {
                        long leftHand    = 0;
                        long rightHand   = 0;
                        bool rOverflowed = false;
                        guessDigit++; // to have the proper value in the loop
                        // below
                        do
                        {
                            guessDigit--;
                            if (rOverflowed)
                            {
                                break;
                            }

                            // leftHand always fits in an unsigned long
                            leftHand = (guessDigit & 0xffffffffL) * (normB[normBLength - 2] & 0xffffffffL);
                            // rightHand can overflow; in this case the loop
                            // condition will be true in the next step of the loop
                            rightHand = ((long)rem << 32) + (normA[j - 2] & 0xffffffffL);
                            long longR = (rem & 0xffffffffL) + (firstDivisorDigit & 0xffffffffL);
                            // checks that longR does not fit in an unsigned int;
                            // this ensures that rightHand will overflow unsigned long in the next step
                            if (IntUtils.NumberOfLeadingZeros((int)IntUtils.URShift(longR, 32)) < 32)
                            {
                                rOverflowed = true;
                            }
                            else
                            {
                                rem = (int)longR;
                            }
                        } while ((leftHand ^ long.MinValue) > (rightHand ^ long.MinValue));
                    }
                }
                // Step D4: multiply normB by guessDigit and subtract the production from normA.
                if (guessDigit != 0)
                {
                    int borrow = Division.MultiplyAndSubtract(normA, j - normBLength, normB, normBLength, guessDigit);
                    // Step D5: check the borrow
                    if (borrow != 0)
                    {
                        // Step D6: compensating addition
                        guessDigit--;
                        long carry = 0;
                        for (int k = 0; k < normBLength; k++)
                        {
                            carry += (normA[j - normBLength + k] & 0xffffffffL) + (normB[k] & 0xffffffffL);
                            normA[j - normBLength + k] = (int)carry;
                            carry = IntUtils.URShift(carry, 32);
                        }
                    }
                }
                if (Quotient != null)
                {
                    Quotient[i] = guessDigit;
                }
                // Step D7
                j--;
                i--;
            }
            // Step D8: we got the remainder in normA. Denormalize it as needed
            if (divisorShift != 0)
            {
                // reuse normB
                BitLevel.ShiftRight(normB, normBLength, normA, 0, divisorShift);
                return(normB);
            }
            Array.Copy(normA, 0, normB, 0, YLength);

            return(normA);
        }