55
66using System ;
77using System . Diagnostics ;
8- using System . Runtime . Serialization ;
9- using System . Security . Cryptography ;
108
119namespace SimpleBase ;
1210
@@ -29,9 +27,7 @@ public sealed class Base58(Base58Alphabet alphabet) : DividingCoder<Base58Alphab
2927 const int reductionFactor = 733 ;
3028
3129 const int maxCheckPayloadLength = 256 ;
32- const int minCheckDecodedBufferSize = 5 ;
33- const int sha256Bytes = 32 ;
34- const int sha256DigestBytes = 4 ;
30+
3531 static readonly Lazy < Base58 > bitcoin = new ( ( ) => new Base58 ( Base58Alphabet . Bitcoin ) ) ;
3632 static readonly Lazy < Base58 > ripple = new ( ( ) => new Base58 ( Base58Alphabet . Ripple ) ) ;
3733 static readonly Lazy < Base58 > flickr = new ( ( ) => new Base58 ( Base58Alphabet . Flickr ) ) ;
@@ -102,20 +98,20 @@ public string EncodeCheck(ReadOnlySpan<byte> payload, byte version)
10298 public string EncodeCheck ( ReadOnlySpan < byte > payload , ReadOnlySpan < byte > prefix )
10399 {
104100 int totalLength = prefix . Length + payload . Length ;
105- int outputLen = totalLength + sha256DigestBytes ;
101+ int outputLen = totalLength + Sha256 . DigestBytes ;
106102 Span < byte > output = ( outputLen < Bits . SafeStackMaxAllocSize ) ? stackalloc byte [ outputLen ] : new byte [ outputLen ] ;
107103 prefix . CopyTo ( output ) ;
108104 payload . CopyTo ( output [ prefix . Length ..] ) ;
109- Span < byte > sha256 = stackalloc byte [ sha256Bytes ] ;
110- computeDoubleSha256 ( output [ ..totalLength ] , sha256 ) ;
111- sha256 [ ..sha256DigestBytes ] . CopyTo ( output [ totalLength ..] ) ;
105+ Span < byte > sha256 = stackalloc byte [ Sha256 . Bytes ] ;
106+ Sha256 . ComputeTwice ( output [ ..totalLength ] , sha256 ) ;
107+ sha256 [ ..Sha256 . DigestBytes ] . CopyTo ( output [ totalLength ..] ) ;
112108 return Encode ( output ) ;
113109 }
114110
115111 /// <summary>
116112 /// Generate a Base58Check string out of a prefix buffer and payload
117113 /// by skipping leading zeroes in <paramref name="payload"/>.
118- /// Platforms like Tezos expects this behavior.
114+ /// Platforms like Tezos expect this behavior.
119115 /// </summary>
120116 /// <param name="payload">Address data.</param>
121117 /// <param name="prefix">Prefix buffer.</param>
@@ -145,8 +141,11 @@ public string EncodeCheckSkipZeroes(ReadOnlySpan<byte> payload, ReadOnlySpan<byt
145141 /// <param name="address">Address string.</param>
146142 /// <param name="payload">Output address buffer.</param>
147143 /// <param name="version">Address version.</param>
148- /// <param name="bytesWritten">Number of bytes written in the output payload.</param>
149- /// <returns>True if address was decoded successfully and passed validation. False, otherwise.</returns>
144+ /// <param name="bytesWritten">Number of bytes written to <paramref name="payload"/>.</param>
145+ /// <returns>
146+ /// <see langword="true"/> if address was decoded successfully and passed validation.
147+ /// <see langword="false"/> otherwise.
148+ /// </returns>
150149 public bool TryDecodeCheck (
151150 ReadOnlySpan < char > address ,
152151 Span < byte > payload ,
@@ -166,31 +165,30 @@ public bool TryDecodeCheck(
166165 /// <param name="payload">Output address buffer.</param>
167166 /// <param name="prefix">Prefix decoded, must have the exact size of the expected prefix.</param>
168167 /// <param name="payloadBytesWritten">Number of bytes written in the output payload.</param>
169- /// <returns>True if address was decoded successfully and passed validation. False, otherwise.</returns>
168+ /// <returns><see langword="true"/> if address was decoded successfully and passed validation, <see langword="false"/> otherwise.</returns>
170169 public bool TryDecodeCheck (
171170 ReadOnlySpan < char > address ,
172171 Span < byte > payload ,
173172 Span < byte > prefix ,
174173 out int payloadBytesWritten )
175174 {
176- Span < byte > buffer = stackalloc byte [ maxCheckPayloadLength + sha256DigestBytes + 1 ] ;
177- if ( ! TryDecode ( address , buffer , out int decodedBufferSize ) || decodedBufferSize < minCheckDecodedBufferSize )
175+ payloadBytesWritten = 0 ;
176+ Span < byte > buffer = stackalloc byte [ maxCheckPayloadLength + Sha256 . DigestBytes + 1 ] ;
177+ if ( ! TryDecode ( address , buffer , out int decodedBufferSize ) )
178178 {
179- payloadBytesWritten = 0 ;
180179 return false ;
181180 }
182181
183182 buffer = buffer [ ..decodedBufferSize ] ;
184183 buffer [ ..prefix . Length ] . CopyTo ( prefix ) ;
185- Span < byte > sha256 = stackalloc byte [ sha256Bytes ] ;
186- computeDoubleSha256 ( buffer [ ..^ sha256DigestBytes ] , sha256 ) ;
187- if ( ! sha256 [ ..sha256DigestBytes ] . SequenceEqual ( buffer [ ^ sha256DigestBytes ..] ) )
184+ Span < byte > sha256 = stackalloc byte [ Sha256 . Bytes ] ;
185+ Sha256 . ComputeTwice ( buffer [ ..^ Sha256 . DigestBytes ] , sha256 ) ;
186+ if ( ! sha256 [ ..Sha256 . DigestBytes ] . SequenceEqual ( buffer [ ^ Sha256 . DigestBytes ..] ) )
188187 {
189- payloadBytesWritten = 0 ;
190188 return false ;
191189 }
192190
193- var finalBuffer = buffer [ prefix . Length ..^ sha256DigestBytes ] ;
191+ var finalBuffer = buffer [ prefix . Length ..^ Sha256 . DigestBytes ] ;
194192 finalBuffer . CopyTo ( payload ) ;
195193 payloadBytesWritten = finalBuffer . Length ;
196194 return true ;
@@ -208,13 +206,13 @@ public string EncodeCb58(ReadOnlySpan<byte> payload)
208206 throw new ArgumentException ( $ "Payload length { payload . Length } is greater than { maxCheckPayloadLength } ", nameof ( payload ) ) ;
209207 }
210208
211- int outputLen = payload . Length + sha256DigestBytes ;
209+ int outputLen = payload . Length + Sha256 . DigestBytes ;
212210 Span < byte > output = ( outputLen < Bits . SafeStackMaxAllocSize ) ? stackalloc byte [ outputLen ] : new byte [ outputLen ] ;
213211 payload . CopyTo ( output ) ;
214- Span < byte > sha256 = stackalloc byte [ sha256Bytes ] ;
215- computeSha256 ( output [ ..payload . Length ] , sha256 ) ;
212+ Span < byte > sha256 = stackalloc byte [ Sha256 . Bytes ] ;
213+ Sha256 . Compute ( output [ ..payload . Length ] , sha256 ) ;
216214
217- sha256 [ ^ sha256DigestBytes ..] . CopyTo ( output [ payload . Length ..] ) ;
215+ sha256 [ ^ Sha256 . DigestBytes ..] . CopyTo ( output [ payload . Length ..] ) ;
218216 return Encode ( output ) ;
219217 }
220218
@@ -223,51 +221,32 @@ public string EncodeCb58(ReadOnlySpan<byte> payload)
223221 /// </summary>
224222 /// <param name="address">Address string.</param>
225223 /// <param name="payload">Output address buffer.</param>
226- /// <param name="bytesWritten">Number of bytes written in the output payload.</param>
227- /// <returns>True if address was decoded successfully and passed validation. False, otherwise.</returns>
224+ /// <param name="bytesWritten">Number of bytes written to <paramref name=" payload"/> .</param>
225+ /// <returns><see langword="true"/> if address was decoded successfully and passed validation. <see langword="false"/> otherwise.</returns>
228226 public bool TryDecodeCb58 (
229227 ReadOnlySpan < char > address ,
230228 Span < byte > payload ,
231229 out int bytesWritten )
232230 {
233- Span < byte > buffer = stackalloc byte [ maxCheckPayloadLength + sha256DigestBytes ] ;
231+ Span < byte > buffer = stackalloc byte [ maxCheckPayloadLength + Sha256 . DigestBytes ] ;
234232 if ( ! TryDecode ( address , buffer , out bytesWritten ) || bytesWritten < 4 )
235233 {
236234 return false ;
237235 }
238236
239237 buffer = buffer [ ..bytesWritten ] ;
240- Span < byte > sha256 = stackalloc byte [ sha256Bytes ] ;
241- computeSha256 ( buffer [ ..^ sha256DigestBytes ] , sha256 ) ;
238+ Span < byte > sha256 = stackalloc byte [ Sha256 . Bytes ] ;
239+ Sha256 . Compute ( buffer [ ..^ Sha256 . DigestBytes ] , sha256 ) ;
242240
243- if ( ! sha256 [ ^ sha256DigestBytes .. ] . SequenceEqual ( buffer [ ^ sha256DigestBytes ..] ) )
241+ if ( ! sha256 [ ^ Sha256 . DigestBytes .. ] . SequenceEqual ( buffer [ ^ Sha256 . DigestBytes ..] ) )
244242 {
245243 return false ;
246244 }
247245
248- var finalBuffer = buffer [ ..^ sha256DigestBytes ] ;
246+ var finalBuffer = buffer [ ..^ Sha256 . DigestBytes ] ;
249247 finalBuffer . CopyTo ( payload ) ;
250248 bytesWritten = finalBuffer . Length ;
251249 return true ;
252250 }
253251
254- static void computeDoubleSha256 ( ReadOnlySpan < byte > buffer , Span < byte > output )
255- {
256- Span < byte > tempResult = stackalloc byte [ sha256Bytes ] ;
257- computeSha256 ( buffer , tempResult ) ;
258- computeSha256 ( tempResult , output ) ;
259- }
260-
261- static void computeSha256 ( ReadOnlySpan < byte > buffer , Span < byte > output )
262- {
263- if ( ! SHA256 . TryHashData ( buffer , output , out int bytesWritten ) )
264- {
265- throw new InvalidOperationException ( "Couldn't compute SHA256" ) ;
266- }
267-
268- if ( bytesWritten != sha256Bytes )
269- {
270- throw new InvalidOperationException ( "Invalid SHA256 length" ) ;
271- }
272- }
273252}
0 commit comments