aboutsummaryrefslogtreecommitdiffstats
path: root/lib/mpi/mpi-mod.c
blob: 54fcc01564d9dc6f1a1ae5b58ad820e503f64fbe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* mpi-mod.c -  Modular reduction
 * Copyright (C) 1998, 1999, 2001, 2002, 2003,
 *               2007  Free Software Foundation, Inc.
 *
 * This file is part of Libgcrypt.
 */


#include "mpi-internal.h"
#include "longlong.h"

/* Context used with Barrett reduction.  */
struct barrett_ctx_s {
	MPI m;   /* The modulus - may not be modified. */
	int m_copied;   /* If true, M needs to be released.  */
	int k;
	MPI y;
	MPI r1;  /* Helper MPI. */
	MPI r2;  /* Helper MPI. */
	MPI r3;  /* Helper MPI allocated on demand. */
};



void mpi_mod(MPI rem, MPI dividend, MPI divisor)
{
	mpi_fdiv_r(rem, dividend, divisor);
}

/* This function returns a new context for Barrett based operations on
 * the modulus M.  This context needs to be released using
 * _gcry_mpi_barrett_free.  If COPY is true M will be transferred to
 * the context and the user may change M.  If COPY is false, M may not
 * be changed until gcry_mpi_barrett_free has been called.
 */
mpi_barrett_t mpi_barrett_init(MPI m, int copy)
{
	mpi_barrett_t ctx;
	MPI tmp;

	mpi_normalize(m);
	ctx = kcalloc(1, sizeof(*ctx), GFP_KERNEL);
	if (!ctx)
		return NULL;

	if (copy) {
		ctx->m = mpi_copy(m);
		ctx->m_copied = 1;
	} else
		ctx->m = m;

	ctx->k = mpi_get_nlimbs(m);
	tmp = mpi_alloc(ctx->k + 1);

	/* Barrett precalculation: y = floor(b^(2k) / m). */
	mpi_set_ui(tmp, 1);
	mpi_lshift_limbs(tmp, 2 * ctx->k);
	mpi_fdiv_q(tmp, tmp, m);

	ctx->y  = tmp;
	ctx->r1 = mpi_alloc(2 * ctx->k + 1);
	ctx->r2 = mpi_alloc(2 * ctx->k + 1);

	return ctx;
}

void mpi_barrett_free(mpi_barrett_t ctx)
{
	if (ctx) {
		mpi_free(ctx->y);
		mpi_free(ctx->r1);
		mpi_free(ctx->r2);
		if (ctx->r3)
			mpi_free(ctx->r3);
		if (ctx->m_copied)
			mpi_free(ctx->m);
		kfree(ctx);
	}
}


/* R = X mod M
 *
 * Using Barrett reduction.  Before using this function
 * _gcry_mpi_barrett_init must have been called to do the
 * precalculations.  CTX is the context created by this precalculation
 * and also conveys M.  If the Barret reduction could no be done a
 * straightforward reduction method is used.
 *
 * We assume that these conditions are met:
 * Input:  x =(x_2k-1 ...x_0)_b
 *     m =(m_k-1 ....m_0)_b	  with m_k-1 != 0
 * Output: r = x mod m
 */
void mpi_mod_barrett(MPI r, MPI x, mpi_barrett_t ctx)
{
	MPI m = ctx->m;
	int k = ctx->k;
	MPI y = ctx->y;
	MPI r1 = ctx->r1;
	MPI r2 = ctx->r2;
	int sign;

	mpi_normalize(x);
	if (mpi_get_nlimbs(x) > 2*k) {
		mpi_mod(r, x, m);
		return;
	}

	sign = x->sign;
	x->sign = 0;

	/* 1. q1 = floor( x / b^k-1)
	 *    q2 = q1 * y
	 *    q3 = floor( q2 / b^k+1 )
	 * Actually, we don't need qx, we can work direct on r2
	 */
	mpi_set(r2, x);
	mpi_rshift_limbs(r2, k-1);
	mpi_mul(r2, r2, y);
	mpi_rshift_limbs(r2, k+1);

	/* 2. r1 = x mod b^k+1
	 *	r2 = q3 * m mod b^k+1
	 *	r  = r1 - r2
	 * 3. if r < 0 then  r = r + b^k+1
	 */
	mpi_set(r1, x);
	if (r1->nlimbs > k+1) /* Quick modulo operation.  */
		r1->nlimbs = k+1;
	mpi_mul(r2, r2, m);
	if (r2->nlimbs > k+1) /* Quick modulo operation. */
		r2->nlimbs = k+1;
	mpi_sub(r, r1, r2);

	if (mpi_has_sign(r)) {
		if (!ctx->r3) {
			ctx->r3 = mpi_alloc(k + 2);
			mpi_set_ui(ctx->r3, 1);
			mpi_lshift_limbs(ctx->r3, k + 1);
		}
		mpi_add(r, r, ctx->r3);
	}

	/* 4. while r >= m do r = r - m */
	while (mpi_cmp(r, m) >= 0)
		mpi_sub(r, r, m);

	x->sign = sign;
}


void mpi_mul_barrett(MPI w, MPI u, MPI v, mpi_barrett_t ctx)
{
	mpi_mul(w, u, v);
	mpi_mod_barrett(w, w, ctx);
}