/*
* This file is part of the BSGS distribution (https://github.com/JeanLucPons/BSGS).
* Copyright (c) 2020 Jean Luc PONS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
// Big integer class (Fixed size)
#ifndef BIGINTH
#define BIGINTH
#include "Random.h"
#include
#include
// We need 1 extra block for Knuth div algorithm , Montgomery multiplication and ModInv
#define BISIZE 256
#if BISIZE==256
#define NB64BLOCK 5
#define NB32BLOCK 10
#elif BISIZE==512
#define NB64BLOCK 9
#define NB32BLOCK 18
#else
#error Unsuported size
#endif
class Int {
public:
Int();
Int(int32_t i32);
Int(int64_t i64);
Int(uint64_t u64);
Int(Int *a);
// Op
void Add(uint64_t a);
void Add(Int *a);
void Add(Int *a,Int *b);
void AddOne();
void Sub(uint64_t a);
void Sub(Int *a);
void Sub(Int *a, Int *b);
void SubOne();
void Mult(Int *a);
void Mult(uint64_t a);
void IMult(int64_t a);
void Mult(Int *a,uint64_t b);
void IMult(Int *a, int64_t b);
void Mult(Int *a,Int *b);
void Div(Int *a,Int *mod = NULL);
void MultModN(Int *a, Int *b, Int *n);
void Neg();
void Abs();
// Right shift (signed)
void ShiftR(uint32_t n);
void ShiftR32Bit();
void ShiftR64Bit();
// Left shift
void ShiftL(uint32_t n);
void ShiftL32Bit();
void ShiftL64Bit();
// Comp
bool IsGreater(Int *a);
bool IsGreaterOrEqual(Int *a);
bool IsLowerOrEqual(Int *a);
bool IsLower(Int *a);
bool IsEqual(Int *a);
bool IsZero();
bool IsOne();
bool IsStrictPositive();
bool IsPositive();
bool IsNegative();
bool IsEven();
bool IsOdd();
// Modular arithmetic
// Setup field
// n is the field characteristic
// R used in Montgomery mult (R = 2^size(n))
// R2 = R^2, R3 = R^3, R4 = R^4
static void SetupField(Int *n, Int *R = NULL, Int *R2 = NULL, Int *R3 = NULL, Int *R4 = NULL);
static Int *GetR(); // Return R
static Int *GetR2(); // Return R2
static Int *GetR3(); // Return R3
static Int *GetR4(); // Return R4
static Int* GetFieldCharacteristic(); // Return field characteristic
void GCD(Int *a); // this <- GCD(this,a)
void Mod(Int *n); // this <- this (mod n)
void ModInv(); // this <- this^-1 (mod n)
void MontgomeryMult(Int *a,Int *b); // this <- a*b*R^-1 (mod n)
void MontgomeryMult(Int *a); // this <- this*a*R^-1 (mod n)
void ModAdd(Int *a); // this <- this+a (mod n) [0
#endif
static void inline imm_mul(uint64_t *x, uint64_t y, uint64_t *dst) {
unsigned char c = 0;
uint64_t h, carry;
dst[0] = _umul128(x[0], y, &h); carry = h;
c = _addcarry_u64(c, _umul128(x[1], y, &h), carry, dst + 1); carry = h;
c = _addcarry_u64(c, _umul128(x[2], y, &h), carry, dst + 2); carry = h;
c = _addcarry_u64(c, _umul128(x[3], y, &h), carry, dst + 3); carry = h;
c = _addcarry_u64(c, _umul128(x[4], y, &h), carry, dst + 4); carry = h;
#if NB64BLOCK > 5
c = _addcarry_u64(c, _umul128(x[5], y, &h), carry, dst + 5); carry = h;
c = _addcarry_u64(c, _umul128(x[6], y, &h), carry, dst + 6); carry = h;
c = _addcarry_u64(c, _umul128(x[7], y, &h), carry, dst + 7); carry = h;
c = _addcarry_u64(c, _umul128(x[8], y, &h), carry, dst + 8); carry = h;
#endif
}
static void inline imm_umul(uint64_t *x, uint64_t y, uint64_t *dst) {
// Assume that x[NB64BLOCK-1] is 0
unsigned char c = 0;
uint64_t h, carry;
dst[0] = _umul128(x[0], y, &h); carry = h;
c = _addcarry_u64(c, _umul128(x[1], y, &h), carry, dst + 1); carry = h;
c = _addcarry_u64(c, _umul128(x[2], y, &h), carry, dst + 2); carry = h;
c = _addcarry_u64(c, _umul128(x[3], y, &h), carry, dst + 3); carry = h;
#if NB64BLOCK > 5
c = _addcarry_u64(c, _umul128(x[4], y, &h), carry, dst + 4); carry = h;
c = _addcarry_u64(c, _umul128(x[5], y, &h), carry, dst + 5); carry = h;
c = _addcarry_u64(c, _umul128(x[6], y, &h), carry, dst + 6); carry = h;
c = _addcarry_u64(c, _umul128(x[7], y, &h), carry, dst + 7); carry = h;
#endif
_addcarry_u64(c, 0ULL, carry, dst + (NB64BLOCK - 1));
}
static void inline shiftR(unsigned char n, uint64_t *d) {
d[0] = __shiftright128(d[0], d[1], n);
d[1] = __shiftright128(d[1], d[2], n);
d[2] = __shiftright128(d[2], d[3], n);
d[3] = __shiftright128(d[3], d[4], n);
#if NB64BLOCK > 5
d[4] = __shiftright128(d[4], d[5], n);
d[5] = __shiftright128(d[5], d[6], n);
d[6] = __shiftright128(d[6], d[7], n);
d[7] = __shiftright128(d[7], d[8], n);
#endif
d[NB64BLOCK-1] = ((int64_t)d[NB64BLOCK-1]) >> n;
}
static void inline shiftL(unsigned char n, uint64_t *d) {
#if NB64BLOCK > 5
d[8] = __shiftleft128(d[7], d[8], n);
d[7] = __shiftleft128(d[6], d[7], n);
d[6] = __shiftleft128(d[5], d[6], n);
d[5] = __shiftleft128(d[4], d[5], n);
#endif
d[4] = __shiftleft128(d[3], d[4], n);
d[3] = __shiftleft128(d[2], d[3], n);
d[2] = __shiftleft128(d[1], d[2], n);
d[1] = __shiftleft128(d[0], d[1], n);
d[0] = d[0] << n;
}
#endif // BIGINTH