forked from ANSSI-FR/libecc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nn_mul.c
144 lines (125 loc) · 3.46 KB
/
nn_mul.c
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
/*
* Copyright (C) 2017 - This file is part of libecc project
*
* Authors:
* Ryad BENADJILA <[email protected]>
* Arnaud EBALARD <[email protected]>
* Jean-Pierre FLORI <[email protected]>
*
* Contributors:
* Nicolas VIVET <[email protected]>
* Karim KHALFALLAH <[email protected]>
*
* This software is licensed under a dual BSD and GPL v2 license.
* See LICENSE file at the root folder of the project.
*/
#include "nn_mul.h"
#include "nn_add.h"
#include "nn.h"
/*
* Compute out = (in1 * in2) & (2^(WORD_BYTES * wlimits) - 1).
*
* The function is constant time for all sets of parameters of given
* lengths.
*
* Implementation: while most generic library implement some advanced
* algorithm (Karatsuba, Toom-Cook, or FFT based algorithms)
* which provide a performance advantage for large numbers, the code
* below is mainly oriented towards simplicity and readibility. It is
* a direct writing of the naive multiplication algorithm one has
* learned in school.
*
* Portability: in order for the code to be portable, all word by
* word multiplication are actually performed by an helper macro
* on half words.
*
* Note: 'out' is initialized by the function (caller can omit it)
*/
static void _nn_mul_low(nn_t out, nn_src_t in1, nn_src_t in2,
u8 wlimit)
{
word_t carry, prod_high, prod_low;
u8 i, j, pos;
nn_check_initialized(in1);
nn_check_initialized(in2);
/* We have to check that wlimit does not exceed our NN_MAX_WORD_LEN */
MUST_HAVE((wlimit * WORD_BYTES) <= NN_MAX_BYTE_LEN);
nn_init(out, (u16)(wlimit * WORD_BYTES));
for (i = 0; i < in1->wlen; i++) {
carry = 0;
pos = 0;
for (j = 0; j < in2->wlen; j++) {
pos = i + j;
/*
* size of the result provided by the caller may not
* be large enough for what multiplication may
* generate.
*/
if (pos >= wlimit) {
continue;
}
/*
* Compute the result of the multiplication of
* two words.
*/
WORD_MUL(prod_high, prod_low,
in1->val[i], in2->val[j]);
/*
* And add previous carry.
*/
prod_low += carry;
prod_high += prod_low < carry;
/*
* Add computed word to what we can currently
* find at current position in result.
*/
out->val[pos] += prod_low;
carry = prod_high + (out->val[pos] < prod_low);
}
/*
* What remains in acc_high at end of previous loop should
* be added to next word after pos in result.
*/
if ((pos + 1) < wlimit) {
out->val[pos + 1] += carry;
}
}
}
/* Handle aliasing */
void nn_mul_low(nn_t out, nn_src_t in1, nn_src_t in2, u8 wlimit)
{
/* Handle output aliasing */
if ((out == in1) || (out == in2)) {
nn out_cpy;
_nn_mul_low(&out_cpy, in1, in2, wlimit);
nn_init(out, out_cpy.wlen);
nn_copy(out, &out_cpy);
nn_uninit(&out_cpy);
} else {
_nn_mul_low(out, in1, in2, wlimit);
}
}
/* Note: 'out' is initialized by the function (caller can omit it) */
void nn_mul(nn_t out, nn_src_t in1, nn_src_t in2)
{
nn_mul_low(out, in1, in2, in1->wlen + in2->wlen);
}
void nn_sqr_low(nn_t out, nn_src_t in, u8 wlimit)
{
nn_mul_low(out, in, in, wlimit);
}
/* Note: 'out' is initialized by the function (caller can omit it) */
void nn_sqr(nn_t out, nn_src_t in)
{
nn_mul(out, in, in);
}
/* Multiply a multiprecision number by a word. */
void nn_mul_word(nn_t out, nn_src_t in, word_t w)
{
nn w_nn;
nn_check_initialized(in);
nn_init(&w_nn, WORD_BYTES);
w_nn.val[0] = w;
nn_mul(out, in, &w_nn);
nn_uninit(&w_nn);
}