bool intVecCRT(vec_ZZ& vp, const ZZ& p, const zzvec& vq, long q) { long pInv = InvMod(rem(p,q), q); // p^{-1} mod q long n = min(vp.length(),vq.length()); long q_over_2 = q/2; ZZ tmp; long vqi; mulmod_precon_t pqInv = PrepMulModPrecon(pInv, q); for (long i=0; i<n; i++) { conv(vqi, vq[i]); // convert to single precision long vq_minus_vp_mod_q = SubMod(vqi, rem(vp[i],q), q); long delta_times_pInv = MulModPrecon(vq_minus_vp_mod_q, pInv, q, pqInv); if (delta_times_pInv > q_over_2) delta_times_pInv -= q; mul(tmp, delta_times_pInv, p); // tmp = [(vq_i-vp_i)*p^{-1}]_q * p vp[i] += tmp; } // other entries (if any) are 0 mod q for (long i=vq.length(); i<vp.length(); i++) { long minus_vp_mod_q = NegateMod(rem(vp[i],q), q); long delta_times_pInv = MulModPrecon(minus_vp_mod_q, pInv, q, pqInv); if (delta_times_pInv > q_over_2) delta_times_pInv -= q; mul(tmp, delta_times_pInv, p); // tmp = [(vq_i-vp_i)*p^{-1}]_q * p vp[i] += tmp; } return (vp.length()==vq.length()); }
void negate(vec_zz_p& x, const vec_zz_p& a) { long n = a.length(); long p = zz_p::modulus(); x.SetLength(n); const zz_p *ap = a.elts(); zz_p *xp = x.elts(); long i; for (i = 0; i < n; i++) xp[i].LoopHole() = NegateMod(rep(ap[i]), p); }
DoubleCRT& DoubleCRT::Negate(const DoubleCRT& other) { if (dryRun) return *this; if (&context != &other.context) Error("DoubleCRT Negate: incompatible contexts"); if (map.getIndexSet() != other.map.getIndexSet()) { map = other.map; // copy the data } const IndexSet& s = map.getIndexSet(); long phim = context.zMStar.getPhiM(); for (long i = s.first(); i <= s.last(); i = s.next(i)) { long pi = context.ithPrime(i); vec_long& row = map[i]; const vec_long& other_row = other.map[i]; for (long j = 0; j < phim; j++) row[j] = NegateMod(other_row[j], pi); } return *this; }
void ZZ_p::DoInstall() { SmartPtr<ZZ_pTmpSpaceT> tmps = 0; do { // NOTE: thread safe lazy init Lazy<ZZ_pFFTInfoT>::Builder builder(ZZ_pInfo->FFTInfo); if (!builder()) break; UniquePtr<ZZ_pFFTInfoT> FFTInfo; FFTInfo.make(); ZZ B, M, M1, M2, M3; long n, i; long q, t; mulmod_t qinv; sqr(B, ZZ_pInfo->p); LeftShift(B, B, NTL_FFTMaxRoot+NTL_FFTFudge); // FIXME: the following is quadratic time...would // be nice to get a faster solution... // One could estimate the # of primes by summing logs, // then multiply using a tree-based multiply, then // adjust up or down... // Assuming IEEE floating point, the worst case estimate // for error guarantees a correct answer +/- 1 for // numprimes up to 2^25...for sure we won't be // using that many primes...we can certainly put in // a sanity check, though. // If I want a more accuaruate summation (with using Kahan, // which has some portability issues), I could represent // numbers as x = a + f, where a is integer and f is the fractional // part. Summing in this representation introduces an *absolute* // error of 2 epsilon n, which is just as good as Kahan // for this application. // same strategy could also be used in the ZZX HomMul routine, // if we ever want to make that subquadratic set(M); n = 0; while (M <= B) { UseFFTPrime(n); q = GetFFTPrime(n); n++; mul(M, M, q); } FFTInfo->NumPrimes = n; FFTInfo->MaxRoot = CalcMaxRoot(q); double fn = double(n); if (8.0*fn*(fn+48) > NTL_FDOUBLE_PRECISION) ResourceError("modulus too big"); if (8.0*fn*(fn+48) <= NTL_FDOUBLE_PRECISION/double(NTL_SP_BOUND)) FFTInfo->QuickCRT = true; else FFTInfo->QuickCRT = false; // FIXME: some of this stuff does not need to be initialized // at all if FFTInfo->crt_struct.special() FFTInfo->x.SetLength(n); FFTInfo->u.SetLength(n); FFTInfo->uqinv.SetLength(n); FFTInfo->rem_struct.init(n, ZZ_pInfo->p, GetFFTPrime); FFTInfo->crt_struct.init(n, ZZ_pInfo->p, GetFFTPrime); if (!FFTInfo->crt_struct.special()) { ZZ qq, rr; DivRem(qq, rr, M, ZZ_pInfo->p); NegateMod(FFTInfo->MinusMModP, rr, ZZ_pInfo->p); for (i = 0; i < n; i++) { q = GetFFTPrime(i); qinv = GetFFTPrimeInv(i); long tt = rem(qq, q); mul(M2, ZZ_pInfo->p, tt); add(M2, M2, rr); div(M2, M2, q); // = (M/q) rem p div(M1, M, q); t = rem(M1, q); t = InvMod(t, q); mul(M3, M2, t); rem(M3, M3, ZZ_pInfo->p); FFTInfo->crt_struct.insert(i, M3); FFTInfo->x[i] = ((double) t)/((double) q); FFTInfo->u[i] = t; FFTInfo->uqinv[i] = PrepMulModPrecon(FFTInfo->u[i], q, qinv); } } tmps = MakeSmart<ZZ_pTmpSpaceT>(); tmps->crt_tmp_vec.fetch(FFTInfo->crt_struct); tmps->rem_tmp_vec.fetch(FFTInfo->rem_struct); builder.move(FFTInfo); } while (0); if (!tmps) { const ZZ_pFFTInfoT *FFTInfo = ZZ_pInfo->FFTInfo.get(); tmps = MakeSmart<ZZ_pTmpSpaceT>(); tmps->crt_tmp_vec.fetch(FFTInfo->crt_struct); tmps->rem_tmp_vec.fetch(FFTInfo->rem_struct); } ZZ_pTmpSpace = tmps; }
void ZZ_pInfoT::init() { ZZ B, M, M1, M2, M3; long n, i; long q, t; initialized = 1; sqr(B, p); LeftShift(B, B, NTL_FFTMaxRoot+NTL_FFTFudge); set(M); n = 0; while (M <= B) { UseFFTPrime(n); q = FFTPrime[n]; n++; mul(M, M, q); } NumPrimes = n; MaxRoot = CalcMaxRoot(q); double fn = double(n); if (8.0*fn*(fn+32) > NTL_FDOUBLE_PRECISION) Error("modulus too big"); if (8.0*fn*(fn+32) > NTL_FDOUBLE_PRECISION/double(NTL_SP_BOUND)) QuickCRT = 0; else QuickCRT = 1; if (!(x = (double *) NTL_MALLOC(n, sizeof(double), 0))) Error("out of space"); if (!(u = (long *) NTL_MALLOC(n, sizeof(long), 0))) Error("out of space"); ZZ_p_rem_struct_init(&rem_struct, n, p, FFTPrime); ZZ_p_crt_struct_init(&crt_struct, n, p, FFTPrime); if (ZZ_p_crt_struct_special(crt_struct)) return; ZZ qq, rr; DivRem(qq, rr, M, p); NegateMod(MinusMModP, rr, p); for (i = 0; i < n; i++) { q = FFTPrime[i]; long tt = rem(qq, q); mul(M2, p, tt); add(M2, M2, rr); div(M2, M2, q); // = (M/q) rem p div(M1, M, q); t = rem(M1, q); t = InvMod(t, q); mul(M3, M2, t); rem(M3, M3, p); ZZ_p_crt_struct_insert(crt_struct, i, M3); x[i] = ((double) t)/((double) q); u[i] = t; } }
static void NullSpace(long& r, vec_long& D, vec_ZZVec& M, long verbose) { long k, l, n; long i, j; long pos; ZZ t1, t2; ZZ *x, *y; const ZZ& p = ZZ_p::modulus(); n = M.length(); D.SetLength(n); for (j = 0; j < n; j++) D[j] = -1; r = 0; l = 0; for (k = 0; k < n; k++) { if (verbose && k % 10 == 0) cerr << "+"; pos = -1; for (i = l; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) pos = i; } if (pos != -1) { swap(M[pos], M[l]); // make M[l, k] == -1 mod p, and make row l reduced InvMod(t1, M[l][k], p); NegateMod(t1, t1, p); for (j = k+1; j < n; j++) { rem(t2, M[l][j], p); MulMod(M[l][j], t2, t1, p); } for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[l].elts() + (k+1); for (j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } D[k] = l; // variable k is defined by row l l++; } else { r++; } } }
long gauss(mat_ZZ_p& M_in, long w) { long k, l; long i, j; long pos; ZZ t1, t2, t3; ZZ *x, *y; long n = M_in.NumRows(); long m = M_in.NumCols(); if (w < 0 || w > m) Error("gauss: bad args"); const ZZ& p = ZZ_p::modulus(); vec_ZZVec M; sqr(t1, p); mul(t1, t1, n); M.SetLength(n); for (i = 0; i < n; i++) { M[i].SetSize(m, t1.size()); for (j = 0; j < m; j++) { M[i][j] = rep(M_in[i][j]); } } l = 0; for (k = 0; k < w && l < n; k++) { pos = -1; for (i = l; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { swap(M[pos], M[l]); InvMod(t3, M[l][k], p); NegateMod(t3, t3, p); for (j = k+1; j < m; j++) { rem(M[l][j], M[l][j], p); } for (i = l+1; i < n; i++) { // M[i] = M[i] + M[l]*M[i,k]*t3 MulMod(t1, M[i][k], t3, p); clear(M[i][k]); x = M[i].elts() + (k+1); y = M[l].elts() + (k+1); for (j = k+1; j < m; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(t2, t2, *x); *x = t2; } } l++; } } for (i = 0; i < n; i++) for (j = 0; j < m; j++) conv(M_in[i][j], M[i][j]); return l; }
void inv(ZZ_p& d, mat_ZZ_p& X, const mat_ZZ_p& A) { long n = A.NumRows(); if (A.NumCols() != n) Error("inv: nonsquare matrix"); if (n == 0) { set(d); X.SetDims(0, 0); return; } long i, j, k, pos; ZZ t1, t2; ZZ *x, *y; const ZZ& p = ZZ_p::modulus(); vec_ZZVec M; sqr(t1, p); mul(t1, t1, n); M.SetLength(n); for (i = 0; i < n; i++) { M[i].SetSize(2*n, t1.size()); for (j = 0; j < n; j++) { M[i][j] = rep(A[i][j]); clear(M[i][n+j]); } set(M[i][n+i]); } ZZ det; set(det); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); NegateMod(det, det, p); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); NegateMod(t1, t1, p); for (j = k+1; j < 2*n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j < 2*n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); return; } } X.SetDims(n, n); for (k = 0; k < n; k++) { for (i = n-1; i >= 0; i--) { clear(t1); for (j = i+1; j < n; j++) { mul(t2, rep(X[j][k]), M[i][j]); add(t1, t1, t2); } sub(t1, t1, M[i][n+k]); conv(X[i][k], t1); } } conv(d, det); }
void determinant(ZZ_p& d, const mat_ZZ_p& M_in) { long k, n; long i, j; long pos; ZZ t1, t2; ZZ *x, *y; const ZZ& p = ZZ_p::modulus(); n = M_in.NumRows(); if (M_in.NumCols() != n) Error("determinant: nonsquare matrix"); if (n == 0) { set(d); return; } vec_ZZVec M; sqr(t1, p); mul(t1, t1, n); M.SetLength(n); for (i = 0; i < n; i++) { M[i].SetSize(n, t1.size()); for (j = 0; j < n; j++) M[i][j] = rep(M_in[i][j]); } ZZ det; set(det); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) pos = i; } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); NegateMod(det, det, p); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); NegateMod(t1, t1, p); for (j = k+1; j < n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j < n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); return; } } conv(d, det); }
static void solve_impl(ZZ_p& d, vec_ZZ_p& X, const mat_ZZ_p& A, const vec_ZZ_p& b, bool trans) { long n = A.NumRows(); if (A.NumCols() != n) LogicError("solve: nonsquare matrix"); if (b.length() != n) LogicError("solve: dimension mismatch"); if (n == 0) { set(d); X.SetLength(0); return; } long i, j, k, pos; ZZ t1, t2; ZZ *x, *y; const ZZ& p = ZZ_p::modulus(); vec_ZZVec M; sqr(t1, p); mul(t1, t1, n); M.SetLength(n); for (i = 0; i < n; i++) { M[i].SetSize(n+1, t1.size()); if (trans) for (j = 0; j < n; j++) M[i][j] = rep(A[j][i]); else for (j = 0; j < n; j++) M[i][j] = rep(A[i][j]); M[i][n] = rep(b[i]); } ZZ det; set(det); for (k = 0; k < n; k++) { pos = -1; for (i = k; i < n; i++) { rem(t1, M[i][k], p); M[i][k] = t1; if (pos == -1 && !IsZero(t1)) { pos = i; } } if (pos != -1) { if (k != pos) { swap(M[pos], M[k]); NegateMod(det, det, p); } MulMod(det, det, M[k][k], p); // make M[k, k] == -1 mod p, and make row k reduced InvMod(t1, M[k][k], p); NegateMod(t1, t1, p); for (j = k+1; j <= n; j++) { rem(t2, M[k][j], p); MulMod(M[k][j], t2, t1, p); } for (i = k+1; i < n; i++) { // M[i] = M[i] + M[k]*M[i,k] t1 = M[i][k]; // this is already reduced x = M[i].elts() + (k+1); y = M[k].elts() + (k+1); for (j = k+1; j <= n; j++, x++, y++) { // *x = *x + (*y)*t1 mul(t2, *y, t1); add(*x, *x, t2); } } } else { clear(d); return; } } X.SetLength(n); for (i = n-1; i >= 0; i--) { clear(t1); for (j = i+1; j < n; j++) { mul(t2, rep(X[j]), M[i][j]); add(t1, t1, t2); } sub(t1, t1, M[i][n]); conv(X[i], t1); } conv(d, det); }