Merge math.mp.Integer changes from the crypto branch
This commit is contained in:
parent
85380ac3fc
commit
b90517580e
File diff suppressed because it is too large
Load Diff
@ -3,11 +3,11 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copyright: Eugene Wissner 2016.
|
* Copyright: Eugene Wissner 2016-2017.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
*/
|
*/
|
||||||
module tanya.math;
|
module tanya.math;
|
||||||
|
|
||||||
import std.traits;
|
import std.traits;
|
||||||
@ -16,7 +16,7 @@ public import tanya.math.random;
|
|||||||
|
|
||||||
version (unittest)
|
version (unittest)
|
||||||
{
|
{
|
||||||
import std.algorithm.iteration;
|
import std.algorithm.iteration;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -26,12 +26,12 @@ version (unittest)
|
|||||||
* is used to allocate the result.
|
* is used to allocate the result.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* I = Base type.
|
* I = Base type.
|
||||||
* G = Exponent type.
|
* G = Exponent type.
|
||||||
* H = Divisor type:
|
* H = Divisor type:
|
||||||
* x = Base.
|
* x = Base.
|
||||||
* y = Exponent.
|
* y = Exponent.
|
||||||
* z = Divisor.
|
* z = Divisor.
|
||||||
*
|
*
|
||||||
* Returns: Reminder of the division of $(D_PARAM x) to the power $(D_PARAM y)
|
* Returns: Reminder of the division of $(D_PARAM x) to the power $(D_PARAM y)
|
||||||
* by $(D_PARAM z).
|
* by $(D_PARAM z).
|
||||||
@ -39,134 +39,162 @@ version (unittest)
|
|||||||
* Precondition: $(D_INLINECODE z > 0)
|
* Precondition: $(D_INLINECODE z > 0)
|
||||||
*/
|
*/
|
||||||
H pow(I, G, H)(in auto ref I x, in auto ref G y, in auto ref H z)
|
H pow(I, G, H)(in auto ref I x, in auto ref G y, in auto ref H z)
|
||||||
if (isIntegral!I && isIntegral!G && isIntegral!H)
|
if (isIntegral!I && isIntegral!G && isIntegral!H)
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(z > 0, "Division by zero.");
|
assert(z > 0, "Division by zero.");
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
G mask = G.max / 2 + 1;
|
G mask = G.max / 2 + 1;
|
||||||
H result;
|
H result;
|
||||||
|
|
||||||
if (y == 0)
|
if (y == 0)
|
||||||
{
|
{
|
||||||
return 1 % z;
|
return 1 % z;
|
||||||
}
|
}
|
||||||
else if (y == 1)
|
else if (y == 1)
|
||||||
{
|
{
|
||||||
return x % z;
|
return x % z;
|
||||||
}
|
}
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
immutable bit = y & mask;
|
immutable bit = y & mask;
|
||||||
if (!result && bit)
|
if (!result && bit)
|
||||||
{
|
{
|
||||||
result = x;
|
result = x;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
result *= result;
|
result *= result;
|
||||||
if (bit)
|
if (bit)
|
||||||
{
|
{
|
||||||
result *= x;
|
result *= x;
|
||||||
}
|
}
|
||||||
result %= z;
|
result %= z;
|
||||||
}
|
}
|
||||||
while (mask >>= 1);
|
while (mask >>= 1);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
I pow(I)(in auto ref I x, in auto ref I y, in auto ref I z)
|
I pow(I)(const auto ref I x, const auto ref I y, const auto ref I z)
|
||||||
if (is(I == Integer))
|
if (is(I == Integer))
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(z.length > 0, "Division by zero.");
|
assert(z.length > 0, "Division by zero.");
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
size_t i = y.length;
|
size_t i = y.length;
|
||||||
auto tmp2 = Integer(x.allocator), tmp1 = Integer(x, x.allocator);
|
auto tmp1 = Integer(x, x.allocator);
|
||||||
Integer result = Integer(x.allocator);
|
auto result = Integer(x.allocator);
|
||||||
|
|
||||||
if (x.length == 0 && i != 0)
|
if (x.length == 0 && i != 0)
|
||||||
{
|
{
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = 1;
|
result = 1;
|
||||||
}
|
}
|
||||||
while (i)
|
while (i)
|
||||||
{
|
{
|
||||||
--i;
|
--i;
|
||||||
for (ubyte mask = 0x01; mask; mask <<= 1)
|
for (ubyte mask = 0x01; mask; mask <<= 1)
|
||||||
{
|
{
|
||||||
if (y.rep[i] & mask)
|
if (y.rep[i] & mask)
|
||||||
{
|
{
|
||||||
result *= tmp1;
|
result *= tmp1;
|
||||||
result %= z;
|
result %= z;
|
||||||
}
|
}
|
||||||
tmp2 = tmp1;
|
auto tmp2 = tmp1;
|
||||||
tmp1 *= tmp2;
|
tmp1 *= tmp2;
|
||||||
tmp1 %= z;
|
tmp1 %= z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
pure nothrow @safe @nogc unittest
|
||||||
{
|
{
|
||||||
assert(pow(3, 5, 7) == 5);
|
assert(pow(3, 5, 7) == 5);
|
||||||
assert(pow(2, 2, 1) == 0);
|
assert(pow(2, 2, 1) == 0);
|
||||||
assert(pow(3, 3, 3) == 0);
|
assert(pow(3, 3, 3) == 0);
|
||||||
assert(pow(7, 4, 2) == 1);
|
assert(pow(7, 4, 2) == 1);
|
||||||
assert(pow(53, 0, 2) == 1);
|
assert(pow(53, 0, 2) == 1);
|
||||||
assert(pow(53, 1, 3) == 2);
|
assert(pow(53, 1, 3) == 2);
|
||||||
assert(pow(53, 2, 5) == 4);
|
assert(pow(53, 2, 5) == 4);
|
||||||
assert(pow(0, 0, 5) == 1);
|
assert(pow(0, 0, 5) == 1);
|
||||||
assert(pow(0, 5, 5) == 0);
|
assert(pow(0, 5, 5) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
assert(cast(long) pow(Integer(3), Integer(5), Integer(7)) == 5);
|
assert(pow(Integer(3), Integer(5), Integer(7)) == 5);
|
||||||
assert(cast(long) pow(Integer(2), Integer(2), Integer(1)) == 0);
|
assert(pow(Integer(2), Integer(2), Integer(1)) == 0);
|
||||||
assert(cast(long) pow(Integer(3), Integer(3), Integer(3)) == 0);
|
assert(pow(Integer(3), Integer(3), Integer(3)) == 0);
|
||||||
assert(cast(long) pow(Integer(7), Integer(4), Integer(2)) == 1);
|
assert(pow(Integer(7), Integer(4), Integer(2)) == 1);
|
||||||
assert(cast(long) pow(Integer(53), Integer(0), Integer(2)) == 1);
|
assert(pow(Integer(53), Integer(0), Integer(2)) == 1);
|
||||||
assert(cast(long) pow(Integer(53), Integer(1), Integer(3)) == 2);
|
assert(pow(Integer(53), Integer(1), Integer(3)) == 2);
|
||||||
assert(cast(long) pow(Integer(53), Integer(2), Integer(5)) == 4);
|
assert(pow(Integer(53), Integer(2), Integer(5)) == 4);
|
||||||
assert(cast(long) pow(Integer(0), Integer(0), Integer(5)) == 1);
|
assert(pow(Integer(0), Integer(0), Integer(5)) == 1);
|
||||||
assert(cast(long) pow(Integer(0), Integer(5), Integer(5)) == 0);
|
assert(pow(Integer(0), Integer(5), Integer(5)) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if $(D_PARAM x) is a prime.
|
* Checks if $(D_PARAM x) is a prime.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* x = The number should be checked.
|
* x = The number should be checked.
|
||||||
*
|
*
|
||||||
* Returns: $(D_KEYWORD true) if $(D_PARAM x) is a prime number,
|
* Returns: $(D_KEYWORD true) if $(D_PARAM x) is a prime number,
|
||||||
* $(D_KEYWORD false) otherwise.
|
* $(D_KEYWORD false) otherwise.
|
||||||
*/
|
*/
|
||||||
bool isPseudoprime(ulong x) nothrow pure @safe @nogc
|
bool isPseudoprime(ulong x) nothrow pure @safe @nogc
|
||||||
{
|
{
|
||||||
return pow(2, x - 1, x) == 1;
|
return pow(2, x - 1, x) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
uint[30] known = [74623, 74653, 74687, 74699, 74707, 74713, 74717, 74719,
|
uint[30] known = [74623, 74653, 74687, 74699, 74707, 74713, 74717, 74719,
|
||||||
74843, 74747, 74759, 74761, 74771, 74779, 74797, 74821,
|
74843, 74747, 74759, 74761, 74771, 74779, 74797, 74821,
|
||||||
74827, 9973, 104729, 15485867, 49979693, 104395303,
|
74827, 9973, 104729, 15485867, 49979693, 104395303,
|
||||||
593441861, 104729, 15485867, 49979693, 104395303,
|
593441861, 104729, 15485867, 49979693, 104395303,
|
||||||
593441861, 899809363, 982451653];
|
593441861, 899809363, 982451653];
|
||||||
|
|
||||||
known.each!((ref x) => assert(isPseudoprime(x)));
|
known.each!((ref x) => assert(isPseudoprime(x)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Params:
|
||||||
|
* I = Value type.
|
||||||
|
* x = Value.
|
||||||
|
*
|
||||||
|
* Returns: The absolute value of a number.
|
||||||
|
*/
|
||||||
|
I abs(I : Integer)(const auto ref I x)
|
||||||
|
{
|
||||||
|
auto result = Integer(x, x.allocator);
|
||||||
|
result.sign = Sign.positive;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
I abs(I : Integer)(I x)
|
||||||
|
{
|
||||||
|
x.sign = Sign.positive;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ditto.
|
||||||
|
I abs(I)(const I x)
|
||||||
|
if (isIntegral!I)
|
||||||
|
{
|
||||||
|
return x >= 0 ? x : -x;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user