Coverage Report

Created: 2024-11-21 07:03

/src/SymCrypt/lib/crt.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// crt.c   Chinese Remainder Theorem Algorithms
3
//
4
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5
//
6
7
#include "precomp.h"
8
9
SYMCRYPT_ERROR
10
SYMCRYPT_CALL
11
SymCryptCrtGenerateForTwoCoprimes(
12
    _In_    PCSYMCRYPT_MODULUS   pmP,
13
    _In_    PCSYMCRYPT_MODULUS   pmQ,
14
            UINT32               flags,
15
    _Out_   PSYMCRYPT_MODELEMENT peInvQModP,
16
    _Out_   PSYMCRYPT_MODELEMENT peInvPModQ,
17
    _Out_writes_bytes_( cbScratch )
18
            PBYTE               pbScratch,
19
            SIZE_T              cbScratch )
20
0
{
21
0
    SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
22
23
0
    PCSYMCRYPT_INT  piSrc1 = NULL;
24
0
    PCSYMCRYPT_INT  piSrc2 = NULL;
25
26
0
    PSYMCRYPT_INT   piInvSrc1ModSrc2 = NULL;
27
0
    PSYMCRYPT_INT   piInvSrc2ModSrc1 = NULL;
28
29
0
    UINT32 nDigits = 0;
30
0
    UINT32 cbInt = 0;
31
32
0
    BOOLEAN oddP = FALSE;
33
34
0
    SYMCRYPT_ASSERT( pmP != NULL );
35
0
    SYMCRYPT_ASSERT( pmQ != NULL );
36
37
0
    nDigits = SYMCRYPT_MAX( SymCryptModulusDigitsizeOfObject( pmP ), SymCryptModulusDigitsizeOfObject( pmQ ));
38
39
    // Create two temporary integers
40
0
    cbInt = SymCryptSizeofIntFromDigits( nDigits );
41
42
0
    SYMCRYPT_ASSERT( cbScratch >= 2*cbInt + SYMCRYPT_SCRATCH_BYTES_FOR_EXTENDED_GCD( nDigits ));
43
44
0
    piInvSrc1ModSrc2 = SymCryptIntCreate( pbScratch, cbInt, nDigits ); pbScratch += cbInt; cbScratch -= cbInt;
45
0
    piInvSrc2ModSrc1 = SymCryptIntCreate( pbScratch, cbInt, nDigits ); pbScratch += cbInt; cbScratch -= cbInt;
46
47
0
    oddP = ((SymCryptIntGetValueLsbits32(SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmP )) & 1) == 1);
48
0
    if (oddP)
49
0
    {
50
0
        piSrc1 = SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmQ );
51
0
        piSrc2 = SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmP );
52
0
    }
53
0
    else
54
0
    {
55
0
        piSrc1 = SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmP );
56
0
        piSrc2 = SymCryptIntFromModulus( (PSYMCRYPT_MODULUS) pmQ );
57
0
    }
58
59
    // IntExtendedGcd requirements:
60
    //      - First argument > 0
61
    //      - Second argument odd
62
0
    if( SymCryptIntIsEqualUint32(piSrc1, 0) ||
63
0
        ((SymCryptIntGetValueLsbits32(piSrc2) & 1) != 1) )
64
0
    {
65
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
66
0
        goto cleanup;
67
0
    }
68
69
    // Extended GCD
70
0
    SymCryptIntExtendedGcd( piSrc1, piSrc2, flags, NULL, NULL, piInvSrc1ModSrc2, piInvSrc2ModSrc1, pbScratch, cbScratch );
71
72
0
    if (oddP)
73
0
    {
74
0
        SymCryptIntToModElement( piInvSrc2ModSrc1, pmQ, peInvPModQ, pbScratch, cbScratch );
75
0
        SymCryptIntToModElement( piInvSrc1ModSrc2, pmP, peInvQModP, pbScratch, cbScratch );
76
0
    }
77
0
    else
78
0
    {
79
0
        SymCryptIntToModElement( piInvSrc2ModSrc1, pmP, peInvQModP, pbScratch, cbScratch );
80
0
        SymCryptIntToModElement( piInvSrc1ModSrc2, pmQ, peInvPModQ, pbScratch, cbScratch );
81
0
    }
82
83
0
cleanup:
84
0
    return scError;
85
0
}
86
87
88
SYMCRYPT_ERROR
89
SYMCRYPT_CALL
90
SymCryptCrtGenerateInverses(
91
                                    UINT32                  nCoprimes,
92
    _In_reads_( nCoprimes )         PCSYMCRYPT_MODULUS *    ppmCoprimes,
93
                                    UINT32                  flags,
94
    _Out_writes_( nCoprimes )       PSYMCRYPT_MODELEMENT *  ppeCrtInverses,
95
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
96
                                    SIZE_T                  cbScratch )
97
0
{
98
0
    SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
99
100
0
    if (nCoprimes == 2)
101
0
    {
102
0
        SymCryptCrtGenerateForTwoCoprimes(
103
0
                ppmCoprimes[0],
104
0
                ppmCoprimes[1],
105
0
                flags,
106
0
                ppeCrtInverses[0],
107
0
                ppeCrtInverses[1],
108
0
                pbScratch,
109
0
                cbScratch );
110
0
    }
111
0
    else
112
0
    {
113
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
114
0
        goto cleanup;
115
0
    }
116
117
0
cleanup:
118
0
    return scError;
119
0
}
120
121
SYMCRYPT_ERROR
122
SYMCRYPT_CALL
123
SymCryptCrtSolve(
124
                                    UINT32                  nCoprimes,
125
    _In_reads_( nCoprimes )         PCSYMCRYPT_MODULUS *    ppmCoprimes,
126
    _In_reads_( nCoprimes )         PCSYMCRYPT_MODELEMENT * ppeCrtInverses,
127
    _In_reads_( nCoprimes )         PCSYMCRYPT_MODELEMENT * ppeCrtRemainders,
128
                                    UINT32                  flags,
129
    _Out_                           PSYMCRYPT_INT           piSolution,
130
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
131
                                    SIZE_T                  cbScratch )
132
0
{
133
0
    SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
134
135
0
    SYMCRYPT_ASSERT( nCoprimes >= 2 );
136
137
0
    PSYMCRYPT_INT  piTmp = NULL;
138
0
    PSYMCRYPT_MODELEMENT peTmp = NULL;
139
140
0
    PSYMCRYPT_INT  piDouble = NULL;
141
142
0
    UINT32 nDigitsMax = 0;
143
144
0
    UINT32 cbInt = 0;
145
0
    UINT32 cbModElement = 0;
146
0
    UINT32 cbDouble = 0;
147
148
0
    UINT32 carry = 0;
149
150
0
    UNREFERENCED_PARAMETER( flags );
151
152
0
    nDigitsMax = SYMCRYPT_MAX( SymCryptModulusDigitsizeOfObject( ppmCoprimes[0] ), SymCryptModulusDigitsizeOfObject( ppmCoprimes[1] ) );
153
154
0
    cbInt = SymCryptSizeofIntFromDigits( nDigitsMax );
155
0
    cbModElement = SymCryptSizeofModElementFromModulus( ppmCoprimes[0] );
156
0
    cbDouble = SymCryptSizeofIntFromDigits( 2*nDigitsMax );
157
158
0
    if( cbDouble == 0 )
159
0
    {
160
        // It is possible that cbDouble would not fit within the maximum integer
161
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
162
0
        goto cleanup;
163
0
    }
164
165
0
    SYMCRYPT_ASSERT( cbScratch >= cbInt + cbModElement + cbDouble +
166
0
                                  SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigitsMax ),
167
0
                                       SYMCRYPT_SCRATCH_BYTES_FOR_INT_MUL( 2*nDigitsMax ) )
168
0
                    );
169
170
    // Create temporaries
171
0
    piTmp = SymCryptIntCreate( pbScratch, cbInt, nDigitsMax ); pbScratch += cbInt; cbScratch -= cbInt;
172
173
0
    peTmp = SymCryptModElementCreate( pbScratch, cbModElement, ppmCoprimes[0] ); pbScratch += cbModElement; cbScratch -= cbModElement;
174
175
0
    piDouble = SymCryptIntCreate( pbScratch, cbDouble, 2*nDigitsMax ); pbScratch += cbDouble; cbScratch -= cbDouble;
176
177
0
    if (nCoprimes == 2)
178
0
    {
179
        //
180
        // Let r0 and r1 be the two remainders modulo p and q respectively
181
        // Then we calculate (q^{-1}(r0 - r1) mod p)*q + r1
182
        //
183
0
        SymCryptModElementToInt( ppmCoprimes[1], ppeCrtRemainders[1], piTmp, pbScratch, cbScratch );               // Convert r1 to Int
184
0
        SymCryptIntToModElement( piTmp, ppmCoprimes[0], peTmp, pbScratch, cbScratch );                             // Convert it to r1 mod p
185
186
0
        SymCryptModSub( ppmCoprimes[0], ppeCrtRemainders[0], peTmp, peTmp, pbScratch, cbScratch );                 // (r0 - r1) mod p
187
0
        SymCryptModMul( ppmCoprimes[0], ppeCrtInverses[0], peTmp, peTmp, pbScratch, cbScratch );                   // q^{-1}*(r0 - r1) mod p
188
0
        SymCryptModElementToInt( ppmCoprimes[0], peTmp, piTmp, pbScratch, cbScratch );                             // Convert it to integer
189
190
0
        SymCryptIntMulMixedSize( piTmp, SymCryptIntFromModulus((PSYMCRYPT_MODULUS)ppmCoprimes[1]), piDouble, pbScratch, cbScratch );    // Multiply by q
191
0
        scError = SymCryptIntCopyMixedSize( piDouble, piSolution );                                                 // Copy it into the solution
192
0
        if (scError != SYMCRYPT_NO_ERROR)
193
0
        {
194
0
            goto cleanup;
195
0
        }
196
197
0
        SymCryptModElementToInt( ppmCoprimes[1], ppeCrtRemainders[1], piTmp, pbScratch, cbScratch );                // Convert r1 to integer
198
199
0
        carry = SymCryptIntAddMixedSize( piTmp, piSolution, piSolution );                                           // Add it to the solution
200
201
0
        if (carry>0)
202
0
        {
203
0
            scError = SYMCRYPT_INVALID_ARGUMENT;
204
0
            goto cleanup;
205
0
        }
206
0
    }
207
0
    else
208
0
    {
209
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
210
0
        goto cleanup;
211
0
    }
212
213
0
cleanup:
214
0
    return scError;
215
0
}