2011-08-30 10 views

risposta

9

Qualsiasi funzione di hashing incorporata dovrebbe essere eseguita; a seconda di quanto vi preoccupate per le collisioni queste sono le opzioni (dalla maggior parte delle collisioni al meno):

  • MD5
  • SHA1
  • SHA256
  • SHA384
  • SHA512

Essi sono semplici da usare come:

var hash = SHA1.Create().ComputeHash(data); 

Punti bonus: Se non ti importa della sicurezza (che non credo ti faccia dato che stai ottenendo gli hash per le immagini) potresti voler esaminare l'hash di Murmur, che è progettato per l'hashing del contenuto e hashing sicuro (ed è quindi molto più veloce). Tuttavia, non è nel framework, quindi dovrai trovare un'implementazione (e probabilmente dovresti optare per Murmur3).

Edit: Se siete alla ricerca di un HashCode per un [] array di byte è interamente a te, di solito costituita da bit spostamento (da numeri primi) e XOR. Per esempio.

public class ByteArrayEqualityComparer : IEqualityComparer<byte[]> 
{ 
    public static readonly ByteArrayEqualityComparer Default = new ByteArrayEqualityComparer(); 
    private ByteArrayEqualityComparer() { } 

    public bool Equals(byte[] x, byte[] y) 
    { 
     if (x == null && y == null) 
      return true; 
     if (x == null || y == null) 
      return false; 
     if (x.Length != y.Length) 
      return false; 
     for (var i = 0; i < x.Length; i++) 
      if (x[i] != y[i]) 
       return false; 
     return true; 
    } 

    public int GetHashCode(byte[] obj) 
    { 
     if (obj == null || obj.Length == 0) 
      return 0; 
     var hashCode = 0; 
     for (var i = 0; i < obj.Length; i++) 
      // Rotate by 3 bits and XOR the new value. 
      hashCode = (hashCode << 3) | (hashCode >> (29))^obj[i]; 
     return hashCode; 
    } 
} 
// ... 
var hc = ByteArrayEqualityComparer.Default.GetHashCode(data); 

EDIT: Se si desidera convalidare che il valore non è cambiato si dovrebbe usare CRC32.

+0

grazie per la risposta, ho bisogno di un veloce confronto di contenuto di array 'byte []', non c'è bisogno di hash encriptati. Devo assicurarmi che i dati inviati rimangano gli stessi ricevuti all'altra estremità –

+0

@Chesnokov quindi perché non l'hai chiesto in primo luogo? –

+0

Intendevo il confronto per valore hash, come nella domanda, i dati vengono inviati su Internet insieme a un hash. Dall'altro lato l'hash viene ricalcolato e confrontato per assicurarsi che non ci siano state modifiche sui dati durante il trasferimento –

2

Qualsiasi componente di hashing crittografico dovrebbe funzionare. Non sono sicuro della velocità. Forse MD5?

+0

ci sono metodi personalizzati in .NET solo per confronto byte array [], non ho ancora bisogno di crittografia –

+0

@Chesnokov che suona come una domanda diversa; come: http://stackoverflow.com/questions/43289/comparing-two-byte-arrays-in-net –

+0

oh, no. Ho bisogno di un metodo veloce per ottenere il valore a 32 bit per l'array 'byte []'. L'oggetto serializzato viene inviato insieme al suo hash ad un'altra macchina in cui l'hash viene ricalcolato e confrontato –

2

Sulla base del Compiler Generated GetHashCode()

public static int GetHashCode(byte[] array) { 
    unchecked { 
     int i = 0; 
     int hash = 17; 
     int rounded = array.Length & ~3; 

     hash = 31 * hash + array.Length; 

     for (; i < rounded; i += 4) { 
      hash = 31 * hash + BitConverter.ToInt32(array, i); 
     } 

     if (i < array.Length) { 
      int val = array[i]; 
      i++; 

      if (i < array.Length) { 
       val |= array[i] << 8; 
       i++; 

       if (i < array.Length) { 
        val |= array[i] << 16; 
       } 
      } 

      hash = 31 * hash + val; 
     } 

     return hash; 
    } 
} 

Ah ... e un collegamento a C# Murmurhash http://landman-code.blogspot.com/2009/02/c-superfasthash-and-murmurhash2.html

+0

Bella risposta, ma questo è Murmur2 che ha problemi con la ripetizione dei dati (si scontra abbastanza frequentemente se c'è). Non conosco nessuna porta C# di Murmur3. –

+0

Implementazione di Murmur3 http://blog.teamleadnet.com/2012/08/murmurhash3-ultra-fast-hash-algorithm.html – Omar

4

Jon Skeet has a good answer su come ignorare GetHashCode, che si basa su tecniche di hash efficaci generali in cui si inizia con un numero primo, aggiungerlo ai codici hash dei componenti moltiplicati per un altro numero primo, consentendo l'overflow.

Per il vostro caso, si dovrebbe fare:

static int GetByteArrayHashCode(byte[] array) 
{ 
    unchecked 
    { 
     int hash = 17; 

     // Cycle through each element in the array. 
     foreach (var value in array) 
     { 
      // Update the hash. 
      hash = hash * 23 + value.GetHashCode();    
     } 

     return hash; 
    } 
} 

nota in risposta di Jon va sul perché questo è meglio di XOR gli hash dei singoli elementi (e che tipi anonimi in C# attualmente non XOR il hash dei singoli elementi, ma usa qualcosa di simile al precedente).

Mentre questo sarà più veloce degli algoritmi hash dal System.Security.Cryptography namespace (perché si tratta di hash più piccoli), lo svantaggio è che si potrebbero avere più collisioni.

È necessario testare i dati e determinare la frequenza con cui si verificano collisioni o il lavoro da eseguire in caso di collisione.

+0

È 'foreach' più lento di' for'? Inoltre, non c'è bisogno di chiamare 'GetHashCode' su' byte' in quanto restituisce il suo valore cast a 'int'. –

+0

@DrewNoakes Abbastanza sicuro che il compilatore cambi 'foreach' su matrici su' for'. Questo è comunque un dettaglio di implementazione, e in generale dovresti provare se vedi che questo è un collo di bottiglia. Inoltre, lo stesso vale per il valore di ritorno di 'GetHashCode' per byte. – casperOne

Problemi correlati