From bf1b026a7ebd815f4de0e02d86a9c7dc061ffa44 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Wed, 22 Sep 2021 23:49:32 +0100 Subject: [PATCH] Use multiple sum algorithm from zlib for Adler and Fletcher checksums. --- adler32.c | 165 +++++++++++++++++++++++++++++++++++++++++++++------ adler32.h | 2 + fletcher16.c | 145 ++++++++++++++++++++++++++++++++++++++------ fletcher16.h | 2 + fletcher32.c | 131 ++++++++++++++++++++++++++++++++++++++-- fletcher32.h | 2 + 6 files changed, 409 insertions(+), 38 deletions(-) diff --git a/adler32.c b/adler32.c index a061ee6..4441cfc 100644 --- a/adler32.c +++ b/adler32.c @@ -1,21 +1,29 @@ /* * This file is part of the Aaru Data Preservation Suite. * Copyright (c) 2019-2021 Natalia Portillo. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . */ +/* adler32.c -- compute the Adler-32 checksum of a data stream + Copyright (C) 1995-2011 Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu +*/ + #include #include @@ -38,15 +46,138 @@ AARU_EXPORT adler32_ctx* AARU_CALL adler32_init() AARU_EXPORT int AARU_CALL adler32_update(adler32_ctx* ctx, const uint8_t* data, uint32_t len) { - uint32_t i; if(!ctx || !data) return -1; - for(i = 0; i < len; i++) + uint32_t sum1 = ctx->sum1; + uint32_t sum2 = ctx->sum2; + unsigned n; + + /* in case user likes doing a byte at a time, keep it fast */ + if(len == 1) { - ctx->sum1 = (ctx->sum1 + data[i]) % ADLER_MODULE; - ctx->sum2 = (ctx->sum2 + ctx->sum1) % ADLER_MODULE; + sum1 += data[0]; + if(sum1 >= ADLER_MODULE) sum1 -= ADLER_MODULE; + sum2 += sum1; + if(sum2 >= ADLER_MODULE) sum2 -= ADLER_MODULE; + + ctx->sum1 = sum1 & 0xFFFF; + ctx->sum2 = sum2 & 0xFFFF; + return 0; } + /* in case short lengths are provided, keep it somewhat fast */ + if(len < 16) + { + while(len--) + { + sum1 += *data++; + sum2 += sum1; + } + if(sum1 >= ADLER_MODULE) sum1 -= ADLER_MODULE; + sum2 %= ADLER_MODULE; /* only added so many ADLER_MODULE's */ + ctx->sum1 = sum1 & 0xFFFF; + ctx->sum2 = sum2 & 0xFFFF; + return 0; + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while(len >= NMAX) + { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + sum1 += (data)[0]; + sum2 += sum1; + sum1 += (data)[0 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 2]; + sum2 += sum1; + sum1 += (data)[0 + 2 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 4]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 2]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 2 + 1]; + sum2 += sum1; + sum1 += (data)[8]; + sum2 += sum1; + sum1 += (data)[8 + 1]; + sum2 += sum1; + sum1 += (data)[8 + 2]; + sum2 += sum1; + sum1 += (data)[8 + 2 + 1]; + sum2 += sum1; + sum1 += (data)[8 + 4]; + sum2 += sum1; + sum1 += (data)[8 + 4 + 1]; + sum2 += sum1; + sum1 += (data)[8 + 4 + 2]; + sum2 += sum1; + sum1 += (data)[8 + 4 + 2 + 1]; + sum2 += sum1; + + /* 16 sums unrolled */ + data += 16; + } while(--n); + sum1 %= ADLER_MODULE; + sum2 %= ADLER_MODULE; + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if(len) + { /* avoid modulos if none remaining */ + while(len >= 16) + { + len -= 16; + sum1 += (data)[0]; + sum2 += sum1; + sum1 += (data)[0 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 2]; + sum2 += sum1; + sum1 += (data)[0 + 2 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 4]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 2]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 2 + 1]; + sum2 += sum1; + sum1 += (data)[8]; + sum2 += sum1; + sum1 += (data)[8 + 1]; + sum2 += sum1; + sum1 += (data)[8 + 2]; + sum2 += sum1; + sum1 += (data)[8 + 2 + 1]; + sum2 += sum1; + sum1 += (data)[8 + 4]; + sum2 += sum1; + sum1 += (data)[8 + 4 + 1]; + sum2 += sum1; + sum1 += (data)[8 + 4 + 2]; + sum2 += sum1; + sum1 += (data)[8 + 4 + 2 + 1]; + sum2 += sum1; + + data += 16; + } + while(len--) + { + sum1 += *data++; + sum2 += sum1; + } + sum1 %= ADLER_MODULE; + sum2 %= ADLER_MODULE; + } + + ctx->sum1 = sum1 & 0xFFFF; + ctx->sum2 = sum2 & 0xFFFF; return 0; } diff --git a/adler32.h b/adler32.h index 0761340..dc208a8 100644 --- a/adler32.h +++ b/adler32.h @@ -20,6 +20,8 @@ #define AARU_CHECKSUMS_NATIVE_ADLER32_H #define ADLER_MODULE 65521 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(ADLER_MODULE-1) <= 2^32-1 */ +#define NMAX 5552 typedef struct { diff --git a/fletcher16.c b/fletcher16.c index d675699..748f2a1 100644 --- a/fletcher16.c +++ b/fletcher16.c @@ -1,21 +1,29 @@ /* * This file is part of the Aaru Data Preservation Suite. * Copyright (c) 2019-2021 Natalia Portillo. - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . */ +/* adler32.c -- compute the Adler-32 checksum of a data stream + Copyright (C) 1995-2011 Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu +*/ + #include #include @@ -38,15 +46,118 @@ AARU_EXPORT fletcher16_ctx* AARU_CALL fletcher16_init() AARU_EXPORT int AARU_CALL fletcher16_update(fletcher16_ctx* ctx, const uint8_t* data, uint32_t len) { - uint32_t i; if(!ctx || !data) return -1; - for(i = 0; i < len; i++) + uint32_t sum1 = ctx->sum1; + uint32_t sum2 = ctx->sum2; + unsigned n; + + /* in case user likes doing a byte at a time, keep it fast */ + if(len == 1) { - ctx->sum1 = (ctx->sum1 + data[i]) % FLETCHER16_MODULE; - ctx->sum2 = (ctx->sum2 + ctx->sum1) % FLETCHER16_MODULE; + sum1 += data[0]; + if(sum1 >= FLETCHER16_MODULE) sum1 -= FLETCHER16_MODULE; + sum2 += sum1; + if(sum2 >= FLETCHER16_MODULE) sum2 -= FLETCHER16_MODULE; + + ctx->sum1 = sum1 & 0xFF; + ctx->sum2 = sum2 & 0xFF; + return 0; } + /* in case short lengths are provided, keep it somewhat fast */ + if(len < 11) + { + while(len--) + { + sum1 += *data++; + sum2 += sum1; + } + if(sum1 >= FLETCHER16_MODULE) sum1 -= FLETCHER16_MODULE; + sum2 %= FLETCHER16_MODULE; /* only added so many FLETCHER16_MODULE's */ + ctx->sum1 = sum1 & 0xFF; + ctx->sum2 = sum2 & 0xFF; + return 0; + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while(len >= NMAX) + { + len -= NMAX; + n = NMAX / 11; /* NMAX is divisible by 11 */ + do { + sum1 += (data)[0]; + sum2 += sum1; + sum1 += (data)[0 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 2]; + sum2 += sum1; + sum1 += (data)[0 + 2 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 4]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 2]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 2 + 1]; + sum2 += sum1; + sum1 += (data)[8]; + sum2 += sum1; + sum1 += (data)[8 + 1]; + sum2 += sum1; + sum1 += (data)[8 + 2]; + sum2 += sum1; + + /* 11 sums unrolled */ + data += 11; + } while(--n); + sum1 %= FLETCHER16_MODULE; + sum2 %= FLETCHER16_MODULE; + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if(len) + { /* avoid modulos if none remaining */ + while(len >= 11) + { + len -= 11; + sum1 += (data)[0]; + sum2 += sum1; + sum1 += (data)[0 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 2]; + sum2 += sum1; + sum1 += (data)[0 + 2 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 4]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 2]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 2 + 1]; + sum2 += sum1; + sum1 += (data)[8]; + sum2 += sum1; + sum1 += (data)[8 + 1]; + sum2 += sum1; + sum1 += (data)[8 + 2]; + sum2 += sum1; + + data += 11; + } + while(len--) + { + sum1 += *data++; + sum2 += sum1; + } + sum1 %= FLETCHER16_MODULE; + sum2 %= FLETCHER16_MODULE; + } + + ctx->sum1 = sum1 & 0xFF; + ctx->sum2 = sum2 & 0xFF; return 0; } diff --git a/fletcher16.h b/fletcher16.h index 2aa2f58..8742895 100644 --- a/fletcher16.h +++ b/fletcher16.h @@ -20,6 +20,8 @@ #define AARU_CHECKSUMS_NATIVE_FLETCHER16_H #define FLETCHER16_MODULE 0xFF +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(ADLER_MODULE-1) <= 2^16-1 */ +#define NMAX 22 typedef struct { diff --git a/fletcher32.c b/fletcher32.c index 246bb6d..7323517 100644 --- a/fletcher32.c +++ b/fletcher32.c @@ -38,15 +38,138 @@ AARU_EXPORT fletcher32_ctx* AARU_CALL fletcher32_init() AARU_EXPORT int AARU_CALL fletcher32_update(fletcher32_ctx* ctx, const uint8_t* data, uint32_t len) { - uint32_t i; if(!ctx || !data) return -1; - for(i = 0; i < len; i++) + uint32_t sum1 = ctx->sum1; + uint32_t sum2 = ctx->sum2; + unsigned n; + + /* in case user likes doing a byte at a time, keep it fast */ + if(len == 1) { - ctx->sum1 = (ctx->sum1 + data[i]) % FLETCHER32_MODULE; - ctx->sum2 = (ctx->sum2 + ctx->sum1) % FLETCHER32_MODULE; + sum1 += data[0]; + if(sum1 >= FLETCHER32_MODULE) sum1 -= FLETCHER32_MODULE; + sum2 += sum1; + if(sum2 >= FLETCHER32_MODULE) sum2 -= FLETCHER32_MODULE; + + ctx->sum1 = sum1 & 0xFFFF; + ctx->sum2 = sum2 & 0xFFFF; + return 0; } + /* in case short lengths are provided, keep it somewhat fast */ + if(len < 16) + { + while(len--) + { + sum1 += *data++; + sum2 += sum1; + } + if(sum1 >= FLETCHER32_MODULE) sum1 -= FLETCHER32_MODULE; + sum2 %= FLETCHER32_MODULE; /* only added so many FLETCHER32_MODULE's */ + ctx->sum1 = sum1 & 0xFFFF; + ctx->sum2 = sum2 & 0xFFFF; + return 0; + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while(len >= NMAX) + { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + sum1 += (data)[0]; + sum2 += sum1; + sum1 += (data)[0 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 2]; + sum2 += sum1; + sum1 += (data)[0 + 2 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 4]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 2]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 2 + 1]; + sum2 += sum1; + sum1 += (data)[8]; + sum2 += sum1; + sum1 += (data)[8 + 1]; + sum2 += sum1; + sum1 += (data)[8 + 2]; + sum2 += sum1; + sum1 += (data)[8 + 2 + 1]; + sum2 += sum1; + sum1 += (data)[8 + 4]; + sum2 += sum1; + sum1 += (data)[8 + 4 + 1]; + sum2 += sum1; + sum1 += (data)[8 + 4 + 2]; + sum2 += sum1; + sum1 += (data)[8 + 4 + 2 + 1]; + sum2 += sum1; + + /* 16 sums unrolled */ + data += 16; + } while(--n); + sum1 %= FLETCHER32_MODULE; + sum2 %= FLETCHER32_MODULE; + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if(len) + { /* avoid modulos if none remaining */ + while(len >= 16) + { + len -= 16; + sum1 += (data)[0]; + sum2 += sum1; + sum1 += (data)[0 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 2]; + sum2 += sum1; + sum1 += (data)[0 + 2 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 4]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 1]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 2]; + sum2 += sum1; + sum1 += (data)[0 + 4 + 2 + 1]; + sum2 += sum1; + sum1 += (data)[8]; + sum2 += sum1; + sum1 += (data)[8 + 1]; + sum2 += sum1; + sum1 += (data)[8 + 2]; + sum2 += sum1; + sum1 += (data)[8 + 2 + 1]; + sum2 += sum1; + sum1 += (data)[8 + 4]; + sum2 += sum1; + sum1 += (data)[8 + 4 + 1]; + sum2 += sum1; + sum1 += (data)[8 + 4 + 2]; + sum2 += sum1; + sum1 += (data)[8 + 4 + 2 + 1]; + sum2 += sum1; + + data += 16; + } + while(len--) + { + sum1 += *data++; + sum2 += sum1; + } + sum1 %= FLETCHER32_MODULE; + sum2 %= FLETCHER32_MODULE; + } + + ctx->sum1 = sum1 & 0xFFFF; + ctx->sum2 = sum2 & 0xFFFF; return 0; } diff --git a/fletcher32.h b/fletcher32.h index c5d991f..09b5156 100644 --- a/fletcher32.h +++ b/fletcher32.h @@ -20,6 +20,8 @@ #define AARU_CHECKSUMS_NATIVE_FLETCHER32_H #define FLETCHER32_MODULE 0xFFFF +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(ADLER_MODULE-1) <= 2^32-1 */ +#define NMAX 5552 typedef struct {