/* * * Copyright (c) 2014, James S. Plank and Kevin Greenan * All rights reserved. * * Jerasure - A C/C++ Library for a Variety of Reed-Solomon and RAID-6 Erasure * Coding Techniques * * Revision 2.0: Galois Field backend now links to GF-Complete * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * - Neither the name of the University of Tennessee nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* Jerasure's authors: Revision 2.x - 2014: James S. Plank and Kevin M. Greenan Revision 1.2 - 2008: James S. Plank, Scott Simmerman and Catherine D. Schuman. Revision 1.0 - 2007: James S. Plank */ #include #include #include #include #include #include "galois.h" #define MAX_GF_INSTANCES 64 gf_t *gfp_array[MAX_GF_INSTANCES] = { 0 }; int gfp_is_composite[MAX_GF_INSTANCES] = { 0 }; gf_t *galois_get_field_ptr(int w) { if (gfp_array[w] != NULL) { return gfp_array[w]; } return NULL; } gf_t* galois_init_field(int w, int mult_type, int region_type, int divide_type, uint64_t prim_poly, int arg1, int arg2) { int scratch_size; void *scratch_memory; gf_t *gfp; if (w <= 0 || w > 32) { fprintf(stderr, "ERROR -- cannot init default Galois field for w=%d\n", w); assert(0); } gfp = (gf_t *) malloc(sizeof(gf_t)); if (!gfp) { fprintf(stderr, "ERROR -- cannot allocate memory for Galois field w=%d\n", w); assert(0); } scratch_size = gf_scratch_size(w, mult_type, region_type, divide_type, arg1, arg2); if (!scratch_size) { fprintf(stderr, "ERROR -- cannot get scratch size for base field w=%d\n", w); assert(0); } scratch_memory = malloc(scratch_size); if (!scratch_memory) { fprintf(stderr, "ERROR -- cannot get scratch memory for base field w=%d\n", w); assert(0); } if(!gf_init_hard(gfp, w, mult_type, region_type, divide_type, prim_poly, arg1, arg2, NULL, scratch_memory)) { fprintf(stderr, "ERROR -- cannot init default Galois field for w=%d\n", w); assert(0); } gfp_is_composite[w] = 0; return gfp; } gf_t* galois_init_composite_field(int w, int region_type, int divide_type, int degree, gf_t* base_gf) { int scratch_size; void *scratch_memory; gf_t *gfp; if (w <= 0 || w > 32) { fprintf(stderr, "ERROR -- cannot init composite field for w=%d\n", w); assert(0); } gfp = (gf_t *) malloc(sizeof(gf_t)); if (!gfp) { fprintf(stderr, "ERROR -- cannot allocate memory for Galois field w=%d\n", w); assert(0); } scratch_size = gf_scratch_size(w, GF_MULT_COMPOSITE, region_type, divide_type, degree, 0); if (!scratch_size) { fprintf(stderr, "ERROR -- cannot get scratch size for composite field w=%d\n", w); assert(0); } scratch_memory = malloc(scratch_size); if (!scratch_memory) { fprintf(stderr, "ERROR -- cannot get scratch memory for composite field w=%d\n", w); assert(0); } if(!gf_init_hard(gfp, w, GF_MULT_COMPOSITE, region_type, divide_type, 0, degree, 0, base_gf, scratch_memory)) { fprintf(stderr, "ERROR -- cannot init default composite field for w=%d\n", w); assert(0); } gfp_is_composite[w] = 1; return gfp; } int galois_init_default_field(int w) { if (gfp_array[w] == NULL) { gfp_array[w] = (gf_t*)malloc(sizeof(gf_t)); if(gfp_array[w] == NULL) return ENOMEM; if (!gf_init_easy(gfp_array[w], w)) return EINVAL; } return 0; } int galois_uninit_field(int w) { int ret = 0; if (gfp_array[w] != NULL) { int recursive = 1; ret = gf_free(gfp_array[w], recursive); free(gfp_array[w]); gfp_array[w] = NULL; } return ret; } static void galois_init(int w) { if (w <= 0 || w > 32) { fprintf(stderr, "ERROR -- cannot init default Galois field for w=%d\n", w); assert(0); } switch (galois_init_default_field(w)) { case ENOMEM: fprintf(stderr, "ERROR -- cannot allocate memory for Galois field w=%d\n", w); assert(0); break; case EINVAL: fprintf(stderr, "ERROR -- cannot init default Galois field for w=%d\n", w); assert(0); break; } } static int is_valid_gf(gf_t *gf, int w) { // TODO: I assume we may eventually // want to do w=64 and 128, so w // will be needed to perform this check (void)w; if (gf == NULL) { return 0; } if (gf->multiply.w32 == NULL) { return 0; } if (gf->multiply_region.w32 == NULL) { return 0; } if (gf->divide.w32 == NULL) { return 0; } if (gf->inverse.w32 == NULL) { return 0; } if (gf->extract_word.w32 == NULL) { return 0; } return 1; } void galois_change_technique(gf_t *gf, int w) { if (w <= 0 || w > 32) { fprintf(stderr, "ERROR -- cannot support Galois field for w=%d\n", w); assert(0); } if (!is_valid_gf(gf, w)) { fprintf(stderr, "ERROR -- overriding with invalid Galois field for w=%d\n", w); assert(0); } if (gfp_array[w] != NULL) { gf_free(gfp_array[w], gfp_is_composite[w]); } gfp_array[w] = gf; } int galois_single_multiply(int x, int y, int w) { if (x == 0 || y == 0) return 0; if (gfp_array[w] == NULL) { galois_init(w); } if (w <= 32) { return gfp_array[w]->multiply.w32(gfp_array[w], x, y); } else { fprintf(stderr, "ERROR -- Galois field not implemented for w=%d\n", w); return 0; } } int galois_single_divide(int x, int y, int w) { if (x == 0) return 0; if (y == 0) return -1; if (gfp_array[w] == NULL) { galois_init(w); } if (w <= 32) { return gfp_array[w]->divide.w32(gfp_array[w], x, y); } else { fprintf(stderr, "ERROR -- Galois field not implemented for w=%d\n", w); return 0; } } void galois_w08_region_multiply(char *region, /* Region to multiply */ int multby, /* Number to multiply by */ int nbytes, /* Number of bytes in region */ char *r2, /* If r2 != NULL, products go here */ int add) { if (gfp_array[8] == NULL) { galois_init(8); } gfp_array[8]->multiply_region.w32(gfp_array[8], region, r2, multby, nbytes, add); } void galois_w16_region_multiply(char *region, /* Region to multiply */ int multby, /* Number to multiply by */ int nbytes, /* Number of bytes in region */ char *r2, /* If r2 != NULL, products go here */ int add) { if (gfp_array[16] == NULL) { galois_init(16); } gfp_array[16]->multiply_region.w32(gfp_array[16], region, r2, multby, nbytes, add); } void galois_w32_region_multiply(char *region, /* Region to multiply */ int multby, /* Number to multiply by */ int nbytes, /* Number of bytes in region */ char *r2, /* If r2 != NULL, products go here */ int add) { if (gfp_array[32] == NULL) { galois_init(32); } gfp_array[32]->multiply_region.w32(gfp_array[32], region, r2, multby, nbytes, add); } void galois_w8_region_xor(void *src, void *dest, int nbytes) { if (gfp_array[8] == NULL) { galois_init(8); } gfp_array[8]->multiply_region.w32(gfp_array[32], src, dest, 1, nbytes, 1); } void galois_w16_region_xor(void *src, void *dest, int nbytes) { if (gfp_array[16] == NULL) { galois_init(16); } gfp_array[16]->multiply_region.w32(gfp_array[16], src, dest, 1, nbytes, 1); } void galois_w32_region_xor(void *src, void *dest, int nbytes) { if (gfp_array[32] == NULL) { galois_init(32); } gfp_array[32]->multiply_region.w32(gfp_array[32], src, dest, 1, nbytes, 1); } void galois_region_xor(char *src, char *dest, int nbytes) { if (nbytes >= 16) { galois_w32_region_xor(src, dest, nbytes); } else { int i = 0; for (i = 0; i < nbytes; i++) { *dest ^= *src; dest++; src++; } } } int galois_inverse(int y, int w) { if (y == 0) return -1; return galois_single_divide(1, y, w); }