/// <summary> /// Осуществляет процесс восстановления ключа из его частей при помощи многочлена Лагранжа /// </summary> /// <param name="Fragments">Набор частей ключа</param> /// <param name="module">Модуль, по которому необходимо производить вычисления</param> /// <returns>Значение ключа</returns> public static BigInteger RestoreByLagrangePolynomial(KeyValuePair <int, BigInteger>[] Fragments, BigInteger module) { Comparison.LinearComparison Result = new Comparison.LinearComparison(0, module); Comparison.LinearComparison buffer = new Comparison.LinearComparison(1, module); foreach (KeyValuePair <int, BigInteger> fragment1 in Fragments) { buffer.A = 1; foreach (KeyValuePair <int, BigInteger> fragment2 in Fragments) { Comparison.LinearComparison fract = new Comparison.LinearComparison(fragment2.Key - fragment1.Key, module); if (fract.A == 0) { continue; } buffer.A *= fragment2.Key * Comparison.MultiplicativeInverse.Solve(fract.A, module); } Result.A += buffer.A * fragment1.Value; } return(Result.A); }
/// <summary> /// Возвращает символ, полученный в результате дешифрования символа текста символом ключа. /// </summary> /// <param name="EncryptedShar"></param> /// <param name="KeyChar"></param> /// <returns></returns> public static char GetDecryptedChar(char EncryptedShar, char KeyChar) { int SourceIndex = Languages.CurrentLanguage.Alphabet.IndexOf(EncryptedShar); int KeyIndex = Languages.CurrentLanguage.Alphabet.IndexOf(KeyChar); Comparison.LinearComparison ResultIndex = new Comparison.LinearComparison(SourceIndex - KeyIndex, Languages.CurrentLanguage.Alphabet.Length); return(Languages.CurrentLanguage.Alphabet[(int)ResultIndex.A]); }
/// <summary> /// Возвращает результат восстановления секрета по имеющимся частям и пороговому значению. /// </summary> /// <param name="Parts"></param> /// <param name="Limit"></param> /// <returns></returns> public static BigInteger Restore(List <CRTPart> Parts, int Limit) { if (Parts.Count < Limit) { throw new InvalidOperationException( "Невозможно восстановить секрет: число долей меньше порогового значения"); } Comparison.LinearComparison NewM = Maths.CRT.Solve(Parts.Select(part => part.Comparison)); return(new Comparison.LinearComparison(NewM.A, Parts.First().P).A); }
private static BigInteger SolveByGaussianMethod(KeyValuePair <int, BigInteger>[] Fragments, BigInteger module) { int polynomdegree = Fragments.Length; Comparison.LinearComparison[][] Matrix = new Comparison.LinearComparison[polynomdegree][]; for (int i = 0; i < polynomdegree; i++) { Matrix[i] = new Comparison.LinearComparison[polynomdegree + 1].Select(_ => new Comparison.LinearComparison(0, module)) .ToArray(); Matrix[i][polynomdegree - 1].A = 1; for (int j = polynomdegree - 2; j >= 0; j--) { Matrix[i][j].A = Matrix[i][j + 1].A * Fragments[i].Key; } Matrix[i][Matrix[i].Length - 1].A = Fragments[i].Value; } //Матрица проинициализирована //Фиксируем i-ую строку и начинаем у всех остальных создавать нули в столбце i for (int i = 0; i < polynomdegree - 1; i++) { if (Matrix.Any(row => row.Skip(row.Length - 1).All(element => element.A != 0) && row.Take(row.Length - 1).All(element => element.A == 0))) { Comparison.LinearComparison[] target = Matrix.First(row => row.Skip(row.Length - 2).All(element => element.A != 0) && row.Take(row.Length - 2).All(element => element.A == 0)).ToArray(); Solve(target[target.Length - 2].A, target[target.Length - 1].A, module, out Comparison.LinearComparison result); return(result.A); } int FirstNonZeroIndex = i; while (FirstNonZeroIndex < Matrix.Length && Matrix[FirstNonZeroIndex][i].A == 0) { FirstNonZeroIndex++; } if (FirstNonZeroIndex == Matrix.Length) { continue; } SwapLines(Matrix, i, FirstNonZeroIndex); //перебираем все остальные j-ые строки и производим вычитание for (int j = i + 1; j < polynomdegree; j++) { if (Matrix[j][i].A == 0) { continue; } //высчитываем НОД и коэффициенты BigInteger firstmultiplier = AdvancedEuclidsalgorithm.LCM(Matrix[i][i].A, Matrix[j][i].A) / Matrix[i][i].A; BigInteger secondmultiplier = firstmultiplier * Matrix[i][i].A / Matrix[j][i].A; Matrix[j][i].A = 0; //пробегаем по всей строке и задаем значения после вычитания for (int k = i + 1; k < polynomdegree + 1; k++) { Matrix[j][k].A = Matrix[j][k].A * secondmultiplier - Matrix[i][k].A * firstmultiplier; } } } //получили выражение вида ak=b(mod m) return(Solve(Matrix[polynomdegree - 1][polynomdegree - 1].A, Matrix[polynomdegree - 1][polynomdegree].A, module, out Comparison.LinearComparison Result) ? Result.A : int.MaxValue); }
/// <summary> /// Осуществляет генерацию кодов, подходящим заданным частотам так, чтобы добиться наименьшей средней длины сообщения. /// </summary> /// <param name="Probabilities">Массив - частотный анализ исходного алфавита.</param> /// <param name="k">Система счисления, в которой будет произведено кодирование.</param> /// <param name="AverageLength">Вычисленная в процессе генерации кодов средняя длина сообщения.</param> /// <returns> /// Массив <see cref="ByteSet" />[], содержащий в себе коды, расположенные в соответствии введенным частотам в /// порядке убывания. /// </returns> public static ByteSet[] GetCodes(double[] Probabilities, int k, out double AverageLength) { AverageLength = 0; if (k >= Probabilities.Length) { ByteSet[] answer = new ByteSet[Probabilities.Length]; for (int i = 0; i < Probabilities.Length; i++) { answer[i] = new ByteSet { Value = new[] { (byte)i } }; AverageLength += Probabilities[i]; } return(answer); } //k - это число частей, на которые нам необходимо разбивать вероятности double[] ProbCop = new double[Probabilities.Length]; Probabilities.CopyTo(ProbCop, 0); Array.Sort(ProbCop, (d, d1) => Math.Sign((d1 - d))); //отсортировали свою копию массива в порядке убывания вероятностей Stack <int> Insertions = new Stack <int>(); //n - мощность исходного алфавита (кол-во вероятностей, которое на вход дали) //k - мощность конечного алфавита (система счисления) //ПЕРВАЯ СВЕРТКА int FirstConvolutionLength; if (k == 2) { FirstConvolutionLength = 2; } else { Comparison.LinearComparison k0 = new Comparison.LinearComparison(ProbCop.Length, k - 1); if (k0.A == 0) { FirstConvolutionLength = k - 1; } else if (k0.A == 1) { FirstConvolutionLength = k; } else { FirstConvolutionLength = (int)k0.A; } } double Sum = ProbCop.Skip(ProbCop.Length - FirstConvolutionLength).Sum(); Sum = Math.Round(Sum, 3); int Index = 0; int ResultLength = ProbCop.Length - FirstConvolutionLength + 1; while (ProbCop[Index] >= Sum && Index < ResultLength) { Index++; } Insertions.Push(Index); List <double> bufferProb = new List <double>(ProbCop); bufferProb.Insert(Index, Sum); ProbCop = bufferProb.Take(ResultLength).ToArray(); //Последующие свертки while (ProbCop.Length != k) { Sum = ProbCop.Skip(ProbCop.Length - k).Sum(); Sum = Math.Round(Sum, 3); //вычислили сумму последних k элементов //надо определить, на какой индекс будем вставлять Index = 0; ResultLength = ProbCop.Length - k + 1; while (ProbCop[Index] >= Sum && Index < ResultLength) { Index++; } //нашли индекс, на который необходимо вставить полученную сумму Insertions.Push(Index); bufferProb = new List <double>(ProbCop); bufferProb.Insert(Index, Sum); ProbCop = bufferProb.Take(ResultLength).ToArray(); } List <ByteSet> Answer = new List <ByteSet>(); for (int i = 0; i < ProbCop.Length; i++) { Answer.Add(new ByteSet { Value = new[] { (byte)i } }); } int Moving; List <ByteSet> buffer; //Все восстановления, кроме последнего while (Insertions.Count != 1) { Moving = Insertions.Pop(); //узнали о перестановке buffer = new List <ByteSet>(Answer); buffer.RemoveAt(Moving); for (int i = 0; i < k; i++) { buffer.Add(new ByteSet(Answer[Moving])); buffer.Last().Append((byte)i); } Answer = buffer; } //ВОССТАНОВЛЕНИЕ ПОСЛЕДНЕЙ СВЕРТКИ Moving = Insertions.Pop(); //узнали о перестановке buffer = new List <ByteSet>(Answer); buffer.RemoveAt(Moving); for (int i = 0; i < FirstConvolutionLength; i++) { buffer.Add(new ByteSet(Answer[Moving])); buffer.Last().Append((byte)i); } Answer = buffer; AverageLength += Probabilities.Select((t, i) => t * Answer[i].Length).Sum(); return(Answer.ToArray()); }