@@ -256,44 +256,49 @@ public static bool IsValid(ReadOnlySpan<byte> key, bool validateCurve = false)
256
256
/// <summary>
257
257
/// The bytes of the `ProgramDerivedAddress` string.
258
258
/// </summary>
259
- private static readonly byte [ ] ProgramDerivedAddressBytes = Encoding . UTF8 . GetBytes ( "ProgramDerivedAddress" ) ;
259
+ private static readonly byte [ ] ProgramDerivedAddressBytes = "ProgramDerivedAddress"u8 . ToArray ( ) ;
260
260
261
261
/// <summary>
262
262
/// Derives a program address.
263
263
/// </summary>
264
264
/// <param name="seeds">The address seeds.</param>
265
265
/// <param name="programId">The program Id.</param>
266
266
/// <param name="publicKey">The derived public key, returned as inline out.</param>
267
- /// <returns>true if it could derive the program address for the given seeds, otherwise false.. </returns>
267
+ /// <returns>true if it could derive the program address for the given seeds, otherwise false.</returns>
268
268
/// <exception cref="ArgumentException">Throws exception when one of the seeds has an invalid length.</exception>
269
269
public static bool TryCreateProgramAddress ( ICollection < byte [ ] > seeds , PublicKey programId , out PublicKey publicKey )
270
270
{
271
- MemoryStream buffer = new ( PublicKeyLength * seeds . Count + ProgramDerivedAddressBytes . Length + programId . KeyBytes . Length ) ;
272
-
271
+ using SHA256 sha256 = SHA256 . Create ( ) ;
272
+ sha256 . Initialize ( ) ;
273
+
273
274
foreach ( byte [ ] seed in seeds )
274
275
{
275
276
if ( seed . Length > PublicKeyLength )
276
277
{
277
278
throw new ArgumentException ( "max seed length exceeded" , nameof ( seeds ) ) ;
278
279
}
279
- buffer . Write ( seed , 0 , seed . Length ) ;
280
+
281
+ sha256 . TransformBlock ( seed , 0 , seed . Length , null , 0 ) ;
280
282
}
281
283
282
- buffer . Write ( programId . KeyBytes , 0 , programId . KeyBytes . Length ) ;
283
- buffer . Write ( ProgramDerivedAddressBytes , 0 , ProgramDerivedAddressBytes . Length ) ;
284
-
285
- SHA256 sha256 = SHA256 . Create ( ) ;
286
- byte [ ] hash = sha256 . ComputeHash ( new ReadOnlySpan < byte > ( buffer . GetBuffer ( ) , 0 , ( int ) buffer . Length ) . ToArray ( ) ) ;
287
-
284
+ sha256 . TransformBlock ( programId . KeyBytes , 0 , programId . KeyBytes . Length , null , 0 ) ;
285
+ sha256 . TransformBlock ( ProgramDerivedAddressBytes , 0 , ProgramDerivedAddressBytes . Length , null , 0 ) ;
286
+ sha256 . TransformFinalBlock ( [ ] , 0 , 0 ) ;
287
+
288
+ byte [ ] hash = sha256 . Hash ! ;
288
289
if ( hash . IsOnCurve ( ) )
289
290
{
290
291
publicKey = null ;
291
292
return false ;
292
293
}
293
- publicKey = new ( hash ) ;
294
+
295
+ publicKey = new PublicKey ( hash ) ;
294
296
return true ;
295
297
}
296
298
299
+ private static readonly List < byte [ ] > PdaSeedsBuffer = [ ] ;
300
+ private static readonly byte [ ] BumpArray = new byte [ 1 ] ;
301
+
297
302
/// <summary>
298
303
/// Attempts to find a program address for the passed seeds and program Id.
299
304
/// </summary>
@@ -304,28 +309,42 @@ public static bool TryCreateProgramAddress(ICollection<byte[]> seeds, PublicKey
304
309
/// <returns>True whenever the address for a nonce was found, otherwise false.</returns>
305
310
public static bool TryFindProgramAddress ( IEnumerable < byte [ ] > seeds , PublicKey programId , out PublicKey address , out byte bump )
306
311
{
307
- byte seedBump = 255 ;
308
- List < byte [ ] > buffer = seeds . ToList ( ) ;
309
- var bumpArray = new byte [ 1 ] ;
310
- buffer . Add ( bumpArray ) ;
312
+ PdaSeedsBuffer . Clear ( ) ;
313
+ PdaSeedsBuffer . AddRange ( seeds ) ;
311
314
312
- while ( seedBump != 0 )
315
+ if ( PdaSeedsBuffer . Any ( seed => seed . Length > PublicKeyLength ) )
316
+ {
317
+ throw new ArgumentException ( "max seed length exceeded" , nameof ( seeds ) ) ;
318
+ }
319
+
320
+ using SHA256 sha256 = SHA256 . Create ( ) ;
321
+ for ( bump = 255 ; ; bump -- )
313
322
{
314
- bumpArray [ 0 ] = seedBump ;
315
- bool success = TryCreateProgramAddress ( buffer , programId , out PublicKey derivedAddress ) ;
323
+ sha256 . Initialize ( ) ;
316
324
317
- if ( success )
325
+ foreach ( byte [ ] seed in PdaSeedsBuffer )
326
+ {
327
+ sha256 . TransformBlock ( seed , 0 , seed . Length , null , 0 ) ;
328
+ }
329
+
330
+ BumpArray [ 0 ] = bump ;
331
+ sha256 . TransformBlock ( BumpArray , 0 , 1 , null , 0 ) ;
332
+ sha256 . TransformBlock ( programId . KeyBytes , 0 , programId . KeyBytes . Length , null , 0 ) ;
333
+ sha256 . TransformBlock ( ProgramDerivedAddressBytes , 0 , ProgramDerivedAddressBytes . Length , null , 0 ) ;
334
+ sha256 . TransformFinalBlock ( [ ] , 0 , 0 ) ;
335
+
336
+ byte [ ] hash = sha256 . Hash ! ;
337
+ if ( ! hash . IsOnCurve ( ) )
318
338
{
319
- address = derivedAddress ;
320
- bump = seedBump ;
339
+ address = new PublicKey ( hash ) ;
321
340
return true ;
322
341
}
323
342
324
- seedBump -- ;
343
+ if ( bump == 0 )
344
+ break ;
325
345
}
326
346
327
- address = null ;
328
- bump = 0 ;
347
+ address = null ! ;
329
348
return false ;
330
349
}
331
350
0 commit comments