int root(mpz_class& result, const mpz_class arg, const mpz_class prime) { mpz_class y, b, t; unsigned int r, m; if (arg % prime == 0) { result = 0; return 1; } if (mpz_legendre(arg.get_mpz_t(), prime.get_mpz_t()) == -1) return -1; b = 0; t = 0; y = 2; while(mpz_legendre(y.get_mpz_t(), prime.get_mpz_t()) != -1) { y++; } result = prime - 1; r = mpz_scan1(result.get_mpz_t(), 0); mpz_rshift(result.get_mpz_t(), result.get_mpz_t(), r); mpz_powm(y.get_mpz_t(), y.get_mpz_t(), result.get_mpz_t(), prime.get_mpz_t()); mpz_rshift(result.get_mpz_t(), result.get_mpz_t(), 1); mpz_powm(b.get_mpz_t(), arg.get_mpz_t(), result.get_mpz_t(), prime.get_mpz_t()); result = (arg * b) % prime; b = (result * b) % prime; while(b != 1) { t = (b * b) % prime; for(m = 1; t != 1; m++) { t = (t * t) % prime; } t = 0; mpz_setbit(t.get_mpz_t(), r - m - 1); mpz_powm(t.get_mpz_t(), y.get_mpz_t(), t.get_mpz_t(), prime.get_mpz_t()); y = t * t; r = m; result = (result * t) % prime; b = (b * y) % prime; } return 1; }
static PyObject * GMPy_MPZ_Function_Legendre(PyObject *self, PyObject *args) { MPZ_Object *tempx = NULL, *tempy = NULL; long res; if (PyTuple_GET_SIZE(args) != 2) { TYPE_ERROR("legendre() requires 'mpz','mpz' arguments"); return NULL; } if (!(tempx = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 0), NULL)) || !(tempy = GMPy_MPZ_From_Integer(PyTuple_GET_ITEM(args, 1), NULL))) { Py_XDECREF((PyObject*)tempx); Py_XDECREF((PyObject*)tempy); return NULL; } if (mpz_sgn(tempy->z) <= 0 || mpz_even_p(tempy->z)) { VALUE_ERROR("y must be odd, prime, and >0"); Py_DECREF((PyObject*)tempx); Py_DECREF((PyObject*)tempy); return NULL; } res = (long)(mpz_legendre(tempx->z, tempy->z)); Py_DECREF((PyObject*)tempx); Py_DECREF((PyObject*)tempy); return PyIntOrLong_FromLong(res); }
static int fp_is_sqr(element_ptr a) { int res; mpz_t z; mpz_init(z); //0 is a square if (fp_is0(a)) return 1; fp_to_mpz(z, a); res = mpz_legendre(z, a->field->order) == 1; mpz_clear(z); return res; }
static int fp_is_sqr(element_ptr a) { eptr ad = (eptr)a->data; int res; mpz_t z; mpz_init(z); // 0 is a square. if (!ad->flag) return 1; fp_to_mpz(z, a); res = mpz_legendre(z, a->field->order) == 1; mpz_clear(z); return res; }
static Variant HHVM_FUNCTION(gmp_legendre, const Variant& dataA, const Variant& dataB) { mpz_t gmpDataA, gmpDataB; if (!variantToGMPData(cs_GMP_FUNC_NAME_GMP_LEGENDRE, gmpDataA, dataA)) { return false; } if (!variantToGMPData(cs_GMP_FUNC_NAME_GMP_LEGENDRE, gmpDataB, dataB)) { mpz_clear(gmpDataA); return false; } int64_t result = mpz_legendre(gmpDataA, gmpDataB); mpz_clear(gmpDataA); mpz_clear(gmpDataB); return result; }
void Sieve::CreateFactorBase(void) { factorbase.push_back(2); mpz_class tmpmpz; for (int i = 1; i < lowprimes::n && lowprimes::primearray[i] < B; i++) { tmpmpz = lowprimes::primearray[i]; if (mpz_legendre(N.get_mpz_t(), tmpmpz.get_mpz_t()) == 1) { #ifdef PRINTALL std::cout << lowprimes::primearray[i] << " "; #endif factorbase.push_back(lowprimes::primearray[i]); } } #ifdef PRINTALL std::cout << std::endl; #endif array = new int[factorbase.size()]; }
static int zp_is_sqr(element_ptr a) { //0 is a square if (mpz_is0(a->data)) return 1; return mpz_legendre(a->data, a->field->order) == 1; }
// A quadratic sieve implementation for integers up to 100 bits. N must be composite. mpz_class quadratic_sieve(mpz_class &N) { std::vector<uint32_t> factor_base; mpz_class sqrt_N = sqrt(N); //const unsigned long sqrt_N_long = sqrt_N.get_ui(); // Set the smoothness bound. uint32_t B; { // Approximation of the natural logarithm of N. float log_N = mpz_sizeinbase(N.get_mpz_t(), 2) * log(2); // The optimal smoothness bound is exp((0.5 + o(1)) * sqrt(log(n)*log(log(n)))). B = (uint32_t)ceil(exp(0.56 * sqrt(log_N * log(log_N)))) + 300; } // Generate the factor base using a sieve. { char *sieve = new char[B + 1]; memset(sieve, 1, B + 1); for(unsigned long p = 2; p <= B; ++p) { if(!sieve[p]) continue; if(mpz_legendre(N.get_mpz_t(), mpz_class(p).get_mpz_t()) == 1) factor_base.push_back(p); for(unsigned long i = p; i <= B; i += p) sieve[i] = 0; } delete[] sieve; } std::vector<uint32_t> X; float *Y = new float[SIEVE_CHUNK]; std::vector<std::vector<uint32_t> > smooth; int fails = 0; // The sieve boundary. uint32_t min_x = 0; uint32_t max_x = SIEVE_CHUNK; // Calculate sieve index (where to start the sieve) for each factor base number. uint32_t **fb_indexes = new uint32_t*[2]; fb_indexes[0] = new uint32_t[factor_base.size()]; fb_indexes[1] = new uint32_t[factor_base.size()]; for(uint32_t p = 0; p < factor_base.size(); ++p) { // At what indexes do we start this sieve? Solve the congruence x^2 = n (mod p) to find out. // Results in two solutions, so we do two sieve iterations for each prime in the factor base. uint32_t idxs[2]; mpz_class temp = N % mpz_class(factor_base[p]); tonelli_shanks(temp.get_ui(), factor_base[p], idxs); temp = idxs[0] - sqrt_N; temp = ((temp % factor_base[p]) + factor_base[p]) % factor_base[p]; fb_indexes[0][p] = temp.get_ui(); temp = idxs[1] - sqrt_N; temp = ((temp % factor_base[p]) + factor_base[p]) % factor_base[p]; fb_indexes[1][p] = temp.get_ui(); } float last_estimate = 0; uint32_t next_estimate = 1; // Sieve new chunks until we have enough smooth numbers. while(smooth.size() < (factor_base.size() + 20)) { // Generate our Y vector for the sieve, containing log approximations that fit in machine words. for(uint32_t t = 1; t < SIEVE_CHUNK; ++t) { // Calculating a log estimate is expensive, so don't do it for every Y[t]. if(next_estimate <= (t + min_x)) { mpz_class y = (sqrt_N + t + min_x) * (sqrt_N + t + min_x) - N; // To estimate the 2 logarithm, just count the number of bits that v takes up. last_estimate = mpz_sizeinbase(y.get_mpz_t(), 2); // The higher t gets, the less the logarithm of Y[t] changes. next_estimate = next_estimate * 1.8 + 1; } Y[t] = last_estimate; } // Perform the actual sieve. for(uint32_t p = 0; p < factor_base.size(); ++p) { float lg = log(factor_base[p]) / log(2); for(uint32_t t = 0; t < 2; ++t) { while(fb_indexes[t][p] < max_x) { Y[fb_indexes[t][p] - min_x] -= lg; fb_indexes[t][p] += factor_base[p]; } // p = 2 only has one modular root. if(factor_base[p] == 2) break; } } // Factor all values whose logarithms were reduced to approximately zero using trial division. { float threshold = log(factor_base.back()) / log(2); for(uint32_t i = 0; i < SIEVE_CHUNK; ++i) { if(fabs(Y[i]) < threshold) { mpz_class y = (sqrt_N + i + min_x) * (sqrt_N + i + min_x) - N; smooth.push_back(std::vector<uint32_t>()); for(uint32_t p = 0; p < factor_base.size(); ++p) { while(mpz_divisible_ui_p(y.get_mpz_t(), factor_base[p])) { mpz_divexact_ui(y.get_mpz_t(), y.get_mpz_t(), factor_base[p]); smooth.back().push_back(p); } } if(y == 1) { // This V was indeed B-smooth. X.push_back(i + min_x); // Break out of trial division loop if we've found enou gh smooth numbers. if(smooth.size() >= (factor_base.size() + 20)) break; } else { // This V was apparently not B-smooth, remove it. smooth.pop_back(); ++fails; } } } } min_x += SIEVE_CHUNK; max_x += SIEVE_CHUNK; } uint64_t **matrix = new uint64_t*[factor_base.size()]; // The amount of words needed to accomodate a row in the augmented matrix. int row_words = (smooth.size() + sizeof(uint64_t)) / sizeof(uint64_t); for(uint32_t i = 0; i < factor_base.size(); ++i) { matrix[i] = new uint64_t[row_words]; memset(matrix[i], 0, row_words * sizeof(uint64_t)); } for(uint32_t s = 0; s < smooth.size(); ++s) { // For each factor in the smooth number, add the factor to the corresponding element in the matrix. for(uint32_t p = 0; p < smooth[s].size(); ++p) toggle_bit(s, matrix[smooth[s][p]]); } // Gauss elimination. The dimension of the augmented matrix is factor_base.size() x (smooth.size() + 1). { uint32_t i = 0, j = 0; while(i < factor_base.size() && j < (smooth.size() + 1)) { uint32_t maxi = i; // Find pivot element. for(uint32_t k = i + 1; k < factor_base.size(); ++k) { if(get_bit(j, matrix[k]) == 1) { maxi = k; break; } } if(get_bit(j, matrix[maxi]) == 1) { std::swap(matrix[i], matrix[maxi]); for(uint32_t u = i + 1; u < factor_base.size(); ++u) { if(get_bit(j, matrix[u]) == 1) { for(int32_t w = 0; w < row_words; ++w) matrix[u][w] ^= matrix[i][w]; } } ++i; } ++j; } } mpz_class a; mpz_class b; // A copy of matrix that we'll perform back-substitution on. uint64_t **back_matrix = new uint64_t*[factor_base.size()]; for(uint32_t i = 0; i < factor_base.size(); ++i) back_matrix[i] = new uint64_t[row_words]; uint32_t *x = new uint32_t[smooth.size()]; uint32_t *combination = new uint32_t[factor_base.size()]; // Loop until we've found a non-trivial factor. do { // Copy the gauss eliminated matrix. for(uint32_t i = 0; i < factor_base.size(); ++i) memcpy(back_matrix[i], matrix[i], row_words * sizeof(uint64_t)); // Clear the x vector. memset(x, 0, smooth.size() * sizeof(uint32_t)); // Perform back-substitution on our matrix that's now in row echelon form to get x. { int32_t i = factor_base.size() - 1; while(i >= 0) { // Count non-zero elements in current row. int32_t count = 0; int32_t current = -1; for(uint32_t c = 0; c < smooth.size(); ++c) { count += get_bit(c, back_matrix[i]); current = get_bit(c, back_matrix[i]) ? c : current; } // Empty row, advance to next. if(count == 0) { --i; continue; } // The system is underdetermined and we can choose x[current] freely. // To avoid the trivial solution we avoid always setting it to 0. uint32_t val = count > 1 ? rand() % 2 : get_bit(smooth.size(), back_matrix[i]); x[current] = val; for(int32_t u = 0; u <= i; ++u) { if(get_bit(current, back_matrix[u]) == 1) { if(val == 1) toggle_bit(smooth.size(), back_matrix[u]); unset_bit(current, back_matrix[u]); } } if(count == 1) --i; } } a = 1; b = 1; // The way to combine the factor base to get our square. memset(combination, 0, sizeof(uint32_t) * factor_base.size()); for(uint32_t i = 0; i < smooth.size(); ++i) { if(x[i] == 1) { for(uint32_t p = 0; p < smooth[i].size(); ++p) ++combination[smooth[i][p]]; b *= (X[i] + sqrt_N); } } for(uint32_t p = 0; p < factor_base.size(); ++p) { for(uint32_t i = 0; i < (combination[p] / 2); ++i) a *= factor_base[p]; } // If a = +/- b (mod N) we found a trivial factor, run the loop again to find a new a and b. } while(a % N == b % N || a % N == (- b) % N + N); b -= a; mpz_class factor; mpz_gcd(factor.get_mpz_t(), b.get_mpz_t(), N.get_mpz_t()); for(uint32_t i = 0; i < factor_base.size(); ++i) { delete[] matrix[i]; delete[] back_matrix[i]; } delete[] combination; delete[] Y; delete[] fb_indexes[0]; delete[] fb_indexes[1]; delete[] fb_indexes; delete[] matrix; delete[] back_matrix; delete[] x; return factor; }
/* sqrtmod_prime */ static int sqrtmod_prime(void *n, void *prime, void *ret) { int res, legendre, i; mpz_t t1, C, Q, S, Z, M, T, R, two; LTC_ARGCHK(n != NULL); LTC_ARGCHK(prime != NULL); LTC_ARGCHK(ret != NULL); /* first handle the simple cases */ if (mpz_cmp_ui(((__mpz_struct *)n), 0) == 0) { mpz_set_ui(ret, 0); return CRYPT_OK; } if (mpz_cmp_ui(((__mpz_struct *)prime), 2) == 0) return CRYPT_ERROR; /* prime must be odd */ legendre = mpz_legendre(n, prime); if (legendre == -1) return CRYPT_ERROR; /* quadratic non-residue mod prime */ mpz_init(t1); mpz_init(C); mpz_init(Q); mpz_init(S); mpz_init(Z); mpz_init(M); mpz_init(T); mpz_init(R); mpz_init(two); /* SPECIAL CASE: if prime mod 4 == 3 * compute directly: res = n^(prime+1)/4 mod prime * Handbook of Applied Cryptography algorithm 3.36 */ i = mpz_mod_ui(t1, prime, 4); /* t1 is ignored here */ if (i == 3) { mpz_add_ui(t1, prime, 1); mpz_fdiv_q_2exp(t1, t1, 2); mpz_powm(ret, n, t1, prime); res = CRYPT_OK; goto cleanup; } /* NOW: Tonelli-Shanks algorithm */ /* factor out powers of 2 from prime-1, defining Q and S as: prime-1 = Q*2^S */ mpz_set(Q, prime); mpz_sub_ui(Q, Q, 1); /* Q = prime - 1 */ mpz_set_ui(S, 0); /* S = 0 */ while (mpz_even_p(Q)) { mpz_fdiv_q_2exp(Q, Q, 1); /* Q = Q / 2 */ mpz_add_ui(S, S, 1); /* S = S + 1 */ } /* find a Z such that the Legendre symbol (Z|prime) == -1 */ mpz_set_ui(Z, 2); /* Z = 2 */ while(1) { legendre = mpz_legendre(Z, prime); if (legendre == -1) break; mpz_add_ui(Z, Z, 1); /* Z = Z + 1 */ } mpz_powm(C, Z, Q, prime); /* C = Z ^ Q mod prime */ mpz_add_ui(t1, Q, 1); mpz_fdiv_q_2exp(t1, t1, 1); /* t1 = (Q + 1) / 2 */ mpz_powm(R, n, t1, prime); /* R = n ^ ((Q + 1) / 2) mod prime */ mpz_powm(T, n, Q, prime); /* T = n ^ Q mod prime */ mpz_set(M, S); /* M = S */ mpz_set_ui(two, 2); while (1) { mpz_set(t1, T); i = 0; while (1) { if (mpz_cmp_ui(((__mpz_struct *)t1), 1) == 0) break; mpz_powm(t1, t1, two, prime); i++; } if (i == 0) { mpz_set(ret, R); res = CRYPT_OK; goto cleanup; } mpz_sub_ui(t1, M, i); mpz_sub_ui(t1, t1, 1); mpz_powm(t1, two, t1, prime); /* t1 = 2 ^ (M - i - 1) */ mpz_powm(t1, C, t1, prime); /* t1 = C ^ (2 ^ (M - i - 1)) mod prime */ mpz_mul(C, t1, t1); mpz_mod(C, C, prime); /* C = (t1 * t1) mod prime */ mpz_mul(R, R, t1); mpz_mod(R, R, prime); /* R = (R * t1) mod prime */ mpz_mul(T, T, C); mpz_mod(T, T, prime); /* T = (T * C) mod prime */ mpz_set_ui(M, i); /* M = i */ } cleanup: mpz_clear(t1); mpz_clear(C); mpz_clear(Q); mpz_clear(S); mpz_clear(Z); mpz_clear(M); mpz_clear(T); mpz_clear(R); mpz_clear(two); return res; }
/* * Compute the Rabin signature and the useful value of f. */ int rs_sign_rabin(mpz_t res, /* mpz to store signature */ int* f, /* f value chosen */ const mpz_t hash, /* MD5 hash of app */ int rootnum, /* root number (0, 1, 2, 3) */ RSKey* key) /* key structure */ { mpz_t mm; int mLp, mLq; int pm8, qm8; if (!mpz_sgn(key->n)) { rs_error(key, NULL, "unable to sign: public key missing"); return RS_ERR_MISSING_PUBLIC_KEY; } if (!mpz_sgn(key->p) || !mpz_sgn(key->q)) { rs_error(key, NULL, "unable to sign: private key missing"); return RS_ERR_MISSING_PRIVATE_KEY; } mpz_init(mm); /* Calculate q^-1 if necessary */ if (!mpz_sgn(key->qinv)) { #ifndef USE_MPZ_GCDEXT mpz_sub_ui(mm, key->p, 2); mpz_powm(key->qinv, key->q, mm, key->p); #else mpz_gcdext(mm, key->qinv, NULL, key->q, key->p); if (mpz_cmp_ui(mm, 1)) { mpz_clear(mm); rs_error(key, NULL, "unable to sign: unsuitable key"); return RS_ERR_UNSUITABLE_RABIN_KEY; } #endif } applyf(mm, hash, key->n, 2); mLp = mpz_legendre(mm, key->p); mLq = mpz_legendre(mm, key->q); pm8 = mpz_get_ui(key->p) % 8; qm8 = mpz_get_ui(key->q) % 8; if (pm8 == 1 || qm8 == 1 || (pm8 % 2) == 0 || (qm8 % 2) == 0) { mpz_clear(mm); rs_error(key, NULL, "unable to sign: unsuitable key"); return RS_ERR_UNSUITABLE_RABIN_KEY; } *f = ftab[(mLp == 1 ? 0 : 1) + (mLq == 1 ? 0 : 2) + (((qm8 - 3) / 2) * 4) + (((pm8 - 3) / 2) * 12)]; if (*f == 99) { mpz_clear(mm); rs_error(key, NULL, "unable to sign: unsuitable key"); return RS_ERR_UNSUITABLE_RABIN_KEY; } rabsigf(res, hash, key->n, key->p, key->q, key->qinv, *f, rootnum); mpz_clear(mm); return RS_SUCCESS; }
/* See Cohen section 1.5. * See http://www.math.vt.edu/people/brown/doc/sqrts.pdf */ int sqrtmod(mpz_t x, mpz_t a, mpz_t p, mpz_t t, mpz_t q, mpz_t b, mpz_t z) /* 4 temp variables */ { int r, e, m; /* Easy cases from page 31 (or Menezes 3.36, 3.37) */ if (mpz_congruent_ui_p(p, 3, 4)) { mpz_add_ui(t, p, 1); mpz_tdiv_q_2exp(t, t, 2); mpz_powm(x, a, t, p); return verify_sqrt(x, a, p, t, q); } if (mpz_congruent_ui_p(p, 5, 8)) { mpz_sub_ui(t, p, 1); mpz_tdiv_q_2exp(t, t, 2); mpz_powm(q, a, t, p); if (mpz_cmp_si(q, 1) == 0) { /* s = a^((p+3)/8) mod p */ mpz_add_ui(t, p, 3); mpz_tdiv_q_2exp(t, t, 3); mpz_powm(x, a, t, p); } else { /* s = 2a * (4a)^((p-5)/8) mod p */ mpz_sub_ui(t, p, 5); mpz_tdiv_q_2exp(t, t, 3); mpz_mul_ui(q, a, 4); mpz_powm(x, q, t, p); mpz_mul_ui(x, x, 2); mpz_mulmod(x, x, a, p, x); } return verify_sqrt(x, a, p, t, q); } if (mpz_kronecker(a, p) != 1) { /* Possible no solution exists. Check Euler criterion. */ mpz_sub_ui(t, p, 1); mpz_tdiv_q_2exp(t, t, 1); mpz_powm(x, a, t, p); if (mpz_cmp_si(x, 1) != 0) { mpz_set_ui(x, 0); return 0; } } mpz_sub_ui(q, p, 1); e = mpz_scan1(q, 0); /* Remove 2^e from q */ mpz_tdiv_q_2exp(q, q, e); mpz_set_ui(t, 2); while (mpz_legendre(t, p) != -1) /* choose t "at random" */ mpz_add_ui(t, t, 1); mpz_powm(z, t, q, p); /* Step 1 complete */ r = e; mpz_powm(b, a, q, p); mpz_add_ui(q, q, 1); mpz_divexact_ui(q, q, 2); mpz_powm(x, a, q, p); /* Done with q, will use it for y now */ while (mpz_cmp_ui(b, 1)) { /* calculate how many times b^2 mod p == 1 */ mpz_set(t, b); m = 0; do { mpz_powm_ui(t, t, 2, p); m++; } while (m < r && mpz_cmp_ui(t, 1)); if (m >= r) break; mpz_ui_pow_ui(t, 2, r-m-1); mpz_powm(t, z, t, p); mpz_mulmod(x, x, t, p, x); mpz_powm_ui(z, t, 2, p); mpz_mulmod(b, b, z, p, b); r = m; } return verify_sqrt(x, a, p, t, q); }
int quadratic_residue(mpz_t x,mpz_t q,mpz_t n) { int leg; mpz_t tmp,ofac,nr,t,r,c,b; unsigned int mod4; mp_bitcnt_t twofac=0,m,i,ix; mod4=mpz_tstbit(n,0); if(!mod4) // must be odd return 0; mod4+=2*mpz_tstbit(n,1); leg=mpz_legendre(q,n); if(leg!=1) return leg; mpz_init_set(tmp,n); if(mod4==3) // directly, x = q^(n+1)/4 mod n { printf("diretamente\n\n"); mpz_add_ui(tmp,tmp,1UL); mpz_tdiv_q_2exp(tmp,tmp,2); mpz_powm(x,q,tmp,n); gmp_printf("NUMERO X %Zd \n\n",x); mpz_clear(tmp); } else // Tonelli-Shanks { printf("Tonelli shanks!!!\n"); mpz_inits(ofac,t,r,c,b,NULL); // split n - 1 into odd number times power of 2 ofac*2^twofac mpz_sub_ui(tmp,tmp,1UL); twofac=mpz_scan1(tmp,twofac); // largest power of 2 divisor if(twofac) mpz_tdiv_q_2exp(ofac,tmp,twofac); // shift right // look for non-residue mpz_init_set_ui(nr,2UL); while(mpz_legendre(nr,n)!=-1) mpz_add_ui(nr,nr,1UL); mpz_powm(c,nr,ofac,n); // c = nr^ofac mod n mpz_add_ui(tmp,ofac,1UL); mpz_tdiv_q_2exp(tmp,tmp,1); mpz_powm(r,q,tmp,n); // r = q^(ofac+1)/2 mod n mpz_powm(t,q,ofac,n); mpz_mod(t,t,n); // t = q^ofac mod n if(mpz_cmp_ui(t,1UL)!=0) // if t = 1 mod n we're done { m=twofac; do { i=2; ix=1; while(ix<m) { // find lowest 0 < ix < m | t^2^ix = 1 mod n mpz_powm_ui(tmp,t,i,n); // repeatedly square t if(mpz_cmp_ui(tmp,1UL)==0) break; i<<=1; // i = 2, 4, 8, ... ix++; // ix is log2 i } mpz_powm_ui(b,c,1<<(m-ix-1),n); // b = c^2^(m-ix-1) mod n mpz_mul(r,r,b); mpz_mod(r,r,n); // r = r*b mod n mpz_mul(c,b,b); mpz_mod(c,c,n); // c = b^2 mod n mpz_mul(t,t,c); mpz_mod(t,t,n); // t = t b^2 mod n m=ix; }while(mpz_cmp_ui(t,1UL)!=0); // while t mod n != 1 } mpz_set(x,r); mpz_clears(tmp,ofac,nr,t,r,c,b,NULL); } return 1; }