Adding running tests on Alpine for coreclr build (#17038)
[platform/upstream/coreclr.git] / src / vm / marvin32.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 //
6 // This module contains the routines to implement the Marvin32 checksum function
7 //
8 //
9
10 #include "common.h"
11 #include "marvin32.h"
12
13 //
14 // See the symcrypt.h file for documentation on what the various functions do.
15 //
16
17 //
18 // Round rotation amounts. This array is optimized away by the compiler
19 // as we inline all our rotations.
20 //
21 static const int rotate[4] = {
22     20, 9, 27, 19, 
23 };
24
25
26 #define ROL32( x, n ) _rotl( (x), (n) )
27 #define ROR32( x, n ) _rotr( (x), (n) )
28
29 #define BLOCK( a, b ) \
30 {\
31     b ^= a; a = ROL32( a, rotate[0] );\
32     a += b; b = ROL32( b, rotate[1] );\
33     b ^= a; a = ROL32( a, rotate[2] );\
34     a += b; b = ROL32( b, rotate[3] );\
35 }
36
37
38
39 HRESULT
40 SymCryptMarvin32ExpandSeed(   
41     __out               PSYMCRYPT_MARVIN32_EXPANDED_SEED    pExpandedSeed,
42     __in_ecount(cbSeed) PCBYTE                              pbSeed,
43                         SIZE_T                              cbSeed )
44 {
45     HRESULT retVal = S_OK;
46
47     if( cbSeed != SYMCRYPT_MARVIN32_SEED_SIZE )
48     {
49         retVal =E_INVALIDARG;
50         goto cleanup;
51     }
52     pExpandedSeed->s[0] = LOAD_LSBFIRST32( pbSeed );
53     pExpandedSeed->s[1] = LOAD_LSBFIRST32( pbSeed + 4 );
54
55 cleanup:
56     return retVal;
57 }
58
59
60 VOID
61 SymCryptMarvin32Init(   _Out_   PSYMCRYPT_MARVIN32_STATE            pState,
62                         _In_    PCSYMCRYPT_MARVIN32_EXPANDED_SEED   pExpandedSeed)
63 {
64     pState->chain = *pExpandedSeed;
65     pState->dataLength = 0;
66     pState->pSeed = pExpandedSeed;
67
68     *(ULONG *) &pState->buffer[4] = 0; // wipe the last 4 bytes of the buffer.
69 }
70
71 VOID
72 SymCryptMarvin32AppendBlocks(
73     _Inout_                 PSYMCRYPT_MARVIN32_CHAINING_STATE   pChain,
74     _In_reads_( cbData )    PCBYTE                              pbData,
75                             SIZE_T                              cbData )
76 {
77     ULONG s0 = pChain->s[0];
78     ULONG s1 = pChain->s[1];
79
80     SIZE_T bytesInFirstBlock = cbData & 0xc;        // 0, 4, 8, or 12
81
82     pbData += bytesInFirstBlock;
83     cbData -= bytesInFirstBlock;
84
85     switch( bytesInFirstBlock )
86     {
87     case 0: // This handles the cbData == 0 case too
88         while( cbData > 0 )
89         {
90             pbData += 16;
91             cbData -= 16;
92
93             s0 += LOAD_LSBFIRST32( pbData - 16 );
94             BLOCK( s0, s1 );
95     case 12:
96             s0 += LOAD_LSBFIRST32( pbData - 12 );
97             BLOCK( s0, s1 );
98     case 8:
99             s0 += LOAD_LSBFIRST32( pbData -  8 );
100             BLOCK( s0, s1 );
101     case 4:
102             s0 += LOAD_LSBFIRST32( pbData -  4 );
103             BLOCK( s0, s1 );
104         }
105     }
106
107     pChain->s[0] = s0;
108     pChain->s[1] = s1;
109 }
110
111 VOID
112 SymCryptMarvin32Append(_Inout_                    SYMCRYPT_MARVIN32_STATE * state,
113 _In_reads_bytes_(cbData) PCBYTE                    pbData,
114 SIZE_T               cbData)
115 {
116     ULONG bytesInBuffer = state->dataLength;
117
118     state->dataLength += (ULONG)cbData;    // We only keep track of the last 2 bits...
119
120     //
121     // Truncate bytesInBuffer so that we never have an integer overflow.
122     //
123     bytesInBuffer &= SYMCRYPT_MARVIN32_INPUT_BLOCK_SIZE - 1;
124
125     //
126     // If previous data in buffer, buffer new input and transform if possible.
127     //
128     if (bytesInBuffer > 0)
129     {
130         SIZE_T freeInBuffer = SYMCRYPT_MARVIN32_INPUT_BLOCK_SIZE - bytesInBuffer;
131         if (cbData < freeInBuffer)
132         {
133             //
134             // All the data will fit in the buffer.
135             // We don't do anything here. 
136             // As cbData < INPUT_BLOCK_SIZE the bulk data processing is skipped,
137             // and the data will be copied to the buffer at the end
138             // of this code.
139         }
140         else {
141             //
142             // Enough data to fill the whole buffer & process it
143             //
144             memcpy(&state->buffer[bytesInBuffer], pbData, freeInBuffer);
145             pbData += freeInBuffer;
146             cbData -= freeInBuffer;
147             SymCryptMarvin32AppendBlocks(&state->chain, state->buffer, SYMCRYPT_MARVIN32_INPUT_BLOCK_SIZE);
148
149             //
150             // Set bytesInBuffer to zero to ensure that the trailing data in the
151             // buffer will be copied to the right location of the buffer below.
152             //
153             bytesInBuffer = 0;
154         }
155     }
156
157     //
158     // Internal buffer is empty; process all remaining whole blocks in the input
159     //
160     if (cbData >= SYMCRYPT_MARVIN32_INPUT_BLOCK_SIZE)
161     {
162         SIZE_T cbDataRoundedDown = cbData & ~(SIZE_T)(SYMCRYPT_MARVIN32_INPUT_BLOCK_SIZE - 1);
163         SymCryptMarvin32AppendBlocks(&state->chain, pbData, cbDataRoundedDown);
164         pbData += cbDataRoundedDown;
165         cbData -= cbDataRoundedDown;
166     }
167
168     //
169     // buffer remaining input if necessary.
170     //
171     if (cbData > 0)
172     {
173         memcpy(&state->buffer[bytesInBuffer], pbData, cbData);
174     }
175
176 }
177
178 VOID
179 SymCryptMarvin32Result( 
180      _Inout_                                        PSYMCRYPT_MARVIN32_STATE    pState,
181      _Out_writes_( SYMCRYPT_MARVIN32_RESULT_SIZE )  PBYTE                       pbResult )
182 {
183     SIZE_T bytesInBuffer = ( pState->dataLength) & 0x3;
184
185     //
186     // Wipe four bytes in the buffer.
187     // Doing this first ensures that this write is aligned when the input was of
188     // length 0 mod 4. 
189     // The buffer is 8 bytes long, so we never overwrite anything else.
190     //
191     *(ULONG *) &pState->buffer[bytesInBuffer] = 0;
192
193     //
194     // The buffer is never completely full, so we can always put the first
195     // padding byte in.
196     //
197     pState->buffer[bytesInBuffer++] = 0x80;
198
199     //
200     // Process the final block
201     //
202     SymCryptMarvin32AppendBlocks( &pState->chain, pState->buffer, 8 );
203
204     STORE_LSBFIRST32( pbResult    , pState->chain.s[0] );
205     STORE_LSBFIRST32( pbResult + 4, pState->chain.s[1] );
206
207     //
208     // Wipe only those things that we need to wipe.
209     //
210
211     *(ULONG *) &pState->buffer[0] = 0;
212     pState->dataLength = 0;
213
214     pState->chain = *pState->pSeed;
215 }
216
217
218 VOID
219 SymCryptMarvin32( 
220   __in                                           PCSYMCRYPT_MARVIN32_EXPANDED_SEED   pExpandedSeed,
221   __in_ecount(cbData)                            PCBYTE                              pbData,
222                                                  SIZE_T                              cbData,
223   __out_ecount(SYMCRYPT_MARVIN32_RESULT_SIZE)    PBYTE                               pbResult)
224 //
225 // To reduce the per-computation overhead, we have a dedicated code here instead of the whole Init/Append/Result stuff.
226 //
227 {
228     ULONG tmp;
229
230     ULONG s0 = pExpandedSeed->s[0];
231     ULONG s1 = pExpandedSeed->s[1];
232     
233     while( cbData > 7 )
234     {
235         s0 += LOAD_LSBFIRST32( pbData );
236         BLOCK( s0, s1 );
237         s0 += LOAD_LSBFIRST32( pbData + 4 );
238         BLOCK( s0, s1 );
239         pbData += 8;
240         cbData -= 8;
241     }
242
243     switch( cbData )
244     {
245     default:
246     case 4: s0 += LOAD_LSBFIRST32( pbData ); BLOCK( s0, s1 ); pbData += 4;
247     case 0: tmp = 0x80; break;
248
249     case 5: s0 += LOAD_LSBFIRST32( pbData ); BLOCK( s0, s1 ); pbData += 4;
250     case 1: tmp = 0x8000 | pbData[0]; break;
251
252     case 6: s0 += LOAD_LSBFIRST32( pbData ); BLOCK( s0, s1 ); pbData += 4;
253     case 2: tmp = 0x800000 | LOAD_LSBFIRST16( pbData ); break;
254
255     case 7: s0 += LOAD_LSBFIRST32( pbData ); BLOCK( s0, s1 ); pbData += 4;
256     case 3: tmp = LOAD_LSBFIRST16( pbData ) | (pbData[2] << 16) | 0x80000000; break;
257     }
258     s0 += tmp;
259
260
261     BLOCK( s0, s1 );
262     BLOCK( s0, s1 );
263
264     STORE_LSBFIRST32( pbResult    , s0 );
265     STORE_LSBFIRST32( pbResult + 4, s1 );
266 }