Coverage Report

Created: 2024-11-21 07:03

/src/SymCrypt/lib/recoding.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// recoding.c   Algorithms for recoding the factors / exponents in various implementations
3
//
4
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5
//
6
//
7
8
#include "precomp.h"
9
10
//
11
// The following is an adaptation of algorithm 6: "Protected
12
// odd-only recoding algorithm for the fixed-window representation"
13
// from the paper
14
//      "Selecting Elliptic Curves for Cryptography: An Efficiency and
15
//       Security Analysis" by Bos, Costello, Longa, and Naehrig
16
//
17
// Input:   odd integer k \in [1,GOrd], window width w>=2, and
18
//          t = ceil( GOrdBitsize / w-1 )
19
//
20
// Output:  (k_t, ... , k_0) where k_i \in {+-1, +-3, ..., +-(2^(w-1) -1)}
21
//
22
// Algorithm:
23
//          for i=0 to (t-1) do
24
//              k_i = (k mod 2^w) - 2^(w-1)
25
//              k = (k-k_i)/2^(w-1)
26
//          k_t = k mod 2^(w-1)
27
//          return (k_t, ..., k_0)
28
//
29
// Remarks:
30
//          1. An invariant of the main loop is that (k > 0 and k odd). This means
31
//             that all k_i's are odd and that k_t > 0.
32
//          2. We will store the values of k_i's as absolute values and signs in
33
//             absofKIs and sigofKIs arrays, resp. The sigofKIs[i] is 0xffffffff if
34
//             k_i < 0, otherwise it is 0.
35
//          3. In the multiplication algorithm we always access the precomputed point
36
//             P[(|k_i|-1)/2]. Therefore here we just shift the |k_i| value left by
37
//             one bit before storing it in absofKIs table.
38
//          4. Caller should check k in range [1,GOrd] to ensure use of recoding will
39
//             give correct results. This algorithm always recodes the t * (w-1) least
40
//             significant bits of the provided k, interpreted as an unsigned integer.
41
//
42
VOID
43
SYMCRYPT_CALL
44
SymCryptFixedWindowRecoding(
45
            UINT32          W,
46
    _Inout_ PSYMCRYPT_INT   piK,
47
    _Inout_ PSYMCRYPT_INT   piTmp,
48
    _Out_writes_( nRecodedDigits )
49
            PUINT32         absofKIs,
50
    _Out_writes_( nRecodedDigits )
51
            PUINT32         sigofKIs,
52
            UINT32          nRecodedDigits )
53
795
{
54
795
    UINT32 T1 = 0;
55
795
    UINT32 T2 = 0;
56
795
    UINT32 mask = ~(0xffffffff << W);       // Window mask = 2^w - 1 (e.g. 0x0000003f for w = 6)
57
795
    UINT32 smask = 0x1 << (W-1);            // Sign mask   = 2^(w-1) (e.g. 0x00000020 for w = 6)
58
59
795
    SYMCRYPT_ASSERT( W < 32 );
60
61
60.5k
    for (UINT32 i=0; i < nRecodedDigits - 1; i++)
62
59.7k
    {
63
59.7k
        T1 = SymCryptIntGetValueLsbits32( piK ) & mask;         // T1 = k mod 2^W
64
65
        // At this point if the w-th bit of T1 is 1 then we know that T1 > 2^(w-1)
66
        // (Since k = odd is a loop invariant).
67
        //
68
        // In this case, (case A), T1 & ~smask is equal to (k mod 2^w) - 2^(w-1) = k_i = |k_i|.
69
        //
70
        // Otherwise, (case B), we know that T1 < 2^(w-1). Therefore 2^(w-1) - T1 = |k_i|.
71
72
59.7k
        sigofKIs[i] = SYMCRYPT_MASK32_ZERO( T1 & smask );       // If the sign of k_i is - this mask is set to 0xffffffff. (Case B)
73
74
59.7k
        T2 = T1 & ~smask;                                       // |k_i| in case A
75
59.7k
        T1 = smask - T1;                                        // |k_i| in case B
76
77
59.7k
        absofKIs[i] = ((T1 & sigofKIs[i]) | (T2 & ~sigofKIs[i])) >> 1; // Setting (masked) the absolute value of k_i in absofKIs (divided by 2)
78
79
59.7k
        SymCryptIntSubUint32( piK, T2, piTmp );                 // This gives k - k_i in case (A)
80
59.7k
        SymCryptIntAddUint32( piK, T1, piK );                   // This gives k - k_i in case (B)
81
82
59.7k
        SymCryptIntMaskedCopy( piTmp, piK, ~sigofKIs[i] );      // Copy the result to piK in case (B)
83
84
59.7k
        SymCryptIntDivPow2( piK, W-1, piK );                    // k := k / 2^(w-1)
85
59.7k
    }
86
87
    // The last sign is positive given k < GOrd => k_t < 2^w
88
795
    sigofKIs[nRecodedDigits - 1] = 0;
89
    // Belts and braces, select only the bottom w-1 bits (ensure all absofKIs represent odd values in range [1,2^(w-1)-1])
90
795
    absofKIs[nRecodedDigits - 1] = (SymCryptIntGetValueLsbits32( piK ) & mask & ~smask) >> 1;
91
795
}
92
93
//
94
// The following is an algorithm for computing the width-w NAF of a positive integer.
95
//
96
// Input:   integer k \in [1,GOrd), window width w>=2, and nRecodedDigits = GOrdBitsize + 1
97
//
98
// Output:  (k_(nRecodedDigits-1), ... , k_0) where k_i \in {0, +-1, +-3, ..., +-(2^(w-1) -1)}
99
//
100
// Algorithm:
101
//          for i = 0 to (nRecodedDigits-1)
102
//              if (k is odd)
103
//                  k_i = (k mods 2^w)
104
//                  k = k - k_i
105
//              else
106
//                  k_i = 0
107
//              k = k/2
108
//          return (k_(nRecodedDigits-1), ..., k_0)
109
//
110
// Note: k mods 2^w is the integer u with (u == k mod 2^w) and (-2^(w-1) <= u < 2^(w-1) ).
111
//
112
// Remarks:
113
//          1. The above algorithm and the implementation are NOT SIDE-CHANNEL SAFE.
114
//             Therefore, it should only be used when the SYMCRYPT_FLAG_DATA_PUBLIC is
115
//             specified.
116
//          2. The multiplication algorithm uses |k_i|/2 as indexes. Therefore we will shift left
117
//             the absolute value of k_i by 1 bit and store only |k_i|/2.
118
//          3. Since now the k_i's can be zero we will store the following in sigofKIs:
119
//                  sigofKIs[i] = 0x00000001    if k_i > 0
120
//                  sigofKIs[i] = 0x00000000    if k_i = 0
121
//                  sigofKIs[i] = 0xffffffff    if k_i < 0
122
//
123
VOID
124
SYMCRYPT_CALL
125
SymCryptWidthNafRecoding(
126
            UINT32          W,
127
    _Inout_ PSYMCRYPT_INT   piK,
128
    _Out_writes_( nRecodedDigits )
129
            PUINT32         absofKIs,
130
    _Out_writes_( nRecodedDigits )
131
            PUINT32         sigofKIs,
132
            UINT32          nRecodedDigits )
133
351
{
134
351
    UINT32 T1 = 0;
135
351
    UINT32 mask = ~(0xffffffff << W);       // Window mask = 2^w - 1 (e.g. 0x0000003f for w = 6)
136
351
    UINT32 modulus = mask + 1;              // 2^w
137
351
    UINT32 smask = 0x1 << (W-1);            // Sign mask   = 2^(w-1) (e.g. 0x00000020 for w = 6)
138
139
351
    SYMCRYPT_ASSERT( W < 32 );
140
141
142k
    for (UINT32 i=0; i < nRecodedDigits; i++)
142
142k
    {
143
142k
        T1 = SymCryptIntGetValueLsbits32( piK ) & mask;         // T1 = k mod 2^W
144
145
142k
        if (T1 & 0x1)
146
20.3k
        {
147
20.3k
            if (T1 > smask)
148
9.94k
            {
149
9.94k
                sigofKIs[i] = 0xffffffff;
150
9.94k
                absofKIs[i] = modulus - T1;                         // 2^W - T1 = |T1 - 2^W|
151
9.94k
                SymCryptIntAddUint32( piK, absofKIs[i], piK );      // k-k_i
152
9.94k
            }
153
10.3k
            else
154
10.3k
            {
155
                // Here (k mod 2^W) is already in the specified range
156
10.3k
                sigofKIs[i] = 0x00000001;
157
10.3k
                absofKIs[i] = T1;
158
10.3k
                SymCryptIntSubUint32( piK, absofKIs[i], piK );      // k-k_i
159
10.3k
            }
160
20.3k
        }
161
121k
        else
162
121k
        {
163
121k
            absofKIs[i] = 0;
164
121k
            sigofKIs[i] = 0;
165
121k
        }
166
167
142k
        SymCryptIntDivPow2( piK, 1, piK );                      // k := k / 2
168
142k
    }
169
351
}
170
171
//
172
// The following is an algorithm similar to the above
173
// but the output is only non-negative (odd) digits.
174
//
175
// Requirements:
176
//      nRecodedDigits == nBitsExp
177
//
178
VOID
179
SYMCRYPT_CALL
180
SymCryptPositiveWidthNafRecoding(
181
            UINT32          W,
182
    _In_    PCSYMCRYPT_INT  piK,
183
            UINT32          nBitsExp,
184
    _Out_writes_( nRecodedDigits )
185
            PUINT32         absofKIs,
186
            UINT32          nRecodedDigits )
187
0
{
188
0
    UINT32 T1 = 0;
189
0
    UINT32 cntrZ = W;       // Counter that specifies when we filled the last non-zero NAF digit
190
191
0
    SYMCRYPT_ASSERT( nRecodedDigits <= SymCryptIntBitsizeOfObject( piK ) );
192
193
0
    for (UINT32 i=0; i < nRecodedDigits; i++)
194
0
    {
195
0
        T1 = SymCryptIntGetBits( piK, i, SYMCRYPT_MIN(W, nBitsExp-i) );   // Get a batch of W bits (but don't go over nBitsExp)
196
197
0
        if ((cntrZ>=W) && ((T1 & 0x01) > 0))    // Only store odd digits
198
0
        {
199
0
            absofKIs[i] = T1;
200
0
            cntrZ = 0;
201
0
        }
202
0
        else
203
0
        {
204
0
            absofKIs[i] = 0;
205
0
        }
206
207
0
        cntrZ++;        // Prepare the counter for the next iteration
208
0
    }
209
0
}