Algorithme de somme de contrôle robuste et rapide?


23

Quel algorithme de somme de contrôle pouvez-vous recommander dans le cas d'utilisation suivant?

Je veux générer des sommes de contrôle de petits fichiers JPEG (~ 8 Ko chacun) pour vérifier si le contenu a changé. L'utilisation de la date du système de fichiers modifiée n'est malheureusement pas une option.
La somme de contrôle n'a pas besoin d'être être cryptographiquement forte, mais elle doit indiquer de manière robuste les changements de toute taille.

Le deuxième critère est vitesse car il devrait être possible de traiter au moins des centaines d'images par seconde (sur un processeur moderne).

Le calcul sera effectué sur un serveur avec plusieurs clients. Les clients envoient les images via Gigabit TCP au serveur. Il y a donc aucun disque E/S comme goulot d'étranglement.

  0

1 Gigabit est de 125 mégaoctets (duplex intégral). Parmi ces 125 Mo/s, une part très importante sera consacrée aux réseaux (en particulier lorsque vous voulez envoyer des centaines de petits). Étant donné que MD5 sur un petit noyau peut fonctionner à près de 250 Mo/s, vous devez le remplacer par ** sans disque E/S comme goulot d'étranglement ** par quelque chose comme ** E/S entièrement disque comme goulot d'étranglement **. Cette question remonte à 7 ans et personne ne semble avoir mentionné que si vous aviez essayé quelque chose avant de poster sur StackOverflow, vous l'auriez vu par vous-même. 01 mars. 162016-03-01 14:42:24

17

Si vous avez beaucoup de petits fichiers, votre goulot d'étranglement va être des E/S de fichiers et probablement pas un algorithme de somme de contrôle.

Une liste des fonctions de hachage (que l'on peut considérer comme une somme de contrôle) se trouve here.

Y a-t-il une raison quelconque pour laquelle vous ne pouvez pas utiliser la date de modification du système de fichiers pour déterminer si un fichier a été modifié? Ce serait probablement plus rapide.

+2

D'accord. La plupart des algorithmes de hachage non cryptographiquement sécurisés sont suffisamment courts pour qu'il y ait un risque appréciable de faux négatifs, donc j'utiliserais simplement MD5 ou SHA1 et j'en aurais fini avec. La vitesse de calcul est peu susceptible d'être un problème. 24 sept.. 082008-09-24 07:44:53

+3

@luke Je veux aussi vérifier la modification de fichier, et la dernière fois que j'ai passé en revue mes archives, j'ai remarqué que quelques pourcentages des fichiers de mon archive (une petite archive de 100GB sur deux disques différents) sont cassés! L'horodatage n'a pas été modifié, mais le contenu du fichier a été endommagé de manière silencieuse. Certains fichiers datent de plus de 10 ans, je dois donc les avoir déplacés au moins deux fois d'une machine à l'autre. Donc la somme de contrôle est un must. 06 févr.. 122012-02-06 15:44:59


5

CRC

  0

CRC n'est pas cryptographiquement forte 23 sept.. 082008-09-23 19:01:39

+15

Ce qui le rend approprié pour cette application. 23 sept.. 082008-09-23 19:12:57

+7

l'OP n'a pas demandé d'algorithme de hachage cryptographiquement fort :) 23 sept.. 082008-09-23 19:13:36


5
  • CRC-32 vient à l'esprit, principalement parce qu'il est pas cher pour calculer

  • Tout type d'E/S vient à l'esprit principalement parce que ce sera le facteur limitant pour une telle entreprise;) Le problème n'est pas de calculer les sommes de contrôle, le problème est d'obtenir les images en mémoire pour calculer la somme de contrôle.

  • Je proposerais « stagged » surveillance:

    • étape 1: vérifier les changements de horodatages de fichiers et si vous constatez un changement à la main il y a plus ...
      (pas nécessaire dans votre cas décrit dans la version éditée)

    • étape 2: obtenir l'image dans la mémoire et calculer la somme de contrôle

  • Egalement important: multi-threading: mise en place d'un pipeline permettant le traitement de plusieurs images en parallèle si plusieurs cœurs de CPU sont disponibles.


7

Il y a beaucoup d'algorithmes CRC rapides qui devrait faire l'affaire: http://www.google.com/search?hl=en&q=fast+crc&aq=f&oq=

Edit: Pourquoi la haine? CRC est totalement approprié, comme en témoignent les autres réponses.Une recherche sur Google était également appropriée, car aucune langue n'était spécifiée. C'est un vieux problème qui a été résolu tellement de fois qu'il n'y a pas de réponse définitive.


2

adler32, disponible dans les en-têtes zlib, est annoncé comme étant nettement plus rapide que crc32, tout en étant légèrement moins précis.

+4

La somme de contrôle Adler est très faible pour les petites quantités de données, inférieures à quelques centaines d'octets. Le protocole SCTP utilisé à l'origine Adler-32 comme sa somme de contrôle, mais a dû passer à CRC-32 pour cette raison (RFC 3309). Bien que la taille moyenne des questionneurs soit de 8K, pour les plus petits fichiers cela pourrait poser problème. 23 sept.. 082008-09-23 19:23:35

  0

C'est bon à savoir, merci! 24 sept.. 082008-09-24 01:35:07


3

CRC32 est probablement assez bon, bien qu'il y ait un petit petit que vous pourriez obtenir une collision, de sorte qu'un fichier qui a été modifié pourrait ressembler à ce qu'il n'a pas été parce que les deux versions génèrent la même somme de contrôle. Pour éviter cette possibilité, je suggère donc d'utiliser MD5, qui sera facilement assez rapide, et les chances d'une collision se réduisent au point où il est presque infinitessimal.

Comme d'autres l'ont déjà dit, avec beaucoup de petits fichiers, votre véritable goulet d'étranglement en termes de performances va être les E/S, donc le problème est de gérer cela. Si vous postez un peu plus de détails, quelqu'un vous proposera probablement un moyen de trier cela aussi.


2

Votre exigence la plus importante est de "vérifier si le contenu a changé".

S'il est important de détecter tout CHANGEMENT de fichier, vous devez choisir MD-5, SHA-1 ou même SHA-256. Étant donné que vous avez indiqué que la somme de contrôle NE serait PAS cryptographiquement bonne, je recommanderais CRC-32 pour trois raisons. Le CRC-32 donne de bonnes distances de hamming sur un fichier 8K. Le CRC-32 sera au moins d'un ordre de grandeur plus rapide que le MD-5 à calculer (votre deuxième exigence). Parfois aussi important, le CRC-32 n'a besoin que de 32 bits pour stocker la valeur à comparer. MD-5 nécessite 4 fois le stockage et SHA-1 nécessite 5 fois le stockage.

BTW, toute technique sera renforcée en ajoutant la longueur du fichier lors du calcul du hachage.


2

Selon le Wiki page pointé par Luke, MD5 est en réalité plus rapide que CRC32!

J'ai essayé ceci moi-même en utilisant Python 2.6 sur Windows Vista, et j'ai obtenu le même résultat.

Voici quelques résultats:

crc32: 162.481544276 MBps md5: 224.489791549 MBps

crc32: 168.332996575 MBps md5: 226.089336532 MBps

crc32: 155.851515828 MBps md5: 194.943289532 MBps

Je pense aussi à la même question, et je suis tenté d'utiliser la variante de Rsync d'Adler-32 pour détecter le fil Les différences

+2

C'est inhabituel. Est-ce que la qualité de l'implémentation de CRC32 et MD5 est équivalente, ou utilise-t-on l'astuce de l'optimisation du compilateur et de la table de recherche, alors que l'autre ne l'utilise pas? 24 mars. 102010-03-24 23:59:30


1

Juste un post-scriptum à ce qui précède; Les jpeg utilisent une compression avec perte et l'étendue de la compression peut dépendre du programme utilisé pour créer le jpeg, la palette de couleurs et/ou la profondeur du système, le gamma d'affichage, la carte graphique et les niveaux de compression/couleurs. Par conséquent, comparer des jpeg construits sur différents ordinateurs/plates-formes ou en utilisant un logiciel différent sera très difficile au niveau des octets.

  0

merci pour ce commentaire. J'ai déjà pris ce fait en compte. 19 mai. 092009-05-19 08:13:25


5

Si vous recevez les fichiers sur le réseau, vous pouvez calculer la somme de contrôle lorsque vous recevez le fichier. Cela garantira que vous calculerez la somme de contrôle pendant que les données sont en mémoire. Vous n'aurez donc pas à les charger en mémoire à partir du disque.

Je crois que si vous appliquez cette méthode, vous verrez presque zéro sur votre système.

Ce sont les routines que j'utilise sur un système embarqué qui contrôle la somme de contrôle sur le firmware et d'autres choses.

static const uint32_t crctab[] = { 
    0x0, 
    0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 
    0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 
    0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 
    0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 
    0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 
    0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 
    0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 
    0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 
    0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 
    0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 
    0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 
    0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 
    0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 
    0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 
    0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 
    0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 
    0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 
    0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 
    0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 
    0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 
    0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 
    0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 
    0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 
    0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 
    0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 
    0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 
    0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 
    0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 
    0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 
    0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 
    0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 
    0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 
    0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 
    0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 
    0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 
    0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 
    0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 
    0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 
    0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 
    0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 
    0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 
    0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 
    0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 
    0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 
    0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 
    0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 
    0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 
    0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 
    0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 
    0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 
    0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 
}; 

typedef struct crc32ctx 
{ 
    uint32_t crc; 
    uint32_t length; 
} CRC32Ctx; 


#define COMPUTE(var, ch) (var) = (var) << 8^crctab[(var) >> 24^(ch)] 

void crc32_stream_init(CRC32Ctx* ctx) 
{ 
    ctx->crc = 0; 
    ctx->length = 0; 
} 

void crc32_stream_compute_uint32(CRC32Ctx* ctx, uint32_t data) 
{ 
    COMPUTE(ctx->crc, data & 0xFF); 
    COMPUTE(ctx->crc, (data >> 8) & 0xFF); 
    COMPUTE(ctx->crc, (data >> 16) & 0xFF); 
    COMPUTE(ctx->crc, (data >> 24) & 0xFF); 
    ctx->length += 4; 
} 

void crc32_stream_compute_uint8(CRC32Ctx* ctx, uint8_t data) 
{ 
    COMPUTE(ctx->crc, data); 
    ctx->length++; 
} 

void crc32_stream_finilize(CRC32Ctx* ctx) 
{ 
    uint32_t len = ctx->length; 
    for(; len != 0; len >>= 8) 
    { 
     COMPUTE(ctx->crc, len & 0xFF); 
    } 
    ctx->crc = ~ctx->crc; 
} 

/*** pseudo code ***/ 
CRC32Ctx crc; 
crc32_stream_init(&crc); 

while((just_received_buffer_len = received_anything())) 
{ 
    for(int i = 0; i < just_received_buffer_len; i++) 
    { 
     crc32_stream_compute_uint8(&crc, buf[i]); // assuming buf is uint8_t* 
    } 
} 
crc32_stream_finilize(&crc); 
printf("%x", crc.crc); // ta daaa