162306a36Sopenharmony_ci/* mpi-mod.c - Modular reduction 262306a36Sopenharmony_ci * Copyright (C) 1998, 1999, 2001, 2002, 2003, 362306a36Sopenharmony_ci * 2007 Free Software Foundation, Inc. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This file is part of Libgcrypt. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "mpi-internal.h" 1062306a36Sopenharmony_ci#include "longlong.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* Context used with Barrett reduction. */ 1362306a36Sopenharmony_cistruct barrett_ctx_s { 1462306a36Sopenharmony_ci MPI m; /* The modulus - may not be modified. */ 1562306a36Sopenharmony_ci int m_copied; /* If true, M needs to be released. */ 1662306a36Sopenharmony_ci int k; 1762306a36Sopenharmony_ci MPI y; 1862306a36Sopenharmony_ci MPI r1; /* Helper MPI. */ 1962306a36Sopenharmony_ci MPI r2; /* Helper MPI. */ 2062306a36Sopenharmony_ci MPI r3; /* Helper MPI allocated on demand. */ 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_civoid mpi_mod(MPI rem, MPI dividend, MPI divisor) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci mpi_fdiv_r(rem, dividend, divisor); 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* This function returns a new context for Barrett based operations on 3162306a36Sopenharmony_ci * the modulus M. This context needs to be released using 3262306a36Sopenharmony_ci * _gcry_mpi_barrett_free. If COPY is true M will be transferred to 3362306a36Sopenharmony_ci * the context and the user may change M. If COPY is false, M may not 3462306a36Sopenharmony_ci * be changed until gcry_mpi_barrett_free has been called. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_cimpi_barrett_t mpi_barrett_init(MPI m, int copy) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci mpi_barrett_t ctx; 3962306a36Sopenharmony_ci MPI tmp; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci mpi_normalize(m); 4262306a36Sopenharmony_ci ctx = kcalloc(1, sizeof(*ctx), GFP_KERNEL); 4362306a36Sopenharmony_ci if (!ctx) 4462306a36Sopenharmony_ci return NULL; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (copy) { 4762306a36Sopenharmony_ci ctx->m = mpi_copy(m); 4862306a36Sopenharmony_ci ctx->m_copied = 1; 4962306a36Sopenharmony_ci } else 5062306a36Sopenharmony_ci ctx->m = m; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci ctx->k = mpi_get_nlimbs(m); 5362306a36Sopenharmony_ci tmp = mpi_alloc(ctx->k + 1); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* Barrett precalculation: y = floor(b^(2k) / m). */ 5662306a36Sopenharmony_ci mpi_set_ui(tmp, 1); 5762306a36Sopenharmony_ci mpi_lshift_limbs(tmp, 2 * ctx->k); 5862306a36Sopenharmony_ci mpi_fdiv_q(tmp, tmp, m); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci ctx->y = tmp; 6162306a36Sopenharmony_ci ctx->r1 = mpi_alloc(2 * ctx->k + 1); 6262306a36Sopenharmony_ci ctx->r2 = mpi_alloc(2 * ctx->k + 1); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci return ctx; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_civoid mpi_barrett_free(mpi_barrett_t ctx) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci if (ctx) { 7062306a36Sopenharmony_ci mpi_free(ctx->y); 7162306a36Sopenharmony_ci mpi_free(ctx->r1); 7262306a36Sopenharmony_ci mpi_free(ctx->r2); 7362306a36Sopenharmony_ci if (ctx->r3) 7462306a36Sopenharmony_ci mpi_free(ctx->r3); 7562306a36Sopenharmony_ci if (ctx->m_copied) 7662306a36Sopenharmony_ci mpi_free(ctx->m); 7762306a36Sopenharmony_ci kfree(ctx); 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* R = X mod M 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * Using Barrett reduction. Before using this function 8562306a36Sopenharmony_ci * _gcry_mpi_barrett_init must have been called to do the 8662306a36Sopenharmony_ci * precalculations. CTX is the context created by this precalculation 8762306a36Sopenharmony_ci * and also conveys M. If the Barret reduction could no be done a 8862306a36Sopenharmony_ci * straightforward reduction method is used. 8962306a36Sopenharmony_ci * 9062306a36Sopenharmony_ci * We assume that these conditions are met: 9162306a36Sopenharmony_ci * Input: x =(x_2k-1 ...x_0)_b 9262306a36Sopenharmony_ci * m =(m_k-1 ....m_0)_b with m_k-1 != 0 9362306a36Sopenharmony_ci * Output: r = x mod m 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_civoid mpi_mod_barrett(MPI r, MPI x, mpi_barrett_t ctx) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci MPI m = ctx->m; 9862306a36Sopenharmony_ci int k = ctx->k; 9962306a36Sopenharmony_ci MPI y = ctx->y; 10062306a36Sopenharmony_ci MPI r1 = ctx->r1; 10162306a36Sopenharmony_ci MPI r2 = ctx->r2; 10262306a36Sopenharmony_ci int sign; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci mpi_normalize(x); 10562306a36Sopenharmony_ci if (mpi_get_nlimbs(x) > 2*k) { 10662306a36Sopenharmony_ci mpi_mod(r, x, m); 10762306a36Sopenharmony_ci return; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci sign = x->sign; 11162306a36Sopenharmony_ci x->sign = 0; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci /* 1. q1 = floor( x / b^k-1) 11462306a36Sopenharmony_ci * q2 = q1 * y 11562306a36Sopenharmony_ci * q3 = floor( q2 / b^k+1 ) 11662306a36Sopenharmony_ci * Actually, we don't need qx, we can work direct on r2 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci mpi_set(r2, x); 11962306a36Sopenharmony_ci mpi_rshift_limbs(r2, k-1); 12062306a36Sopenharmony_ci mpi_mul(r2, r2, y); 12162306a36Sopenharmony_ci mpi_rshift_limbs(r2, k+1); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* 2. r1 = x mod b^k+1 12462306a36Sopenharmony_ci * r2 = q3 * m mod b^k+1 12562306a36Sopenharmony_ci * r = r1 - r2 12662306a36Sopenharmony_ci * 3. if r < 0 then r = r + b^k+1 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci mpi_set(r1, x); 12962306a36Sopenharmony_ci if (r1->nlimbs > k+1) /* Quick modulo operation. */ 13062306a36Sopenharmony_ci r1->nlimbs = k+1; 13162306a36Sopenharmony_ci mpi_mul(r2, r2, m); 13262306a36Sopenharmony_ci if (r2->nlimbs > k+1) /* Quick modulo operation. */ 13362306a36Sopenharmony_ci r2->nlimbs = k+1; 13462306a36Sopenharmony_ci mpi_sub(r, r1, r2); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (mpi_has_sign(r)) { 13762306a36Sopenharmony_ci if (!ctx->r3) { 13862306a36Sopenharmony_ci ctx->r3 = mpi_alloc(k + 2); 13962306a36Sopenharmony_ci mpi_set_ui(ctx->r3, 1); 14062306a36Sopenharmony_ci mpi_lshift_limbs(ctx->r3, k + 1); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci mpi_add(r, r, ctx->r3); 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* 4. while r >= m do r = r - m */ 14662306a36Sopenharmony_ci while (mpi_cmp(r, m) >= 0) 14762306a36Sopenharmony_ci mpi_sub(r, r, m); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci x->sign = sign; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_civoid mpi_mul_barrett(MPI w, MPI u, MPI v, mpi_barrett_t ctx) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci mpi_mul(w, u, v); 15662306a36Sopenharmony_ci mpi_mod_barrett(w, w, ctx); 15762306a36Sopenharmony_ci} 158