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 mul(vec_ZZ& x, const vec_ZZ& a, long b) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); }
void negate(vec_ZZ& x, const vec_ZZ& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) negate(x[i], a[i]); }
void mul(vec_ZZ& x, const vec_ZZ& a, const ZZ& b_in) { ZZ b = b_in; long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) mul(x[i], a[i], b); }
void sub(vec_ZZ& x, const vec_ZZ& a, const vec_ZZ& b) { long n = a.length(); if (b.length() != n) LogicError("vector sub: dimension mismatch"); x.SetLength(n); long i; for (i = 0; i < n; i++) sub(x[i], a[i], b[i]); }
static void MulSubFrom(vec_ZZ& c, const vec_ZZ& c2, long x) // c = c - x*c2 { long n = c.length(); if (c2.length() != n) Error("MulSubFrom: length mismatch"); long i; for (i = 1; i <= n; i++) MulSubFrom(c(i), c2(i), x); }
void conv(vec_zz_p& x, const vec_ZZ& a) { long i, n; n = a.length(); x.SetLength(n); zz_p* xp = x.elts(); const ZZ* ap = a.elts(); for (i = 0; i < n; i++) conv(xp[i], ap[i]); }
NTL_START_IMPL // NOTE: the signature for this is in lzz_p.h void conv(vec_zz_p& x, const vec_ZZ& a) { long i, n; n = a.length(); x.SetLength(n); VectorConv(n, x.elts(), a.elts()); }
static void SubDiv(vec_ZZ& e, const vec_ZZ& t, long p) { long n = e.length(); if (t.length() != n) Error("SubDiv: dimension mismatch"); ZZ s; long i; for (i = 0; i < n; i++) { sub(s, e[i], t[i]); div(e[i], s, p); } }
static void MulSubDiv(vec_ZZ& c, const vec_ZZ& c1, const vec_ZZ& c2, const ZZ& x, const ZZ& y, const ZZ& z) // c = (x*c1 + y*c2)/z { long n = c1.length(); if (c2.length() != n) Error("MulSubDiv: length mismatch"); c.SetLength(n); long i; for (i = 1; i <= n; i++) MulSubDiv(c(i), c1(i), c2(i), x, y, z); }
void clear(vec_ZZ& x) { long n = x.length(); long i; for (i = 0; i < n; i++) clear(x[i]); }
long CRT(vec_ZZ& gg, ZZ& a, const vec_zz_p& G) { long n = gg.length(); if (G.length() != n) Error("CRT: vector length mismatch"); long p = zz_p::modulus(); ZZ new_a; mul(new_a, a, p); long a_inv; a_inv = rem(a, p); a_inv = InvMod(a_inv, p); long p1; p1 = p >> 1; ZZ a1; RightShift(a1, a, 1); long p_odd = (p & 1); long modified = 0; long h; ZZ g; long i; for (i = 0; i < n; i++) { if (!CRTInRange(gg[i], a)) { modified = 1; rem(g, gg[i], a); if (g > a1) sub(g, g, a); } else g = gg[i]; h = rem(g, p); h = SubMod(rep(G[i]), h, p); h = MulMod(h, a_inv, p); if (h > p1) h = h - p; if (h != 0) { modified = 1; if (!p_odd && g > 0 && (h == p1)) MulSubFrom(g, a, h); else MulAddTo(g, a, h); } gg[i] = g; } a = new_a; return modified; }
void conv(vec_ZZ& x, const vec_zz_p& a) { long n = a.length(); x.SetLength(n); long i; for (i = 0; i < n; i++) x[i] = rep(a[i]); }
void VectorCopy(vec_ZZ& x, const vec_ZZ& a, long n) { if (n < 0) LogicError("VectorCopy: negative length"); if (NTL_OVERFLOW(n, 1, 0)) ResourceError("overflow in VectorCopy"); long m = min(n, a.length()); x.SetLength(n); long i; for (i = 0; i < m; i++) x[i] = a[i]; for (i = m; i < n; i++) clear(x[i]); }
NTL_START_IMPL void InnerProduct(ZZ& xx, const vec_ZZ& a, const vec_ZZ& b) { ZZ t1, x; long n = min(a.length(), b.length()); long i; clear(x); for (i = 1; i <= n; i++) { mul(t1, a(i), b(i)); add(x, x, t1); } xx = x; }
static void ExactDiv(vec_ZZ& x, const ZZ& d) { long n = x.length(); long i; for (i = 0; i < n; i++) if (!divide(x[i], x[i], d)) Error("inexact division"); }
long IsZero(const vec_ZZ& a) { long n = a.length(); long i; for (i = 0; i < n; i++) if (!IsZero(a[i])) return 0; return 1; }
vec_ZZ vec_shift(vec_ZZ v, int dim) { vec_ZZ shifted_vec; int len; len = v.length(); shifted_vec.SetLength(dim); // if (len>dim-1) // cout<<"incorrect length "<<len<<" "<<dim<<endl; for (int i=0; i<len-1;i++) shifted_vec[i+1] = v[i]; return shifted_vec; }
static void RowTransform2(vec_ZZ& A, vec_ZZ& B, const ZZ& MU1) // x = x + y*MU { NTL_ZZRegister(T); NTL_ZZRegister(MU); long k; long n = A.length(); long i; MU = MU1; if (MU == 1) { for (i = 1; i <= n; i++) add(A(i), A(i), B(i)); return; } if (MU == -1) { for (i = 1; i <= n; i++) sub(A(i), A(i), B(i)); return; } if (MU == 0) return; if (NumTwos(MU) >= NTL_ZZ_NBITS) k = MakeOdd(MU); else k = 0; if (MU.WideSinglePrecision()) { long mu1; conv(mu1, MU); for (i = 1; i <= n; i++) { mul(T, B(i), mu1); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } else { for (i = 1; i <= n; i++) { mul(T, B(i), MU); if (k > 0) LeftShift(T, T, k); add(A(i), A(i), T); } } }
static void mul_aux(vec_ZZ& x, const vec_ZZ& a, const mat_ZZ& B) { long n = B.NumRows(); long l = B.NumCols(); if (n != a.length()) Error("matrix mul: dimension mismatch"); x.SetLength(l); long i, k; ZZ acc, tmp; for (i = 1; i <= l; i++) { clear(acc); for (k = 1; k <= n; k++) { mul(tmp, a(k), B(k,i)); add(acc, acc, tmp); } x(i) = acc; } }
NTL_CLIENT long SubsetSumSolution(const vec_ZZ& z) { long n = z.length()-3; long j; if (z(n+1) != 0) return 0; if (z(n+2) != -1 && z(n+2) != 1) return 0; for (j = 1; j <= n; j++) if (z(j) != -1 && z(j) != 1) return 0; return 1; }
static void MulAdd(vec_ZZ& x, const ZZ& prod, const vec_zz_p& h) { long n = x.length(); if (h.length() != n) Error("MulAdd: dimension mismatch"); ZZ t; long i; for (i = 0; i < n; i++) { mul(t, prod, rep(h[i])); add(x[i], x[i], t); } }
static void mul_aux(vec_ZZ& x, const mat_ZZ& A, const vec_ZZ& b) { long n = A.NumRows(); long l = A.NumCols(); if (l != b.length()) Error("matrix mul: dimension mismatch"); x.SetLength(n); long i, k; ZZ acc, tmp; for (i = 1; i <= n; i++) { clear(acc); for (k = 1; k <= l; k++) { mul(tmp, A(i,k), b(k)); add(acc, acc, tmp); } x(i) = acc; } }
static void RowTransform(vec_ZZ& c1, vec_ZZ& c2, const ZZ& x, const ZZ& y, const ZZ& u, const ZZ& v) // (c1, c2) = (x*c1 + y*c2, u*c1 + v*c2) { long n = c1.length(); if (c2.length() != n) Error("MulSubDiv: length mismatch"); static ZZ t1, t2, t3, t4; long i; for (i = 1; i <= n; i++) { mul(t1, x, c1(i)); mul(t2, y, c2(i)); add(t1, t1, t2); mul(t3, u, c1(i)); mul(t4, v, c2(i)); add(t3, t3, t4); c1(i) = t1; c2(i) = t3; } }
NTL_START_IMPL // This implements a variation of an algorithm in // [P. Domich, R. Kannan and L. Trotter, Math. Oper. Research 12:50-59, 1987]. // I started with the description in Henri Cohen's book, but had to modify // that because Cohen does not actually keep the numbers reduced modulo // the determinant, which leads to larger than necessary numbers. // This modifiaction was put in place in v3.9b. static void EuclUpdate(vec_ZZ& u, vec_ZZ& v, const ZZ& a, const ZZ& b, const ZZ& c, const ZZ& d, const ZZ& M) { long m = u.length(); long i; ZZ M1; RightShift(M1, M, 1); ZZ t1, t2, t3; for (i = 1; i <= m; i++) { mul(t1, u(i), a); mul(t2, v(i), b); add(t1, t1, t2); rem(t1, t1, M); if (t1 > M1) sub(t1, t1, M); t3 = t1; mul(t1, u(i), c); mul(t2, v(i), d); add(t1, t1, t2); rem(t1, t1, M); if (t1 > M1) sub(t1, t1, M); u(i) = t3; v(i) = t1; } }
//Ideal lattice challenge problem generator //modified from generate_ideal.cpp in Ideal lattice Challenge web page void gen_idealsvpchallenge(mat_ZZ& B,int index,ZZ seed,vec_ZZ& phivec) { ZZX phi=find_cyclotomic(index); long n=deg(phi); ZZ det=find_determinant(index,10*n,seed); ZZ alpha=find_unity_root(index,det,phi); B.SetDims(n,n); clear(B); B(1,1) = det; for (long i=2; i<=n; i++) { B(i,1)=det-PowerMod(alpha,i-1,det); B(i,i)=1; } phivec.SetLength(n+1); for (int i=0;i<=n;i++) phivec[i] = coeff(phi,i); }
mat_ZZ mat_expand(mat_ZZ M, vec_ZZ v) { int len, col, row; mat_ZZ mat_exp; len = v.length(); col = M.NumCols(); row = M.NumRows(); if (len!=col) cout<<"Incompatible rows"<<endl; mat_exp = M; mat_exp.SetDims(row+1, col); mat_exp[row] = v; return mat_exp; }
template <typename T> T ProjectedLength(LatticeBasis<T>& B,int istart,int iend, vec_ZZ& vector) { B.updateGSBasis(1,iend); ZZ ip; T ipapprox; T* mu = (T*)shared_memory::allocate1<T>(123,iend+1); T result = LengthOf<T>(vector); result *= result; for (int j=istart;j<=iend;j++) { ipapprox = 0; for (int i=0;i<vector.length();i++) { //inner product of two vectors if ((vector[i]!=0) && (B.L[j-1][i]!=0)) { T part; part = log(to_double( log(abs(vector[i] )))) + log(to_double( log(abs( B.L[j-1][i] )))); char sign1=1; char sign2=1; if (vector[i] < 0) sign1 = -1; if (B.L[j-1][i] < 0) sign2 = -1; if (sign1*sign2==1) { ipapprox += exp(part); } else { ipapprox -= exp(part); } } } mu[j] = ipapprox; for (int k=1;k<j;k++) { mu[j] -= B.gs.mu[j][k] * mu[k] * B.gs.cd[k]; } mu[j] /= B.gs.cd[j]; result -= mu[j] * mu[j] * B.gs.cd[j]; if (result < 0.5) return 0; } return sqrt(result); }
void solve(ZZ& d_out, vec_ZZ& x_out, const mat_ZZ& A, const vec_ZZ& b, long deterministic) { long n = A.NumRows(); if (A.NumCols() != n) Error("solve: nonsquare matrix"); if (b.length() != n) Error("solve: dimension mismatch"); if (n == 0) { set(d_out); x_out.SetLength(0); return; } zz_pBak zbak; zbak.save(); ZZ_pBak Zbak; Zbak.save(); vec_ZZ x(INIT_SIZE, n); ZZ d, d1; ZZ d_prod, x_prod; set(d_prod); set(x_prod); long d_instable = 1; long x_instable = 1; long check = 0; long gp_cnt = 0; vec_ZZ y, b1; long i; long bound = 2+DetBound(A); for (i = 0; ; i++) { if ((check || IsZero(d)) && !d_instable) { if (NumBits(d_prod) > bound) { break; } else if (!deterministic && bound > 1000 && NumBits(d_prod) < 0.25*bound) { ZZ P; long plen = 90 + NumBits(max(bound, NumBits(d))); GenPrime(P, plen, 90 + 2*NumBits(gp_cnt++)); ZZ_p::init(P); mat_ZZ_p AA; conv(AA, A); ZZ_p dd; determinant(dd, AA); if (CRT(d, d_prod, rep(dd), P)) d_instable = 1; else break; } } zz_p::FFTInit(i); long p = zz_p::modulus(); mat_zz_p AA; conv(AA, A); if (!check) { vec_zz_p bb, xx; conv(bb, b); zz_p dd; solve(dd, xx, AA, bb); d_instable = CRT(d, d_prod, rep(dd), p); if (!IsZero(dd)) { mul(xx, xx, dd); x_instable = CRT(x, x_prod, xx); } else x_instable = 1; if (!d_instable && !x_instable) { mul(y, x, A); mul(b1, b, d); if (y == b1) { d1 = d; check = 1; } } } else { zz_p dd; determinant(dd, AA); d_instable = CRT(d, d_prod, rep(dd), p); } } if (check && d1 != d) { mul(x, x, d); ExactDiv(x, d1); } d_out = d; if (check) x_out = x; zbak.restore(); Zbak.restore(); }
void solve1(ZZ& d_out, vec_ZZ& x_out, const mat_ZZ& A, const vec_ZZ& b) { long n = A.NumRows(); if (A.NumCols() != n) Error("solve1: nonsquare matrix"); if (b.length() != n) Error("solve1: dimension mismatch"); if (n == 0) { set(d_out); x_out.SetLength(0); return; } ZZ num_bound, den_bound; hadamard(num_bound, den_bound, A, b); if (den_bound == 0) { clear(d_out); return; } zz_pBak zbak; zbak.save(); long i; long j; ZZ prod; prod = 1; mat_zz_p B; for (i = 0; ; i++) { zz_p::FFTInit(i); mat_zz_p AA, BB; zz_p dd; conv(AA, A); inv(dd, BB, AA); if (dd != 0) { transpose(B, BB); break; } mul(prod, prod, zz_p::modulus()); if (prod > den_bound) { d_out = 0; return; } } long max_A_len = MaxBits(A); long use_double_mul1 = 0; long use_double_mul2 = 0; long double_limit = 0; if (max_A_len + NTL_SP_NBITS + NumBits(n) <= NTL_DOUBLE_PRECISION-1) use_double_mul1 = 1; if (!use_double_mul1 && max_A_len+NTL_SP_NBITS+2 <= NTL_DOUBLE_PRECISION-1) { use_double_mul2 = 1; double_limit = (1L << (NTL_DOUBLE_PRECISION-1-max_A_len-NTL_SP_NBITS)); } long use_long_mul1 = 0; long use_long_mul2 = 0; long long_limit = 0; if (max_A_len + NTL_SP_NBITS + NumBits(n) <= NTL_BITS_PER_LONG-1) use_long_mul1 = 1; if (!use_long_mul1 && max_A_len+NTL_SP_NBITS+2 <= NTL_BITS_PER_LONG-1) { use_long_mul2 = 1; long_limit = (1L << (NTL_BITS_PER_LONG-1-max_A_len-NTL_SP_NBITS)); } if (use_double_mul1 && use_long_mul1) use_long_mul1 = 0; else if (use_double_mul1 && use_long_mul2) use_long_mul2 = 0; else if (use_double_mul2 && use_long_mul1) use_double_mul2 = 0; else if (use_double_mul2 && use_long_mul2) { if (long_limit > double_limit) use_double_mul2 = 0; else use_long_mul2 = 0; } double **double_A; double *double_h; typedef double *double_ptr; if (use_double_mul1 || use_double_mul2) { double_h = NTL_NEW_OP double[n]; double_A = NTL_NEW_OP double_ptr[n]; if (!double_h || !double_A) Error("solve1: out of mem"); for (i = 0; i < n; i++) { double_A[i] = NTL_NEW_OP double[n]; if (!double_A[i]) Error("solve1: out of mem"); } for (i = 0; i < n; i++) for (j = 0; j < n; j++) double_A[j][i] = to_double(A[i][j]); }