11// Licensed to the .NET Foundation under one or more agreements.
22// The .NET Foundation licenses this file to you under the MIT license.
33
4+ using System . Buffers . Binary ;
5+ using System . Diagnostics ;
46using System . Numerics ;
57
68namespace System
@@ -17,20 +19,77 @@ internal struct Sha1ForNonSecretPurposes
1719 private uint [ ] _w ; // Workspace
1820 private int _pos ; // Length of current chunk in bytes
1921
22+ /// <summary>
23+ /// Computes the SHA1 hash of the provided data.
24+ /// </summary>
25+ /// <param name="source">The data to hash.</param>
26+ /// <param name="destination">The buffer to receive the hash value.</param>
27+ public static void HashData ( ReadOnlySpan < byte > source , Span < byte > destination )
28+ {
29+ Debug . Assert ( destination . Length == 20 ) ;
30+
31+ Span < uint > w = stackalloc uint [ 85 ] ;
32+
33+ Start ( w ) ;
34+
35+ int originalLength = source . Length ;
36+
37+ while ( source . Length >= 64 )
38+ {
39+ for ( int i = 0 ; i < 16 ; i ++ )
40+ {
41+ w [ i ] = BinaryPrimitives . ReadUInt32BigEndian ( source ) ;
42+ source = source . Slice ( 4 ) ;
43+ }
44+ Drain ( w ) ;
45+ }
46+
47+ Span < byte > tail = stackalloc byte [ 2 * 64 ] ;
48+ source . CopyTo ( tail ) ;
49+ int pos = source . Length ;
50+ tail [ pos ++ ] = 0x80 ;
51+ while ( ( pos & 63 ) != 56 )
52+ {
53+ tail [ pos ++ ] = 0x00 ;
54+ }
55+ BinaryPrimitives . WriteUInt64BigEndian ( tail . Slice ( pos ) , ( ulong ) originalLength * 8 ) ;
56+ tail = tail . Slice ( 0 , pos + 8 ) ;
57+
58+ while ( tail . Length > 0 )
59+ {
60+ for ( int i = 0 ; i < 16 ; i ++ )
61+ {
62+ w [ i ] = BinaryPrimitives . ReadUInt32BigEndian ( tail ) ;
63+ tail = tail . Slice ( 4 ) ;
64+ }
65+ Drain ( w ) ;
66+ }
67+
68+ for ( int i = 80 ; i < w . Length ; i ++ )
69+ {
70+ BinaryPrimitives . WriteUInt32BigEndian ( destination , w [ i ] ) ;
71+ destination = destination . Slice ( 4 ) ;
72+ }
73+ }
74+
2075 /// <summary>
2176 /// Call Start() to initialize the hash object.
2277 /// </summary>
2378 public void Start ( )
2479 {
25- _w ??= new uint [ 85 ] ;
80+ Start ( _w ??= new uint [ 85 ] ) ;
2681
2782 _length = 0 ;
2883 _pos = 0 ;
29- _w [ 80 ] = 0x67452301 ;
30- _w [ 81 ] = 0xEFCDAB89 ;
31- _w [ 82 ] = 0x98BADCFE ;
32- _w [ 83 ] = 0x10325476 ;
33- _w [ 84 ] = 0xC3D2E1F0 ;
84+ }
85+
86+ private static void Start ( Span < uint > w )
87+ {
88+ w [ 80 ] = 0x67452301 ;
89+ w [ 81 ] = 0xEFCDAB89 ;
90+ w [ 82 ] = 0x98BADCFE ;
91+ w [ 83 ] = 0x10325476 ;
92+ w [ 84 ] = 0xC3D2E1F0 ;
3493 }
3594
3695 /// <summary>
@@ -77,6 +136,8 @@ public void Append(ReadOnlySpan<byte> input)
77136 /// </param>
78137 public void Finish ( Span < byte > output )
79138 {
139+ Debug . Assert ( output . Length == 20 ) ;
140+
80141 long l = _length + 8 * _pos ;
81142 Append ( 0x80 ) ;
82143 while ( _pos != 56 )
@@ -93,12 +154,10 @@ public void Finish(Span<byte> output)
93154 Append ( ( byte ) ( l >> 8 ) ) ;
94155 Append ( ( byte ) l ) ;
95156
96- int end = output . Length < 20 ? output . Length : 20 ;
97- for ( int i = 0 ; i != end ; i ++ )
157+ for ( int i = 80 ; i < _w . Length ; i ++ )
98158 {
99- uint temp = _w [ 80 + i / 4 ] ;
100- output [ i ] = ( byte ) ( temp >> 24 ) ;
101- _w [ 80 + i / 4 ] = temp << 8 ;
159+ BinaryPrimitives . WriteUInt32BigEndian ( output , _w [ i ] ) ;
160+ output = output . Slice ( 4 ) ;
102161 }
103162 }
104163
@@ -107,53 +166,59 @@ public void Finish(Span<byte> output)
107166 /// </summary>
108167 private void Drain ( )
109168 {
110- for ( int i = 16 ; i != 80 ; i ++ )
169+ Drain ( _w ) ;
170+ _length += 512 ; // 64 bytes == 512 bits
171+ _pos = 0 ;
172+ }
173+
174+ private static void Drain ( Span < uint > w )
175+ {
176+ var _ = w [ 84 ] ; // Hint to eliminate bounds checks
177+
178+ for ( int i = 16 ; i < 80 ; i ++ )
111179 {
112- _w [ i ] = BitOperations . RotateLeft ( _w [ i - 3 ] ^ _w [ i - 8 ] ^ _w [ i - 14 ] ^ _w [ i - 16 ] , 1 ) ;
180+ w [ i ] = BitOperations . RotateLeft ( w [ i - 3 ] ^ w [ i - 8 ] ^ w [ i - 14 ] ^ w [ i - 16 ] , 1 ) ;
113181 }
114182
115- uint a = _w [ 80 ] ;
116- uint b = _w [ 81 ] ;
117- uint c = _w [ 82 ] ;
118- uint d = _w [ 83 ] ;
119- uint e = _w [ 84 ] ;
183+ uint a = w [ 80 ] ;
184+ uint b = w [ 81 ] ;
185+ uint c = w [ 82 ] ;
186+ uint d = w [ 83 ] ;
187+ uint e = w [ 84 ] ;
120188
121- for ( int i = 0 ; i != 20 ; i ++ )
189+ for ( int i = 0 ; i < 20 ; i ++ )
122190 {
123191 const uint k = 0x5A827999 ;
124192 uint f = ( b & c ) | ( ( ~ b ) & d ) ;
125- uint temp = BitOperations . RotateLeft ( a , 5 ) + f + e + k + _w [ i ] ; e = d ; d = c ; c = BitOperations . RotateLeft ( b , 30 ) ; b = a ; a = temp ;
193+ uint temp = BitOperations . RotateLeft ( a , 5 ) + f + e + k + w [ i ] ; e = d ; d = c ; c = BitOperations . RotateLeft ( b , 30 ) ; b = a ; a = temp ;
126194 }
127195
128- for ( int i = 20 ; i != 40 ; i ++ )
196+ for ( int i = 20 ; i < 40 ; i ++ )
129197 {
130198 uint f = b ^ c ^ d ;
131199 const uint k = 0x6ED9EBA1 ;
132- uint temp = BitOperations . RotateLeft ( a , 5 ) + f + e + k + _w [ i ] ; e = d ; d = c ; c = BitOperations . RotateLeft ( b , 30 ) ; b = a ; a = temp ;
200+ uint temp = BitOperations . RotateLeft ( a , 5 ) + f + e + k + w [ i ] ; e = d ; d = c ; c = BitOperations . RotateLeft ( b , 30 ) ; b = a ; a = temp ;
133201 }
134202
135- for ( int i = 40 ; i != 60 ; i ++ )
203+ for ( int i = 40 ; i < 60 ; i ++ )
136204 {
137205 uint f = ( b & c ) | ( b & d ) | ( c & d ) ;
138206 const uint k = 0x8F1BBCDC ;
139- uint temp = BitOperations . RotateLeft ( a , 5 ) + f + e + k + _w [ i ] ; e = d ; d = c ; c = BitOperations . RotateLeft ( b , 30 ) ; b = a ; a = temp ;
207+ uint temp = BitOperations . RotateLeft ( a , 5 ) + f + e + k + w [ i ] ; e = d ; d = c ; c = BitOperations . RotateLeft ( b , 30 ) ; b = a ; a = temp ;
140208 }
141209
142- for ( int i = 60 ; i != 80 ; i ++ )
210+ for ( int i = 60 ; i < 80 ; i ++ )
143211 {
144212 uint f = b ^ c ^ d ;
145213 const uint k = 0xCA62C1D6 ;
146- uint temp = BitOperations . RotateLeft ( a , 5 ) + f + e + k + _w [ i ] ; e = d ; d = c ; c = BitOperations . RotateLeft ( b , 30 ) ; b = a ; a = temp ;
214+ uint temp = BitOperations . RotateLeft ( a , 5 ) + f + e + k + w [ i ] ; e = d ; d = c ; c = BitOperations . RotateLeft ( b , 30 ) ; b = a ; a = temp ;
147215 }
148216
149- _w [ 80 ] += a ;
150- _w [ 81 ] += b ;
151- _w [ 82 ] += c ;
152- _w [ 83 ] += d ;
153- _w [ 84 ] += e ;
154-
155- _length += 512 ; // 64 bytes == 512 bits
156- _pos = 0 ;
217+ w [ 80 ] += a ;
218+ w [ 81 ] += b ;
219+ w [ 82 ] += c ;
220+ w [ 83 ] += d ;
221+ w [ 84 ] += e ;
157222 }
158223 }
159224}
0 commit comments