/* * 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