/// <summary> /// Returns the first half of the [rootDegree]th roots of unity series in the BigInteger field. /// Used in the recursive FFT algorithm in LongInt.Helper class. /// /// Root degree should be an exact power of two. /// </summary> /// <param name="rootDegree"></param> /// <returns></returns> public static BigInteger[] rootsOfUnityHalfGalois(int rootDegree, bool inverted) { Contract.Requires <ArgumentOutOfRangeException>(rootDegree > 0, "The degree of the root should be a positive power of two."); Contract.Ensures( Contract.ForAll( Contract.Result <BigInteger[]>(), (x => WhiteMath <BigInteger, CalcBigInteger> .PowerIntegerModular(x, (ulong)rootDegree, NTT_MODULUS) == 1))); BigInteger[] result = new BigInteger[rootDegree / 2]; // The first root of unity is obviously one. // - result[0] = 1; // Now we will learn what k it is in rootDegree == 2^k // - int rootDegreeCopy = rootDegree; int rootDegreeExponent = 0; while (rootDegreeCopy > 1) { rootDegreeCopy /= 2; ++rootDegreeExponent; } // Now we obtain the principal 2^rootDegreeExponent-th root of unity. // - BigInteger principalRoot = WhiteMath <BigInteger, CalcBigInteger> .PowerIntegerModular( NTT_MAX_ROOT_OF_UNITY_2_30, WhiteMath <ulong, CalcULong> .PowerInteger(2, NTT_MAX_ROOT_OF_UNITY_DEGREE_EXPONENT - rootDegreeExponent), NTT_MODULUS); // Calculate the desired roots of unity. // - for (int i = 1; i < rootDegree / 2; i++) { // All the desired roots of unity are obtained as powers of the principal root. // - result[i] = result[i - 1] * principalRoot % NTT_MODULUS; } // If performing the inverse NTT, we should invert the roots. // - if (inverted) { for (int i = 0; i < rootDegree / 2; ++i) { result[i] = WhiteMath <BigInteger, CalcBigInteger> .MultiplicativeInverse(result[i], NTT_MODULUS); } } return(result); }
/// <summary> /// Returns the first half of the [rootDegree]th roots of unity series in the BigInteger field. /// Used in the recursive FFT algorithm in LongInt.Helper class. /// /// Root degree should be an exact power of two. /// </summary> /// <param name="rootDegree"></param> /// <returns></returns> internal static BigInteger[] rootsOfUnityHalfGalois( NTTFiniteFieldInfo finiteFieldInfo, int rootDegree, bool inverted) { Contract.Requires <ArgumentOutOfRangeException>(rootDegree > 0, "The degree of the root should be a positive power of two."); Contract.Ensures( Contract.ForAll( Contract.Result <BigInteger[]>(), (x => WhiteMath <BigInteger, CalcBigInteger> .PowerIntegerModular(x, (ulong)rootDegree, finiteFieldInfo.primeModulus) == 1))); BigInteger[] result = new BigInteger[rootDegree / 2]; // The first root of unity is obviously one, // but we start with -1 if we need the inverse roots. // - if (!inverted) { result[0] = 1; } else { result[0] = finiteFieldInfo.primeModulus - 1; } // Calculate the desired roots of unity. // - for (int i = 1; i < rootDegree / 2; ++i) { // All the desired roots of unity are obtained as powers of the principal root. // - result[i] = result[i - 1] * finiteFieldInfo.rootOfUnity % finiteFieldInfo.primeModulus; } // If performing the inverse NTT, we should reverse the array along // with a magic shift by 1 to get the inverted roots in the necessary order. // if (inverted) { result[0] = 1; for (int i = 1; i < rootDegree / 4; ++i) { result.Swap(i, rootDegree / 2 - i); } } return(result); }