169 lines
3.2 KiB
C#
169 lines
3.2 KiB
C#
using System;
|
|
using Org.BouncyCastle.Crypto.Utilities;
|
|
using Org.BouncyCastle.Security;
|
|
|
|
namespace Org.BouncyCastle.Math.Raw;
|
|
|
|
internal abstract class Mod
|
|
{
|
|
private static readonly SecureRandom RandomSource = new SecureRandom();
|
|
|
|
public static void Invert(uint[] p, uint[] x, uint[] z)
|
|
{
|
|
int num = p.Length;
|
|
if (Nat.IsZero(num, x))
|
|
{
|
|
throw new ArgumentException("cannot be 0", "x");
|
|
}
|
|
if (Nat.IsOne(num, x))
|
|
{
|
|
Array.Copy(x, 0, z, 0, num);
|
|
return;
|
|
}
|
|
uint[] array = Nat.Copy(num, x);
|
|
uint[] array2 = Nat.Create(num);
|
|
array2[0] = 1u;
|
|
int xc = 0;
|
|
if ((array[0] & 1) == 0)
|
|
{
|
|
InversionStep(p, array, num, array2, ref xc);
|
|
}
|
|
if (Nat.IsOne(num, array))
|
|
{
|
|
InversionResult(p, xc, array2, z);
|
|
return;
|
|
}
|
|
uint[] array3 = Nat.Copy(num, p);
|
|
uint[] array4 = Nat.Create(num);
|
|
int xc2 = 0;
|
|
int num2 = num;
|
|
while (true)
|
|
{
|
|
if (array[num2 - 1] == 0 && array3[num2 - 1] == 0)
|
|
{
|
|
num2--;
|
|
}
|
|
else if (Nat.Gte(num, array, array3))
|
|
{
|
|
Nat.SubFrom(num, array3, array);
|
|
xc += Nat.SubFrom(num, array4, array2) - xc2;
|
|
InversionStep(p, array, num2, array2, ref xc);
|
|
if (Nat.IsOne(num, array))
|
|
{
|
|
InversionResult(p, xc, array2, z);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Nat.SubFrom(num, array, array3);
|
|
xc2 += Nat.SubFrom(num, array2, array4) - xc;
|
|
InversionStep(p, array3, num2, array4, ref xc2);
|
|
if (Nat.IsOne(num, array3))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
InversionResult(p, xc2, array4, z);
|
|
}
|
|
|
|
public static uint[] Random(uint[] p)
|
|
{
|
|
int num = p.Length;
|
|
uint[] array = Nat.Create(num);
|
|
uint num2 = p[num - 1];
|
|
num2 |= num2 >> 1;
|
|
num2 |= num2 >> 2;
|
|
num2 |= num2 >> 4;
|
|
num2 |= num2 >> 8;
|
|
num2 |= num2 >> 16;
|
|
do
|
|
{
|
|
byte[] array2 = new byte[num << 2];
|
|
RandomSource.NextBytes(array2);
|
|
Pack.BE_To_UInt32(array2, 0, array);
|
|
uint[] array4;
|
|
uint[] array3 = (array4 = array);
|
|
int num3 = num - 1;
|
|
nint num4 = num3;
|
|
array3[num3] = array4[num4] & num2;
|
|
}
|
|
while (Nat.Gte(num, array, p));
|
|
return array;
|
|
}
|
|
|
|
public static void Add(uint[] p, uint[] x, uint[] y, uint[] z)
|
|
{
|
|
int len = p.Length;
|
|
if (Nat.Add(len, x, y, z) != 0)
|
|
{
|
|
Nat.SubFrom(len, p, z);
|
|
}
|
|
}
|
|
|
|
public static void Subtract(uint[] p, uint[] x, uint[] y, uint[] z)
|
|
{
|
|
int len = p.Length;
|
|
if (Nat.Sub(len, x, y, z) != 0)
|
|
{
|
|
Nat.AddTo(len, p, z);
|
|
}
|
|
}
|
|
|
|
private static void InversionResult(uint[] p, int ac, uint[] a, uint[] z)
|
|
{
|
|
if (ac < 0)
|
|
{
|
|
Nat.Add(p.Length, a, p, z);
|
|
}
|
|
else
|
|
{
|
|
Array.Copy(a, 0, z, 0, p.Length);
|
|
}
|
|
}
|
|
|
|
private static void InversionStep(uint[] p, uint[] u, int uLen, uint[] x, ref int xc)
|
|
{
|
|
int len = p.Length;
|
|
int num = 0;
|
|
while (u[0] == 0)
|
|
{
|
|
Nat.ShiftDownWord(uLen, u, 0u);
|
|
num += 32;
|
|
}
|
|
int trailingZeroes = GetTrailingZeroes(u[0]);
|
|
if (trailingZeroes > 0)
|
|
{
|
|
Nat.ShiftDownBits(uLen, u, trailingZeroes, 0u);
|
|
num += trailingZeroes;
|
|
}
|
|
for (int i = 0; i < num; i++)
|
|
{
|
|
if ((x[0] & 1) != 0)
|
|
{
|
|
if (xc < 0)
|
|
{
|
|
xc += (int)Nat.AddTo(len, p, x);
|
|
}
|
|
else
|
|
{
|
|
xc += Nat.SubFrom(len, p, x);
|
|
}
|
|
}
|
|
Nat.ShiftDownBit(len, x, (uint)xc);
|
|
}
|
|
}
|
|
|
|
private static int GetTrailingZeroes(uint x)
|
|
{
|
|
int num = 0;
|
|
while ((x & 1) == 0)
|
|
{
|
|
x >>= 1;
|
|
num++;
|
|
}
|
|
return num;
|
|
}
|
|
}
|