mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-08 03:24:19 +00:00
Merge pull request #1057 from odin-lang/new-big-int-library-integration
New Big Int Library Integration
This commit is contained in:
53
Makefile
53
Makefile
@@ -1,5 +1,5 @@
|
||||
GIT_SHA=$(shell git rev-parse --short HEAD)
|
||||
DISABLED_WARNINGS=-Wno-switch -Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare -Wno-macro-redefined
|
||||
DISABLED_WARNINGS=-Wno-switch -Wno-pointer-sign -Wno-tautological-constant-out-of-range-compare -Wno-tautological-compare -Wno-macro-redefined -Wno-unused-value
|
||||
LDFLAGS=-pthread -ldl -lm -lstdc++
|
||||
CFLAGS=-std=c++14 -DGIT_SHA=\"$(GIT_SHA)\"
|
||||
CFLAGS:=$(CFLAGS) -DODIN_VERSION_RAW=\"dev-$(shell date +"%Y-%m")\"
|
||||
@@ -8,31 +8,31 @@ CC=clang
|
||||
OS=$(shell uname)
|
||||
|
||||
ifeq ($(OS), Darwin)
|
||||
LLVM_CONFIG=llvm-config
|
||||
ifneq ($(shell llvm-config --version | grep '^11\.'),)
|
||||
LLVM_CONFIG=llvm-config
|
||||
else
|
||||
$(error "Requirement: llvm-config must be version 11")
|
||||
endif
|
||||
LLVM_CONFIG=llvm-config
|
||||
ifneq ($(shell llvm-config --version | grep '^11\.'),)
|
||||
LLVM_CONFIG=llvm-config
|
||||
else
|
||||
$(error "Requirement: llvm-config must be version 11")
|
||||
endif
|
||||
|
||||
LDFLAGS:=$(LDFLAGS) -liconv
|
||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
||||
LDFLAGS:=$(LDFLAGS) -lLLVM-C
|
||||
LDFLAGS:=$(LDFLAGS) -liconv
|
||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
||||
LDFLAGS:=$(LDFLAGS) -lLLVM-C
|
||||
endif
|
||||
ifeq ($(OS), Linux)
|
||||
LLVM_CONFIG=llvm-config-11
|
||||
ifneq ($(shell which llvm-config-11 2>/dev/null),)
|
||||
LLVM_CONFIG=llvm-config-11
|
||||
else
|
||||
ifneq ($(shell llvm-config --version | grep '^11\.'),)
|
||||
LLVM_CONFIG=llvm-config
|
||||
else
|
||||
$(error "Requirement: llvm-config must be version 11")
|
||||
endif
|
||||
endif
|
||||
LLVM_CONFIG=llvm-config-11
|
||||
ifneq ($(shell which llvm-config-11 2>/dev/null),)
|
||||
LLVM_CONFIG=llvm-config-11
|
||||
else
|
||||
ifneq ($(shell llvm-config --version | grep '^11\.'),)
|
||||
LLVM_CONFIG=llvm-config
|
||||
else
|
||||
$(error "Requirement: llvm-config must be version 11")
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
||||
LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
|
||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
||||
LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
|
||||
endif
|
||||
|
||||
all: debug demo
|
||||
@@ -41,13 +41,16 @@ demo:
|
||||
./odin run examples/demo/demo.odin
|
||||
|
||||
debug:
|
||||
$(CC) src/main.cpp $(DISABLED_WARNINGS) $(CFLAGS) -g $(LDFLAGS) -o odin
|
||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -g $(LDFLAGS) -o odin
|
||||
|
||||
release:
|
||||
$(CC) src/main.cpp $(DISABLED_WARNINGS) $(CFLAGS) -O3 -march=native $(LDFLAGS) -o odin
|
||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -O3 $(LDFLAGS) -o odin
|
||||
|
||||
release_native:
|
||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -O3 -march=native $(LDFLAGS) -o odin
|
||||
|
||||
nightly:
|
||||
$(CC) src/main.cpp $(DISABLED_WARNINGS) $(CFLAGS) -DNIGHTLY -O3 $(LDFLAGS) -o odin
|
||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -DNIGHTLY -O3 $(LDFLAGS) -o odin
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ if %release_mode% EQU 0 ( rem Debug
|
||||
|
||||
set compiler_warnings= ^
|
||||
-W4 -WX ^
|
||||
-wd4100 -wd4101 -wd4127 -wd4189 ^
|
||||
-wd4100 -wd4101 -wd4127 -wd4146 -wd4189 ^
|
||||
-wd4201 -wd4204 ^
|
||||
-wd4456 -wd4457 -wd4480 ^
|
||||
-wd4512
|
||||
@@ -70,7 +70,7 @@ set linker_settings=%libs% %linker_flags%
|
||||
del *.pdb > NUL 2> NUL
|
||||
del *.ilk > NUL 2> NUL
|
||||
|
||||
cl %compiler_settings% "src\main.cpp" /link %linker_settings% -OUT:%exe_name%
|
||||
cl %compiler_settings% "src\main.cpp" "src\libtommath.cpp" /link %linker_settings% -OUT:%exe_name%
|
||||
|
||||
if %errorlevel% neq 0 goto end_of_build
|
||||
if %release_mode% EQU 0 odin run examples/demo/demo.odin
|
||||
|
||||
1218
src/big_int.cpp
1218
src/big_int.cpp
File diff suppressed because it is too large
Load Diff
@@ -745,7 +745,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
return false;
|
||||
}
|
||||
|
||||
if (op.value.value_integer.neg) {
|
||||
if (big_int_is_neg(&op.value.value_integer)) {
|
||||
error(op.expr, "Negative 'swizzle' index");
|
||||
return false;
|
||||
}
|
||||
@@ -795,10 +795,12 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false;
|
||||
if (x.mode == Addressing_Constant &&
|
||||
y.mode == Addressing_Constant) {
|
||||
if (is_type_numeric(x.type) && exact_value_imag(x.value).value_float == 0) {
|
||||
x.value = exact_value_to_float(x.value);
|
||||
y.value = exact_value_to_float(y.value);
|
||||
if (is_type_numeric(x.type) && x.value.kind == ExactValue_Float) {
|
||||
x.type = t_untyped_float;
|
||||
}
|
||||
if (is_type_numeric(y.type) && exact_value_imag(y.value).value_float == 0) {
|
||||
if (is_type_numeric(y.type) && y.value.kind == ExactValue_Float) {
|
||||
y.type = t_untyped_float;
|
||||
}
|
||||
}
|
||||
@@ -882,16 +884,20 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
y.mode == Addressing_Constant &&
|
||||
z.mode == Addressing_Constant &&
|
||||
w.mode == Addressing_Constant) {
|
||||
if (is_type_numeric(x.type) && exact_value_imag(x.value).value_float == 0) {
|
||||
x.value = exact_value_to_float(x.value);
|
||||
y.value = exact_value_to_float(y.value);
|
||||
z.value = exact_value_to_float(z.value);
|
||||
w.value = exact_value_to_float(w.value);
|
||||
if (is_type_numeric(x.type) && x.value.kind == ExactValue_Float) {
|
||||
x.type = t_untyped_float;
|
||||
}
|
||||
if (is_type_numeric(y.type) && exact_value_imag(y.value).value_float == 0) {
|
||||
if (is_type_numeric(y.type) && y.value.kind == ExactValue_Float) {
|
||||
y.type = t_untyped_float;
|
||||
}
|
||||
if (is_type_numeric(z.type) && exact_value_imag(z.value).value_float == 0) {
|
||||
if (is_type_numeric(z.type) && z.value.kind == ExactValue_Float) {
|
||||
z.type = t_untyped_float;
|
||||
}
|
||||
if (is_type_numeric(w.type) && exact_value_imag(w.value).value_float == 0) {
|
||||
if (is_type_numeric(w.type) && w.value.kind == ExactValue_Float) {
|
||||
w.type = t_untyped_float;
|
||||
}
|
||||
}
|
||||
@@ -1484,7 +1490,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
if (operand->mode == Addressing_Constant) {
|
||||
switch (operand->value.kind) {
|
||||
case ExactValue_Integer:
|
||||
operand->value.value_integer.neg = false;
|
||||
mp_abs(&operand->value.value_integer, &operand->value.value_integer);
|
||||
break;
|
||||
case ExactValue_Float:
|
||||
operand->value.value_float = gb_abs(operand->value.value_float);
|
||||
@@ -1837,7 +1843,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
operand->type = t_invalid;
|
||||
return false;
|
||||
}
|
||||
if (x.value.value_integer.neg) {
|
||||
if (big_int_is_neg(&x.value.value_integer)) {
|
||||
error(call, "Negative vector element length");
|
||||
operand->mode = Addressing_Type;
|
||||
operand->type = t_invalid;
|
||||
@@ -1877,7 +1883,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
operand->type = t_invalid;
|
||||
return false;
|
||||
}
|
||||
if (x.value.value_integer.neg) {
|
||||
if (big_int_is_neg(&x.value.value_integer)) {
|
||||
error(call, "Negative array element length");
|
||||
operand->mode = Addressing_Type;
|
||||
operand->type = t_invalid;
|
||||
|
||||
@@ -1503,13 +1503,13 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
|
||||
big_int_from_i64(&bi127, 127);
|
||||
|
||||
big_int_shl_eq(&umax, &bi128);
|
||||
big_int_sub_eq(&umax, &BIG_INT_ONE);
|
||||
mp_decr(&umax);
|
||||
|
||||
big_int_shl_eq(&imin, &bi127);
|
||||
big_int_neg(&imin, &imin);
|
||||
|
||||
big_int_shl_eq(&imax, &bi127);
|
||||
big_int_sub_eq(&imax, &BIG_INT_ONE);
|
||||
mp_decr(&imax);
|
||||
}
|
||||
|
||||
switch (type->Basic.kind) {
|
||||
@@ -1555,7 +1555,7 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
|
||||
{
|
||||
// return 0ull <= i && i <= umax;
|
||||
int b = big_int_cmp(&i, &umax);
|
||||
return !i.neg && (b <= 0);
|
||||
return !i.sign && (b <= 0);
|
||||
}
|
||||
|
||||
case Basic_UntypedInteger:
|
||||
@@ -1758,12 +1758,6 @@ void check_is_expressible(CheckerContext *ctx, Operand *o, Type *type) {
|
||||
if (!is_type_integer(o->type) && is_type_integer(type)) {
|
||||
error(o->expr, "'%s' truncated to '%s'", a, b);
|
||||
} else {
|
||||
#if 0
|
||||
gb_printf_err("AddressingMode, %d\n", o->mode);
|
||||
gb_printf_err("ExactValueKind, %d\n", o->value.kind);
|
||||
bool ok = check_representable_as_constant(ctx, o->value, type, &out_value);
|
||||
gb_printf_err("ok, %d\n", ok);
|
||||
#endif
|
||||
error(o->expr, "Cannot convert numeric value '%s' to '%s' from '%s", a, b, c);
|
||||
check_assignment_error_suggestion(ctx, o, type);
|
||||
}
|
||||
@@ -2206,7 +2200,7 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ
|
||||
}
|
||||
|
||||
BigInt max_shift = {};
|
||||
big_int_from_u64(&max_shift, 128);
|
||||
big_int_from_u64(&max_shift, MAX_BIG_INT_SHIFT);
|
||||
|
||||
if (big_int_cmp(&y_val.value_integer, &max_shift) > 0) {
|
||||
gbString err_str = expr_to_string(y->expr);
|
||||
@@ -2248,7 +2242,7 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ
|
||||
}
|
||||
}
|
||||
|
||||
if (y->mode == Addressing_Constant && y->value.value_integer.neg) {
|
||||
if (y->mode == Addressing_Constant && big_int_is_neg(&y->value.value_integer)) {
|
||||
gbString err_str = expr_to_string(y->expr);
|
||||
error(node, "Shift amount cannot be negative: '%s'", err_str);
|
||||
gb_string_free(err_str);
|
||||
@@ -3320,7 +3314,7 @@ bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64
|
||||
if (operand.mode == Addressing_Constant &&
|
||||
(c->state_flags & StateFlag_no_bounds_check) == 0) {
|
||||
BigInt i = exact_value_to_integer(operand.value).value_integer;
|
||||
if (i.neg && !is_type_enum(index_type)) {
|
||||
if (i.sign && !is_type_enum(index_type)) {
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
error(operand.expr, "Index '%s' cannot be a negative value", expr_str);
|
||||
gb_string_free(expr_str);
|
||||
@@ -3366,7 +3360,7 @@ bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64
|
||||
|
||||
} else { // NOTE(bill): Do array bound checking
|
||||
i64 v = -1;
|
||||
if (i.len <= 1) {
|
||||
if (i.used <= 1) {
|
||||
v = big_int_to_i64(&i);
|
||||
}
|
||||
if (value) *value = v;
|
||||
|
||||
@@ -207,7 +207,7 @@ bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) {
|
||||
if (is_type_untyped(type) || is_type_integer(type)) {
|
||||
if (o.value.kind == ExactValue_Integer) {
|
||||
BigInt v = o.value.value_integer;
|
||||
if (v.len > 1) {
|
||||
if (v.used > 1) {
|
||||
gbAllocator a = heap_allocator();
|
||||
String str = big_int_to_string(a, &v);
|
||||
error(node, "#align too large, %.*s", LIT(str));
|
||||
@@ -1998,16 +1998,16 @@ i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
|
||||
if (is_type_untyped(type) || is_type_integer(type)) {
|
||||
if (o->value.kind == ExactValue_Integer) {
|
||||
BigInt count = o->value.value_integer;
|
||||
if (o->value.value_integer.neg) {
|
||||
if (big_int_is_neg(&o->value.value_integer)) {
|
||||
gbAllocator a = heap_allocator();
|
||||
String str = big_int_to_string(a, &count);
|
||||
error(e, "Invalid negative array count, %.*s", LIT(str));
|
||||
gb_free(a, str.text);
|
||||
return 0;
|
||||
}
|
||||
switch (count.len) {
|
||||
switch (count.used) {
|
||||
case 0: return 0;
|
||||
case 1: return count.d.word;
|
||||
case 1: return big_int_to_u64(&count);
|
||||
}
|
||||
gbAllocator a = heap_allocator();
|
||||
String str = big_int_to_string(a, &count);
|
||||
|
||||
@@ -75,8 +75,8 @@ HashKey hash_exact_value(ExactValue v) {
|
||||
}
|
||||
case ExactValue_Integer:
|
||||
{
|
||||
HashKey key = hashing_proc(big_int_ptr(&v.value_integer), v.value_integer.len * gb_size_of(u64));
|
||||
u8 last = (u8)v.value_integer.neg;
|
||||
HashKey key = hashing_proc(v.value_integer.dp, gb_size_of(*v.value_integer.dp) * v.value_integer.used);
|
||||
u8 last = (u8)v.value_integer.sign;
|
||||
key.key = (key.key ^ last) * 0x100000001b3ll;
|
||||
return key;
|
||||
}
|
||||
@@ -719,7 +719,6 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
|
||||
case Token_Shr: big_int_shr(&c, a, b); break;
|
||||
default: goto error;
|
||||
}
|
||||
big_int_normalize(&c);
|
||||
ExactValue res = {ExactValue_Integer};
|
||||
res.value_integer = c;
|
||||
return res;
|
||||
|
||||
@@ -1,744 +0,0 @@
|
||||
|
||||
#if defined(GB_COMPILER_MSVC) && defined(GB_ARCH_64_BIT) && defined(GB_CPU_X86)
|
||||
#define MSVC_AMD64_INTRINSICS
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_mul128)
|
||||
#endif
|
||||
|
||||
#define BIT128_U64_HIGHBIT 0x8000000000000000ull
|
||||
#define BIT128_U64_BITS62 0x7fffffffffffffffull
|
||||
#define BIT128_U64_ALLBITS 0xffffffffffffffffull
|
||||
|
||||
|
||||
typedef struct u128 { u64 lo; u64 hi; } u128;
|
||||
typedef struct i128 { u64 lo; i64 hi; } i128;
|
||||
|
||||
|
||||
static u128 const U128_ZERO = {0, 0};
|
||||
static u128 const U128_ONE = {1, 0};
|
||||
static i128 const I128_ZERO = {0, 0};
|
||||
static i128 const I128_ONE = {1, 0};
|
||||
static u128 const U128_NEG_ONE = {BIT128_U64_ALLBITS, BIT128_U64_ALLBITS};
|
||||
static i128 const I128_NEG_ONE = {BIT128_U64_ALLBITS, cast(i64)BIT128_U64_ALLBITS};
|
||||
|
||||
u128 u128_lo_hi (u64 lo, u64 hi);
|
||||
u128 u128_from_u32 (u32 u);
|
||||
u128 u128_from_u64 (u64 u);
|
||||
u128 u128_from_i64 (i64 u);
|
||||
u128 u128_from_f32 (f32 f);
|
||||
u128 u128_from_f64 (f64 f);
|
||||
u128 u128_from_string(String string);
|
||||
|
||||
i128 i128_lo_hi (u64 lo, i64 hi);
|
||||
i128 i128_from_u32 (u32 u);
|
||||
i128 i128_from_u64 (u64 u);
|
||||
i128 i128_from_i64 (i64 u);
|
||||
i128 i128_from_f32 (f32 f);
|
||||
i128 i128_from_f64 (f64 f);
|
||||
i128 i128_from_string(String string);
|
||||
|
||||
u64 u128_to_u64(u128 a);
|
||||
i64 u128_to_i64(u128 a);
|
||||
f64 u128_to_f64(u128 a);
|
||||
i128 u128_to_i128(u128 a);
|
||||
|
||||
u64 i128_to_u64(i128 a);
|
||||
i64 i128_to_i64(i128 a);
|
||||
f64 i128_to_f64(i128 a);
|
||||
u128 i128_to_u128(i128 a);
|
||||
|
||||
String u128_to_string(u128 a, char *buf, isize len);
|
||||
String i128_to_string(i128 a, char *buf, isize len);
|
||||
|
||||
i32 u128_cmp (u128 a, u128 b);
|
||||
bool u128_eq (u128 a, u128 b);
|
||||
bool u128_ne (u128 a, u128 b);
|
||||
bool u128_lt (u128 a, u128 b);
|
||||
bool u128_gt (u128 a, u128 b);
|
||||
bool u128_le (u128 a, u128 b);
|
||||
bool u128_ge (u128 a, u128 b);
|
||||
u128 u128_add (u128 a, u128 b);
|
||||
u128 u128_not (u128 a);
|
||||
u128 u128_neg (u128 a);
|
||||
u128 u128_sub (u128 a, u128 b);
|
||||
u128 u128_and (u128 a, u128 b);
|
||||
u128 u128_or (u128 a, u128 b);
|
||||
u128 u128_xor (u128 a, u128 b);
|
||||
u128 u128_and_not(u128 a, u128 b);
|
||||
u128 u128_shl (u128 a, u32 n);
|
||||
u128 u128_shr (u128 a, u32 n);
|
||||
u128 u128_mul (u128 a, u128 b);
|
||||
void u128_divide (u128 num, u128 den, u128 *quo, u128 *rem);
|
||||
u128 u128_quo (u128 a, u128 b);
|
||||
u128 u128_mod (u128 a, u128 b);
|
||||
|
||||
i128 i128_abs (i128 a);
|
||||
i32 i128_cmp (i128 a, i128 b);
|
||||
bool i128_eq (i128 a, i128 b);
|
||||
bool i128_ne (i128 a, i128 b);
|
||||
bool i128_lt (i128 a, i128 b);
|
||||
bool i128_gt (i128 a, i128 b);
|
||||
bool i128_le (i128 a, i128 b);
|
||||
bool i128_ge (i128 a, i128 b);
|
||||
i128 i128_add (i128 a, i128 b);
|
||||
i128 i128_not (i128 a);
|
||||
i128 i128_neg (i128 a);
|
||||
i128 i128_sub (i128 a, i128 b);
|
||||
i128 i128_and (i128 a, i128 b);
|
||||
i128 i128_or (i128 a, i128 b);
|
||||
i128 i128_xor (i128 a, i128 b);
|
||||
i128 i128_and_not(i128 a, i128 b);
|
||||
i128 i128_shl (i128 a, u32 n);
|
||||
i128 i128_shr (i128 a, u32 n);
|
||||
i128 i128_mul (i128 a, i128 b);
|
||||
void i128_divide (i128 num, i128 den, i128 *quo, i128 *rem);
|
||||
i128 i128_quo (i128 a, i128 b);
|
||||
i128 i128_mod (i128 a, i128 b);
|
||||
|
||||
bool operator==(u128 const &a, u128 const &b) { return u128_eq(a, b); }
|
||||
bool operator!=(u128 const &a, u128 const &b) { return u128_ne(a, b); }
|
||||
bool operator< (u128 const &a, u128 const &b) { return u128_lt(a, b); }
|
||||
bool operator> (u128 const &a, u128 const &b) { return u128_gt(a, b); }
|
||||
bool operator<=(u128 const &a, u128 const &b) { return u128_le(a, b); }
|
||||
bool operator>=(u128 const &a, u128 const &b) { return u128_ge(a, b); }
|
||||
|
||||
u128 operator+ (u128 const &a, u128 const &b) { return u128_add(a, b); }
|
||||
u128 operator- (u128 const &a, u128 const &b) { return u128_sub(a, b); }
|
||||
u128 operator* (u128 const &a, u128 const &b) { return u128_mul(a, b); }
|
||||
u128 operator/ (u128 const &a, u128 const &b) { return u128_quo(a, b); }
|
||||
u128 operator% (u128 const &a, u128 const &b) { return u128_mod(a, b); }
|
||||
u128 operator& (u128 const &a, u128 const &b) { return u128_and(a, b); }
|
||||
u128 operator| (u128 const &a, u128 const &b) { return u128_or (a, b); }
|
||||
u128 operator^ (u128 const &a, u128 const &b) { return u128_xor(a, b); }
|
||||
u128 operator~ (u128 const &a) { return u128_not(a); }
|
||||
u128 operator+ (u128 const &a) { return a; }
|
||||
u128 operator- (u128 const &a) { return u128_neg(a); }
|
||||
u128 operator<<(u128 const &a, u32 const &b) { return u128_shl(a, b); }
|
||||
u128 operator>>(u128 const &a, u32 const &b) { return u128_shr(a, b); }
|
||||
|
||||
|
||||
bool operator==(i128 const &a, i128 const &b) { return i128_eq(a, b); }
|
||||
bool operator!=(i128 const &a, i128 const &b) { return i128_ne(a, b); }
|
||||
bool operator< (i128 const &a, i128 const &b) { return i128_lt(a, b); }
|
||||
bool operator> (i128 const &a, i128 const &b) { return i128_gt(a, b); }
|
||||
bool operator<=(i128 const &a, i128 const &b) { return i128_le(a, b); }
|
||||
bool operator>=(i128 const &a, i128 const &b) { return i128_ge(a, b); }
|
||||
|
||||
i128 operator+ (i128 const &a, i128 const &b) { return i128_add(a, b); }
|
||||
i128 operator- (i128 const &a, i128 const &b) { return i128_sub(a, b); }
|
||||
i128 operator* (i128 const &a, i128 const &b) { return i128_mul(a, b); }
|
||||
i128 operator/ (i128 const &a, i128 const &b) { return i128_quo(a, b); }
|
||||
i128 operator% (i128 const &a, i128 const &b) { return i128_mod(a, b); }
|
||||
i128 operator& (i128 const &a, i128 const &b) { return i128_and(a, b); }
|
||||
i128 operator| (i128 const &a, i128 const &b) { return i128_or (a, b); }
|
||||
i128 operator^ (i128 const &a, i128 const &b) { return i128_xor(a, b); }
|
||||
i128 operator~ (i128 const &a) { return i128_not(a); }
|
||||
i128 operator+ (i128 const &a) { return a; }
|
||||
i128 operator- (i128 const &a) { return i128_neg(a); }
|
||||
i128 operator<<(i128 const &a, u32 b) { return i128_shl(a, b); }
|
||||
i128 operator>>(i128 const &a, u32 b) { return i128_shr(a, b); }
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
u64 bit128__digit_value(Rune r) {
|
||||
if ('0' <= r && r <= '9') {
|
||||
return r - '0';
|
||||
} else if ('a' <= r && r <= 'f') {
|
||||
return r - 'a' + 10;
|
||||
} else if ('A' <= r && r <= 'F') {
|
||||
return r - 'A' + 10;
|
||||
}
|
||||
return 16; // NOTE(bill): Larger than highest possible
|
||||
}
|
||||
|
||||
u128 u128_lo_hi(u64 lo, u64 hi) {
|
||||
u128 r = {};
|
||||
r.lo = lo;
|
||||
r.hi = hi;
|
||||
return r;
|
||||
}
|
||||
u128 u128_from_u32(u32 u) { return u128_lo_hi(cast(u64)u, 0); }
|
||||
u128 u128_from_u64(u64 u) { return u128_lo_hi(cast(u64)u, 0); }
|
||||
u128 u128_from_i64(i64 u) { return u128_lo_hi(cast(u64)u, u < 0 ? -1 : 0); }
|
||||
u128 u128_from_f32(f32 f) { return u128_lo_hi(cast(u64)f, 0); }
|
||||
u128 u128_from_f64(f64 f) { return u128_lo_hi(cast(u64)f, 0); }
|
||||
u128 u128_from_string(String string) {
|
||||
// TODO(bill): Allow for numbers with underscores in them
|
||||
u64 base = 10;
|
||||
bool has_prefix = false;
|
||||
if (string.len > 2 && string[0] == '0') {
|
||||
switch (string[1]) {
|
||||
case 'b': base = 2; has_prefix = true; break;
|
||||
case 'o': base = 8; has_prefix = true; break;
|
||||
case 'd': base = 10; has_prefix = true; break;
|
||||
case 'z': base = 12; has_prefix = true; break;
|
||||
case 'x': base = 16; has_prefix = true; break;
|
||||
}
|
||||
}
|
||||
|
||||
u8 *text = string.text;
|
||||
isize len = string.len;
|
||||
if (has_prefix) {
|
||||
text += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
u128 base_ = u128_from_u64(base);
|
||||
|
||||
u128 result = {0};
|
||||
for (isize i = 0; i < len; i++) {
|
||||
Rune r = cast(Rune)text[i];
|
||||
if (r == '_') {
|
||||
continue;
|
||||
}
|
||||
u64 v = bit128__digit_value(r);
|
||||
if (v >= base) {
|
||||
break;
|
||||
}
|
||||
result = u128_mul(result, base_);
|
||||
result = u128_add(result, u128_from_u64(v));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
i128 i128_lo_hi(u64 lo, i64 hi) {
|
||||
i128 i;
|
||||
i.lo = lo;
|
||||
i.hi = hi;
|
||||
return i;
|
||||
}
|
||||
i128 i128_from_u32(u32 u) { return i128_lo_hi(cast(u64)u, 0); }
|
||||
i128 i128_from_u64(u64 u) { return i128_lo_hi(cast(u64)u, 0); }
|
||||
i128 i128_from_i64(i64 u) { return i128_lo_hi(cast(u64)u, u < 0 ? -1 : 0); }
|
||||
i128 i128_from_f32(f32 f) { return i128_lo_hi(cast(u64)f, 0); }
|
||||
i128 i128_from_f64(f64 f) { return i128_lo_hi(cast(u64)f, 0); }
|
||||
i128 i128_from_string(String string) {
|
||||
// TODO(bill): Allow for numbers with underscores in them
|
||||
u64 base = 10;
|
||||
bool has_prefix = false;
|
||||
if (string.len > 2 && string[0] == '0') {
|
||||
switch (string[1]) {
|
||||
case 'b': base = 2; has_prefix = true; break;
|
||||
case 'o': base = 8; has_prefix = true; break;
|
||||
case 'd': base = 10; has_prefix = true; break;
|
||||
case 'z': base = 12; has_prefix = true; break;
|
||||
case 'x': base = 16; has_prefix = true; break;
|
||||
}
|
||||
}
|
||||
|
||||
u8 *text = string.text;
|
||||
isize len = string.len;
|
||||
if (has_prefix) {
|
||||
text += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
i128 base_ = i128_from_u64(base);
|
||||
|
||||
i128 result = {0};
|
||||
for (isize i = 0; i < len; i++) {
|
||||
Rune r = cast(Rune)text[i];
|
||||
if (r == '_') {
|
||||
continue;
|
||||
}
|
||||
u64 v = bit128__digit_value(r);
|
||||
if (v >= base) {
|
||||
break;
|
||||
}
|
||||
result = i128_mul(result, base_);
|
||||
result = i128_add(result, i128_from_u64(v));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
u64 u128_to_u64(u128 a) {
|
||||
return (a.lo&BIT128_U64_BITS62) | (a.hi&BIT128_U64_HIGHBIT);
|
||||
}
|
||||
i64 u128_to_i64(u128 a) {
|
||||
return a.lo;
|
||||
}
|
||||
f64 u128_to_f64(u128 a) {
|
||||
if (a.hi >= 0) {
|
||||
return (cast(f64)a.hi * 18446744073709551616.0) + cast(f64)a.lo;
|
||||
}
|
||||
i64 h = cast(i64)a.hi;
|
||||
u64 l = a.lo;
|
||||
h = ~h;
|
||||
l = ~l;
|
||||
l += 1;
|
||||
if (l == 0) {
|
||||
h += 1;
|
||||
}
|
||||
|
||||
return -((cast(f64)h * 18446744073709551616.0) + cast(f64)l);
|
||||
}
|
||||
i128 u128_to_i128(u128 a) {
|
||||
return bit_cast<i128>(a);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
u64 i128_to_u64(i128 a) {
|
||||
return (a.lo&BIT128_U64_BITS62) | (a.hi&BIT128_U64_HIGHBIT);
|
||||
}
|
||||
i64 i128_to_i64(i128 a) {
|
||||
return cast(i64)a.lo;
|
||||
}
|
||||
f64 i128_to_f64(i128 a) {
|
||||
if (a.hi >= 0) {
|
||||
return (cast(f64)a.hi * 18446744073709551616.0) + cast(f64)a.lo;
|
||||
}
|
||||
i64 h = a.hi;
|
||||
u64 l = a.lo;
|
||||
h = ~h;
|
||||
l = ~l;
|
||||
l += 1;
|
||||
if (l == 0) {
|
||||
h += 1;
|
||||
}
|
||||
|
||||
return -((cast(f64)h * 18446744073709551616.0) + cast(f64)l);
|
||||
}
|
||||
u128 i128_to_u128(i128 a) {
|
||||
return bit_cast<u128>(a);
|
||||
}
|
||||
|
||||
|
||||
|
||||
String u128_to_string(u128 v, char *out_buf, isize out_buf_len) {
|
||||
char buf[200] = {0};
|
||||
isize i = gb_size_of(buf);
|
||||
|
||||
u128 b = u128_from_u64(10);;
|
||||
while (u128_ge(v, b)) {
|
||||
buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))];
|
||||
v = u128_quo(v, b);
|
||||
}
|
||||
buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))];
|
||||
|
||||
isize len = gb_min(gb_size_of(buf)-i, out_buf_len);
|
||||
gb_memmove(out_buf, &buf[i], len);
|
||||
return make_string(cast(u8 *)out_buf, len);
|
||||
}
|
||||
String i128_to_string(i128 a, char *out_buf, isize out_buf_len) {
|
||||
char buf[200] = {0};
|
||||
isize i = gb_size_of(buf);
|
||||
bool negative = false;
|
||||
if (i128_lt(a, I128_ZERO)) {
|
||||
negative = true;
|
||||
a = i128_neg(a);
|
||||
}
|
||||
|
||||
u128 v = bit_cast<u128>(a);
|
||||
u128 b = u128_from_u64(10);;
|
||||
while (u128_ge(v, b)) {
|
||||
buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))];
|
||||
v = u128_quo(v, b);
|
||||
}
|
||||
buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))];
|
||||
|
||||
if (negative) {
|
||||
buf[--i] = '-';
|
||||
}
|
||||
|
||||
isize len = gb_min(gb_size_of(buf)-i, out_buf_len);
|
||||
gb_memmove(out_buf, &buf[i], len);
|
||||
return make_string(cast(u8 *)out_buf, len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
i32 u128_cmp(u128 a, u128 b) {
|
||||
if (a.hi == b.hi && b.lo == b.lo) {
|
||||
return 0;
|
||||
}
|
||||
if (a.hi == b.hi) {
|
||||
return a.lo < b.lo ? -1 : +1;
|
||||
}
|
||||
return a.hi < b.hi ? -1 : +1;
|
||||
}
|
||||
|
||||
bool u128_eq(u128 a, u128 b) { return a.hi == b.hi && a.lo == b.lo; }
|
||||
bool u128_ne(u128 a, u128 b) { return !u128_eq(a, b); }
|
||||
bool u128_lt(u128 a, u128 b) { return a.hi == b.hi ? a.lo < b.lo : a.hi < b.hi; }
|
||||
bool u128_gt(u128 a, u128 b) { return a.hi == b.hi ? a.lo > b.lo : a.hi > b.hi; }
|
||||
bool u128_le(u128 a, u128 b) { return !u128_gt(a, b); }
|
||||
bool u128_ge(u128 a, u128 b) { return !u128_lt(a, b); }
|
||||
|
||||
u128 u128_add(u128 a, u128 b) {
|
||||
u128 old_a = a;
|
||||
a.lo += b.lo;
|
||||
a.hi += b.hi;
|
||||
if (a.lo < old_a.lo) {
|
||||
a.hi += 1;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
u128 u128_not(u128 a) { return u128_lo_hi(~a.lo, ~a.hi); }
|
||||
|
||||
u128 u128_neg(u128 a) {
|
||||
return u128_add(u128_not(a), u128_from_u64(1));
|
||||
}
|
||||
u128 u128_sub(u128 a, u128 b) {
|
||||
return u128_add(a, u128_neg(b));
|
||||
}
|
||||
u128 u128_and(u128 a, u128 b) { return u128_lo_hi(a.lo&b.lo, a.hi&b.hi); }
|
||||
u128 u128_or (u128 a, u128 b) { return u128_lo_hi(a.lo|b.lo, a.hi|b.hi); }
|
||||
u128 u128_xor(u128 a, u128 b) { return u128_lo_hi(a.lo^b.lo, a.hi^b.hi); }
|
||||
u128 u128_and_not(u128 a, u128 b) { return u128_lo_hi(a.lo&(~b.lo), a.hi&(~b.hi)); }
|
||||
|
||||
|
||||
u128 u128_shl(u128 a, u32 n) {
|
||||
if (n >= 128) {
|
||||
return u128_lo_hi(0, 0);
|
||||
}
|
||||
#if 0 && defined(MSVC_AMD64_INTRINSICS)
|
||||
a.hi = __shiftleft128(a.lo, a.hi, n);
|
||||
a.lo = a.lo << n;
|
||||
return a;
|
||||
#else
|
||||
if (n >= 64) {
|
||||
n -= 64;
|
||||
a.hi = a.lo;
|
||||
a.lo = 0;
|
||||
}
|
||||
|
||||
if (n != 0) {
|
||||
u64 mask = ~(BIT128_U64_ALLBITS >> n);
|
||||
|
||||
a.hi <<= n;
|
||||
a.hi |= (a.lo&mask) >> (64 - n);
|
||||
a.lo <<= n;
|
||||
}
|
||||
return a;
|
||||
#endif
|
||||
}
|
||||
|
||||
u128 u128_shr(u128 a, u32 n) {
|
||||
if (n >= 128) {
|
||||
return u128_lo_hi(0, 0);
|
||||
}
|
||||
#if 0 && defined(MSVC_AMD64_INTRINSICS)
|
||||
a.lo = __shiftright128(a.lo, a.hi, n);
|
||||
a.hi = a.hi >> n;
|
||||
return a;
|
||||
#else
|
||||
if (n >= 64) {
|
||||
n -= 64;
|
||||
a.lo = a.hi;
|
||||
a.hi = 0;
|
||||
}
|
||||
|
||||
if (n != 0) {
|
||||
u64 mask = ~(BIT128_U64_ALLBITS << n);
|
||||
a.lo >>= n;
|
||||
a.lo |= (a.hi&mask) << (64 - n);
|
||||
a.hi >>= n;
|
||||
}
|
||||
return a;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
u128 u128_mul(u128 a, u128 b) {
|
||||
if (a.lo == 0 && a.hi == 0) {
|
||||
return u128_from_u64(0);
|
||||
} else if (b.lo == 0 && b.hi == 0) {
|
||||
return u128_from_u64(0);
|
||||
}
|
||||
if (u128_eq(a, U128_ONE)) {
|
||||
return b;
|
||||
}
|
||||
if (u128_eq(b, U128_ONE)) {
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
#if defined(MSVC_AMD64_INTRINSICS)
|
||||
if (a.hi == 0 && b.hi == 0) {
|
||||
a.lo = _umul128(a.lo, b.lo, &a.hi);
|
||||
return a;
|
||||
}
|
||||
#endif
|
||||
|
||||
u128 res = {0};
|
||||
u128 t = b;
|
||||
for (u32 i = 0; i < 128; i++) {
|
||||
if ((t.lo&1) != 0) {
|
||||
res = u128_add(res, u128_shl(a, i));
|
||||
}
|
||||
|
||||
t = u128_shr(t, 1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool u128_hibit(u128 const &d) { return (d.hi & BIT128_U64_HIGHBIT) != 0; }
|
||||
bool i128_hibit(i128 const &d) { return d.hi < 0; }
|
||||
|
||||
void u128_divide(u128 a, u128 b, u128 *quo, u128 *rem) {
|
||||
if (u128_eq(b, U128_ZERO)) {
|
||||
if (quo) *quo = u128_from_u64(a.lo/b.lo);
|
||||
if (rem) *rem = U128_ZERO;
|
||||
return;
|
||||
}
|
||||
if (a.hi == 0 && b.hi == 0) {
|
||||
if (quo) *quo = u128_from_u64(a.lo/b.lo);
|
||||
if (rem) *rem = u128_from_u64(a.lo%b.lo);
|
||||
return;
|
||||
}
|
||||
u128 r = a;
|
||||
u128 d = b;
|
||||
u128 x = U128_ONE;
|
||||
u128 q = U128_ZERO;
|
||||
|
||||
while (u128_ge(r, d) && !u128_hibit(d)) {
|
||||
x = u128_shl(x, 1);
|
||||
d = u128_shl(d, 1);
|
||||
}
|
||||
|
||||
while (u128_ne(x, U128_ZERO)) {
|
||||
if (u128_ge(r, d)) {
|
||||
r = u128_sub(r, d);
|
||||
q = u128_or(q, x);
|
||||
}
|
||||
|
||||
x = u128_shr(x, 1);
|
||||
d = u128_shr(d, 1);
|
||||
}
|
||||
|
||||
if (quo) *quo = q;
|
||||
if (rem) *rem = r;
|
||||
}
|
||||
|
||||
u128 u128_quo(u128 a, u128 b) {
|
||||
if (a.hi == 0 && b.hi == 0) {
|
||||
return u128_from_u64(a.lo/b.lo);
|
||||
}
|
||||
|
||||
u128 res = {0};
|
||||
u128_divide(a, b, &res, nullptr);
|
||||
return res;
|
||||
}
|
||||
u128 u128_mod(u128 a, u128 b) {
|
||||
if (a.hi == 0 && b.hi == 0) {
|
||||
return u128_from_u64(a.lo%b.lo);
|
||||
}
|
||||
u128 res = {0};
|
||||
u128_divide(a, b, nullptr, &res);
|
||||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
i128 i128_abs(i128 a) {
|
||||
if ((a.hi&BIT128_U64_HIGHBIT) != 0) {
|
||||
return i128_neg(a);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
i32 i128_cmp(i128 a, i128 b) {
|
||||
if (a.hi == b.hi && b.lo == b.lo) {
|
||||
return 0;
|
||||
}
|
||||
if (a.hi == b.hi) {
|
||||
return a.lo < b.lo ? -1 : +1;
|
||||
}
|
||||
return a.hi < b.hi ? -1 : +1;
|
||||
}
|
||||
|
||||
bool i128_eq(i128 a, i128 b) { return a.hi == b.hi && a.lo == b.lo; }
|
||||
bool i128_ne(i128 a, i128 b) { return !i128_eq(a, b); }
|
||||
bool i128_lt(i128 a, i128 b) { return a.hi == b.hi ? a.lo < b.lo : a.hi < b.hi; }
|
||||
bool i128_gt(i128 a, i128 b) { return a.hi == b.hi ? a.lo > b.lo : a.hi > b.hi; }
|
||||
bool i128_le(i128 a, i128 b) { return a.hi == b.hi ? a.lo <= b.lo : a.hi <= b.hi; }
|
||||
bool i128_ge(i128 a, i128 b) { return a.hi == b.hi ? a.lo >= b.lo : a.hi >= b.hi; }
|
||||
|
||||
i128 i128_add(i128 a, i128 b) {
|
||||
i128 old_a = a;
|
||||
a.lo += b.lo;
|
||||
a.hi += b.hi;
|
||||
if (a.lo < old_a.lo) {
|
||||
a.hi += 1;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
i128 i128_not(i128 a) { return i128_lo_hi(~a.lo, ~a.hi); }
|
||||
|
||||
i128 i128_neg(i128 a) {
|
||||
return i128_add(i128_not(a), i128_from_u64(1));
|
||||
}
|
||||
i128 i128_sub(i128 a, i128 b) {
|
||||
return i128_add(a, i128_neg(b));
|
||||
}
|
||||
i128 i128_and(i128 a, i128 b) { return i128_lo_hi(a.lo&b.lo, a.hi&b.hi); }
|
||||
i128 i128_or (i128 a, i128 b) { return i128_lo_hi(a.lo|b.lo, a.hi|b.hi); }
|
||||
i128 i128_xor(i128 a, i128 b) { return i128_lo_hi(a.lo^b.lo, a.hi^b.hi); }
|
||||
i128 i128_and_not(i128 a, i128 b) { return i128_lo_hi(a.lo&(~b.lo), a.hi&(~b.hi)); }
|
||||
|
||||
|
||||
i128 i128_shl(i128 a, u32 n) {
|
||||
if (n >= 128) {
|
||||
return i128_lo_hi(0, 0);
|
||||
}
|
||||
|
||||
#if 0 && defined(MSVC_AMD64_INTRINSICS)
|
||||
a.hi = __shiftleft128(a.lo, a.hi, n);
|
||||
a.lo = a.lo << n;
|
||||
return a;
|
||||
#else
|
||||
if (n >= 64) {
|
||||
n -= 64;
|
||||
a.hi = a.lo;
|
||||
a.lo = 0;
|
||||
}
|
||||
|
||||
if (n != 0) {
|
||||
u64 mask = ~(BIT128_U64_ALLBITS >> n);
|
||||
|
||||
a.hi <<= n;
|
||||
a.hi |= (a.lo&mask) >> (64 - n);
|
||||
a.lo <<= n;
|
||||
}
|
||||
return a;
|
||||
#endif
|
||||
}
|
||||
|
||||
i128 i128_shr(i128 a, u32 n) {
|
||||
if (n >= 128) {
|
||||
return i128_lo_hi(0, 0);
|
||||
}
|
||||
|
||||
#if 0 && defined(MSVC_AMD64_INTRINSICS)
|
||||
a.lo = __shiftright128(a.lo, a.hi, n);
|
||||
a.hi = a.hi >> n;
|
||||
return a;
|
||||
#else
|
||||
if (n >= 64) {
|
||||
n -= 64;
|
||||
a.lo = a.hi;
|
||||
a.hi = 0;
|
||||
}
|
||||
|
||||
if (n != 0) {
|
||||
u64 mask = ~(BIT128_U64_ALLBITS << n);
|
||||
a.lo >>= n;
|
||||
a.lo |= (a.hi&mask) << (64 - n);
|
||||
a.hi >>= n;
|
||||
}
|
||||
return a;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
i128 i128_mul(i128 a, i128 b) {
|
||||
if (a.lo == 0 && a.hi == 0) {
|
||||
return i128_from_u64(0);
|
||||
} else if (b.lo == 0 && b.hi == 0) {
|
||||
return i128_from_u64(0);
|
||||
}
|
||||
if (i128_eq(a, I128_ONE)) {
|
||||
return b;
|
||||
}
|
||||
if (i128_eq(b, I128_ONE)) {
|
||||
return a;
|
||||
}
|
||||
|
||||
#if defined(MSVC_AMD64_INTRINSICS)
|
||||
if (a.hi == 0 && b.hi == 0) {
|
||||
a.lo = _mul128(a.lo, b.lo, &a.hi);
|
||||
return a;
|
||||
}
|
||||
#endif
|
||||
|
||||
i128 res = {0};
|
||||
i128 t = b;
|
||||
for (u32 i = 0; i < 128; i++) {
|
||||
if ((t.lo&1) != 0) {
|
||||
res = i128_add(res, i128_shl(a, i));
|
||||
}
|
||||
|
||||
t = i128_shr(t, 1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void i128_divide(i128 a, i128 b, i128 *quo_, i128 *rem_) {
|
||||
// IMPORTANT TODO(bill): Optimize this i128 division calculation
|
||||
i128 iquo = {0};
|
||||
i128 irem = {0};
|
||||
if (a.hi == 0 && b.hi == 0) {
|
||||
u64 q = a.lo / b.lo;
|
||||
u64 r = a.lo % b.lo;
|
||||
iquo = i128_from_u64(q);
|
||||
irem = i128_from_u64(r);
|
||||
} else if ((~a.hi) == 0 && (~b.hi) == 0) {
|
||||
i64 x = i128_to_i64(a);
|
||||
i64 y = i128_to_i64(b);
|
||||
i64 q = x / y;
|
||||
i64 r = x % y;
|
||||
iquo = i128_from_i64(q);
|
||||
irem = i128_from_i64(r);
|
||||
} else if (a.hi > 0 || b.hi > 0) {
|
||||
u128 q, r = {0};
|
||||
u128_divide(bit_cast<u128>(a), bit_cast<u128>(b), &q, &r);
|
||||
iquo = bit_cast<i128>(q);
|
||||
irem = bit_cast<i128>(r);
|
||||
} else if (i128_eq(b, I128_ZERO)) {
|
||||
iquo = i128_from_u64(a.lo/b.lo);
|
||||
} else {
|
||||
i32 rem_sign = 1;
|
||||
i32 quo_sign = 1;
|
||||
if (i128_lt(a, I128_ZERO)) {
|
||||
a = i128_neg(a);
|
||||
rem_sign = -1;
|
||||
}
|
||||
if (i128_lt(b, I128_ZERO)) {
|
||||
b = i128_neg(b);
|
||||
quo_sign = -1;
|
||||
}
|
||||
quo_sign *= rem_sign;
|
||||
|
||||
iquo = a;
|
||||
|
||||
for (isize i = 0; i < 128; i++) {
|
||||
irem = i128_shl(irem, 1);
|
||||
if (i128_lt(iquo, I128_ZERO)) {
|
||||
irem.lo |= 1;
|
||||
}
|
||||
iquo = i128_shl(iquo, 1);
|
||||
if (i128_ge(irem, b)) {
|
||||
irem = i128_sub(irem, b);
|
||||
iquo = i128_add(iquo, I128_ONE);
|
||||
}
|
||||
}
|
||||
|
||||
if (quo_sign < 0) iquo = i128_neg(iquo);
|
||||
if (rem_sign < 0) irem = i128_neg(irem);
|
||||
}
|
||||
|
||||
if (quo_) *quo_ = iquo;
|
||||
if (rem_) *rem_ = irem;
|
||||
}
|
||||
|
||||
i128 i128_quo(i128 a, i128 b) {
|
||||
i128 res = {0};
|
||||
i128_divide(a, b, &res, nullptr);
|
||||
return res;
|
||||
}
|
||||
i128 i128_mod(i128 a, i128 b) {
|
||||
i128 res = {0};
|
||||
i128_divide(a, b, nullptr, &res);
|
||||
return res;
|
||||
}
|
||||
154
src/libtommath.cpp
Normal file
154
src/libtommath.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
#include "libtommath/mp_2expt.c"
|
||||
#include "libtommath/mp_abs.c"
|
||||
#include "libtommath/mp_add.c"
|
||||
#include "libtommath/mp_add_d.c"
|
||||
#include "libtommath/mp_addmod.c"
|
||||
#include "libtommath/mp_and.c"
|
||||
#include "libtommath/mp_clamp.c"
|
||||
#include "libtommath/mp_clear.c"
|
||||
#include "libtommath/mp_clear_multi.c"
|
||||
#include "libtommath/mp_cmp.c"
|
||||
#include "libtommath/mp_cmp_d.c"
|
||||
#include "libtommath/mp_cmp_mag.c"
|
||||
#include "libtommath/mp_cnt_lsb.c"
|
||||
#include "libtommath/mp_complement.c"
|
||||
#include "libtommath/mp_copy.c"
|
||||
#include "libtommath/mp_count_bits.c"
|
||||
#include "libtommath/mp_cutoffs.c"
|
||||
#include "libtommath/mp_div.c"
|
||||
#include "libtommath/mp_div_2.c"
|
||||
#include "libtommath/mp_div_2d.c"
|
||||
#include "libtommath/mp_div_d.c"
|
||||
#include "libtommath/mp_dr_is_modulus.c"
|
||||
#include "libtommath/mp_dr_reduce.c"
|
||||
#include "libtommath/mp_dr_setup.c"
|
||||
#include "libtommath/mp_error_to_string.c"
|
||||
#include "libtommath/mp_exch.c"
|
||||
#include "libtommath/mp_expt_n.c"
|
||||
#include "libtommath/mp_exptmod.c"
|
||||
#include "libtommath/mp_exteuclid.c"
|
||||
#include "libtommath/mp_fread.c"
|
||||
#include "libtommath/mp_from_sbin.c"
|
||||
#include "libtommath/mp_from_ubin.c"
|
||||
#include "libtommath/mp_fwrite.c"
|
||||
#include "libtommath/mp_gcd.c"
|
||||
#include "libtommath/mp_get_double.c"
|
||||
#include "libtommath/mp_get_i32.c"
|
||||
#include "libtommath/mp_get_i64.c"
|
||||
#include "libtommath/mp_get_l.c"
|
||||
#include "libtommath/mp_get_mag_u32.c"
|
||||
#include "libtommath/mp_get_mag_u64.c"
|
||||
#include "libtommath/mp_get_mag_ul.c"
|
||||
#include "libtommath/mp_grow.c"
|
||||
#include "libtommath/mp_init.c"
|
||||
#include "libtommath/mp_init_copy.c"
|
||||
#include "libtommath/mp_init_i32.c"
|
||||
#include "libtommath/mp_init_i64.c"
|
||||
#include "libtommath/mp_init_l.c"
|
||||
#include "libtommath/mp_init_multi.c"
|
||||
#include "libtommath/mp_init_set.c"
|
||||
#include "libtommath/mp_init_size.c"
|
||||
#include "libtommath/mp_init_u32.c"
|
||||
#include "libtommath/mp_init_u64.c"
|
||||
#include "libtommath/mp_init_ul.c"
|
||||
#include "libtommath/mp_invmod.c"
|
||||
#include "libtommath/mp_is_square.c"
|
||||
#include "libtommath/mp_kronecker.c"
|
||||
#include "libtommath/mp_lcm.c"
|
||||
#include "libtommath/mp_log_n.c"
|
||||
#include "libtommath/mp_lshd.c"
|
||||
#include "libtommath/mp_mod.c"
|
||||
#include "libtommath/mp_mod_2d.c"
|
||||
#include "libtommath/mp_montgomery_calc_normalization.c"
|
||||
#include "libtommath/mp_montgomery_reduce.c"
|
||||
#include "libtommath/mp_montgomery_setup.c"
|
||||
#include "libtommath/mp_mul.c"
|
||||
#include "libtommath/mp_mul_2.c"
|
||||
#include "libtommath/mp_mul_2d.c"
|
||||
#include "libtommath/mp_mul_d.c"
|
||||
#include "libtommath/mp_mulmod.c"
|
||||
#include "libtommath/mp_neg.c"
|
||||
#include "libtommath/mp_or.c"
|
||||
#include "libtommath/mp_pack.c"
|
||||
#include "libtommath/mp_pack_count.c"
|
||||
// #include "libtommath/mp_prime_fermat.c"
|
||||
// #include "libtommath/mp_prime_frobenius_underwood.c"
|
||||
// #include "libtommath/mp_prime_is_prime.c"
|
||||
// #include "libtommath/mp_prime_miller_rabin.c"
|
||||
// #include "libtommath/mp_prime_next_prime.c"
|
||||
// #include "libtommath/mp_prime_rabin_miller_trials.c"
|
||||
// #include "libtommath/mp_prime_rand.c"
|
||||
// #include "libtommath/mp_prime_strong_lucas_selfridge.c"
|
||||
#include "libtommath/mp_radix_size.c"
|
||||
#include "libtommath/mp_radix_size_overestimate.c"
|
||||
// #include "libtommath/mp_rand.c"
|
||||
// #include "libtommath/mp_rand_source.c"
|
||||
#include "libtommath/mp_read_radix.c"
|
||||
#include "libtommath/mp_reduce.c"
|
||||
#include "libtommath/mp_reduce_2k.c"
|
||||
#include "libtommath/mp_reduce_2k_l.c"
|
||||
#include "libtommath/mp_reduce_2k_setup.c"
|
||||
#include "libtommath/mp_reduce_2k_setup_l.c"
|
||||
#include "libtommath/mp_reduce_is_2k.c"
|
||||
#include "libtommath/mp_reduce_is_2k_l.c"
|
||||
#include "libtommath/mp_reduce_setup.c"
|
||||
#include "libtommath/mp_root_n.c"
|
||||
#include "libtommath/mp_rshd.c"
|
||||
#include "libtommath/mp_sbin_size.c"
|
||||
#include "libtommath/mp_set.c"
|
||||
#include "libtommath/mp_set_double.c"
|
||||
#include "libtommath/mp_set_i32.c"
|
||||
#include "libtommath/mp_set_i64.c"
|
||||
#include "libtommath/mp_set_l.c"
|
||||
#include "libtommath/mp_set_u32.c"
|
||||
#include "libtommath/mp_set_u64.c"
|
||||
#include "libtommath/mp_set_ul.c"
|
||||
#include "libtommath/mp_shrink.c"
|
||||
#include "libtommath/mp_signed_rsh.c"
|
||||
#include "libtommath/mp_sqrmod.c"
|
||||
#include "libtommath/mp_sqrt.c"
|
||||
#include "libtommath/mp_sqrtmod_prime.c"
|
||||
#include "libtommath/mp_sub.c"
|
||||
#include "libtommath/mp_sub_d.c"
|
||||
#include "libtommath/mp_submod.c"
|
||||
#include "libtommath/mp_to_radix.c"
|
||||
#include "libtommath/mp_to_sbin.c"
|
||||
#include "libtommath/mp_to_ubin.c"
|
||||
#include "libtommath/mp_ubin_size.c"
|
||||
#include "libtommath/mp_unpack.c"
|
||||
#include "libtommath/mp_xor.c"
|
||||
#include "libtommath/mp_zero.c"
|
||||
#include "libtommath/s_mp_add.c"
|
||||
#include "libtommath/s_mp_copy_digs.c"
|
||||
#include "libtommath/s_mp_div_3.c"
|
||||
#include "libtommath/s_mp_div_recursive.c"
|
||||
#include "libtommath/s_mp_div_school.c"
|
||||
#include "libtommath/s_mp_div_small.c"
|
||||
#include "libtommath/s_mp_exptmod.c"
|
||||
#include "libtommath/s_mp_exptmod_fast.c"
|
||||
#include "libtommath/s_mp_get_bit.c"
|
||||
#include "libtommath/s_mp_invmod.c"
|
||||
#include "libtommath/s_mp_invmod_odd.c"
|
||||
#include "libtommath/s_mp_log.c"
|
||||
#include "libtommath/s_mp_log_2expt.c"
|
||||
#include "libtommath/s_mp_log_d.c"
|
||||
#include "libtommath/s_mp_montgomery_reduce_comba.c"
|
||||
#include "libtommath/s_mp_mul.c"
|
||||
#include "libtommath/s_mp_mul_balance.c"
|
||||
#include "libtommath/s_mp_mul_comba.c"
|
||||
#include "libtommath/s_mp_mul_high.c"
|
||||
#include "libtommath/s_mp_mul_high_comba.c"
|
||||
#include "libtommath/s_mp_mul_karatsuba.c"
|
||||
#include "libtommath/s_mp_mul_toom.c"
|
||||
#include "libtommath/s_mp_prime_is_divisible.c"
|
||||
#include "libtommath/s_mp_prime_tab.c"
|
||||
#include "libtommath/s_mp_radix_map.c"
|
||||
#include "libtommath/s_mp_radix_size_overestimate.c"
|
||||
// #include "libtommath/s_mp_rand_platform.c"
|
||||
#include "libtommath/s_mp_sqr.c"
|
||||
#include "libtommath/s_mp_sqr_comba.c"
|
||||
#include "libtommath/s_mp_sqr_karatsuba.c"
|
||||
#include "libtommath/s_mp_sqr_toom.c"
|
||||
#include "libtommath/s_mp_sub.c"
|
||||
#include "libtommath/s_mp_zero_buf.c"
|
||||
#include "libtommath/s_mp_zero_digs.c"
|
||||
26
src/libtommath/LICENSE
Normal file
26
src/libtommath/LICENSE
Normal file
@@ -0,0 +1,26 @@
|
||||
The LibTom license
|
||||
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
44
src/libtommath/README.md
Normal file
44
src/libtommath/README.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# libtommath
|
||||
|
||||
This is the git repository for [LibTomMath](http://www.libtom.net/LibTomMath/), a free open source portable number theoretic multiple-precision integer (MPI) library written entirely in C.
|
||||
|
||||
## Build Status
|
||||
|
||||
### Travis CI
|
||||
|
||||
master: [](https://travis-ci.org/libtom/libtommath)
|
||||
|
||||
develop: [](https://travis-ci.org/libtom/libtommath)
|
||||
|
||||
### AppVeyor
|
||||
|
||||
master: [](https://ci.appveyor.com/project/libtom/libtommath/branch/master)
|
||||
|
||||
develop: [](https://ci.appveyor.com/project/libtom/libtommath/branch/develop)
|
||||
|
||||
### ABI Laboratory
|
||||
|
||||
API/ABI changes: [check here](https://abi-laboratory.pro/tracker/timeline/libtommath/)
|
||||
|
||||
## Summary
|
||||
|
||||
The `develop` branch contains the in-development version. Stable releases are tagged.
|
||||
|
||||
Documentation is built from the LaTeX file `bn.tex`. There is also limited documentation in `tommath.h`.
|
||||
There is also a document, `tommath.pdf`, which describes the goals of the project and many of the algorithms used.
|
||||
|
||||
The project can be build by using `make`. Along with the usual `make`, `make clean` and `make install`,
|
||||
there are several other build targets, see the makefile for details.
|
||||
There are also makefiles for certain specific platforms.
|
||||
|
||||
## Testing
|
||||
|
||||
Tests are located in `demo/` and can be built in two flavors.
|
||||
* `make test` creates a stand-alone test binary that executes several test routines.
|
||||
* `make mtest_opponent` creates a test binary that is intended to be run against `mtest`.
|
||||
`mtest` can be built with `make mtest` and test execution is done like `./mtest/mtest | ./mtest_opponent`.
|
||||
`mtest` is creating test vectors using an alternative MPI library and `test` is consuming these vectors to verify correct behavior of ltm
|
||||
|
||||
## Building and Installing
|
||||
|
||||
Building is straightforward for GNU Linux only, the section "Building LibTomMath" in the documentation in `doc/bn.pdf` has the details.
|
||||
31
src/libtommath/mp_2expt.c
Normal file
31
src/libtommath/mp_2expt.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_2EXPT_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* computes a = 2**b
|
||||
*
|
||||
* Simple algorithm which zeroes the int, grows it then just sets one bit
|
||||
* as required.
|
||||
*/
|
||||
mp_err mp_2expt(mp_int *a, int b)
|
||||
{
|
||||
mp_err err;
|
||||
|
||||
/* zero a as per default */
|
||||
mp_zero(a);
|
||||
|
||||
/* grow a to accomodate the single bit */
|
||||
if ((err = mp_grow(a, (b / MP_DIGIT_BIT) + 1)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* set the used count of where the bit will go */
|
||||
a->used = (b / MP_DIGIT_BIT) + 1;
|
||||
|
||||
/* put the single bit in its place */
|
||||
a->dp[b / MP_DIGIT_BIT] = (mp_digit)1 << (mp_digit)(b % MP_DIGIT_BIT);
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
24
src/libtommath/mp_abs.c
Normal file
24
src/libtommath/mp_abs.c
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_ABS_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* b = |a|
|
||||
*
|
||||
* Simple function copies the input and fixes the sign to positive
|
||||
*/
|
||||
mp_err mp_abs(const mp_int *a, mp_int *b)
|
||||
{
|
||||
mp_err err;
|
||||
|
||||
/* copy a to b */
|
||||
if ((err = mp_copy(a, b)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* force the sign of b to positive */
|
||||
b->sign = MP_ZPOS;
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
29
src/libtommath/mp_add.c
Normal file
29
src/libtommath/mp_add.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_ADD_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* high level addition (handles signs) */
|
||||
mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c)
|
||||
{
|
||||
/* handle two cases, not four */
|
||||
if (a->sign == b->sign) {
|
||||
/* both positive or both negative */
|
||||
/* add their magnitudes, copy the sign */
|
||||
c->sign = a->sign;
|
||||
return s_mp_add(a, b, c);
|
||||
}
|
||||
|
||||
/* one positive, the other negative */
|
||||
/* subtract the one with the greater magnitude from */
|
||||
/* the one of the lesser magnitude. The result gets */
|
||||
/* the sign of the one with the greater magnitude. */
|
||||
if (mp_cmp_mag(a, b) == MP_LT) {
|
||||
MP_EXCH(const mp_int *, a, b);
|
||||
}
|
||||
|
||||
c->sign = a->sign;
|
||||
return s_mp_sub(a, b, c);
|
||||
}
|
||||
|
||||
#endif
|
||||
86
src/libtommath/mp_add_d.c
Normal file
86
src/libtommath/mp_add_d.c
Normal file
@@ -0,0 +1,86 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_ADD_D_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* single digit addition */
|
||||
mp_err mp_add_d(const mp_int *a, mp_digit b, mp_int *c)
|
||||
{
|
||||
mp_err err;
|
||||
int oldused;
|
||||
|
||||
/* fast path for a == c */
|
||||
if (a == c) {
|
||||
if (!mp_isneg(c) &&
|
||||
!mp_iszero(c) &&
|
||||
((c->dp[0] + b) < MP_DIGIT_MAX)) {
|
||||
c->dp[0] += b;
|
||||
return MP_OKAY;
|
||||
}
|
||||
if (mp_isneg(c) &&
|
||||
(c->dp[0] > b)) {
|
||||
c->dp[0] -= b;
|
||||
return MP_OKAY;
|
||||
}
|
||||
}
|
||||
|
||||
/* grow c as required */
|
||||
if ((err = mp_grow(c, a->used + 1)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* if a is negative and |a| >= b, call c = |a| - b */
|
||||
if (mp_isneg(a) && ((a->used > 1) || (a->dp[0] >= b))) {
|
||||
mp_int a_ = *a;
|
||||
/* temporarily fix sign of a */
|
||||
a_.sign = MP_ZPOS;
|
||||
|
||||
/* c = |a| - b */
|
||||
err = mp_sub_d(&a_, b, c);
|
||||
|
||||
/* fix sign */
|
||||
c->sign = MP_NEG;
|
||||
|
||||
/* clamp */
|
||||
mp_clamp(c);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* old number of used digits in c */
|
||||
oldused = c->used;
|
||||
|
||||
/* if a is positive */
|
||||
if (!mp_isneg(a)) {
|
||||
/* add digits, mu is carry */
|
||||
int i;
|
||||
mp_digit mu = b;
|
||||
for (i = 0; i < a->used; i++) {
|
||||
c->dp[i] = a->dp[i] + mu;
|
||||
mu = c->dp[i] >> MP_DIGIT_BIT;
|
||||
c->dp[i] &= MP_MASK;
|
||||
}
|
||||
/* set final carry */
|
||||
c->dp[i] = mu;
|
||||
|
||||
/* setup size */
|
||||
c->used = a->used + 1;
|
||||
} else {
|
||||
/* a was negative and |a| < b */
|
||||
c->used = 1;
|
||||
|
||||
/* the result is a single digit */
|
||||
c->dp[0] = (a->used == 1) ? b - a->dp[0] : b;
|
||||
}
|
||||
|
||||
/* sign always positive */
|
||||
c->sign = MP_ZPOS;
|
||||
|
||||
/* now zero to oldused */
|
||||
s_mp_zero_digs(c->dp + c->used, oldused - c->used);
|
||||
mp_clamp(c);
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
#endif
|
||||
15
src/libtommath/mp_addmod.c
Normal file
15
src/libtommath/mp_addmod.c
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_ADDMOD_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* d = a + b (mod c) */
|
||||
mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d)
|
||||
{
|
||||
mp_err err;
|
||||
if ((err = mp_add(a, b, d)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
return mp_mod(d, c, d);
|
||||
}
|
||||
#endif
|
||||
54
src/libtommath/mp_and.c
Normal file
54
src/libtommath/mp_and.c
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_AND_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* two complement and */
|
||||
mp_err mp_and(const mp_int *a, const mp_int *b, mp_int *c)
|
||||
{
|
||||
int used = MP_MAX(a->used, b->used) + 1, i;
|
||||
mp_err err;
|
||||
mp_digit ac = 1, bc = 1, cc = 1;
|
||||
bool neg = (mp_isneg(a) && mp_isneg(b));
|
||||
|
||||
if ((err = mp_grow(c, used)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < used; i++) {
|
||||
mp_digit x, y;
|
||||
|
||||
/* convert to two complement if negative */
|
||||
if (mp_isneg(a)) {
|
||||
ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK);
|
||||
x = ac & MP_MASK;
|
||||
ac >>= MP_DIGIT_BIT;
|
||||
} else {
|
||||
x = (i >= a->used) ? 0uL : a->dp[i];
|
||||
}
|
||||
|
||||
/* convert to two complement if negative */
|
||||
if (mp_isneg(b)) {
|
||||
bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK);
|
||||
y = bc & MP_MASK;
|
||||
bc >>= MP_DIGIT_BIT;
|
||||
} else {
|
||||
y = (i >= b->used) ? 0uL : b->dp[i];
|
||||
}
|
||||
|
||||
c->dp[i] = x & y;
|
||||
|
||||
/* convert to to sign-magnitude if negative */
|
||||
if (neg) {
|
||||
cc += ~c->dp[i] & MP_MASK;
|
||||
c->dp[i] = cc & MP_MASK;
|
||||
cc >>= MP_DIGIT_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
c->used = used;
|
||||
c->sign = (neg ? MP_NEG : MP_ZPOS);
|
||||
mp_clamp(c);
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
27
src/libtommath/mp_clamp.c
Normal file
27
src/libtommath/mp_clamp.c
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_CLAMP_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* trim unused digits
|
||||
*
|
||||
* This is used to ensure that leading zero digits are
|
||||
* trimed and the leading "used" digit will be non-zero
|
||||
* Typically very fast. Also fixes the sign if there
|
||||
* are no more leading digits
|
||||
*/
|
||||
void mp_clamp(mp_int *a)
|
||||
{
|
||||
/* decrease used while the most significant digit is
|
||||
* zero.
|
||||
*/
|
||||
while ((a->used > 0) && (a->dp[a->used - 1] == 0u)) {
|
||||
--(a->used);
|
||||
}
|
||||
|
||||
/* reset the sign flag if zero */
|
||||
if (mp_iszero(a)) {
|
||||
a->sign = MP_ZPOS;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
20
src/libtommath/mp_clear.c
Normal file
20
src/libtommath/mp_clear.c
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_CLEAR_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* clear one (frees) */
|
||||
void mp_clear(mp_int *a)
|
||||
{
|
||||
/* only do anything if a hasn't been freed previously */
|
||||
if (a->dp != NULL) {
|
||||
/* free ram */
|
||||
MP_FREE_DIGS(a->dp, a->alloc);
|
||||
|
||||
/* reset members to make debugging easier */
|
||||
a->dp = NULL;
|
||||
a->alloc = a->used = 0;
|
||||
a->sign = MP_ZPOS;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
18
src/libtommath/mp_clear_multi.c
Normal file
18
src/libtommath/mp_clear_multi.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_CLEAR_MULTI_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
void mp_clear_multi(mp_int *mp, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, mp);
|
||||
while (mp != NULL) {
|
||||
mp_clear(mp);
|
||||
mp = va_arg(args, mp_int *);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
21
src/libtommath/mp_cmp.c
Normal file
21
src/libtommath/mp_cmp.c
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_CMP_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* compare two ints (signed)*/
|
||||
mp_ord mp_cmp(const mp_int *a, const mp_int *b)
|
||||
{
|
||||
/* compare based on sign */
|
||||
if (a->sign != b->sign) {
|
||||
return mp_isneg(a) ? MP_LT : MP_GT;
|
||||
}
|
||||
|
||||
/* if negative compare opposite direction */
|
||||
if (mp_isneg(a)) {
|
||||
MP_EXCH(const mp_int *, a, b);
|
||||
}
|
||||
|
||||
return mp_cmp_mag(a, b);
|
||||
}
|
||||
#endif
|
||||
26
src/libtommath/mp_cmp_d.c
Normal file
26
src/libtommath/mp_cmp_d.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_CMP_D_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* compare a digit */
|
||||
mp_ord mp_cmp_d(const mp_int *a, mp_digit b)
|
||||
{
|
||||
/* compare based on sign */
|
||||
if (mp_isneg(a)) {
|
||||
return MP_LT;
|
||||
}
|
||||
|
||||
/* compare based on magnitude */
|
||||
if (a->used > 1) {
|
||||
return MP_GT;
|
||||
}
|
||||
|
||||
/* compare the only digit of a to b */
|
||||
if (a->dp[0] != b) {
|
||||
return a->dp[0] > b ? MP_GT : MP_LT;
|
||||
}
|
||||
|
||||
return MP_EQ;
|
||||
}
|
||||
#endif
|
||||
25
src/libtommath/mp_cmp_mag.c
Normal file
25
src/libtommath/mp_cmp_mag.c
Normal file
@@ -0,0 +1,25 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_CMP_MAG_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* compare maginitude of two ints (unsigned) */
|
||||
mp_ord mp_cmp_mag(const mp_int *a, const mp_int *b)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* compare based on # of non-zero digits */
|
||||
if (a->used != b->used) {
|
||||
return a->used > b->used ? MP_GT : MP_LT;
|
||||
}
|
||||
|
||||
/* compare based on digits */
|
||||
for (n = a->used; n --> 0;) {
|
||||
if (a->dp[n] != b->dp[n]) {
|
||||
return a->dp[n] > b->dp[n] ? MP_GT : MP_LT;
|
||||
}
|
||||
}
|
||||
|
||||
return MP_EQ;
|
||||
}
|
||||
#endif
|
||||
38
src/libtommath/mp_cnt_lsb.c
Normal file
38
src/libtommath/mp_cnt_lsb.c
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_CNT_LSB_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
static const char lnz[16] = {
|
||||
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
|
||||
};
|
||||
|
||||
/* Counts the number of lsbs which are zero before the first zero bit */
|
||||
int mp_cnt_lsb(const mp_int *a)
|
||||
{
|
||||
int x;
|
||||
mp_digit q;
|
||||
|
||||
/* easy out */
|
||||
if (mp_iszero(a)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* scan lower digits until non-zero */
|
||||
for (x = 0; (x < a->used) && (a->dp[x] == 0u); x++) {}
|
||||
q = a->dp[x];
|
||||
x *= MP_DIGIT_BIT;
|
||||
|
||||
/* now scan this digit until a 1 is found */
|
||||
if ((q & 1u) == 0u) {
|
||||
mp_digit p;
|
||||
do {
|
||||
p = q & 15u;
|
||||
x += lnz[p];
|
||||
q >>= 4;
|
||||
} while (p == 0u);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
#endif
|
||||
13
src/libtommath/mp_complement.c
Normal file
13
src/libtommath/mp_complement.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_COMPLEMENT_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* b = ~a */
|
||||
mp_err mp_complement(const mp_int *a, mp_int *b)
|
||||
{
|
||||
mp_int a_ = *a;
|
||||
a_.sign = ((a_.sign == MP_ZPOS) && !mp_iszero(a)) ? MP_NEG : MP_ZPOS;
|
||||
return mp_sub_d(&a_, 1uL, b);
|
||||
}
|
||||
#endif
|
||||
29
src/libtommath/mp_copy.c
Normal file
29
src/libtommath/mp_copy.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_COPY_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* copy, b = a */
|
||||
mp_err mp_copy(const mp_int *a, mp_int *b)
|
||||
{
|
||||
mp_err err;
|
||||
|
||||
/* if dst == src do nothing */
|
||||
if (a == b) {
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
/* grow dest */
|
||||
if ((err = mp_grow(b, a->used)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* copy everything over and zero high digits */
|
||||
s_mp_copy_digs(b->dp, a->dp, a->used);
|
||||
s_mp_zero_digs(b->dp + a->used, b->used - a->used);
|
||||
b->used = a->used;
|
||||
b->sign = a->sign;
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
28
src/libtommath/mp_count_bits.c
Normal file
28
src/libtommath/mp_count_bits.c
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_COUNT_BITS_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* returns the number of bits in an int */
|
||||
int mp_count_bits(const mp_int *a)
|
||||
{
|
||||
int r;
|
||||
mp_digit q;
|
||||
|
||||
/* shortcut */
|
||||
if (mp_iszero(a)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get number of digits and add that */
|
||||
r = (a->used - 1) * MP_DIGIT_BIT;
|
||||
|
||||
/* take the last digit and count the bits in it */
|
||||
q = a->dp[a->used - 1];
|
||||
while (q > 0u) {
|
||||
++r;
|
||||
q >>= 1u;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
14
src/libtommath/mp_cutoffs.c
Normal file
14
src/libtommath/mp_cutoffs.c
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_CUTOFFS_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
#ifndef MP_FIXED_CUTOFFS
|
||||
#include "tommath_cutoffs.h"
|
||||
int MP_MUL_KARATSUBA_CUTOFF = MP_DEFAULT_MUL_KARATSUBA_CUTOFF,
|
||||
MP_SQR_KARATSUBA_CUTOFF = MP_DEFAULT_SQR_KARATSUBA_CUTOFF,
|
||||
MP_MUL_TOOM_CUTOFF = MP_DEFAULT_MUL_TOOM_CUTOFF,
|
||||
MP_SQR_TOOM_CUTOFF = MP_DEFAULT_SQR_TOOM_CUTOFF;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
42
src/libtommath/mp_div.c
Normal file
42
src/libtommath/mp_div.c
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_DIV_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *c, mp_int *d)
|
||||
{
|
||||
mp_err err;
|
||||
|
||||
/* is divisor zero ? */
|
||||
if (mp_iszero(b)) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
/* if a < b then q = 0, r = a */
|
||||
if (mp_cmp_mag(a, b) == MP_LT) {
|
||||
if (d != NULL) {
|
||||
if ((err = mp_copy(a, d)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
if (c != NULL) {
|
||||
mp_zero(c);
|
||||
}
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
if (MP_HAS(S_MP_DIV_RECURSIVE)
|
||||
&& (b->used > (2 * MP_MUL_KARATSUBA_CUTOFF))
|
||||
&& (b->used <= ((a->used/3)*2))) {
|
||||
err = s_mp_div_recursive(a, b, c, d);
|
||||
} else if (MP_HAS(S_MP_DIV_SCHOOL)) {
|
||||
err = s_mp_div_school(a, b, c, d);
|
||||
} else if (MP_HAS(S_MP_DIV_SMALL)) {
|
||||
err = s_mp_div_small(a, b, c, d);
|
||||
} else {
|
||||
err = MP_VAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
40
src/libtommath/mp_div_2.c
Normal file
40
src/libtommath/mp_div_2.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_DIV_2_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* b = a/2 */
|
||||
mp_err mp_div_2(const mp_int *a, mp_int *b)
|
||||
{
|
||||
mp_err err;
|
||||
int x, oldused;
|
||||
mp_digit r;
|
||||
|
||||
if ((err = mp_grow(b, a->used)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
oldused = b->used;
|
||||
b->used = a->used;
|
||||
|
||||
/* carry */
|
||||
r = 0;
|
||||
for (x = b->used; x --> 0;) {
|
||||
/* get the carry for the next iteration */
|
||||
mp_digit rr = a->dp[x] & 1u;
|
||||
|
||||
/* shift the current digit, add in carry and store */
|
||||
b->dp[x] = (a->dp[x] >> 1) | (r << (MP_DIGIT_BIT - 1));
|
||||
|
||||
/* forward carry to next iteration */
|
||||
r = rr;
|
||||
}
|
||||
|
||||
/* zero excess digits */
|
||||
s_mp_zero_digs(b->dp + b->used, oldused - b->used);
|
||||
|
||||
b->sign = a->sign;
|
||||
mp_clamp(b);
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
61
src/libtommath/mp_div_2d.c
Normal file
61
src/libtommath/mp_div_2d.c
Normal file
@@ -0,0 +1,61 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_DIV_2D_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* shift right by a certain bit count (store quotient in c, optional remainder in d) */
|
||||
mp_err mp_div_2d(const mp_int *a, int b, mp_int *c, mp_int *d)
|
||||
{
|
||||
mp_err err;
|
||||
|
||||
if (b < 0) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
if ((err = mp_copy(a, c)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* 'a' should not be used after here - it might be the same as d */
|
||||
|
||||
/* get the remainder */
|
||||
if (d != NULL) {
|
||||
if ((err = mp_mod_2d(a, b, d)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* shift by as many digits in the bit count */
|
||||
if (b >= MP_DIGIT_BIT) {
|
||||
mp_rshd(c, b / MP_DIGIT_BIT);
|
||||
}
|
||||
|
||||
/* shift any bit count < MP_DIGIT_BIT */
|
||||
b %= MP_DIGIT_BIT;
|
||||
if (b != 0u) {
|
||||
int x;
|
||||
mp_digit r, mask, shift;
|
||||
|
||||
/* mask */
|
||||
mask = ((mp_digit)1 << b) - 1uL;
|
||||
|
||||
/* shift for lsb */
|
||||
shift = (mp_digit)(MP_DIGIT_BIT - b);
|
||||
|
||||
/* carry */
|
||||
r = 0;
|
||||
for (x = c->used; x --> 0;) {
|
||||
/* get the lower bits of this word in a temp */
|
||||
mp_digit rr = c->dp[x] & mask;
|
||||
|
||||
/* shift the current word and mix in the carry bits from the previous word */
|
||||
c->dp[x] = (c->dp[x] >> b) | (r << shift);
|
||||
|
||||
/* set the carry to the carry bits of the current word found above */
|
||||
r = rr;
|
||||
}
|
||||
}
|
||||
mp_clamp(c);
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
84
src/libtommath/mp_div_d.c
Normal file
84
src/libtommath/mp_div_d.c
Normal file
@@ -0,0 +1,84 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_DIV_D_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* single digit division (based on routine from MPI) */
|
||||
mp_err mp_div_d(const mp_int *a, mp_digit b, mp_int *c, mp_digit *d)
|
||||
{
|
||||
mp_int q;
|
||||
mp_word w;
|
||||
mp_err err;
|
||||
int ix;
|
||||
|
||||
/* cannot divide by zero */
|
||||
if (b == 0u) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
/* quick outs */
|
||||
if ((b == 1u) || mp_iszero(a)) {
|
||||
if (d != NULL) {
|
||||
*d = 0;
|
||||
}
|
||||
if (c != NULL) {
|
||||
return mp_copy(a, c);
|
||||
}
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
/* power of two ? */
|
||||
if (MP_HAS(MP_DIV_2) && (b == 2u)) {
|
||||
if (d != NULL) {
|
||||
*d = mp_isodd(a) ? 1u : 0u;
|
||||
}
|
||||
return (c == NULL) ? MP_OKAY : mp_div_2(a, c);
|
||||
}
|
||||
if (MP_HAS(MP_DIV_2D) && MP_IS_2EXPT(b)) {
|
||||
ix = 1;
|
||||
while ((ix < MP_DIGIT_BIT) && (b != (((mp_digit)1)<<ix))) {
|
||||
ix++;
|
||||
}
|
||||
if (d != NULL) {
|
||||
*d = a->dp[0] & (((mp_digit)1<<(mp_digit)ix) - 1uL);
|
||||
}
|
||||
return (c == NULL) ? MP_OKAY : mp_div_2d(a, ix, c, NULL);
|
||||
}
|
||||
|
||||
/* three? */
|
||||
if (MP_HAS(S_MP_DIV_3) && (b == 3u)) {
|
||||
return s_mp_div_3(a, c, d);
|
||||
}
|
||||
|
||||
/* no easy answer [c'est la vie]. Just division */
|
||||
if ((err = mp_init_size(&q, a->used)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
q.used = a->used;
|
||||
q.sign = a->sign;
|
||||
w = 0;
|
||||
for (ix = a->used; ix --> 0;) {
|
||||
mp_digit t = 0;
|
||||
w = (w << (mp_word)MP_DIGIT_BIT) | (mp_word)a->dp[ix];
|
||||
if (w >= b) {
|
||||
t = (mp_digit)(w / b);
|
||||
w -= (mp_word)t * (mp_word)b;
|
||||
}
|
||||
q.dp[ix] = t;
|
||||
}
|
||||
|
||||
if (d != NULL) {
|
||||
*d = (mp_digit)w;
|
||||
}
|
||||
|
||||
if (c != NULL) {
|
||||
mp_clamp(&q);
|
||||
mp_exch(&q, c);
|
||||
}
|
||||
mp_clear(&q);
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
#endif
|
||||
27
src/libtommath/mp_dr_is_modulus.c
Normal file
27
src/libtommath/mp_dr_is_modulus.c
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_DR_IS_MODULUS_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* determines if a number is a valid DR modulus */
|
||||
bool mp_dr_is_modulus(const mp_int *a)
|
||||
{
|
||||
int ix;
|
||||
|
||||
/* must be at least two digits */
|
||||
if (a->used < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* must be of the form b**k - a [a <= b] so all
|
||||
* but the first digit must be equal to -1 (mod b).
|
||||
*/
|
||||
for (ix = 1; ix < a->used; ix++) {
|
||||
if (a->dp[ix] != MP_MASK) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
68
src/libtommath/mp_dr_reduce.c
Normal file
68
src/libtommath/mp_dr_reduce.c
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_DR_REDUCE_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* reduce "x" in place modulo "n" using the Diminished Radix algorithm.
|
||||
*
|
||||
* Based on algorithm from the paper
|
||||
*
|
||||
* "Generating Efficient Primes for Discrete Log Cryptosystems"
|
||||
* Chae Hoon Lim, Pil Joong Lee,
|
||||
* POSTECH Information Research Laboratories
|
||||
*
|
||||
* The modulus must be of a special format [see manual]
|
||||
*
|
||||
* Has been modified to use algorithm 7.10 from the LTM book instead
|
||||
*
|
||||
* Input x must be in the range 0 <= x <= (n-1)**2
|
||||
*/
|
||||
mp_err mp_dr_reduce(mp_int *x, const mp_int *n, mp_digit k)
|
||||
{
|
||||
mp_err err;
|
||||
|
||||
/* m = digits in modulus */
|
||||
int m = n->used;
|
||||
|
||||
/* ensure that "x" has at least 2m digits */
|
||||
if ((err = mp_grow(x, m + m)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* top of loop, this is where the code resumes if
|
||||
* another reduction pass is required.
|
||||
*/
|
||||
for (;;) {
|
||||
int i;
|
||||
mp_digit mu = 0;
|
||||
|
||||
/* compute (x mod B**m) + k * [x/B**m] inline and inplace */
|
||||
for (i = 0; i < m; i++) {
|
||||
mp_word r = ((mp_word)x->dp[i + m] * (mp_word)k) + x->dp[i] + mu;
|
||||
x->dp[i] = (mp_digit)(r & MP_MASK);
|
||||
mu = (mp_digit)(r >> ((mp_word)MP_DIGIT_BIT));
|
||||
}
|
||||
|
||||
/* set final carry */
|
||||
x->dp[i] = mu;
|
||||
|
||||
/* zero words above m */
|
||||
s_mp_zero_digs(x->dp + m + 1, (x->used - m) - 1);
|
||||
|
||||
/* clamp, sub and return */
|
||||
mp_clamp(x);
|
||||
|
||||
/* if x >= n then subtract and reduce again
|
||||
* Each successive "recursion" makes the input smaller and smaller.
|
||||
*/
|
||||
if (mp_cmp_mag(x, n) == MP_LT) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((err = s_mp_sub(x, n, x)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
15
src/libtommath/mp_dr_setup.c
Normal file
15
src/libtommath/mp_dr_setup.c
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_DR_SETUP_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* determines the setup value */
|
||||
void mp_dr_setup(const mp_int *a, mp_digit *d)
|
||||
{
|
||||
/* the casts are required if MP_DIGIT_BIT is one less than
|
||||
* the number of bits in a mp_digit [e.g. MP_DIGIT_BIT==31]
|
||||
*/
|
||||
*d = (mp_digit)(((mp_word)1 << (mp_word)MP_DIGIT_BIT) - (mp_word)a->dp[0]);
|
||||
}
|
||||
|
||||
#endif
|
||||
29
src/libtommath/mp_error_to_string.c
Normal file
29
src/libtommath/mp_error_to_string.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_ERROR_TO_STRING_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* return a char * string for a given code */
|
||||
const char *mp_error_to_string(mp_err code)
|
||||
{
|
||||
switch (code) {
|
||||
case MP_OKAY:
|
||||
return "Successful";
|
||||
case MP_ERR:
|
||||
return "Unknown error";
|
||||
case MP_MEM:
|
||||
return "Out of heap";
|
||||
case MP_VAL:
|
||||
return "Value out of range";
|
||||
case MP_ITER:
|
||||
return "Max. iterations reached";
|
||||
case MP_BUF:
|
||||
return "Buffer overflow";
|
||||
case MP_OVF:
|
||||
return "Integer overflow";
|
||||
default:
|
||||
return "Invalid error code";
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
13
src/libtommath/mp_exch.c
Normal file
13
src/libtommath/mp_exch.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_EXCH_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* swap the elements of two integers, for cases where you can't simply swap the
|
||||
* mp_int pointers around
|
||||
*/
|
||||
void mp_exch(mp_int *a, mp_int *b)
|
||||
{
|
||||
MP_EXCH(mp_int, *a, *b);
|
||||
}
|
||||
#endif
|
||||
43
src/libtommath/mp_expt_n.c
Normal file
43
src/libtommath/mp_expt_n.c
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_EXPT_N_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* calculate c = a**b using a square-multiply algorithm */
|
||||
mp_err mp_expt_n(const mp_int *a, int b, mp_int *c)
|
||||
{
|
||||
mp_err err;
|
||||
mp_int g;
|
||||
|
||||
if ((err = mp_init_copy(&g, a)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* set initial result */
|
||||
mp_set(c, 1uL);
|
||||
|
||||
while (b > 0) {
|
||||
/* if the bit is set multiply */
|
||||
if ((b & 1) != 0) {
|
||||
if ((err = mp_mul(c, &g, c)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/* square */
|
||||
if (b > 1) {
|
||||
if ((err = mp_sqr(&g, &g)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/* shift to next bit */
|
||||
b >>= 1;
|
||||
}
|
||||
|
||||
LBL_ERR:
|
||||
mp_clear(&g);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
78
src/libtommath/mp_exptmod.c
Normal file
78
src/libtommath/mp_exptmod.c
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_EXPTMOD_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* this is a shell function that calls either the normal or Montgomery
|
||||
* exptmod functions. Originally the call to the montgomery code was
|
||||
* embedded in the normal function but that wasted alot of stack space
|
||||
* for nothing (since 99% of the time the Montgomery code would be called)
|
||||
*/
|
||||
mp_err mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y)
|
||||
{
|
||||
int dr;
|
||||
|
||||
/* modulus P must be positive */
|
||||
if (mp_isneg(P)) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
/* if exponent X is negative we have to recurse */
|
||||
if (mp_isneg(X)) {
|
||||
mp_int tmpG, tmpX;
|
||||
mp_err err;
|
||||
|
||||
if (!MP_HAS(MP_INVMOD)) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
if ((err = mp_init_multi(&tmpG, &tmpX, NULL)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* first compute 1/G mod P */
|
||||
if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
/* now get |X| */
|
||||
if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
/* and now compute (1/G)**|X| instead of G**X [X < 0] */
|
||||
err = mp_exptmod(&tmpG, &tmpX, P, Y);
|
||||
LBL_ERR:
|
||||
mp_clear_multi(&tmpG, &tmpX, NULL);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* modified diminished radix reduction */
|
||||
if (MP_HAS(MP_REDUCE_IS_2K_L) && MP_HAS(MP_REDUCE_2K_L) && MP_HAS(S_MP_EXPTMOD) &&
|
||||
mp_reduce_is_2k_l(P)) {
|
||||
return s_mp_exptmod(G, X, P, Y, 1);
|
||||
}
|
||||
|
||||
/* is it a DR modulus? default to no */
|
||||
dr = (MP_HAS(MP_DR_IS_MODULUS) && mp_dr_is_modulus(P)) ? 1 : 0;
|
||||
|
||||
/* if not, is it a unrestricted DR modulus? */
|
||||
if (MP_HAS(MP_REDUCE_IS_2K) && (dr == 0)) {
|
||||
dr = (mp_reduce_is_2k(P)) ? 2 : 0;
|
||||
}
|
||||
|
||||
/* if the modulus is odd or dr != 0 use the montgomery method */
|
||||
if (MP_HAS(S_MP_EXPTMOD_FAST) && (mp_isodd(P) || (dr != 0))) {
|
||||
return s_mp_exptmod_fast(G, X, P, Y, dr);
|
||||
}
|
||||
|
||||
/* otherwise use the generic Barrett reduction technique */
|
||||
if (MP_HAS(S_MP_EXPTMOD)) {
|
||||
return s_mp_exptmod(G, X, P, Y, 0);
|
||||
}
|
||||
|
||||
/* no exptmod for evens */
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
#endif
|
||||
72
src/libtommath/mp_exteuclid.c
Normal file
72
src/libtommath/mp_exteuclid.c
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_EXTEUCLID_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* Extended euclidean algorithm of (a, b) produces
|
||||
a*u1 + b*u2 = u3
|
||||
*/
|
||||
mp_err mp_exteuclid(const mp_int *a, const mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3)
|
||||
{
|
||||
mp_int u1, u2, u3, v1, v2, v3, t1, t2, t3, q, tmp;
|
||||
mp_err err;
|
||||
|
||||
if ((err = mp_init_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* initialize, (u1,u2,u3) = (1,0,a) */
|
||||
mp_set(&u1, 1uL);
|
||||
if ((err = mp_copy(a, &u3)) != MP_OKAY) goto LBL_ERR;
|
||||
|
||||
/* initialize, (v1,v2,v3) = (0,1,b) */
|
||||
mp_set(&v2, 1uL);
|
||||
if ((err = mp_copy(b, &v3)) != MP_OKAY) goto LBL_ERR;
|
||||
|
||||
/* loop while v3 != 0 */
|
||||
while (!mp_iszero(&v3)) {
|
||||
/* q = u3/v3 */
|
||||
if ((err = mp_div(&u3, &v3, &q, NULL)) != MP_OKAY) goto LBL_ERR;
|
||||
|
||||
/* (t1,t2,t3) = (u1,u2,u3) - (v1,v2,v3)q */
|
||||
if ((err = mp_mul(&v1, &q, &tmp)) != MP_OKAY) goto LBL_ERR;
|
||||
if ((err = mp_sub(&u1, &tmp, &t1)) != MP_OKAY) goto LBL_ERR;
|
||||
if ((err = mp_mul(&v2, &q, &tmp)) != MP_OKAY) goto LBL_ERR;
|
||||
if ((err = mp_sub(&u2, &tmp, &t2)) != MP_OKAY) goto LBL_ERR;
|
||||
if ((err = mp_mul(&v3, &q, &tmp)) != MP_OKAY) goto LBL_ERR;
|
||||
if ((err = mp_sub(&u3, &tmp, &t3)) != MP_OKAY) goto LBL_ERR;
|
||||
|
||||
/* (u1,u2,u3) = (v1,v2,v3) */
|
||||
if ((err = mp_copy(&v1, &u1)) != MP_OKAY) goto LBL_ERR;
|
||||
if ((err = mp_copy(&v2, &u2)) != MP_OKAY) goto LBL_ERR;
|
||||
if ((err = mp_copy(&v3, &u3)) != MP_OKAY) goto LBL_ERR;
|
||||
|
||||
/* (v1,v2,v3) = (t1,t2,t3) */
|
||||
if ((err = mp_copy(&t1, &v1)) != MP_OKAY) goto LBL_ERR;
|
||||
if ((err = mp_copy(&t2, &v2)) != MP_OKAY) goto LBL_ERR;
|
||||
if ((err = mp_copy(&t3, &v3)) != MP_OKAY) goto LBL_ERR;
|
||||
}
|
||||
|
||||
/* make sure U3 >= 0 */
|
||||
if (mp_isneg(&u3)) {
|
||||
if ((err = mp_neg(&u1, &u1)) != MP_OKAY) goto LBL_ERR;
|
||||
if ((err = mp_neg(&u2, &u2)) != MP_OKAY) goto LBL_ERR;
|
||||
if ((err = mp_neg(&u3, &u3)) != MP_OKAY) goto LBL_ERR;
|
||||
}
|
||||
|
||||
/* copy result out */
|
||||
if (U1 != NULL) {
|
||||
mp_exch(U1, &u1);
|
||||
}
|
||||
if (U2 != NULL) {
|
||||
mp_exch(U2, &u2);
|
||||
}
|
||||
if (U3 != NULL) {
|
||||
mp_exch(U3, &u3);
|
||||
}
|
||||
|
||||
LBL_ERR:
|
||||
mp_clear_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
66
src/libtommath/mp_fread.c
Normal file
66
src/libtommath/mp_fread.c
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_FREAD_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
#ifndef MP_NO_FILE
|
||||
/* read a bigint from a file stream in ASCII */
|
||||
mp_err mp_fread(mp_int *a, int radix, FILE *stream)
|
||||
{
|
||||
mp_err err;
|
||||
mp_sign sign = MP_ZPOS;
|
||||
int ch;
|
||||
|
||||
/* make sure the radix is ok */
|
||||
if ((radix < 2) || (radix > 64)) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
/* if first digit is - then set negative */
|
||||
ch = fgetc(stream);
|
||||
if (ch == (int)'-') {
|
||||
sign = MP_NEG;
|
||||
ch = fgetc(stream);
|
||||
}
|
||||
|
||||
/* no digits, return error */
|
||||
if (ch == EOF) {
|
||||
return MP_ERR;
|
||||
}
|
||||
|
||||
/* clear a */
|
||||
mp_zero(a);
|
||||
|
||||
do {
|
||||
uint8_t y;
|
||||
unsigned pos;
|
||||
ch = (radix <= 36) ? MP_TOUPPER(ch) : ch;
|
||||
pos = (unsigned)(ch - (int)'+');
|
||||
if (MP_RADIX_MAP_REVERSE_SIZE <= pos) {
|
||||
break;
|
||||
}
|
||||
|
||||
y = s_mp_radix_map_reverse[pos];
|
||||
|
||||
if (y >= radix) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* shift up and add */
|
||||
if ((err = mp_mul_d(a, (mp_digit)radix, a)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
if ((err = mp_add_d(a, y, a)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
} while ((ch = fgetc(stream)) != EOF);
|
||||
|
||||
if (!mp_iszero(a)) {
|
||||
a->sign = sign;
|
||||
}
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
21
src/libtommath/mp_from_sbin.c
Normal file
21
src/libtommath/mp_from_sbin.c
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_FROM_SBIN_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* read signed bin, big endian, first byte is 0==positive or 1==negative */
|
||||
mp_err mp_from_sbin(mp_int *a, const uint8_t *buf, size_t size)
|
||||
{
|
||||
mp_err err;
|
||||
|
||||
/* read magnitude */
|
||||
if ((err = mp_from_ubin(a, buf + 1, size - 1u)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* first byte is 0 for positive, non-zero for negative */
|
||||
a->sign = (buf[0] != (uint8_t)0) ? MP_NEG : MP_ZPOS;
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
30
src/libtommath/mp_from_ubin.c
Normal file
30
src/libtommath/mp_from_ubin.c
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_FROM_UBIN_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* reads a uint8_t array, assumes the msb is stored first [big endian] */
|
||||
mp_err mp_from_ubin(mp_int *a, const uint8_t *buf, size_t size)
|
||||
{
|
||||
mp_err err;
|
||||
|
||||
/* make sure there are at least two digits */
|
||||
if ((err = mp_grow(a, 2)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* zero the int */
|
||||
mp_zero(a);
|
||||
|
||||
/* read the bytes in */
|
||||
while (size-- > 0u) {
|
||||
if ((err = mp_mul_2d(a, 8, a)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
a->dp[0] |= *buf++;
|
||||
a->used += 1;
|
||||
}
|
||||
mp_clamp(a);
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
33
src/libtommath/mp_fwrite.c
Normal file
33
src/libtommath/mp_fwrite.c
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_FWRITE_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
#ifndef MP_NO_FILE
|
||||
mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream)
|
||||
{
|
||||
char *buf;
|
||||
mp_err err;
|
||||
size_t size, written;
|
||||
|
||||
if ((err = mp_radix_size_overestimate(a, radix, &size)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
buf = (char *) MP_MALLOC(size);
|
||||
if (buf == NULL) {
|
||||
return MP_MEM;
|
||||
}
|
||||
|
||||
if ((err = mp_to_radix(a, buf, size, &written, radix)) == MP_OKAY) {
|
||||
if (fwrite(buf, written, 1uL, stream) != 1uL) {
|
||||
err = MP_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
MP_FREE_BUF(buf, size);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
92
src/libtommath/mp_gcd.c
Normal file
92
src/libtommath/mp_gcd.c
Normal file
@@ -0,0 +1,92 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_GCD_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* Greatest Common Divisor using the binary method */
|
||||
mp_err mp_gcd(const mp_int *a, const mp_int *b, mp_int *c)
|
||||
{
|
||||
mp_int u, v;
|
||||
int k, u_lsb, v_lsb;
|
||||
mp_err err;
|
||||
|
||||
/* either zero than gcd is the largest */
|
||||
if (mp_iszero(a)) {
|
||||
return mp_abs(b, c);
|
||||
}
|
||||
if (mp_iszero(b)) {
|
||||
return mp_abs(a, c);
|
||||
}
|
||||
|
||||
/* get copies of a and b we can modify */
|
||||
if ((err = mp_init_copy(&u, a)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = mp_init_copy(&v, b)) != MP_OKAY) {
|
||||
goto LBL_U;
|
||||
}
|
||||
|
||||
/* must be positive for the remainder of the algorithm */
|
||||
u.sign = v.sign = MP_ZPOS;
|
||||
|
||||
/* B1. Find the common power of two for u and v */
|
||||
u_lsb = mp_cnt_lsb(&u);
|
||||
v_lsb = mp_cnt_lsb(&v);
|
||||
k = MP_MIN(u_lsb, v_lsb);
|
||||
|
||||
if (k > 0) {
|
||||
/* divide the power of two out */
|
||||
if ((err = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) {
|
||||
goto LBL_V;
|
||||
}
|
||||
|
||||
if ((err = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) {
|
||||
goto LBL_V;
|
||||
}
|
||||
}
|
||||
|
||||
/* divide any remaining factors of two out */
|
||||
if (u_lsb != k) {
|
||||
if ((err = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) {
|
||||
goto LBL_V;
|
||||
}
|
||||
}
|
||||
|
||||
if (v_lsb != k) {
|
||||
if ((err = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) {
|
||||
goto LBL_V;
|
||||
}
|
||||
}
|
||||
|
||||
while (!mp_iszero(&v)) {
|
||||
/* make sure v is the largest */
|
||||
if (mp_cmp_mag(&u, &v) == MP_GT) {
|
||||
/* swap u and v to make sure v is >= u */
|
||||
mp_exch(&u, &v);
|
||||
}
|
||||
|
||||
/* subtract smallest from largest */
|
||||
if ((err = s_mp_sub(&v, &u, &v)) != MP_OKAY) {
|
||||
goto LBL_V;
|
||||
}
|
||||
|
||||
/* Divide out all factors of two */
|
||||
if ((err = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) {
|
||||
goto LBL_V;
|
||||
}
|
||||
}
|
||||
|
||||
/* multiply by 2**k which we divided out at the beginning */
|
||||
if ((err = mp_mul_2d(&u, k, c)) != MP_OKAY) {
|
||||
goto LBL_V;
|
||||
}
|
||||
c->sign = MP_ZPOS;
|
||||
err = MP_OKAY;
|
||||
LBL_V:
|
||||
mp_clear(&u);
|
||||
LBL_U:
|
||||
mp_clear(&v);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
18
src/libtommath/mp_get_double.c
Normal file
18
src/libtommath/mp_get_double.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_GET_DOUBLE_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
double mp_get_double(const mp_int *a)
|
||||
{
|
||||
int i;
|
||||
double d = 0.0, fac = 1.0;
|
||||
for (i = 0; i < MP_DIGIT_BIT; ++i) {
|
||||
fac *= 2.0;
|
||||
}
|
||||
for (i = a->used; i --> 0;) {
|
||||
d = (d * fac) + (double)a->dp[i];
|
||||
}
|
||||
return mp_isneg(a) ? -d : d;
|
||||
}
|
||||
#endif
|
||||
7
src/libtommath/mp_get_i32.c
Normal file
7
src/libtommath/mp_get_i32.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_GET_I32_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
MP_GET_SIGNED(mp_get_i32, mp_get_mag_u32, int32_t, uint32_t)
|
||||
#endif
|
||||
7
src/libtommath/mp_get_i64.c
Normal file
7
src/libtommath/mp_get_i64.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_GET_I64_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
MP_GET_SIGNED(mp_get_i64, mp_get_mag_u64, int64_t, uint64_t)
|
||||
#endif
|
||||
7
src/libtommath/mp_get_l.c
Normal file
7
src/libtommath/mp_get_l.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_GET_L_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
MP_GET_SIGNED(mp_get_l, mp_get_mag_ul, long, unsigned long)
|
||||
#endif
|
||||
7
src/libtommath/mp_get_mag_u32.c
Normal file
7
src/libtommath/mp_get_mag_u32.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_GET_MAG_U32_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
MP_GET_MAG(mp_get_mag_u32, uint32_t)
|
||||
#endif
|
||||
7
src/libtommath/mp_get_mag_u64.c
Normal file
7
src/libtommath/mp_get_mag_u64.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_GET_MAG_U64_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
MP_GET_MAG(mp_get_mag_u64, uint64_t)
|
||||
#endif
|
||||
7
src/libtommath/mp_get_mag_ul.c
Normal file
7
src/libtommath/mp_get_mag_ul.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_GET_MAG_UL_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
MP_GET_MAG(mp_get_mag_ul, unsigned long)
|
||||
#endif
|
||||
40
src/libtommath/mp_grow.c
Normal file
40
src/libtommath/mp_grow.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_GROW_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* grow as required */
|
||||
mp_err mp_grow(mp_int *a, int size)
|
||||
{
|
||||
/* if the alloc size is smaller alloc more ram */
|
||||
if (a->alloc < size) {
|
||||
mp_digit *dp;
|
||||
|
||||
if (size > MP_MAX_DIGIT_COUNT) {
|
||||
return MP_OVF;
|
||||
}
|
||||
|
||||
/* reallocate the array a->dp
|
||||
*
|
||||
* We store the return in a temporary variable
|
||||
* in case the operation failed we don't want
|
||||
* to overwrite the dp member of a.
|
||||
*/
|
||||
dp = (mp_digit *) MP_REALLOC(a->dp,
|
||||
(size_t)a->alloc * sizeof(mp_digit),
|
||||
(size_t)size * sizeof(mp_digit));
|
||||
if (dp == NULL) {
|
||||
/* reallocation failed but "a" is still valid [can be freed] */
|
||||
return MP_MEM;
|
||||
}
|
||||
|
||||
/* reallocation succeeded so set a->dp */
|
||||
a->dp = dp;
|
||||
|
||||
/* zero excess digits */
|
||||
s_mp_zero_digs(a->dp + a->alloc, size - a->alloc);
|
||||
a->alloc = size;
|
||||
}
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
23
src/libtommath/mp_init.c
Normal file
23
src/libtommath/mp_init.c
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_INIT_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* init a new mp_int */
|
||||
mp_err mp_init(mp_int *a)
|
||||
{
|
||||
/* allocate memory required and clear it */
|
||||
a->dp = (mp_digit *) MP_CALLOC((size_t)MP_DEFAULT_DIGIT_COUNT, sizeof(mp_digit));
|
||||
if (a->dp == NULL) {
|
||||
return MP_MEM;
|
||||
}
|
||||
|
||||
/* set the used to zero, allocated digits to the default precision
|
||||
* and sign to positive */
|
||||
a->used = 0;
|
||||
a->alloc = MP_DEFAULT_DIGIT_COUNT;
|
||||
a->sign = MP_ZPOS;
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
21
src/libtommath/mp_init_copy.c
Normal file
21
src/libtommath/mp_init_copy.c
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_INIT_COPY_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* creates "a" then copies b into it */
|
||||
mp_err mp_init_copy(mp_int *a, const mp_int *b)
|
||||
{
|
||||
mp_err err;
|
||||
|
||||
if ((err = mp_init_size(a, b->used)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = mp_copy(b, a)) != MP_OKAY) {
|
||||
mp_clear(a);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
7
src/libtommath/mp_init_i32.c
Normal file
7
src/libtommath/mp_init_i32.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_INIT_I32_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
MP_INIT_INT(mp_init_i32, mp_set_i32, int32_t)
|
||||
#endif
|
||||
7
src/libtommath/mp_init_i64.c
Normal file
7
src/libtommath/mp_init_i64.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_INIT_I64_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
MP_INIT_INT(mp_init_i64, mp_set_i64, int64_t)
|
||||
#endif
|
||||
7
src/libtommath/mp_init_l.c
Normal file
7
src/libtommath/mp_init_l.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_INIT_L_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
MP_INIT_INT(mp_init_l, mp_set_l, long)
|
||||
#endif
|
||||
41
src/libtommath/mp_init_multi.c
Normal file
41
src/libtommath/mp_init_multi.c
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_INIT_MULTI_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
mp_err mp_init_multi(mp_int *mp, ...)
|
||||
{
|
||||
mp_err err = MP_OKAY;
|
||||
int n = 0; /* Number of ok inits */
|
||||
mp_int *cur_arg = mp;
|
||||
va_list args;
|
||||
|
||||
va_start(args, mp); /* init args to next argument from caller */
|
||||
while (cur_arg != NULL) {
|
||||
err = mp_init(cur_arg);
|
||||
if (err != MP_OKAY) {
|
||||
/* Oops - error! Back-track and mp_clear what we already
|
||||
succeeded in init-ing, then return error.
|
||||
*/
|
||||
va_list clean_args;
|
||||
|
||||
/* now start cleaning up */
|
||||
cur_arg = mp;
|
||||
va_start(clean_args, mp);
|
||||
while (n-- != 0) {
|
||||
mp_clear(cur_arg);
|
||||
cur_arg = va_arg(clean_args, mp_int *);
|
||||
}
|
||||
va_end(clean_args);
|
||||
break;
|
||||
}
|
||||
n++;
|
||||
cur_arg = va_arg(args, mp_int *);
|
||||
}
|
||||
va_end(args);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
16
src/libtommath/mp_init_set.c
Normal file
16
src/libtommath/mp_init_set.c
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_INIT_SET_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* initialize and set a digit */
|
||||
mp_err mp_init_set(mp_int *a, mp_digit b)
|
||||
{
|
||||
mp_err err;
|
||||
if ((err = mp_init(a)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
mp_set(a, b);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
28
src/libtommath/mp_init_size.c
Normal file
28
src/libtommath/mp_init_size.c
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_INIT_SIZE_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* init an mp_init for a given size */
|
||||
mp_err mp_init_size(mp_int *a, int size)
|
||||
{
|
||||
size = MP_MAX(MP_MIN_DIGIT_COUNT, size);
|
||||
|
||||
if (size > MP_MAX_DIGIT_COUNT) {
|
||||
return MP_OVF;
|
||||
}
|
||||
|
||||
/* alloc mem */
|
||||
a->dp = (mp_digit *) MP_CALLOC((size_t)size, sizeof(mp_digit));
|
||||
if (a->dp == NULL) {
|
||||
return MP_MEM;
|
||||
}
|
||||
|
||||
/* set the members */
|
||||
a->used = 0;
|
||||
a->alloc = size;
|
||||
a->sign = MP_ZPOS;
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
7
src/libtommath/mp_init_u32.c
Normal file
7
src/libtommath/mp_init_u32.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_INIT_U32_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
MP_INIT_INT(mp_init_u32, mp_set_u32, uint32_t)
|
||||
#endif
|
||||
7
src/libtommath/mp_init_u64.c
Normal file
7
src/libtommath/mp_init_u64.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_INIT_U64_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
MP_INIT_INT(mp_init_u64, mp_set_u64, uint64_t)
|
||||
#endif
|
||||
7
src/libtommath/mp_init_ul.c
Normal file
7
src/libtommath/mp_init_ul.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_INIT_UL_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
MP_INIT_INT(mp_init_ul, mp_set_ul, unsigned long)
|
||||
#endif
|
||||
29
src/libtommath/mp_invmod.c
Normal file
29
src/libtommath/mp_invmod.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_INVMOD_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* hac 14.61, pp608 */
|
||||
mp_err mp_invmod(const mp_int *a, const mp_int *b, mp_int *c)
|
||||
{
|
||||
/* for all n in N and n > 0, n = 0 mod 1 */
|
||||
if (!mp_isneg(a) && mp_cmp_d(b, 1uL) == MP_EQ) {
|
||||
mp_zero(c);
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
/* b cannot be negative and has to be >1 */
|
||||
if (mp_isneg(b) || (mp_cmp_d(b, 1uL) != MP_GT)) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
/* if the modulus is odd we can use a faster routine instead */
|
||||
if (MP_HAS(S_MP_INVMOD_ODD) && mp_isodd(b)) {
|
||||
return s_mp_invmod_odd(a, b, c);
|
||||
}
|
||||
|
||||
return MP_HAS(S_MP_INVMOD)
|
||||
? s_mp_invmod(a, b, c)
|
||||
: MP_VAL;
|
||||
}
|
||||
#endif
|
||||
93
src/libtommath/mp_is_square.c
Normal file
93
src/libtommath/mp_is_square.c
Normal file
@@ -0,0 +1,93 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_IS_SQUARE_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* Check if remainders are possible squares - fast exclude non-squares */
|
||||
static const char rem_128[128] = {
|
||||
0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||
1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||
1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||
1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||
1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||
1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1
|
||||
};
|
||||
|
||||
static const char rem_105[105] = {
|
||||
0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
|
||||
0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1,
|
||||
0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1,
|
||||
1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1,
|
||||
1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1
|
||||
};
|
||||
|
||||
/* Store non-zero to ret if arg is square, and zero if not */
|
||||
mp_err mp_is_square(const mp_int *arg, bool *ret)
|
||||
{
|
||||
mp_err err;
|
||||
mp_digit c;
|
||||
mp_int t;
|
||||
uint32_t r;
|
||||
|
||||
/* Default to Non-square :) */
|
||||
*ret = false;
|
||||
|
||||
if (mp_isneg(arg)) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
if (mp_iszero(arg)) {
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
/* First check mod 128 (suppose that MP_DIGIT_BIT is at least 7) */
|
||||
if (rem_128[127u & arg->dp[0]] == (char)1) {
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
/* Next check mod 105 (3*5*7) */
|
||||
if ((err = mp_mod_d(arg, 105uL, &c)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
if (rem_105[c] == (char)1) {
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
|
||||
if ((err = mp_init_u32(&t, 11u*13u*17u*19u*23u*29u*31u)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
if ((err = mp_mod(arg, &t, &t)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
r = mp_get_u32(&t);
|
||||
/* Check for other prime modules, note it's not an ERROR but we must
|
||||
* free "t" so the easiest way is to goto LBL_ERR. We know that err
|
||||
* is already equal to MP_OKAY from the mp_mod call
|
||||
*/
|
||||
if (((1uL<<(r%11uL)) & 0x5C4uL) != 0uL) goto LBL_ERR;
|
||||
if (((1uL<<(r%13uL)) & 0x9E4uL) != 0uL) goto LBL_ERR;
|
||||
if (((1uL<<(r%17uL)) & 0x5CE8uL) != 0uL) goto LBL_ERR;
|
||||
if (((1uL<<(r%19uL)) & 0x4F50CuL) != 0uL) goto LBL_ERR;
|
||||
if (((1uL<<(r%23uL)) & 0x7ACCA0uL) != 0uL) goto LBL_ERR;
|
||||
if (((1uL<<(r%29uL)) & 0xC2EDD0CuL) != 0uL) goto LBL_ERR;
|
||||
if (((1uL<<(r%31uL)) & 0x6DE2B848uL) != 0uL) goto LBL_ERR;
|
||||
|
||||
/* Final check - is sqr(sqrt(arg)) == arg ? */
|
||||
if ((err = mp_sqrt(arg, &t)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
if ((err = mp_sqr(&t, &t)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
*ret = (mp_cmp_mag(&t, arg) == MP_EQ);
|
||||
LBL_ERR:
|
||||
mp_clear(&t);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
129
src/libtommath/mp_kronecker.c
Normal file
129
src/libtommath/mp_kronecker.c
Normal file
@@ -0,0 +1,129 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_KRONECKER_C
|
||||
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/*
|
||||
Kronecker symbol (a|p)
|
||||
Straightforward implementation of algorithm 1.4.10 in
|
||||
Henri Cohen: "A Course in Computational Algebraic Number Theory"
|
||||
|
||||
@book{cohen2013course,
|
||||
title={A course in computational algebraic number theory},
|
||||
author={Cohen, Henri},
|
||||
volume={138},
|
||||
year={2013},
|
||||
publisher={Springer Science \& Business Media}
|
||||
}
|
||||
*/
|
||||
mp_err mp_kronecker(const mp_int *a, const mp_int *p, int *c)
|
||||
{
|
||||
mp_int a1, p1, r;
|
||||
mp_err err;
|
||||
int v, k;
|
||||
|
||||
static const char table[] = {0, 1, 0, -1, 0, -1, 0, 1};
|
||||
|
||||
if (mp_iszero(p)) {
|
||||
if ((a->used == 1) && (a->dp[0] == 1u)) {
|
||||
*c = 1;
|
||||
} else {
|
||||
*c = 0;
|
||||
}
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
if (mp_iseven(a) && mp_iseven(p)) {
|
||||
*c = 0;
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
if ((err = mp_init_copy(&a1, a)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
if ((err = mp_init_copy(&p1, p)) != MP_OKAY) {
|
||||
goto LBL_KRON_0;
|
||||
}
|
||||
|
||||
v = mp_cnt_lsb(&p1);
|
||||
if ((err = mp_div_2d(&p1, v, &p1, NULL)) != MP_OKAY) {
|
||||
goto LBL_KRON_1;
|
||||
}
|
||||
|
||||
if ((v & 1) == 0) {
|
||||
k = 1;
|
||||
} else {
|
||||
k = table[a->dp[0] & 7u];
|
||||
}
|
||||
|
||||
if (mp_isneg(&p1)) {
|
||||
p1.sign = MP_ZPOS;
|
||||
if (mp_isneg(&a1)) {
|
||||
k = -k;
|
||||
}
|
||||
}
|
||||
|
||||
if ((err = mp_init(&r)) != MP_OKAY) {
|
||||
goto LBL_KRON_1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (mp_iszero(&a1)) {
|
||||
if (mp_cmp_d(&p1, 1uL) == MP_EQ) {
|
||||
*c = k;
|
||||
goto LBL_KRON;
|
||||
} else {
|
||||
*c = 0;
|
||||
goto LBL_KRON;
|
||||
}
|
||||
}
|
||||
|
||||
v = mp_cnt_lsb(&a1);
|
||||
if ((err = mp_div_2d(&a1, v, &a1, NULL)) != MP_OKAY) {
|
||||
goto LBL_KRON;
|
||||
}
|
||||
|
||||
if ((v & 1) == 1) {
|
||||
k = k * table[p1.dp[0] & 7u];
|
||||
}
|
||||
|
||||
if (mp_isneg(&a1)) {
|
||||
/*
|
||||
* Compute k = (-1)^((a1)*(p1-1)/4) * k
|
||||
* a1.dp[0] + 1 cannot overflow because the MSB
|
||||
* of the type mp_digit is not set by definition
|
||||
*/
|
||||
if (((a1.dp[0] + 1u) & p1.dp[0] & 2u) != 0u) {
|
||||
k = -k;
|
||||
}
|
||||
} else {
|
||||
/* compute k = (-1)^((a1-1)*(p1-1)/4) * k */
|
||||
if ((a1.dp[0] & p1.dp[0] & 2u) != 0u) {
|
||||
k = -k;
|
||||
}
|
||||
}
|
||||
|
||||
if ((err = mp_copy(&a1, &r)) != MP_OKAY) {
|
||||
goto LBL_KRON;
|
||||
}
|
||||
r.sign = MP_ZPOS;
|
||||
if ((err = mp_mod(&p1, &r, &a1)) != MP_OKAY) {
|
||||
goto LBL_KRON;
|
||||
}
|
||||
if ((err = mp_copy(&r, &p1)) != MP_OKAY) {
|
||||
goto LBL_KRON;
|
||||
}
|
||||
}
|
||||
|
||||
LBL_KRON:
|
||||
mp_clear(&r);
|
||||
LBL_KRON_1:
|
||||
mp_clear(&p1);
|
||||
LBL_KRON_0:
|
||||
mp_clear(&a1);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
44
src/libtommath/mp_lcm.c
Normal file
44
src/libtommath/mp_lcm.c
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_LCM_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* computes least common multiple as |a*b|/(a, b) */
|
||||
mp_err mp_lcm(const mp_int *a, const mp_int *b, mp_int *c)
|
||||
{
|
||||
mp_err err;
|
||||
mp_int t1, t2;
|
||||
|
||||
|
||||
if ((err = mp_init_multi(&t1, &t2, NULL)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* t1 = get the GCD of the two inputs */
|
||||
if ((err = mp_gcd(a, b, &t1)) != MP_OKAY) {
|
||||
goto LBL_T;
|
||||
}
|
||||
|
||||
/* divide the smallest by the GCD */
|
||||
if (mp_cmp_mag(a, b) == MP_LT) {
|
||||
/* store quotient in t2 such that t2 * b is the LCM */
|
||||
if ((err = mp_div(a, &t1, &t2, NULL)) != MP_OKAY) {
|
||||
goto LBL_T;
|
||||
}
|
||||
err = mp_mul(b, &t2, c);
|
||||
} else {
|
||||
/* store quotient in t2 such that t2 * a is the LCM */
|
||||
if ((err = mp_div(b, &t1, &t2, NULL)) != MP_OKAY) {
|
||||
goto LBL_T;
|
||||
}
|
||||
err = mp_mul(a, &t2, c);
|
||||
}
|
||||
|
||||
/* fix the sign to positive */
|
||||
c->sign = MP_ZPOS;
|
||||
|
||||
LBL_T:
|
||||
mp_clear_multi(&t1, &t2, NULL);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
29
src/libtommath/mp_log_n.c
Normal file
29
src/libtommath/mp_log_n.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_LOG_N_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
mp_err mp_log_n(const mp_int *a, int base, int *c)
|
||||
{
|
||||
if (mp_isneg(a) || mp_iszero(a) || (base < 2) || (unsigned)base > (unsigned)MP_DIGIT_MAX) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
if (MP_HAS(S_MP_LOG_2EXPT) && MP_IS_2EXPT((mp_digit)base)) {
|
||||
*c = s_mp_log_2expt(a, (mp_digit)base);
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
if (MP_HAS(S_MP_LOG_D) && (a->used == 1)) {
|
||||
*c = s_mp_log_d((mp_digit)base, a->dp[0]);
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
if (MP_HAS(S_MP_LOG)) {
|
||||
return s_mp_log(a, (mp_digit)base, c);
|
||||
}
|
||||
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
#endif
|
||||
42
src/libtommath/mp_lshd.c
Normal file
42
src/libtommath/mp_lshd.c
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_LSHD_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* shift left a certain amount of digits */
|
||||
mp_err mp_lshd(mp_int *a, int b)
|
||||
{
|
||||
mp_err err;
|
||||
int x;
|
||||
|
||||
/* if its less than zero return */
|
||||
if (b <= 0) {
|
||||
return MP_OKAY;
|
||||
}
|
||||
/* no need to shift 0 around */
|
||||
if (mp_iszero(a)) {
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
/* grow to fit the new digits */
|
||||
if ((err = mp_grow(a, a->used + b)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* increment the used by the shift amount then copy upwards */
|
||||
a->used += b;
|
||||
|
||||
/* much like mp_rshd this is implemented using a sliding window
|
||||
* except the window goes the otherway around. Copying from
|
||||
* the bottom to the top. see mp_rshd.c for more info.
|
||||
*/
|
||||
for (x = a->used; x --> b;) {
|
||||
a->dp[x] = a->dp[x - b];
|
||||
}
|
||||
|
||||
/* zero the lower digits */
|
||||
s_mp_zero_digs(a->dp, b);
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
15
src/libtommath/mp_mod.c
Normal file
15
src/libtommath/mp_mod.c
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_MOD_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* c = a mod b, 0 <= c < b if b > 0, b < c <= 0 if b < 0 */
|
||||
mp_err mp_mod(const mp_int *a, const mp_int *b, mp_int *c)
|
||||
{
|
||||
mp_err err;
|
||||
if ((err = mp_div(a, b, NULL, c)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
return mp_iszero(c) || (c->sign == b->sign) ? MP_OKAY : mp_add(b, c, c);
|
||||
}
|
||||
#endif
|
||||
40
src/libtommath/mp_mod_2d.c
Normal file
40
src/libtommath/mp_mod_2d.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_MOD_2D_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* calc a value mod 2**b */
|
||||
mp_err mp_mod_2d(const mp_int *a, int b, mp_int *c)
|
||||
{
|
||||
int x;
|
||||
mp_err err;
|
||||
|
||||
if (b < 0) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
if (b == 0) {
|
||||
mp_zero(c);
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
/* if the modulus is larger than the value than return */
|
||||
if (b >= (a->used * MP_DIGIT_BIT)) {
|
||||
return mp_copy(a, c);
|
||||
}
|
||||
|
||||
if ((err = mp_copy(a, c)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* zero digits above the last digit of the modulus */
|
||||
x = (b / MP_DIGIT_BIT) + (((b % MP_DIGIT_BIT) == 0) ? 0 : 1);
|
||||
s_mp_zero_digs(c->dp + x, c->used - x);
|
||||
|
||||
/* clear the digit that is not completely outside/inside the modulus */
|
||||
c->dp[b / MP_DIGIT_BIT] &=
|
||||
((mp_digit)1 << (mp_digit)(b % MP_DIGIT_BIT)) - (mp_digit)1;
|
||||
mp_clamp(c);
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
43
src/libtommath/mp_montgomery_calc_normalization.c
Normal file
43
src/libtommath/mp_montgomery_calc_normalization.c
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_MONTGOMERY_CALC_NORMALIZATION_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/*
|
||||
* shifts with subtractions when the result is greater than b.
|
||||
*
|
||||
* The method is slightly modified to shift B unconditionally upto just under
|
||||
* the leading bit of b. This saves alot of multiple precision shifting.
|
||||
*/
|
||||
mp_err mp_montgomery_calc_normalization(mp_int *a, const mp_int *b)
|
||||
{
|
||||
int x, bits;
|
||||
mp_err err;
|
||||
|
||||
/* how many bits of last digit does b use */
|
||||
bits = mp_count_bits(b) % MP_DIGIT_BIT;
|
||||
|
||||
if (b->used > 1) {
|
||||
if ((err = mp_2expt(a, ((b->used - 1) * MP_DIGIT_BIT) + bits - 1)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
mp_set(a, 1uL);
|
||||
bits = 1;
|
||||
}
|
||||
|
||||
/* now compute C = A * B mod b */
|
||||
for (x = bits - 1; x < (int)MP_DIGIT_BIT; x++) {
|
||||
if ((err = mp_mul_2(a, a)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
if (mp_cmp_mag(a, b) != MP_LT) {
|
||||
if ((err = s_mp_sub(a, b, a)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
89
src/libtommath/mp_montgomery_reduce.c
Normal file
89
src/libtommath/mp_montgomery_reduce.c
Normal file
@@ -0,0 +1,89 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_MONTGOMERY_REDUCE_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* computes xR**-1 == x (mod N) via Montgomery Reduction */
|
||||
mp_err mp_montgomery_reduce(mp_int *x, const mp_int *n, mp_digit rho)
|
||||
{
|
||||
mp_err err;
|
||||
int ix, digs;
|
||||
|
||||
/* can the fast reduction [comba] method be used?
|
||||
*
|
||||
* Note that unlike in mul you're safely allowed *less*
|
||||
* than the available columns [255 per default] since carries
|
||||
* are fixed up in the inner loop.
|
||||
*/
|
||||
digs = (n->used * 2) + 1;
|
||||
if ((digs < MP_WARRAY) &&
|
||||
(x->used <= MP_WARRAY) &&
|
||||
(n->used < MP_MAX_COMBA)) {
|
||||
return s_mp_montgomery_reduce_comba(x, n, rho);
|
||||
}
|
||||
|
||||
/* grow the input as required */
|
||||
if ((err = mp_grow(x, digs)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
x->used = digs;
|
||||
|
||||
for (ix = 0; ix < n->used; ix++) {
|
||||
int iy;
|
||||
mp_digit u, mu;
|
||||
|
||||
/* mu = ai * rho mod b
|
||||
*
|
||||
* The value of rho must be precalculated via
|
||||
* montgomery_setup() such that
|
||||
* it equals -1/n0 mod b this allows the
|
||||
* following inner loop to reduce the
|
||||
* input one digit at a time
|
||||
*/
|
||||
mu = (mp_digit)(((mp_word)x->dp[ix] * (mp_word)rho) & MP_MASK);
|
||||
|
||||
/* a = a + mu * m * b**i */
|
||||
|
||||
/* Multiply and add in place */
|
||||
u = 0;
|
||||
for (iy = 0; iy < n->used; iy++) {
|
||||
/* compute product and sum */
|
||||
mp_word r = ((mp_word)mu * (mp_word)n->dp[iy]) +
|
||||
(mp_word)u + (mp_word)x->dp[ix + iy];
|
||||
|
||||
/* get carry */
|
||||
u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
|
||||
|
||||
/* fix digit */
|
||||
x->dp[ix + iy] = (mp_digit)(r & (mp_word)MP_MASK);
|
||||
}
|
||||
/* At this point the ix'th digit of x should be zero */
|
||||
|
||||
/* propagate carries upwards as required*/
|
||||
while (u != 0u) {
|
||||
x->dp[ix + iy] += u;
|
||||
u = x->dp[ix + iy] >> MP_DIGIT_BIT;
|
||||
x->dp[ix + iy] &= MP_MASK;
|
||||
++iy;
|
||||
}
|
||||
}
|
||||
|
||||
/* at this point the n.used'th least
|
||||
* significant digits of x are all zero
|
||||
* which means we can shift x to the
|
||||
* right by n.used digits and the
|
||||
* residue is unchanged.
|
||||
*/
|
||||
|
||||
/* x = x/b**n.used */
|
||||
mp_clamp(x);
|
||||
mp_rshd(x, n->used);
|
||||
|
||||
/* if x >= n then x = x - n */
|
||||
if (mp_cmp_mag(x, n) != MP_LT) {
|
||||
return s_mp_sub(x, n, x);
|
||||
}
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
40
src/libtommath/mp_montgomery_setup.c
Normal file
40
src/libtommath/mp_montgomery_setup.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_MONTGOMERY_SETUP_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* setups the montgomery reduction stuff */
|
||||
mp_err mp_montgomery_setup(const mp_int *n, mp_digit *rho)
|
||||
{
|
||||
mp_digit x, b;
|
||||
|
||||
/* fast inversion mod 2**k
|
||||
*
|
||||
* Based on the fact that
|
||||
*
|
||||
* XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n)
|
||||
* => 2*X*A - X*X*A*A = 1
|
||||
* => 2*(1) - (1) = 1
|
||||
*/
|
||||
b = n->dp[0];
|
||||
|
||||
if ((b & 1u) == 0u) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
x = (((b + 2u) & 4u) << 1) + b; /* here x*a==1 mod 2**4 */
|
||||
x *= 2u - (b * x); /* here x*a==1 mod 2**8 */
|
||||
x *= 2u - (b * x); /* here x*a==1 mod 2**16 */
|
||||
#if defined(MP_64BIT) || !(defined(MP_16BIT))
|
||||
x *= 2u - (b * x); /* here x*a==1 mod 2**32 */
|
||||
#endif
|
||||
#ifdef MP_64BIT
|
||||
x *= 2u - (b * x); /* here x*a==1 mod 2**64 */
|
||||
#endif
|
||||
|
||||
/* rho = -1/m mod b */
|
||||
*rho = (mp_digit)(((mp_word)1 << (mp_word)MP_DIGIT_BIT) - x) & MP_MASK;
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
68
src/libtommath/mp_mul.c
Normal file
68
src/libtommath/mp_mul.c
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_MUL_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* high level multiplication (handles sign) */
|
||||
mp_err mp_mul(const mp_int *a, const mp_int *b, mp_int *c)
|
||||
{
|
||||
mp_err err;
|
||||
int min = MP_MIN(a->used, b->used),
|
||||
max = MP_MAX(a->used, b->used),
|
||||
digs = a->used + b->used + 1;
|
||||
bool neg = (a->sign != b->sign);
|
||||
|
||||
if ((a == b) &&
|
||||
MP_HAS(S_MP_SQR_TOOM) && /* use Toom-Cook? */
|
||||
(a->used >= MP_SQR_TOOM_CUTOFF)) {
|
||||
err = s_mp_sqr_toom(a, c);
|
||||
} else if ((a == b) &&
|
||||
MP_HAS(S_MP_SQR_KARATSUBA) && /* Karatsuba? */
|
||||
(a->used >= MP_SQR_KARATSUBA_CUTOFF)) {
|
||||
err = s_mp_sqr_karatsuba(a, c);
|
||||
} else if ((a == b) &&
|
||||
MP_HAS(S_MP_SQR_COMBA) && /* can we use the fast comba multiplier? */
|
||||
(((a->used * 2) + 1) < MP_WARRAY) &&
|
||||
(a->used < (MP_MAX_COMBA / 2))) {
|
||||
err = s_mp_sqr_comba(a, c);
|
||||
} else if ((a == b) &&
|
||||
MP_HAS(S_MP_SQR)) {
|
||||
err = s_mp_sqr(a, c);
|
||||
} else if (MP_HAS(S_MP_MUL_BALANCE) &&
|
||||
/* Check sizes. The smaller one needs to be larger than the Karatsuba cut-off.
|
||||
* The bigger one needs to be at least about one MP_MUL_KARATSUBA_CUTOFF bigger
|
||||
* to make some sense, but it depends on architecture, OS, position of the
|
||||
* stars... so YMMV.
|
||||
* Using it to cut the input into slices small enough for s_mp_mul_comba
|
||||
* was actually slower on the author's machine, but YMMV.
|
||||
*/
|
||||
(min >= MP_MUL_KARATSUBA_CUTOFF) &&
|
||||
((max / 2) >= MP_MUL_KARATSUBA_CUTOFF) &&
|
||||
/* Not much effect was observed below a ratio of 1:2, but again: YMMV. */
|
||||
(max >= (2 * min))) {
|
||||
err = s_mp_mul_balance(a,b,c);
|
||||
} else if (MP_HAS(S_MP_MUL_TOOM) &&
|
||||
(min >= MP_MUL_TOOM_CUTOFF)) {
|
||||
err = s_mp_mul_toom(a, b, c);
|
||||
} else if (MP_HAS(S_MP_MUL_KARATSUBA) &&
|
||||
(min >= MP_MUL_KARATSUBA_CUTOFF)) {
|
||||
err = s_mp_mul_karatsuba(a, b, c);
|
||||
} else if (MP_HAS(S_MP_MUL_COMBA) &&
|
||||
/* can we use the fast multiplier?
|
||||
*
|
||||
* The fast multiplier can be used if the output will
|
||||
* have less than MP_WARRAY digits and the number of
|
||||
* digits won't affect carry propagation
|
||||
*/
|
||||
(digs < MP_WARRAY) &&
|
||||
(min <= MP_MAX_COMBA)) {
|
||||
err = s_mp_mul_comba(a, b, c, digs);
|
||||
} else if (MP_HAS(S_MP_MUL)) {
|
||||
err = s_mp_mul(a, b, c, digs);
|
||||
} else {
|
||||
err = MP_VAL;
|
||||
}
|
||||
c->sign = ((c->used > 0) && neg) ? MP_NEG : MP_ZPOS;
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
53
src/libtommath/mp_mul_2.c
Normal file
53
src/libtommath/mp_mul_2.c
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_MUL_2_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* b = a*2 */
|
||||
mp_err mp_mul_2(const mp_int *a, mp_int *b)
|
||||
{
|
||||
mp_err err;
|
||||
int x, oldused;
|
||||
mp_digit r;
|
||||
|
||||
/* grow to accomodate result */
|
||||
if ((err = mp_grow(b, a->used + 1)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
oldused = b->used;
|
||||
b->used = a->used;
|
||||
|
||||
/* carry */
|
||||
r = 0;
|
||||
for (x = 0; x < a->used; x++) {
|
||||
|
||||
/* get what will be the *next* carry bit from the
|
||||
* MSB of the current digit
|
||||
*/
|
||||
mp_digit rr = a->dp[x] >> (mp_digit)(MP_DIGIT_BIT - 1);
|
||||
|
||||
/* now shift up this digit, add in the carry [from the previous] */
|
||||
b->dp[x] = ((a->dp[x] << 1uL) | r) & MP_MASK;
|
||||
|
||||
/* copy the carry that would be from the source
|
||||
* digit into the next iteration
|
||||
*/
|
||||
r = rr;
|
||||
}
|
||||
|
||||
/* new leading digit? */
|
||||
if (r != 0u) {
|
||||
/* add a MSB which is always 1 at this point */
|
||||
b->dp[b->used++] = 1;
|
||||
}
|
||||
|
||||
/* now zero any excess digits on the destination
|
||||
* that we didn't write to
|
||||
*/
|
||||
s_mp_zero_digs(b->dp + b->used, oldused - b->used);
|
||||
|
||||
b->sign = a->sign;
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
63
src/libtommath/mp_mul_2d.c
Normal file
63
src/libtommath/mp_mul_2d.c
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_MUL_2D_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* shift left by a certain bit count */
|
||||
mp_err mp_mul_2d(const mp_int *a, int b, mp_int *c)
|
||||
{
|
||||
mp_err err;
|
||||
|
||||
if (b < 0) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
if ((err = mp_copy(a, c)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = mp_grow(c, c->used + (b / MP_DIGIT_BIT) + 1)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* shift by as many digits in the bit count */
|
||||
if (b >= MP_DIGIT_BIT) {
|
||||
if ((err = mp_lshd(c, b / MP_DIGIT_BIT)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* shift any bit count < MP_DIGIT_BIT */
|
||||
b %= MP_DIGIT_BIT;
|
||||
if (b != 0u) {
|
||||
mp_digit shift, mask, r;
|
||||
int x;
|
||||
|
||||
/* bitmask for carries */
|
||||
mask = ((mp_digit)1 << b) - (mp_digit)1;
|
||||
|
||||
/* shift for msbs */
|
||||
shift = (mp_digit)(MP_DIGIT_BIT - b);
|
||||
|
||||
/* carry */
|
||||
r = 0;
|
||||
for (x = 0; x < c->used; x++) {
|
||||
/* get the higher bits of the current word */
|
||||
mp_digit rr = (c->dp[x] >> shift) & mask;
|
||||
|
||||
/* shift the current word and OR in the carry */
|
||||
c->dp[x] = ((c->dp[x] << b) | r) & MP_MASK;
|
||||
|
||||
/* set the carry to the carry bits of the current word */
|
||||
r = rr;
|
||||
}
|
||||
|
||||
/* set final carry */
|
||||
if (r != 0u) {
|
||||
c->dp[(c->used)++] = r;
|
||||
}
|
||||
}
|
||||
mp_clamp(c);
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
68
src/libtommath/mp_mul_d.c
Normal file
68
src/libtommath/mp_mul_d.c
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_MUL_D_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* multiply by a digit */
|
||||
mp_err mp_mul_d(const mp_int *a, mp_digit b, mp_int *c)
|
||||
{
|
||||
mp_digit u;
|
||||
mp_err err;
|
||||
int ix, oldused;
|
||||
|
||||
if (b == 1u) {
|
||||
return mp_copy(a, c);
|
||||
}
|
||||
|
||||
/* power of two ? */
|
||||
if (MP_HAS(MP_MUL_2) && (b == 2u)) {
|
||||
return mp_mul_2(a, c);
|
||||
}
|
||||
if (MP_HAS(MP_MUL_2D) && MP_IS_2EXPT(b)) {
|
||||
ix = 1;
|
||||
while ((ix < MP_DIGIT_BIT) && (b != (((mp_digit)1)<<ix))) {
|
||||
ix++;
|
||||
}
|
||||
return mp_mul_2d(a, ix, c);
|
||||
}
|
||||
|
||||
/* make sure c is big enough to hold a*b */
|
||||
if ((err = mp_grow(c, a->used + 1)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* get the original destinations used count */
|
||||
oldused = c->used;
|
||||
|
||||
/* set the sign */
|
||||
c->sign = a->sign;
|
||||
|
||||
/* zero carry */
|
||||
u = 0;
|
||||
|
||||
/* compute columns */
|
||||
for (ix = 0; ix < a->used; ix++) {
|
||||
/* compute product and carry sum for this term */
|
||||
mp_word r = (mp_word)u + ((mp_word)a->dp[ix] * (mp_word)b);
|
||||
|
||||
/* mask off higher bits to get a single digit */
|
||||
c->dp[ix] = (mp_digit)(r & (mp_word)MP_MASK);
|
||||
|
||||
/* send carry into next iteration */
|
||||
u = (mp_digit)(r >> (mp_word)MP_DIGIT_BIT);
|
||||
}
|
||||
|
||||
/* store final carry [if any] and increment ix offset */
|
||||
c->dp[ix] = u;
|
||||
|
||||
/* set used count */
|
||||
c->used = a->used + 1;
|
||||
|
||||
/* now zero digits above the top */
|
||||
s_mp_zero_digs(c->dp + c->used, oldused - c->used);
|
||||
|
||||
mp_clamp(c);
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
15
src/libtommath/mp_mulmod.c
Normal file
15
src/libtommath/mp_mulmod.c
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_MULMOD_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* d = a * b (mod c) */
|
||||
mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *c, mp_int *d)
|
||||
{
|
||||
mp_err err;
|
||||
if ((err = mp_mul(a, b, d)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
return mp_mod(d, c, d);
|
||||
}
|
||||
#endif
|
||||
18
src/libtommath/mp_neg.c
Normal file
18
src/libtommath/mp_neg.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_NEG_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* b = -a */
|
||||
mp_err mp_neg(const mp_int *a, mp_int *b)
|
||||
{
|
||||
mp_err err;
|
||||
if ((err = mp_copy(a, b)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
b->sign = ((!mp_iszero(b) && !mp_isneg(b)) ? MP_NEG : MP_ZPOS);
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
54
src/libtommath/mp_or.c
Normal file
54
src/libtommath/mp_or.c
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_OR_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* two complement or */
|
||||
mp_err mp_or(const mp_int *a, const mp_int *b, mp_int *c)
|
||||
{
|
||||
int used = MP_MAX(a->used, b->used) + 1, i;
|
||||
mp_err err;
|
||||
mp_digit ac = 1, bc = 1, cc = 1;
|
||||
bool neg = (mp_isneg(a) || mp_isneg(b));
|
||||
|
||||
if ((err = mp_grow(c, used)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < used; i++) {
|
||||
mp_digit x, y;
|
||||
|
||||
/* convert to two complement if negative */
|
||||
if (mp_isneg(a)) {
|
||||
ac += (i >= a->used) ? MP_MASK : (~a->dp[i] & MP_MASK);
|
||||
x = ac & MP_MASK;
|
||||
ac >>= MP_DIGIT_BIT;
|
||||
} else {
|
||||
x = (i >= a->used) ? 0uL : a->dp[i];
|
||||
}
|
||||
|
||||
/* convert to two complement if negative */
|
||||
if (mp_isneg(b)) {
|
||||
bc += (i >= b->used) ? MP_MASK : (~b->dp[i] & MP_MASK);
|
||||
y = bc & MP_MASK;
|
||||
bc >>= MP_DIGIT_BIT;
|
||||
} else {
|
||||
y = (i >= b->used) ? 0uL : b->dp[i];
|
||||
}
|
||||
|
||||
c->dp[i] = x | y;
|
||||
|
||||
/* convert to to sign-magnitude if negative */
|
||||
if (neg) {
|
||||
cc += ~c->dp[i] & MP_MASK;
|
||||
c->dp[i] = cc & MP_MASK;
|
||||
cc >>= MP_DIGIT_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
c->used = used;
|
||||
c->sign = (neg ? MP_NEG : MP_ZPOS);
|
||||
mp_clamp(c);
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
69
src/libtommath/mp_pack.c
Normal file
69
src/libtommath/mp_pack.c
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_PACK_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* based on gmp's mpz_export.
|
||||
* see http://gmplib.org/manual/Integer-Import-and-Export.html
|
||||
*/
|
||||
mp_err mp_pack(void *rop, size_t maxcount, size_t *written, mp_order order, size_t size,
|
||||
mp_endian endian, size_t nails, const mp_int *op)
|
||||
{
|
||||
mp_err err;
|
||||
size_t odd_nails, nail_bytes, i, j, count;
|
||||
uint8_t odd_nail_mask;
|
||||
|
||||
mp_int t;
|
||||
|
||||
count = mp_pack_count(op, nails, size);
|
||||
|
||||
if (count > maxcount) {
|
||||
return MP_BUF;
|
||||
}
|
||||
|
||||
if ((err = mp_init_copy(&t, op)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (endian == MP_NATIVE_ENDIAN) {
|
||||
MP_GET_ENDIANNESS(endian);
|
||||
}
|
||||
|
||||
odd_nails = (nails % 8u);
|
||||
odd_nail_mask = 0xff;
|
||||
for (i = 0u; i < odd_nails; ++i) {
|
||||
odd_nail_mask ^= (uint8_t)(1u << (7u - i));
|
||||
}
|
||||
nail_bytes = nails / 8u;
|
||||
|
||||
for (i = 0u; i < count; ++i) {
|
||||
for (j = 0u; j < size; ++j) {
|
||||
uint8_t *byte = (uint8_t *)rop +
|
||||
(((order == MP_LSB_FIRST) ? i : ((count - 1u) - i)) * size) +
|
||||
((endian == MP_LITTLE_ENDIAN) ? j : ((size - 1u) - j));
|
||||
|
||||
if (j >= (size - nail_bytes)) {
|
||||
*byte = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
*byte = (uint8_t)((j == ((size - nail_bytes) - 1u)) ? (t.dp[0] & odd_nail_mask) : (t.dp[0] & 0xFFuL));
|
||||
|
||||
if ((err = mp_div_2d(&t, (j == ((size - nail_bytes) - 1u)) ? (int)(8u - odd_nails) : 8, &t, NULL)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (written != NULL) {
|
||||
*written = count;
|
||||
}
|
||||
err = MP_OKAY;
|
||||
|
||||
LBL_ERR:
|
||||
mp_clear(&t);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
12
src/libtommath/mp_pack_count.c
Normal file
12
src/libtommath/mp_pack_count.c
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_PACK_COUNT_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
size_t mp_pack_count(const mp_int *a, size_t nails, size_t size)
|
||||
{
|
||||
size_t bits = (size_t)mp_count_bits(a);
|
||||
return ((bits / ((size * 8u) - nails)) + (((bits % ((size * 8u) - nails)) != 0u) ? 1u : 0u));
|
||||
}
|
||||
|
||||
#endif
|
||||
41
src/libtommath/mp_prime_fermat.c
Normal file
41
src/libtommath/mp_prime_fermat.c
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_PRIME_FERMAT_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* performs one Fermat test.
|
||||
*
|
||||
* If "a" were prime then b**a == b (mod a) since the order of
|
||||
* the multiplicative sub-group would be phi(a) = a-1. That means
|
||||
* it would be the same as b**(a mod (a-1)) == b**1 == b (mod a).
|
||||
*
|
||||
* Sets result to 1 if the congruence holds, or zero otherwise.
|
||||
*/
|
||||
mp_err mp_prime_fermat(const mp_int *a, const mp_int *b, bool *result)
|
||||
{
|
||||
mp_int t;
|
||||
mp_err err;
|
||||
|
||||
/* ensure b > 1 */
|
||||
if (mp_cmp_d(b, 1uL) != MP_GT) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
/* init t */
|
||||
if ((err = mp_init(&t)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* compute t = b**a mod a */
|
||||
if ((err = mp_exptmod(b, a, a, &t)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
/* is it equal to b? */
|
||||
*result = mp_cmp(&t, b) == MP_EQ;
|
||||
|
||||
LBL_ERR:
|
||||
mp_clear(&t);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
127
src/libtommath/mp_prime_frobenius_underwood.c
Normal file
127
src/libtommath/mp_prime_frobenius_underwood.c
Normal file
@@ -0,0 +1,127 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_PRIME_FROBENIUS_UNDERWOOD_C
|
||||
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/*
|
||||
* See file mp_prime_is_prime.c or the documentation in doc/bn.tex for the details
|
||||
*/
|
||||
#ifndef LTM_USE_ONLY_MR
|
||||
|
||||
/*
|
||||
* floor of positive solution of
|
||||
* (2^16)-1 = (a+4)*(2*a+5)
|
||||
* TODO: Both values are smaller than N^(1/4), would have to use a bigint
|
||||
* for a instead but any a biger than about 120 are already so rare that
|
||||
* it is possible to ignore them and still get enough pseudoprimes.
|
||||
* But it is still a restriction of the set of available pseudoprimes
|
||||
* which makes this implementation less secure if used stand-alone.
|
||||
*/
|
||||
#define LTM_FROBENIUS_UNDERWOOD_A 32764
|
||||
|
||||
mp_err mp_prime_frobenius_underwood(const mp_int *N, bool *result)
|
||||
{
|
||||
mp_int T1z, T2z, Np1z, sz, tz;
|
||||
int a, ap2, i;
|
||||
mp_err err;
|
||||
|
||||
if ((err = mp_init_multi(&T1z, &T2z, &Np1z, &sz, &tz, NULL)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
for (a = 0; a < LTM_FROBENIUS_UNDERWOOD_A; a++) {
|
||||
int j;
|
||||
|
||||
/* TODO: That's ugly! No, really, it is! */
|
||||
if ((a==2) || (a==4) || (a==7) || (a==8) || (a==10) ||
|
||||
(a==14) || (a==18) || (a==23) || (a==26) || (a==28)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mp_set_i32(&T1z, (int32_t)((a * a) - 4));
|
||||
|
||||
if ((err = mp_kronecker(&T1z, N, &j)) != MP_OKAY) goto LBL_END;
|
||||
|
||||
if (j == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (j == 0) {
|
||||
/* composite */
|
||||
*result = false;
|
||||
goto LBL_END;
|
||||
}
|
||||
}
|
||||
/* Tell it a composite and set return value accordingly */
|
||||
if (a >= LTM_FROBENIUS_UNDERWOOD_A) {
|
||||
err = MP_ITER;
|
||||
goto LBL_END;
|
||||
}
|
||||
/* Composite if N and (a+4)*(2*a+5) are not coprime */
|
||||
mp_set_u32(&T1z, (uint32_t)((a+4)*((2*a)+5)));
|
||||
|
||||
if ((err = mp_gcd(N, &T1z, &T1z)) != MP_OKAY) goto LBL_END;
|
||||
|
||||
if (!((T1z.used == 1) && (T1z.dp[0] == 1u))) {
|
||||
/* composite */
|
||||
*result = false;
|
||||
goto LBL_END;
|
||||
}
|
||||
|
||||
ap2 = a + 2;
|
||||
if ((err = mp_add_d(N, 1uL, &Np1z)) != MP_OKAY) goto LBL_END;
|
||||
|
||||
mp_set(&sz, 1uL);
|
||||
mp_set(&tz, 2uL);
|
||||
|
||||
for (i = mp_count_bits(&Np1z) - 2; i >= 0; i--) {
|
||||
/*
|
||||
* temp = (sz*(a*sz+2*tz))%N;
|
||||
* tz = ((tz-sz)*(tz+sz))%N;
|
||||
* sz = temp;
|
||||
*/
|
||||
if ((err = mp_mul_2(&tz, &T2z)) != MP_OKAY) goto LBL_END;
|
||||
|
||||
/* a = 0 at about 50% of the cases (non-square and odd input) */
|
||||
if (a != 0) {
|
||||
if ((err = mp_mul_d(&sz, (mp_digit)a, &T1z)) != MP_OKAY) goto LBL_END;
|
||||
if ((err = mp_add(&T1z, &T2z, &T2z)) != MP_OKAY) goto LBL_END;
|
||||
}
|
||||
|
||||
if ((err = mp_mul(&T2z, &sz, &T1z)) != MP_OKAY) goto LBL_END;
|
||||
if ((err = mp_sub(&tz, &sz, &T2z)) != MP_OKAY) goto LBL_END;
|
||||
if ((err = mp_add(&sz, &tz, &sz)) != MP_OKAY) goto LBL_END;
|
||||
if ((err = mp_mul(&sz, &T2z, &tz)) != MP_OKAY) goto LBL_END;
|
||||
if ((err = mp_mod(&tz, N, &tz)) != MP_OKAY) goto LBL_END;
|
||||
if ((err = mp_mod(&T1z, N, &sz)) != MP_OKAY) goto LBL_END;
|
||||
if (s_mp_get_bit(&Np1z, i)) {
|
||||
/*
|
||||
* temp = (a+2) * sz + tz
|
||||
* tz = 2 * tz - sz
|
||||
* sz = temp
|
||||
*/
|
||||
if (a == 0) {
|
||||
if ((err = mp_mul_2(&sz, &T1z)) != MP_OKAY) goto LBL_END;
|
||||
} else {
|
||||
if ((err = mp_mul_d(&sz, (mp_digit)ap2, &T1z)) != MP_OKAY) goto LBL_END;
|
||||
}
|
||||
if ((err = mp_add(&T1z, &tz, &T1z)) != MP_OKAY) goto LBL_END;
|
||||
if ((err = mp_mul_2(&tz, &T2z)) != MP_OKAY) goto LBL_END;
|
||||
if ((err = mp_sub(&T2z, &sz, &tz)) != MP_OKAY) goto LBL_END;
|
||||
mp_exch(&sz, &T1z);
|
||||
}
|
||||
}
|
||||
|
||||
mp_set_u32(&T1z, (uint32_t)((2 * a) + 5));
|
||||
if ((err = mp_mod(&T1z, N, &T1z)) != MP_OKAY) goto LBL_END;
|
||||
|
||||
*result = mp_iszero(&sz) && (mp_cmp(&tz, &T1z) == MP_EQ);
|
||||
|
||||
LBL_END:
|
||||
mp_clear_multi(&tz, &sz, &Np1z, &T2z, &T1z, NULL);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
282
src/libtommath/mp_prime_is_prime.c
Normal file
282
src/libtommath/mp_prime_is_prime.c
Normal file
@@ -0,0 +1,282 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_PRIME_IS_PRIME_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* portable integer log of two with small footprint */
|
||||
static unsigned int s_floor_ilog2(int value)
|
||||
{
|
||||
unsigned int r = 0;
|
||||
while ((value >>= 1) != 0) {
|
||||
r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
mp_err mp_prime_is_prime(const mp_int *a, int t, bool *result)
|
||||
{
|
||||
mp_int b;
|
||||
int ix;
|
||||
bool res;
|
||||
mp_err err;
|
||||
|
||||
/* default to no */
|
||||
*result = false;
|
||||
|
||||
/* Some shortcuts */
|
||||
/* N > 3 */
|
||||
if (a->used == 1) {
|
||||
if ((a->dp[0] == 0u) || (a->dp[0] == 1u)) {
|
||||
*result = false;
|
||||
return MP_OKAY;
|
||||
}
|
||||
if (a->dp[0] == 2u) {
|
||||
*result = true;
|
||||
return MP_OKAY;
|
||||
}
|
||||
}
|
||||
|
||||
/* N must be odd */
|
||||
if (mp_iseven(a)) {
|
||||
return MP_OKAY;
|
||||
}
|
||||
/* N is not a perfect square: floor(sqrt(N))^2 != N */
|
||||
if ((err = mp_is_square(a, &res)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
if (res) {
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
/* is the input equal to one of the primes in the table? */
|
||||
for (ix = 0; ix < MP_PRIME_TAB_SIZE; ix++) {
|
||||
if (mp_cmp_d(a, s_mp_prime_tab[ix]) == MP_EQ) {
|
||||
*result = true;
|
||||
return MP_OKAY;
|
||||
}
|
||||
}
|
||||
/* first perform trial division */
|
||||
if ((err = s_mp_prime_is_divisible(a, &res)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* return if it was trivially divisible */
|
||||
if (res) {
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
/*
|
||||
Run the Miller-Rabin test with base 2 for the BPSW test.
|
||||
*/
|
||||
if ((err = mp_init_set(&b, 2uL)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
|
||||
goto LBL_B;
|
||||
}
|
||||
if (!res) {
|
||||
goto LBL_B;
|
||||
}
|
||||
/*
|
||||
Rumours have it that Mathematica does a second M-R test with base 3.
|
||||
Other rumours have it that their strong L-S test is slightly different.
|
||||
It does not hurt, though, beside a bit of extra runtime.
|
||||
*/
|
||||
b.dp[0]++;
|
||||
if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
|
||||
goto LBL_B;
|
||||
}
|
||||
if (!res) {
|
||||
goto LBL_B;
|
||||
}
|
||||
|
||||
/*
|
||||
* Both, the Frobenius-Underwood test and the the Lucas-Selfridge test are quite
|
||||
* slow so if speed is an issue, define LTM_USE_ONLY_MR to use M-R tests with
|
||||
* bases 2, 3 and t random bases.
|
||||
*/
|
||||
#ifndef LTM_USE_ONLY_MR
|
||||
if (t >= 0) {
|
||||
#ifdef LTM_USE_FROBENIUS_TEST
|
||||
err = mp_prime_frobenius_underwood(a, &res);
|
||||
if ((err != MP_OKAY) && (err != MP_ITER)) {
|
||||
goto LBL_B;
|
||||
}
|
||||
if (!res) {
|
||||
goto LBL_B;
|
||||
}
|
||||
#else
|
||||
if ((err = mp_prime_strong_lucas_selfridge(a, &res)) != MP_OKAY) {
|
||||
goto LBL_B;
|
||||
}
|
||||
if (!res) {
|
||||
goto LBL_B;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* run at least one Miller-Rabin test with a random base */
|
||||
if (t == 0) {
|
||||
t = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Only recommended if the input range is known to be < 3317044064679887385961981
|
||||
|
||||
It uses the bases necessary for a deterministic M-R test if the input is
|
||||
smaller than 3317044064679887385961981
|
||||
The caller has to check the size.
|
||||
TODO: can be made a bit finer grained but comparing is not free.
|
||||
*/
|
||||
if (t < 0) {
|
||||
int p_max = 0;
|
||||
|
||||
/*
|
||||
Sorenson, Jonathan; Webster, Jonathan (2015).
|
||||
"Strong Pseudoprimes to Twelve Prime Bases".
|
||||
*/
|
||||
/* 0x437ae92817f9fc85b7e5 = 318665857834031151167461 */
|
||||
if ((err = mp_read_radix(&b, "437ae92817f9fc85b7e5", 16)) != MP_OKAY) {
|
||||
goto LBL_B;
|
||||
}
|
||||
|
||||
if (mp_cmp(a, &b) == MP_LT) {
|
||||
p_max = 12;
|
||||
} else {
|
||||
/* 0x2be6951adc5b22410a5fd = 3317044064679887385961981 */
|
||||
if ((err = mp_read_radix(&b, "2be6951adc5b22410a5fd", 16)) != MP_OKAY) {
|
||||
goto LBL_B;
|
||||
}
|
||||
|
||||
if (mp_cmp(a, &b) == MP_LT) {
|
||||
p_max = 13;
|
||||
} else {
|
||||
err = MP_VAL;
|
||||
goto LBL_B;
|
||||
}
|
||||
}
|
||||
|
||||
/* we did bases 2 and 3 already, skip them */
|
||||
for (ix = 2; ix < p_max; ix++) {
|
||||
mp_set(&b, s_mp_prime_tab[ix]);
|
||||
if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
|
||||
goto LBL_B;
|
||||
}
|
||||
if (!res) {
|
||||
goto LBL_B;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
Do "t" M-R tests with random bases between 3 and "a".
|
||||
See Fips 186.4 p. 126ff
|
||||
*/
|
||||
else if (t > 0) {
|
||||
unsigned int mask;
|
||||
int size_a;
|
||||
|
||||
/*
|
||||
* The mp_digit's have a defined bit-size but the size of the
|
||||
* array a.dp is a simple 'int' and this library can not assume full
|
||||
* compliance to the current C-standard (ISO/IEC 9899:2011) because
|
||||
* it gets used for small embeded processors, too. Some of those MCUs
|
||||
* have compilers that one cannot call standard compliant by any means.
|
||||
* Hence the ugly type-fiddling in the following code.
|
||||
*/
|
||||
size_a = mp_count_bits(a);
|
||||
mask = (1u << s_floor_ilog2(size_a)) - 1u;
|
||||
/*
|
||||
Assuming the General Rieman hypothesis (never thought to write that in a
|
||||
comment) the upper bound can be lowered to 2*(log a)^2.
|
||||
E. Bach, "Explicit bounds for primality testing and related problems,"
|
||||
Math. Comp. 55 (1990), 355-380.
|
||||
|
||||
size_a = (size_a/10) * 7;
|
||||
len = 2 * (size_a * size_a);
|
||||
|
||||
E.g.: a number of size 2^2048 would be reduced to the upper limit
|
||||
|
||||
floor(2048/10)*7 = 1428
|
||||
2 * 1428^2 = 4078368
|
||||
|
||||
(would have been ~4030331.9962 with floats and natural log instead)
|
||||
That number is smaller than 2^28, the default bit-size of mp_digit.
|
||||
*/
|
||||
|
||||
/*
|
||||
How many tests, you might ask? Dana Jacobsen of Math::Prime::Util fame
|
||||
does exactly 1. In words: one. Look at the end of _GMP_is_prime() in
|
||||
Math-Prime-Util-GMP-0.50/primality.c if you do not believe it.
|
||||
|
||||
The function mp_rand() goes to some length to use a cryptographically
|
||||
good PRNG. That also means that the chance to always get the same base
|
||||
in the loop is non-zero, although very low.
|
||||
If the BPSW test and/or the addtional Frobenious test have been
|
||||
performed instead of just the Miller-Rabin test with the bases 2 and 3,
|
||||
a single extra test should suffice, so such a very unlikely event
|
||||
will not do much harm.
|
||||
|
||||
To preemptivly answer the dangling question: no, a witness does not
|
||||
need to be prime.
|
||||
*/
|
||||
for (ix = 0; ix < t; ix++) {
|
||||
unsigned int fips_rand;
|
||||
int len;
|
||||
|
||||
/* mp_rand() guarantees the first digit to be non-zero */
|
||||
if ((err = mp_rand(&b, 1)) != MP_OKAY) {
|
||||
goto LBL_B;
|
||||
}
|
||||
/*
|
||||
* Reduce digit before casting because mp_digit might be bigger than
|
||||
* an unsigned int and "mask" on the other side is most probably not.
|
||||
*/
|
||||
fips_rand = (unsigned int)(b.dp[0] & (mp_digit) mask);
|
||||
if (fips_rand > (unsigned int)(INT_MAX - MP_DIGIT_BIT)) {
|
||||
len = INT_MAX / MP_DIGIT_BIT;
|
||||
} else {
|
||||
len = (((int)fips_rand + MP_DIGIT_BIT) / MP_DIGIT_BIT);
|
||||
}
|
||||
/* Unlikely. */
|
||||
if (len < 0) {
|
||||
ix--;
|
||||
continue;
|
||||
}
|
||||
if ((err = mp_rand(&b, len)) != MP_OKAY) {
|
||||
goto LBL_B;
|
||||
}
|
||||
/*
|
||||
* That number might got too big and the witness has to be
|
||||
* smaller than "a"
|
||||
*/
|
||||
len = mp_count_bits(&b);
|
||||
if (len >= size_a) {
|
||||
len = (len - size_a) + 1;
|
||||
if ((err = mp_div_2d(&b, len, &b, NULL)) != MP_OKAY) {
|
||||
goto LBL_B;
|
||||
}
|
||||
}
|
||||
/* Although the chance for b <= 3 is miniscule, try again. */
|
||||
if (mp_cmp_d(&b, 3uL) != MP_GT) {
|
||||
ix--;
|
||||
continue;
|
||||
}
|
||||
if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
|
||||
goto LBL_B;
|
||||
}
|
||||
if (!res) {
|
||||
goto LBL_B;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* passed the test */
|
||||
*result = true;
|
||||
LBL_B:
|
||||
mp_clear(&b);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
91
src/libtommath/mp_prime_miller_rabin.c
Normal file
91
src/libtommath/mp_prime_miller_rabin.c
Normal file
@@ -0,0 +1,91 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_PRIME_MILLER_RABIN_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* Miller-Rabin test of "a" to the base of "b" as described in
|
||||
* HAC pp. 139 Algorithm 4.24
|
||||
*
|
||||
* Sets result to 0 if definitely composite or 1 if probably prime.
|
||||
* Randomly the chance of error is no more than 1/4 and often
|
||||
* very much lower.
|
||||
*/
|
||||
mp_err mp_prime_miller_rabin(const mp_int *a, const mp_int *b, bool *result)
|
||||
{
|
||||
mp_int n1, y, r;
|
||||
mp_err err;
|
||||
int s, j;
|
||||
|
||||
/* ensure b > 1 */
|
||||
if (mp_cmp_d(b, 1uL) != MP_GT) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
/* get n1 = a - 1 */
|
||||
if ((err = mp_init_copy(&n1, a)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
if ((err = mp_sub_d(&n1, 1uL, &n1)) != MP_OKAY) {
|
||||
goto LBL_ERR1;
|
||||
}
|
||||
|
||||
/* set 2**s * r = n1 */
|
||||
if ((err = mp_init_copy(&r, &n1)) != MP_OKAY) {
|
||||
goto LBL_ERR1;
|
||||
}
|
||||
|
||||
/* count the number of least significant bits
|
||||
* which are zero
|
||||
*/
|
||||
s = mp_cnt_lsb(&r);
|
||||
|
||||
/* now divide n - 1 by 2**s */
|
||||
if ((err = mp_div_2d(&r, s, &r, NULL)) != MP_OKAY) {
|
||||
goto LBL_ERR2;
|
||||
}
|
||||
|
||||
/* compute y = b**r mod a */
|
||||
if ((err = mp_init(&y)) != MP_OKAY) {
|
||||
goto LBL_ERR2;
|
||||
}
|
||||
if ((err = mp_exptmod(b, &r, a, &y)) != MP_OKAY) {
|
||||
goto LBL_END;
|
||||
}
|
||||
|
||||
/* if y != 1 and y != n1 do */
|
||||
if ((mp_cmp_d(&y, 1uL) != MP_EQ) && (mp_cmp(&y, &n1) != MP_EQ)) {
|
||||
j = 1;
|
||||
/* while j <= s-1 and y != n1 */
|
||||
while ((j <= (s - 1)) && (mp_cmp(&y, &n1) != MP_EQ)) {
|
||||
if ((err = mp_sqrmod(&y, a, &y)) != MP_OKAY) {
|
||||
goto LBL_END;
|
||||
}
|
||||
|
||||
/* if y == 1 then composite */
|
||||
if (mp_cmp_d(&y, 1uL) == MP_EQ) {
|
||||
*result = false;
|
||||
goto LBL_END;
|
||||
}
|
||||
|
||||
++j;
|
||||
}
|
||||
|
||||
/* if y != n1 then composite */
|
||||
if (mp_cmp(&y, &n1) != MP_EQ) {
|
||||
*result = false;
|
||||
goto LBL_END;
|
||||
}
|
||||
}
|
||||
|
||||
/* probably prime now */
|
||||
*result = true;
|
||||
|
||||
LBL_END:
|
||||
mp_clear(&y);
|
||||
LBL_ERR2:
|
||||
mp_clear(&r);
|
||||
LBL_ERR1:
|
||||
mp_clear(&n1);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
127
src/libtommath/mp_prime_next_prime.c
Normal file
127
src/libtommath/mp_prime_next_prime.c
Normal file
@@ -0,0 +1,127 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_PRIME_NEXT_PRIME_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* finds the next prime after the number "a" using "t" trials
|
||||
* of Miller-Rabin.
|
||||
*
|
||||
* bbs_style = true means the prime must be congruent to 3 mod 4
|
||||
*/
|
||||
mp_err mp_prime_next_prime(mp_int *a, int t, bool bbs_style)
|
||||
{
|
||||
int x;
|
||||
mp_err err;
|
||||
bool res = false;
|
||||
mp_digit res_tab[MP_PRIME_TAB_SIZE], kstep;
|
||||
mp_int b;
|
||||
|
||||
/* force positive */
|
||||
a->sign = MP_ZPOS;
|
||||
|
||||
/* simple algo if a is less than the largest prime in the table */
|
||||
if (mp_cmp_d(a, s_mp_prime_tab[MP_PRIME_TAB_SIZE-1]) == MP_LT) {
|
||||
/* find which prime it is bigger than "a" */
|
||||
for (x = 0; x < MP_PRIME_TAB_SIZE; x++) {
|
||||
mp_ord cmp = mp_cmp_d(a, s_mp_prime_tab[x]);
|
||||
if (cmp == MP_EQ) {
|
||||
continue;
|
||||
}
|
||||
if (cmp != MP_GT) {
|
||||
if ((bbs_style) && ((s_mp_prime_tab[x] & 3u) != 3u)) {
|
||||
/* try again until we get a prime congruent to 3 mod 4 */
|
||||
continue;
|
||||
} else {
|
||||
mp_set(a, s_mp_prime_tab[x]);
|
||||
return MP_OKAY;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* fall through to the sieve */
|
||||
}
|
||||
|
||||
/* generate a prime congruent to 3 mod 4 or 1/3 mod 4? */
|
||||
kstep = bbs_style ? 4 : 2;
|
||||
|
||||
/* at this point we will use a combination of a sieve and Miller-Rabin */
|
||||
|
||||
if (bbs_style) {
|
||||
/* if a mod 4 != 3 subtract the correct value to make it so */
|
||||
if ((a->dp[0] & 3u) != 3u) {
|
||||
if ((err = mp_sub_d(a, (a->dp[0] & 3u) + 1u, a)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (mp_iseven(a)) {
|
||||
/* force odd */
|
||||
if ((err = mp_sub_d(a, 1uL, a)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* generate the restable */
|
||||
for (x = 1; x < MP_PRIME_TAB_SIZE; x++) {
|
||||
if ((err = mp_mod_d(a, s_mp_prime_tab[x], res_tab + x)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* init temp used for Miller-Rabin Testing */
|
||||
if ((err = mp_init(&b)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
mp_digit step = 0;
|
||||
bool y;
|
||||
/* skip to the next non-trivially divisible candidate */
|
||||
do {
|
||||
/* y == true if any residue was zero [e.g. cannot be prime] */
|
||||
y = false;
|
||||
|
||||
/* increase step to next candidate */
|
||||
step += kstep;
|
||||
|
||||
/* compute the new residue without using division */
|
||||
for (x = 1; x < MP_PRIME_TAB_SIZE; x++) {
|
||||
/* add the step to each residue */
|
||||
res_tab[x] += kstep;
|
||||
|
||||
/* subtract the modulus [instead of using division] */
|
||||
if (res_tab[x] >= s_mp_prime_tab[x]) {
|
||||
res_tab[x] -= s_mp_prime_tab[x];
|
||||
}
|
||||
|
||||
/* set flag if zero */
|
||||
if (res_tab[x] == 0u) {
|
||||
y = true;
|
||||
}
|
||||
}
|
||||
} while (y && (step < (((mp_digit)1 << MP_DIGIT_BIT) - kstep)));
|
||||
|
||||
/* add the step */
|
||||
if ((err = mp_add_d(a, step, a)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
/* if didn't pass sieve and step == MP_MAX then skip test */
|
||||
if (y && (step >= (((mp_digit)1 << MP_DIGIT_BIT) - kstep))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
if (res) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LBL_ERR:
|
||||
mp_clear(&b);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
48
src/libtommath/mp_prime_rabin_miller_trials.c
Normal file
48
src/libtommath/mp_prime_rabin_miller_trials.c
Normal file
@@ -0,0 +1,48 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_PRIME_RABIN_MILLER_TRIALS_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
static const struct {
|
||||
int k, t;
|
||||
} sizes[] = {
|
||||
{ 80, -1 }, /* Use deterministic algorithm for size <= 80 bits */
|
||||
{ 81, 37 }, /* max. error = 2^(-96)*/
|
||||
{ 96, 32 }, /* max. error = 2^(-96)*/
|
||||
{ 128, 40 }, /* max. error = 2^(-112)*/
|
||||
{ 160, 35 }, /* max. error = 2^(-112)*/
|
||||
{ 256, 27 }, /* max. error = 2^(-128)*/
|
||||
{ 384, 16 }, /* max. error = 2^(-128)*/
|
||||
{ 512, 18 }, /* max. error = 2^(-160)*/
|
||||
{ 768, 11 }, /* max. error = 2^(-160)*/
|
||||
{ 896, 10 }, /* max. error = 2^(-160)*/
|
||||
{ 1024, 12 }, /* max. error = 2^(-192)*/
|
||||
{ 1536, 8 }, /* max. error = 2^(-192)*/
|
||||
{ 2048, 6 }, /* max. error = 2^(-192)*/
|
||||
{ 3072, 4 }, /* max. error = 2^(-192)*/
|
||||
{ 4096, 5 }, /* max. error = 2^(-256)*/
|
||||
{ 5120, 4 }, /* max. error = 2^(-256)*/
|
||||
{ 6144, 4 }, /* max. error = 2^(-256)*/
|
||||
{ 8192, 3 }, /* max. error = 2^(-256)*/
|
||||
{ 9216, 3 }, /* max. error = 2^(-256)*/
|
||||
{ 10240, 2 } /* For bigger keysizes use always at least 2 Rounds */
|
||||
};
|
||||
|
||||
/* returns # of RM trials required for a given bit size */
|
||||
int mp_prime_rabin_miller_trials(int size)
|
||||
{
|
||||
int x;
|
||||
|
||||
for (x = 0; x < (int)(sizeof(sizes)/(sizeof(sizes[0]))); x++) {
|
||||
if (sizes[x].k == size) {
|
||||
return sizes[x].t;
|
||||
}
|
||||
if (sizes[x].k > size) {
|
||||
return (x == 0) ? sizes[0].t : sizes[x - 1].t;
|
||||
}
|
||||
}
|
||||
return sizes[x-1].t;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
123
src/libtommath/mp_prime_rand.c
Normal file
123
src/libtommath/mp_prime_rand.c
Normal file
@@ -0,0 +1,123 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_PRIME_RAND_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* makes a truly random prime of a given size (bits),
|
||||
*
|
||||
* Flags are as follows:
|
||||
*
|
||||
* MP_PRIME_BBS - make prime congruent to 3 mod 4
|
||||
* MP_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies MP_PRIME_BBS)
|
||||
* MP_PRIME_2MSB_ON - make the 2nd highest bit one
|
||||
*
|
||||
* You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can
|
||||
* have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself
|
||||
* so it can be NULL
|
||||
*
|
||||
*/
|
||||
|
||||
/* This is possibly the mother of all prime generation functions, muahahahahaha! */
|
||||
mp_err mp_prime_rand(mp_int *a, int t, int size, int flags)
|
||||
{
|
||||
uint8_t *tmp, maskAND, maskOR_msb, maskOR_lsb;
|
||||
int bsize, maskOR_msb_offset;
|
||||
bool res;
|
||||
mp_err err;
|
||||
|
||||
/* sanity check the input */
|
||||
if ((size <= 1) || (t <= 0)) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
/* MP_PRIME_SAFE implies MP_PRIME_BBS */
|
||||
if ((flags & MP_PRIME_SAFE) != 0) {
|
||||
flags |= MP_PRIME_BBS;
|
||||
}
|
||||
|
||||
/* calc the byte size */
|
||||
bsize = (size>>3) + ((size&7)?1:0);
|
||||
|
||||
/* we need a buffer of bsize bytes */
|
||||
tmp = (uint8_t *) MP_MALLOC((size_t)bsize);
|
||||
if (tmp == NULL) {
|
||||
return MP_MEM;
|
||||
}
|
||||
|
||||
/* calc the maskAND value for the MSbyte*/
|
||||
maskAND = ((size&7) == 0) ? 0xFFu : (uint8_t)(0xFFu >> (8 - (size & 7)));
|
||||
|
||||
/* calc the maskOR_msb */
|
||||
maskOR_msb = 0;
|
||||
maskOR_msb_offset = ((size & 7) == 1) ? 1 : 0;
|
||||
if ((flags & MP_PRIME_2MSB_ON) != 0) {
|
||||
maskOR_msb |= (uint8_t)(0x80 >> ((9 - size) & 7));
|
||||
}
|
||||
|
||||
/* get the maskOR_lsb */
|
||||
maskOR_lsb = 1u;
|
||||
if ((flags & MP_PRIME_BBS) != 0) {
|
||||
maskOR_lsb |= 3u;
|
||||
}
|
||||
|
||||
do {
|
||||
/* read the bytes */
|
||||
if ((err = s_mp_rand_source(tmp, (size_t)bsize)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
/* work over the MSbyte */
|
||||
tmp[0] &= maskAND;
|
||||
tmp[0] |= (uint8_t)(1 << ((size - 1) & 7));
|
||||
|
||||
/* mix in the maskORs */
|
||||
tmp[maskOR_msb_offset] |= maskOR_msb;
|
||||
tmp[bsize-1] |= maskOR_lsb;
|
||||
|
||||
/* read it in */
|
||||
/* TODO: casting only for now until all lengths have been changed to the type "size_t"*/
|
||||
if ((err = mp_from_ubin(a, tmp, (size_t)bsize)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
/* is it prime? */
|
||||
if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
if (!res) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((flags & MP_PRIME_SAFE) != 0) {
|
||||
/* see if (a-1)/2 is prime */
|
||||
if ((err = mp_sub_d(a, 1uL, a)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
if ((err = mp_div_2(a, a)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
/* is it prime? */
|
||||
if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
}
|
||||
} while (!res);
|
||||
|
||||
if ((flags & MP_PRIME_SAFE) != 0) {
|
||||
/* restore a to the original value */
|
||||
if ((err = mp_mul_2(a, a)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
if ((err = mp_add_d(a, 1uL, a)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
err = MP_OKAY;
|
||||
LBL_ERR:
|
||||
MP_FREE_BUF(tmp, (size_t)bsize);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
281
src/libtommath/mp_prime_strong_lucas_selfridge.c
Normal file
281
src/libtommath/mp_prime_strong_lucas_selfridge.c
Normal file
@@ -0,0 +1,281 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_PRIME_STRONG_LUCAS_SELFRIDGE_C
|
||||
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/*
|
||||
* See file mp_prime_is_prime.c or the documentation in doc/bn.tex for the details
|
||||
*/
|
||||
#ifndef LTM_USE_ONLY_MR
|
||||
|
||||
/*
|
||||
* multiply bigint a with int d and put the result in c
|
||||
* Like mp_mul_d() but with a signed long as the small input
|
||||
*/
|
||||
static mp_err s_mul_si(const mp_int *a, int32_t d, mp_int *c)
|
||||
{
|
||||
mp_int t;
|
||||
mp_err err;
|
||||
|
||||
if ((err = mp_init(&t)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* mp_digit might be smaller than a long, which excludes
|
||||
* the use of mp_mul_d() here.
|
||||
*/
|
||||
mp_set_i32(&t, d);
|
||||
err = mp_mul(a, &t, c);
|
||||
mp_clear(&t);
|
||||
return err;
|
||||
}
|
||||
/*
|
||||
Strong Lucas-Selfridge test.
|
||||
returns true if it is a strong L-S prime, false if it is composite
|
||||
|
||||
Code ported from Thomas Ray Nicely's implementation of the BPSW test
|
||||
at http://www.trnicely.net/misc/bpsw.html
|
||||
|
||||
Freeware copyright (C) 2016 Thomas R. Nicely <http://www.trnicely.net>.
|
||||
Released into the public domain by the author, who disclaims any legal
|
||||
liability arising from its use
|
||||
|
||||
The multi-line comments are made by Thomas R. Nicely and are copied verbatim.
|
||||
Additional comments marked "CZ" (without the quotes) are by the code-portist.
|
||||
|
||||
(If that name sounds familiar, he is the guy who found the fdiv bug in the
|
||||
Pentium (P5x, I think) Intel processor)
|
||||
*/
|
||||
mp_err mp_prime_strong_lucas_selfridge(const mp_int *a, bool *result)
|
||||
{
|
||||
/* CZ TODO: choose better variable names! */
|
||||
mp_int Dz, gcd, Np1, Uz, Vz, U2mz, V2mz, Qmz, Q2mz, Qkdz, T1z, T2z, T3z, T4z, Q2kdz;
|
||||
int32_t D, Ds, J, sign, P, Q, r, s, u, Nbits;
|
||||
mp_err err;
|
||||
bool oddness;
|
||||
|
||||
*result = false;
|
||||
/*
|
||||
Find the first element D in the sequence {5, -7, 9, -11, 13, ...}
|
||||
such that Jacobi(D,N) = -1 (Selfridge's algorithm). Theory
|
||||
indicates that, if N is not a perfect square, D will "nearly
|
||||
always" be "small." Just in case, an overflow trap for D is
|
||||
included.
|
||||
*/
|
||||
|
||||
if ((err = mp_init_multi(&Dz, &gcd, &Np1, &Uz, &Vz, &U2mz, &V2mz, &Qmz, &Q2mz, &Qkdz, &T1z, &T2z, &T3z, &T4z, &Q2kdz,
|
||||
NULL)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
D = 5;
|
||||
sign = 1;
|
||||
|
||||
for (;;) {
|
||||
Ds = sign * D;
|
||||
sign = -sign;
|
||||
mp_set_u32(&Dz, (uint32_t)D);
|
||||
if ((err = mp_gcd(a, &Dz, &gcd)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
|
||||
/* if 1 < GCD < N then N is composite with factor "D", and
|
||||
Jacobi(D,N) is technically undefined (but often returned
|
||||
as zero). */
|
||||
if ((mp_cmp_d(&gcd, 1uL) == MP_GT) && (mp_cmp(&gcd, a) == MP_LT)) {
|
||||
goto LBL_LS_ERR;
|
||||
}
|
||||
if (Ds < 0) {
|
||||
Dz.sign = MP_NEG;
|
||||
}
|
||||
if ((err = mp_kronecker(&Dz, a, &J)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
|
||||
if (J == -1) {
|
||||
break;
|
||||
}
|
||||
D += 2;
|
||||
|
||||
if (D > (INT_MAX - 2)) {
|
||||
err = MP_VAL;
|
||||
goto LBL_LS_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
P = 1; /* Selfridge's choice */
|
||||
Q = (1 - Ds) / 4; /* Required so D = P*P - 4*Q */
|
||||
|
||||
/* NOTE: The conditions (a) N does not divide Q, and
|
||||
(b) D is square-free or not a perfect square, are included by
|
||||
some authors; e.g., "Prime numbers and computer methods for
|
||||
factorization," Hans Riesel (2nd ed., 1994, Birkhauser, Boston),
|
||||
p. 130. For this particular application of Lucas sequences,
|
||||
these conditions were found to be immaterial. */
|
||||
|
||||
/* Now calculate N - Jacobi(D,N) = N + 1 (even), and calculate the
|
||||
odd positive integer d and positive integer s for which
|
||||
N + 1 = 2^s*d (similar to the step for N - 1 in Miller's test).
|
||||
The strong Lucas-Selfridge test then returns N as a strong
|
||||
Lucas probable prime (slprp) if any of the following
|
||||
conditions is met: U_d=0, V_d=0, V_2d=0, V_4d=0, V_8d=0,
|
||||
V_16d=0, ..., etc., ending with V_{2^(s-1)*d}=V_{(N+1)/2}=0
|
||||
(all equalities mod N). Thus d is the highest index of U that
|
||||
must be computed (since V_2m is independent of U), compared
|
||||
to U_{N+1} for the standard Lucas-Selfridge test; and no
|
||||
index of V beyond (N+1)/2 is required, just as in the
|
||||
standard Lucas-Selfridge test. However, the quantity Q^d must
|
||||
be computed for use (if necessary) in the latter stages of
|
||||
the test. The result is that the strong Lucas-Selfridge test
|
||||
has a running time only slightly greater (order of 10 %) than
|
||||
that of the standard Lucas-Selfridge test, while producing
|
||||
only (roughly) 30 % as many pseudoprimes (and every strong
|
||||
Lucas pseudoprime is also a standard Lucas pseudoprime). Thus
|
||||
the evidence indicates that the strong Lucas-Selfridge test is
|
||||
more effective than the standard Lucas-Selfridge test, and a
|
||||
Baillie-PSW test based on the strong Lucas-Selfridge test
|
||||
should be more reliable. */
|
||||
|
||||
if ((err = mp_add_d(a, 1uL, &Np1)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
s = mp_cnt_lsb(&Np1);
|
||||
|
||||
/* CZ
|
||||
* This should round towards zero because
|
||||
* Thomas R. Nicely used GMP's mpz_tdiv_q_2exp()
|
||||
* and mp_div_2d() is equivalent. Additionally:
|
||||
* dividing an even number by two does not produce
|
||||
* any leftovers.
|
||||
*/
|
||||
if ((err = mp_div_2d(&Np1, s, &Dz, NULL)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
/* We must now compute U_d and V_d. Since d is odd, the accumulated
|
||||
values U and V are initialized to U_1 and V_1 (if the target
|
||||
index were even, U and V would be initialized instead to U_0=0
|
||||
and V_0=2). The values of U_2m and V_2m are also initialized to
|
||||
U_1 and V_1; the FOR loop calculates in succession U_2 and V_2,
|
||||
U_4 and V_4, U_8 and V_8, etc. If the corresponding bits
|
||||
(1, 2, 3, ...) of t are on (the zero bit having been accounted
|
||||
for in the initialization of U and V), these values are then
|
||||
combined with the previous totals for U and V, using the
|
||||
composition formulas for addition of indices. */
|
||||
|
||||
mp_set(&Uz, 1uL); /* U=U_1 */
|
||||
mp_set(&Vz, (mp_digit)P); /* V=V_1 */
|
||||
mp_set(&U2mz, 1uL); /* U_1 */
|
||||
mp_set(&V2mz, (mp_digit)P); /* V_1 */
|
||||
|
||||
mp_set_i32(&Qmz, Q);
|
||||
if ((err = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
/* Initializes calculation of Q^d */
|
||||
mp_set_i32(&Qkdz, Q);
|
||||
|
||||
Nbits = mp_count_bits(&Dz);
|
||||
|
||||
for (u = 1; u < Nbits; u++) { /* zero bit off, already accounted for */
|
||||
/* Formulas for doubling of indices (carried out mod N). Note that
|
||||
* the indices denoted as "2m" are actually powers of 2, specifically
|
||||
* 2^(ul-1) beginning each loop and 2^ul ending each loop.
|
||||
*
|
||||
* U_2m = U_m*V_m
|
||||
* V_2m = V_m*V_m - 2*Q^m
|
||||
*/
|
||||
|
||||
if ((err = mp_mul(&U2mz, &V2mz, &U2mz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if ((err = mp_mod(&U2mz, a, &U2mz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if ((err = mp_sqr(&V2mz, &V2mz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if ((err = mp_sub(&V2mz, &Q2mz, &V2mz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if ((err = mp_mod(&V2mz, a, &V2mz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
|
||||
/* Must calculate powers of Q for use in V_2m, also for Q^d later */
|
||||
if ((err = mp_sqr(&Qmz, &Qmz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
|
||||
/* prevents overflow */ /* CZ still necessary without a fixed prealloc'd mem.? */
|
||||
if ((err = mp_mod(&Qmz, a, &Qmz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if ((err = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
|
||||
if (s_mp_get_bit(&Dz, u)) {
|
||||
/* Formulas for addition of indices (carried out mod N);
|
||||
*
|
||||
* U_(m+n) = (U_m*V_n + U_n*V_m)/2
|
||||
* V_(m+n) = (V_m*V_n + D*U_m*U_n)/2
|
||||
*
|
||||
* Be careful with division by 2 (mod N)!
|
||||
*/
|
||||
if ((err = mp_mul(&U2mz, &Vz, &T1z)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if ((err = mp_mul(&Uz, &V2mz, &T2z)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if ((err = mp_mul(&V2mz, &Vz, &T3z)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if ((err = mp_mul(&U2mz, &Uz, &T4z)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if ((err = s_mul_si(&T4z, Ds, &T4z)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if ((err = mp_add(&T1z, &T2z, &Uz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if (mp_isodd(&Uz)) {
|
||||
if ((err = mp_add(&Uz, a, &Uz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
}
|
||||
/* CZ
|
||||
* This should round towards negative infinity because
|
||||
* Thomas R. Nicely used GMP's mpz_fdiv_q_2exp().
|
||||
* But mp_div_2() does not do so, it is truncating instead.
|
||||
*/
|
||||
oddness = mp_isodd(&Uz);
|
||||
if ((err = mp_div_2(&Uz, &Uz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if (mp_isneg(&Uz) && oddness) {
|
||||
if ((err = mp_sub_d(&Uz, 1uL, &Uz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
}
|
||||
if ((err = mp_add(&T3z, &T4z, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if (mp_isodd(&Vz)) {
|
||||
if ((err = mp_add(&Vz, a, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
}
|
||||
oddness = mp_isodd(&Vz);
|
||||
if ((err = mp_div_2(&Vz, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if (mp_isneg(&Vz) && oddness) {
|
||||
if ((err = mp_sub_d(&Vz, 1uL, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
}
|
||||
if ((err = mp_mod(&Uz, a, &Uz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if ((err = mp_mod(&Vz, a, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
|
||||
/* Calculating Q^d for later use */
|
||||
if ((err = mp_mul(&Qkdz, &Qmz, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if ((err = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/* If U_d or V_d is congruent to 0 mod N, then N is a prime or a
|
||||
strong Lucas pseudoprime. */
|
||||
if (mp_iszero(&Uz) || mp_iszero(&Vz)) {
|
||||
*result = true;
|
||||
goto LBL_LS_ERR;
|
||||
}
|
||||
|
||||
/* NOTE: Ribenboim ("The new book of prime number records," 3rd ed.,
|
||||
1995/6) omits the condition V0 on p.142, but includes it on
|
||||
p. 130. The condition is NECESSARY; otherwise the test will
|
||||
return false negatives---e.g., the primes 29 and 2000029 will be
|
||||
returned as composite. */
|
||||
|
||||
/* Otherwise, we must compute V_2d, V_4d, V_8d, ..., V_{2^(s-1)*d}
|
||||
by repeated use of the formula V_2m = V_m*V_m - 2*Q^m. If any of
|
||||
these are congruent to 0 mod N, then N is a prime or a strong
|
||||
Lucas pseudoprime. */
|
||||
|
||||
/* Initialize 2*Q^(d*2^r) for V_2m */
|
||||
if ((err = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
|
||||
for (r = 1; r < s; r++) {
|
||||
if ((err = mp_sqr(&Vz, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if ((err = mp_sub(&Vz, &Q2kdz, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if ((err = mp_mod(&Vz, a, &Vz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if (mp_iszero(&Vz)) {
|
||||
*result = true;
|
||||
goto LBL_LS_ERR;
|
||||
}
|
||||
/* Calculate Q^{d*2^r} for next r (final iteration irrelevant). */
|
||||
if (r < (s - 1)) {
|
||||
if ((err = mp_sqr(&Qkdz, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if ((err = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
if ((err = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) goto LBL_LS_ERR;
|
||||
}
|
||||
}
|
||||
LBL_LS_ERR:
|
||||
mp_clear_multi(&Q2kdz, &T4z, &T3z, &T2z, &T1z, &Qkdz, &Q2mz, &Qmz, &V2mz, &U2mz, &Vz, &Uz, &Np1, &gcd, &Dz, NULL);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
34
src/libtommath/mp_radix_size.c
Normal file
34
src/libtommath/mp_radix_size.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_RADIX_SIZE_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* returns size of ASCII representation */
|
||||
mp_err mp_radix_size(const mp_int *a, int radix, size_t *size)
|
||||
{
|
||||
mp_err err;
|
||||
mp_int a_;
|
||||
int b;
|
||||
|
||||
/* make sure the radix is in range */
|
||||
if ((radix < 2) || (radix > 64)) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
if (mp_iszero(a)) {
|
||||
*size = 2;
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
a_ = *a;
|
||||
a_.sign = MP_ZPOS;
|
||||
if ((err = mp_log_n(&a_, radix, &b)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* mp_ilogb truncates to zero, hence we need one extra put on top and one for `\0`. */
|
||||
*size = (size_t)b + 2U + (mp_isneg(a) ? 1U : 0U);
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
17
src/libtommath/mp_radix_size_overestimate.c
Normal file
17
src/libtommath/mp_radix_size_overestimate.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_RADIX_SIZE_OVERESTIMATE_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
mp_err mp_radix_size_overestimate(const mp_int *a, const int radix, size_t *size)
|
||||
{
|
||||
if (MP_HAS(S_MP_RADIX_SIZE_OVERESTIMATE)) {
|
||||
return s_mp_radix_size_overestimate(a, radix, size);
|
||||
}
|
||||
if (MP_HAS(MP_RADIX_SIZE)) {
|
||||
return mp_radix_size(a, radix, size);
|
||||
}
|
||||
return MP_ERR;
|
||||
}
|
||||
|
||||
#endif
|
||||
39
src/libtommath/mp_rand.c
Normal file
39
src/libtommath/mp_rand.c
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_RAND_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
mp_err mp_rand(mp_int *a, int digits)
|
||||
{
|
||||
int i;
|
||||
mp_err err;
|
||||
|
||||
mp_zero(a);
|
||||
|
||||
if (digits <= 0) {
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
if ((err = mp_grow(a, digits)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = s_mp_rand_source(a->dp, (size_t)digits * sizeof(mp_digit))) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* TODO: We ensure that the highest digit is nonzero. Should this be removed? */
|
||||
while ((a->dp[digits - 1] & MP_MASK) == 0u) {
|
||||
if ((err = s_mp_rand_source(a->dp + digits - 1, sizeof(mp_digit))) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
a->used = digits;
|
||||
for (i = 0; i < digits; ++i) {
|
||||
a->dp[i] &= MP_MASK;
|
||||
}
|
||||
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
12
src/libtommath/mp_rand_source.c
Normal file
12
src/libtommath/mp_rand_source.c
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_RAND_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
mp_err(*s_mp_rand_source)(void *out, size_t size) = s_mp_rand_platform;
|
||||
|
||||
void mp_rand_source(mp_err(*source)(void *out, size_t size))
|
||||
{
|
||||
s_mp_rand_source = (source == NULL) ? s_mp_rand_platform : source;
|
||||
}
|
||||
#endif
|
||||
69
src/libtommath/mp_read_radix.c
Normal file
69
src/libtommath/mp_read_radix.c
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_READ_RADIX_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* read a string [ASCII] in a given radix */
|
||||
mp_err mp_read_radix(mp_int *a, const char *str, int radix)
|
||||
{
|
||||
mp_err err;
|
||||
mp_sign sign = MP_ZPOS;
|
||||
|
||||
/* make sure the radix is ok */
|
||||
if ((radix < 2) || (radix > 64)) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
/* if the leading digit is a
|
||||
* minus set the sign to negative.
|
||||
*/
|
||||
if (*str == '-') {
|
||||
++str;
|
||||
sign = MP_NEG;
|
||||
}
|
||||
|
||||
/* set the integer to the default of zero */
|
||||
mp_zero(a);
|
||||
|
||||
/* process each digit of the string */
|
||||
while (*str != '\0') {
|
||||
/* if the radix <= 36 the conversion is case insensitive
|
||||
* this allows numbers like 1AB and 1ab to represent the same value
|
||||
* [e.g. in hex]
|
||||
*/
|
||||
uint8_t y;
|
||||
char ch = (radix <= 36) ? (char)MP_TOUPPER((int)*str) : *str;
|
||||
unsigned pos = (unsigned)(ch - '+');
|
||||
if (MP_RADIX_MAP_REVERSE_SIZE <= pos) {
|
||||
break;
|
||||
}
|
||||
y = s_mp_radix_map_reverse[pos];
|
||||
|
||||
/* if the char was found in the map
|
||||
* and is less than the given radix add it
|
||||
* to the number, otherwise exit the loop.
|
||||
*/
|
||||
if (y >= radix) {
|
||||
break;
|
||||
}
|
||||
if ((err = mp_mul_d(a, (mp_digit)radix, a)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
if ((err = mp_add_d(a, y, a)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
++str;
|
||||
}
|
||||
|
||||
/* if an illegal character was found, fail. */
|
||||
if ((*str != '\0') && (*str != '\r') && (*str != '\n')) {
|
||||
return MP_VAL;
|
||||
}
|
||||
|
||||
/* set the sign only if a != 0 */
|
||||
if (!mp_iszero(a)) {
|
||||
a->sign = sign;
|
||||
}
|
||||
return MP_OKAY;
|
||||
}
|
||||
#endif
|
||||
83
src/libtommath/mp_reduce.c
Normal file
83
src/libtommath/mp_reduce.c
Normal file
@@ -0,0 +1,83 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_REDUCE_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* reduces x mod m, assumes 0 < x < m**2, mu is
|
||||
* precomputed via mp_reduce_setup.
|
||||
* From HAC pp.604 Algorithm 14.42
|
||||
*/
|
||||
mp_err mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu)
|
||||
{
|
||||
mp_int q;
|
||||
mp_err err;
|
||||
int um = m->used;
|
||||
|
||||
/* q = x */
|
||||
if ((err = mp_init_copy(&q, x)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* q1 = x / b**(k-1) */
|
||||
mp_rshd(&q, um - 1);
|
||||
|
||||
/* according to HAC this optimization is ok */
|
||||
if ((mp_digit)um > ((mp_digit)1 << (MP_DIGIT_BIT - 1))) {
|
||||
if ((err = mp_mul(&q, mu, &q)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
} else if (MP_HAS(S_MP_MUL_HIGH)) {
|
||||
if ((err = s_mp_mul_high(&q, mu, &q, um)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
} else if (MP_HAS(S_MP_MUL_HIGH_COMBA)) {
|
||||
if ((err = s_mp_mul_high_comba(&q, mu, &q, um)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
} else {
|
||||
err = MP_VAL;
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
/* q3 = q2 / b**(k+1) */
|
||||
mp_rshd(&q, um + 1);
|
||||
|
||||
/* x = x mod b**(k+1), quick (no division) */
|
||||
if ((err = mp_mod_2d(x, MP_DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
/* q = q * m mod b**(k+1), quick (no division) */
|
||||
if ((err = s_mp_mul(&q, m, &q, um + 1)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
/* x = x - q */
|
||||
if ((err = mp_sub(x, &q, x)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
/* If x < 0, add b**(k+1) to it */
|
||||
if (mp_cmp_d(x, 0uL) == MP_LT) {
|
||||
mp_set(&q, 1uL);
|
||||
if ((err = mp_lshd(&q, um + 1)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
if ((err = mp_add(x, &q, x)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Back off if it's too big */
|
||||
while (mp_cmp(x, m) != MP_LT) {
|
||||
if ((err = s_mp_sub(x, m, x)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
LBL_ERR:
|
||||
mp_clear(&q);
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
49
src/libtommath/mp_reduce_2k.c
Normal file
49
src/libtommath/mp_reduce_2k.c
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_REDUCE_2K_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* reduces a modulo n where n is of the form 2**p - d */
|
||||
mp_err mp_reduce_2k(mp_int *a, const mp_int *n, mp_digit d)
|
||||
{
|
||||
mp_int q;
|
||||
mp_err err;
|
||||
int p;
|
||||
|
||||
if ((err = mp_init(&q)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
p = mp_count_bits(n);
|
||||
for (;;) {
|
||||
/* q = a/2**p, a = a mod 2**p */
|
||||
if ((err = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
if (d != 1u) {
|
||||
/* q = q * d */
|
||||
if ((err = mp_mul_d(&q, d, &q)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/* a = a + q */
|
||||
if ((err = s_mp_add(a, &q, a)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
if (mp_cmp_mag(a, n) == MP_LT) {
|
||||
break;
|
||||
}
|
||||
if ((err = s_mp_sub(a, n, a)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
LBL_ERR:
|
||||
mp_clear(&q);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
52
src/libtommath/mp_reduce_2k_l.c
Normal file
52
src/libtommath/mp_reduce_2k_l.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "tommath_private.h"
|
||||
#ifdef MP_REDUCE_2K_L_C
|
||||
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
|
||||
/* SPDX-License-Identifier: Unlicense */
|
||||
|
||||
/* reduces a modulo n where n is of the form 2**p - d
|
||||
This differs from reduce_2k since "d" can be larger
|
||||
than a single digit.
|
||||
*/
|
||||
mp_err mp_reduce_2k_l(mp_int *a, const mp_int *n, const mp_int *d)
|
||||
{
|
||||
mp_int q;
|
||||
mp_err err;
|
||||
int p;
|
||||
|
||||
if ((err = mp_init(&q)) != MP_OKAY) {
|
||||
return err;
|
||||
}
|
||||
|
||||
p = mp_count_bits(n);
|
||||
|
||||
for (;;) {
|
||||
/* q = a/2**p, a = a mod 2**p */
|
||||
if ((err = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
/* q = q * d */
|
||||
if ((err = mp_mul(&q, d, &q)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
/* a = a + q */
|
||||
if ((err = s_mp_add(a, &q, a)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
if (mp_cmp_mag(a, n) == MP_LT) {
|
||||
break;
|
||||
}
|
||||
if ((err = s_mp_sub(a, n, a)) != MP_OKAY) {
|
||||
goto LBL_ERR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LBL_ERR:
|
||||
mp_clear(&q);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user