Hashe functions Dr/Ibrahim Elawdy Name Dep Section عبدهللا محمد محفوظ IS 4 عمرو كسبان عبدالحافظ IS 4 بسام سراج مصطفى IS 3 دنيا جمعه عباده IS 3 سلوى اشرف عبدالتواب IS 3 سندس عبدالجيد علي IS 3 Team members Introduction (Hashing) Hashing is a technique or process of mapping keys, values into the hash table by using a hash function. It is done for faster access to elements. The efficiency of mapping depends on the efficiency of the hash function used. Hash tables are the most convenient data structures that are easily accessible in most programming languages. It uses an associative array to store data and retrieve data. Each data value has its unique index. Instead of searching through the whole array, the index is used to access the required element directly. It reduces the time taken for search operation irrespective of the data size. Given a keyvalue pair, the hash code of the key is computed and used as the index of the value stored in the table. Introduction (CRC) Cyclic Redundancy Check (CRC) is an error detection technique to detect changes to raw data and is used widely in today’s computer networks.CRC codes are also known as polynomial codes, since it is possible to view the bit string to be sent as a polynomial. Steps and example of (CRC) Send Procedure: 1. Extend the n data bits with k zeros 2. Divide by the generator value C 3. Keep remainder, ignore quotient 4. Adjust k check bits by remainder Receive Procedure: 1. Divide and check for zero remainder Example : Data bits: 1101011111 Check bits: C(x)=x4+x1+1 C = 10011 k=4 Implementation for generating code word from given binary data and key. #include<bits/stdc++.h> using namespace std; // Returns XOR of 'a' and 'b' // (both of same length) string xor1(string a, string b) {// Initialize result string result = ""; int n = b.length(); // Traverse all bits, if bits are // same, then XOR is 0, else 1 for(int i = 1; i < n; i++) { if (a[i] == b[i]) result += "0"; else result += "1"; } return result; } // Performs Modulo-2 division string mod2div(string divident, string divisor) { // Number of bits to be XORed at a time. int pick = divisor.length(); // Slicing the divident to appropriate // length for particular step string tmp = divident.substr(0, pick); int n = divident.length(); while (pick < n) { if (tmp[0] == '1') // Replace the divident by the result // of XOR and pull 1 bit down tmp = xor1(divisor, tmp) + divident[pick]; else // If leftmost bit is '0'. // If the leftmost bit of the dividend (or the // part used in each step) is 0, the step cannot // use the regular divisor; we need to use an // all-0s divisor. tmp = xor1(std::string(pick, '0'), tmp) + divident[pick]; // Increment pick to move further pick += 1; } // For the last n bits, we have to carry it out // normally as increased value of pick will cause // Index Out of Bounds. if (tmp[0] == '1') tmp = xor1(divisor, tmp); else tmp = xor1(std::string(pick, '0'), tmp); return tmp; } // Function used at the sender side to encode // data by appending remainder of modular division // at the end of data. void encodeData(string data, string key) { int l_key = key.length(); // Appends n-1 zeroes at end of data string appended_data = (data + std::string( l_key - 1, '0')); string remainder = mod2div(appended_data, key); // Append remainder in the original data string codeword = data + remainder; cout << "Remainder : " << remainder << "\n"; cout << "Encoded Data (Data + Remainder) :" << codeword << "\n"; } // Driver code int main() {string data = "100100"; string key = "1101"; encodeData(data, key); return 0; } // This code is contributed by MuskanKalra1 Output: Remainder : 001 Encoded Data (Data + Remainder) : 100100001 Cyclic Redundancy Check 64 bit (CRC-64) Hash Checksum Generator In the real world, usually CRC used when sending data. Lets say we want to send our message to someone else, to make sure the data didn't go through unintended changes (small changes, maybe because it goes through unreliable connection/wire), we can put CRC hash in the message. Upon receiving the message, the recipient try to calculate the CRC of the message and compare it to the CRC sent which included on the message. If the CRC hash is different, then there's a possibility of data change on the message. Blocks of data entering these systems get a short check value attached, based on the remainder of a polynomial division of their contents. On retrieval, the calculation is repeated and, in the event the check values do not match, corrective action can be taken against data corruption. CRCs can be used for error correction . CRCs are so called because the check (data verification) value is a redundancy (it expands the message without adding information) and the algorithm is based on cyclic codes. CRCs are popular because they are simple to implement in binary hardware, easy to analyze mathematically, and particularly good at detecting common errors caused by noise in transmission channels. Because the check value has a fixed length, the function that generates it is occasionally used as a hash function. Example on how to create a hash table, hashing process using CRC64-algorithm. // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSDstyle // license that can be found in the LICENSE file. // Package crc64 implements the 64-bit cyclic redundancy check, or CRC-64, // checksum. See https://en.wikipedia.org/wiki/Cyclic_redundancy_che ck for // information. package crc64 import ( "errors" "hash" "sync" ) // The size of a CRC-64 checksum in bytes. const Size = 8 // Predefined polynomials. const ( // The ISO polynomial, defined in ISO 3309 and used in HDLC. ISO = 0xD800000000000000 // The ECMA polynomial, defined in ECMA 182. ECMA = 0xC96C5795D7870F42 ) // Table is a 256-word table representing the polynomial for efficient processing. type Table [256]uint64 var ( slicing8TablesBuildOnce sync.Once slicing8TableISO *[8]Table slicing8TableECMA *[8]Table ) func buildSlicing8TablesOnce() { slicing8TablesBuildOnce.Do(buildSlicing8Tab les) } func buildSlicing8Tables() { slicing8TableISO = makeSlicingBy8Table(makeTable(ISO)) slicing8TableECMA = makeSlicingBy8Table(makeTable(ECMA)) } Example on how to create a hash table, hashing process using CRC64-algorithm. // MakeTable returns a Table constructed from the specified polynomial. // The contents of this Table must not be modified. func MakeTable(poly uint64) *Table { buildSlicing8TablesOnce() switch poly { case ISO: return &slicing8TableISO[0] case ECMA: return &slicing8TableECMA[0] default: return makeTable(poly) } } func makeTable(poly uint64) *Table { t := new(Table) for i := 0; i < 256; i++ { crc := uint64(i) for j := 0; j < 8; j++ { if crc&1 == 1 { crc = (crc >> 1) ^ poly } else { crc >>= 1 } } t[i] = crc } return t } func makeSlicingBy8Table(t *Table) *[8]Table { var helperTable [8]Table helperTable[0] = *t for i := 0; i < 256; i++ { crc := t[i] for j := 1; j < 8; j++ { crc = t[crc&0xff] ^ (crc >> 8) helperTable[j][i] = crc } } return &helperTable } // digest represents the partial evaluation of a checksum. type digest struct { crc uint64 tab *Table } Example on how to create a hash table, hashing process using CRC64-algorithm. // New creates a new hash.Hash64 computing the CRC64 checksum using the // polynomial represented by the Table. Its Sum method will lay the // value out in big-endian byte order. The returned Hash64 also // implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to // marshal and unmarshal the internal state of the hash. func New(tab *Table) hash.Hash64 { return &digest{0, tab} } func (d *digest) Size() int { return Size } func (d *digest) BlockSize() int { return 1 } func (d *digest) Reset() { d.crc = 0 } const ( magic = "crc\x02" marshaledSize = len(magic) + 8 + 8 ) func (d *digest) MarshalBinary() ([]byte, error) { b := make([]byte, 0, marshaledSize) b = append(b, magic...) b = appendUint64(b, tableSum(d.tab)) b = appendUint64(b, d.crc) return b, nil } func (d *digest) UnmarshalBinary(b []byte) error { if len(b) < len(magic) || string(b[:len(magic)]) != magic { return errors.New("hash/crc64: invalid hash state identifier") } if len(b) != marshaledSize { return errors.New("hash/crc64: invalid hash state size") } if tableSum(d.tab) != readUint64(b[4:]) { return errors.New("hash/crc64: tables do not match") } d.crc = readUint64(b[12:]) return nil } func appendUint64(b []byte, x uint64) []byte { a := [8]byte{ byte(x >> 56), byte(x >> 48), byte(x >> 40), byte(x >> 32), byte(x >> 24), byte(x >> 16), byte(x >> 8), byte(x), } return append(b, a[:]...) } Example on how to create a hash table, hashing process using CRC64-algorithm. func readUint64(b []byte) uint64 { _ = b[7] return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 } func update(crc uint64, tab *Table, p []byte) uint64 { buildSlicing8TablesOnce() crc = ^crc // Table comparison is somewhat expensive, so avoid it for small sizes for len(p) >= 64 { var helperTable *[8]Table if *tab == slicing8TableECMA[0] { helperTable = slicing8TableECMA } else if *tab == slicing8TableISO[0] { helperTable = slicing8TableISO // For smaller sizes creating extended table takes too much time } else if len(p) > 16384 { helperTable = makeSlicingBy8Table(tab) } else { break } // Update using slicing-by-8 for len(p) > 8 { crc ^= uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 | uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56 crc = helperTable[7][crc&0xff] ^ helperTable[6][(crc>>8)&0xff] ^ helperTable[5][(crc>>16)&0xff] ^ helperTable[4][(crc>>24)&0xff] ^ helperTable[3][(crc>>32)&0xff] ^ helperTable[2][(crc>>40)&0xff] ^ helperTable[1][(crc>>48)&0xff] ^ helperTable[0][crc>>56] p = p[8:] } } // For reminders or small sizes for _, v := range p { crc = tab[byte(crc)^v] ^ (crc >> 8) } return ^crc } Example on how to create a hash table, hashing process using CRC64-algorithm. // Update returns the result of adding the bytes in p to the crc. func Update(crc uint64, tab *Table, p []byte) uint64 { return update(crc, tab, p) } func (d *digest) Write(p []byte) (n int, err error) { d.crc = update(d.crc, d.tab, p) return len(p), nil } func (d *digest) Sum64() uint64 { return d.crc } func (d *digest) Sum(in []byte) []byte { s := d.Sum64() return append(in, byte(s>>56), byte(s>>48), byte(s>>40), byte(s>>32), byte(s>>24), byte(s>>16), byte(s>>8), byte(s)) } // Checksum returns the CRC-64 checksum of data // using the polynomial represented by the Table. func Checksum(data []byte, tab *Table) uint64 { return update(0, tab, data) } // tableSum returns the ISO checksum of table t. func tableSum(t *Table) uint64 { var a [2048]byte b := a[:0] if t != nil { for _, x := range t { b = appendUint64(b, x) } } return Checksum(b, MakeTable(ISO)) } Thanks