" sha1 digest calculator " This is a port of rfc3174 sha1 function. " http://www.ietf.org/rfc/rfc3174.txt " Last Change: 2010-02-13 " Maintainer: Yukihiro Nakadaira " Original Copyright: " Copyright (C) The Internet Society (2001). All Rights Reserved. " " This document and translations of it may be copied and furnished to " others, and derivative works that comment on or otherwise explain it " or assist in its implementation may be prepared, copied, published " and distributed, in whole or in part, without restriction of any " kind, provided that the above copyright notice and this paragraph are " included on all such copies and derivative works. However, this " document itself may not be modified in any way, such as by removing " the copyright notice or references to the Internet Society or other " Internet organizations, except as needed for the purpose of " developing Internet standards in which case the procedures for " copyrights defined in the Internet Standards process must be " followed, or as required to translate it into languages other than " English. " " The limited permissions granted above are perpetual and will not be " revoked by the Internet Society or its successors or assigns. " " This document and the information contained herein is provided on an " "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING " TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING " BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION " HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF " MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. let s:save_cpo = &cpo set cpo&vim function! sha1#sha1(str) return s:SHA1Digest(s:str2bytes(a:str)) endfunction function! sha1#sha1bin(bin) return s:SHA1Digest(a:bin) endfunction function! sha1#test() call s:main() endfunction function! s:SHA1Digest(bytes) let sha = deepcopy(s:SHA1Context, 1) let Message_Digest = repeat([0], 20) let err = s:SHA1Reset(sha) if err throw printf("SHA1Reset Error %d", err) endif let err = s:SHA1Input(sha, a:bytes) if err throw printf("SHA1Input Error %d", err) endif let err = s:SHA1Result(sha, Message_Digest) if err throw printf("SHA1Result Error %d", err) endif return join(map(Message_Digest, 'printf("%02x", v:val)'), '') endfunction " " sha1.h " " Description: " This is the header file for code which implements the Secure " Hashing Algorithm 1 as defined in FIPS PUB 180-1 published " April 17, 1995. " " Many of the variable names in this code, especially the " single character names, were used because those were the names " used in the publication. " " Please read the file sha1.c for more information. " " If you do not have the ISO standard stdint.h header file, then you " must typdef the following: " name meaning " uint32_t unsigned 32 bit integer " uint8_t unsigned 8 bit integer (i.e., unsigned char) " int_least16_t integer of >= 16 bits " " " enum let s:shaSuccess = 0 let s:shaNull = 1 " Null pointer parameter let s:shaInputTooLong = 2 " input data too long let s:shaStateError = 3 " called Input after Result " define let s:SHA1HashSize = 20 " " This structure will hold context information for the SHA-1 " hashing operation " " struct let s:SHA1Context = {} " uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ let s:SHA1Context.Intermediate_Hash = repeat([0], s:SHA1HashSize / 4) " uint32_t Length_Low; /* Message length in bits */ let s:SHA1Context.Length_Low = 0 " uint32_t Length_High; /* Message length in bits */ let s:SHA1Context.Length_High = 0 " /* Index into message block array */ " int_least16_t Message_Block_Index; let s:SHA1Context.Message_Block_Index = 0 " uint8_t Message_Block[64]; /* 512-bit message blocks */ let s:SHA1Context.Message_Block = repeat([0], 64) " int Computed; /* Is the digest computed? */ let s:SHA1Context.Computed = 0 " int Corrupted; /* Is the message digest corrupted? */ let s:SHA1Context.Corrupted = 0 " " sha1.c " " Description: " This file implements the Secure Hashing Algorithm 1 as " defined in FIPS PUB 180-1 published April 17, 1995. " " The SHA-1, produces a 160-bit message digest for a given " data stream. It should take about 2**n steps to find a " message with the same digest as a given message and " 2**(n/2) to find any two messages with the same digest, " when n is the digest size in bits. Therefore, this " algorithm can serve as a means of providing a " "fingerprint" for a message. " " Portability Issues: " SHA-1 is defined in terms of 32-bit "words". This code " uses (included via "sha1.h" to define 32 and 8 " bit unsigned integer types. If your C compiler does not " support 32 bit unsigned integers, this code is not " appropriate. " " Caveats: " SHA-1 is designed to work with messages less than 2^64 bits " long. Although SHA-1 allows a message digest to be generated " for messages of any number of bits less than 2^64, this " implementation only works with messages with a length that is " a multiple of the size of an 8-bit character. " " " " Define the SHA1 circular left shift macro " "#define SHA1CircularShift(bits,word) \ " (((word) << (bits)) | ((word) >> (32-(bits)))) function s:SHA1CircularShift(bits, word) return s:bitwise_or(s:bitwise_lshift(a:word, a:bits), s:bitwise_rshift(a:word, 32 - a:bits)) endfunction " " SHA1Reset " " Description: " This function will initialize the SHA1Context in preparation " for computing a new SHA1 message digest. " " Parameters: " context: [in/out] " The context to reset. " " Returns: " sha Error Code. " " " int SHA1Reset(SHA1Context *context) function s:SHA1Reset(context) if empty(a:context) return s:shaNull endif let a:context.Length_Low = 0 let a:context.Length_High = 0 let a:context.Message_Block_Index = 0 let a:context.Intermediate_Hash[0] = 0x67452301 let a:context.Intermediate_Hash[1] = 0xEFCDAB89 let a:context.Intermediate_Hash[2] = 0x98BADCFE let a:context.Intermediate_Hash[3] = 0x10325476 let a:context.Intermediate_Hash[4] = 0xC3D2E1F0 let a:context.Computed = 0 let a:context.Corrupted = 0 return s:shaSuccess endfunction " " SHA1Result " " Description: " This function will return the 160-bit message digest into the " Message_Digest array provided by the caller. " NOTE: The first octet of hash is stored in the 0th element, " the last octet of hash in the 19th element. " " Parameters: " context: [in/out] " The context to use to calculate the SHA-1 hash. " Message_Digest: [out] " Where the digest is returned. " " Returns: " sha Error Code. " " "int SHA1Result( SHA1Context *context, " uint8_t Message_Digest[SHA1HashSize]) function s:SHA1Result(context, Message_Digest) if empty(a:context) || empty(a:Message_Digest) return s:shaNull endif if a:context.Corrupted return a:context.Corrupted endif if !a:context.Computed call s:SHA1PadMessage(a:context) for i in range(64) " message may be sensitive, clear it out let a:context.Message_Block[i] = 0 endfor let a:context.Length_Low = 0 " and clear length let a:context.Length_High = 0 let a:context.Computed = 1 endif for i in range(s:SHA1HashSize) let a:Message_Digest[i] = s:uint8( \ s:bitwise_rshift( \ a:context.Intermediate_Hash[s:bitwise_rshift(i, 2)], \ 8 * (3 - s:bitwise_and(i, 0x03)) \ ) \ ) endfor return s:shaSuccess endfunction " " SHA1Input " " Description: " This function accepts an array of octets as the next portion " of the message. " " Parameters: " context: [in/out] " The SHA context to update " message_array: [in] " An array of characters representing the next portion of " the message. " length: [in] " The length of the message in message_array " " Returns: " sha Error Code. " " "int SHA1Input( SHA1Context *context, " const uint8_t *message_array, " unsigned length) function s:SHA1Input(context, message_array) if !len(a:message_array) return s:shaSuccess endif if empty(a:context) || empty(a:message_array) return s:shaNull endif if a:context.Computed let a:context.Corrupted = s:shaStateError return s:shaStateError endif if a:context.Corrupted return a:context.Corrupted endif for x in a:message_array if a:context.Corrupted break endif let a:context.Message_Block[a:context.Message_Block_Index] = s:bitwise_and(x, 0xFF) let a:context.Message_Block_Index += 1 let a:context.Length_Low += 8 if a:context.Length_Low == 0 let a:context.Length_High += 1 if a:context.Length_High == 0 " Message is too long let a:context.Corrupted = 1 endif endif if a:context.Message_Block_Index == 64 call s:SHA1ProcessMessageBlock(a:context) endif endfor return s:shaSuccess endfunction " " SHA1ProcessMessageBlock " " Description: " This function will process the next 512 bits of the message " stored in the Message_Block array. " " Parameters: " None. " " Returns: " Nothing. " " Comments: " Many of the variable names in this code, especially the " single character names, were used because those were the " names used in the publication. " " " " void SHA1ProcessMessageBlock(SHA1Context *context) function s:SHA1ProcessMessageBlock(context) " Constants defined in SHA-1 let K = [ \ 0x5A827999, \ 0x6ED9EBA1, \ 0x8F1BBCDC, \ 0xCA62C1D6 \ ] let t = 0 " Loop counter let temp = 0 " Temporary word value let W = repeat([0], 80) " Word sequence let [A, B, C, D, E] = [0, 0, 0, 0, 0] " Word buffers " " Initialize the first 16 words in the array W " for t in range(16) let W[t] = s:bitwise_lshift(a:context.Message_Block[t * 4], 24) let W[t] = s:bitwise_or(W[t], s:bitwise_lshift(a:context.Message_Block[t * 4 + 1], 16)) let W[t] = s:bitwise_or(W[t], s:bitwise_lshift(a:context.Message_Block[t * 4 + 2], 8)) let W[t] = s:bitwise_or(W[t], a:context.Message_Block[t * 4 + 3]) endfor for t in range(16, 79) let W[t] = s:SHA1CircularShift(1, s:bitwise_xor(s:bitwise_xor(s:bitwise_xor(W[t-3], W[t-8]), W[t-14]), W[t-16])) endfor let A = a:context.Intermediate_Hash[0] let B = a:context.Intermediate_Hash[1] let C = a:context.Intermediate_Hash[2] let D = a:context.Intermediate_Hash[3] let E = a:context.Intermediate_Hash[4] for t in range(20) let temp = s:SHA1CircularShift(5,A) + \ s:bitwise_or(s:bitwise_and(B, C), s:bitwise_and(s:bitwise_not(B), D)) + \ E + W[t] + K[0] let E = D let D = C let C = s:SHA1CircularShift(30,B) let B = A let A = temp endfor for t in range(20, 39) let temp = s:SHA1CircularShift(5,A) + s:bitwise_xor(s:bitwise_xor(B, C), D) + E + W[t] + K[1] let E = D let D = C let C = s:SHA1CircularShift(30,B) let B = A let A = temp endfor for t in range(40, 59) let temp = s:SHA1CircularShift(5,A) + \ s:bitwise_or(s:bitwise_or(s:bitwise_and(B, C), s:bitwise_and(B, D)), s:bitwise_and(C, D)) + \ E + W[t] + K[2] let E = D let D = C let C = s:SHA1CircularShift(30,B) let B = A let A = temp endfor for t in range(60, 79) let temp = s:SHA1CircularShift(5,A) + \ s:bitwise_xor(s:bitwise_xor(B, C), D) + E + W[t] + K[3] let E = D let D = C let C = s:SHA1CircularShift(30,B) let B = A let A = temp endfor let a:context.Intermediate_Hash[0] += A let a:context.Intermediate_Hash[1] += B let a:context.Intermediate_Hash[2] += C let a:context.Intermediate_Hash[3] += D let a:context.Intermediate_Hash[4] += E let a:context.Message_Block_Index = 0 endfunction " " SHA1PadMessage " " Description: " According to the standard, the message must be padded to an even " 512 bits. The first padding bit must be a '1'. The last 64 " bits represent the length of the original message. All bits in " between should be 0. This function will pad the message " according to those rules by filling the Message_Block array " accordingly. It will also call the ProcessMessageBlock function " provided appropriately. When it returns, it can be assumed that " the message digest has been computed. " " Parameters: " context: [in/out] " The context to pad " ProcessMessageBlock: [in] " The appropriate SHA*ProcessMessageBlock function " Returns: " Nothing. " " " void SHA1PadMessage(SHA1Context *context) function s:SHA1PadMessage(context) " " Check to see if the current message block is too small to hold " the initial padding bits and length. If so, we will pad the " block, process it, and then continue padding into a second " block. " if a:context.Message_Block_Index > 55 let a:context.Message_Block[a:context.Message_Block_Index] = 0x80 let a:context.Message_Block_Index += 1 while a:context.Message_Block_Index < 64 let a:context.Message_Block[a:context.Message_Block_Index] = 0 let a:context.Message_Block_Index += 1 endwhile call s:SHA1ProcessMessageBlock(a:context) while a:context.Message_Block_Index < 56 let a:context.Message_Block[a:context.Message_Block_Index] = 0 let a:context.Message_Block_Index += 1 endwhile else let a:context.Message_Block[a:context.Message_Block_Index] = 0x80 let a:context.Message_Block_Index += 1 while a:context.Message_Block_Index < 56 let a:context.Message_Block[a:context.Message_Block_Index] = 0 let a:context.Message_Block_Index += 1 endwhile endif " " Store the message length as the last 8 octets " let a:context.Message_Block[56] = s:uint8(s:bitwise_rshift(a:context.Length_High, 24)) let a:context.Message_Block[57] = s:uint8(s:bitwise_rshift(a:context.Length_High, 16)) let a:context.Message_Block[58] = s:uint8(s:bitwise_rshift(a:context.Length_High, 8)) let a:context.Message_Block[59] = s:uint8(a:context.Length_High) let a:context.Message_Block[60] = s:uint8(s:bitwise_rshift(a:context.Length_Low, 24)) let a:context.Message_Block[61] = s:uint8(s:bitwise_rshift(a:context.Length_Low, 16)) let a:context.Message_Block[62] = s:uint8(s:bitwise_rshift(a:context.Length_Low, 8)) let a:context.Message_Block[63] = s:uint8(a:context.Length_Low) call s:SHA1ProcessMessageBlock(a:context) endfunction " " sha1test.c " " Description: " This file will exercise the SHA-1 code performing the three " tests documented in FIPS PUB 180-1 plus one which calls " SHA1Input with an exact multiple of 512 bits, plus a few " error test checks. " " Portability Issues: " None. " " " " Define patterns for testing " let s:TEST1 = "abc" let s:TEST2a = "abcdbcdecdefdefgefghfghighijhi" let s:TEST2b = "jkijkljklmklmnlmnomnopnopq" let s:TEST2 = s:TEST2a . s:TEST2b let s:TEST3 = "a" let s:TEST4a = "01234567012345670123456701234567" let s:TEST4b = "01234567012345670123456701234567" " an exact multiple of 512 bits let s:TEST4 = s:TEST4a . s:TEST4b let s:testarray = [ \ s:TEST1, \ s:TEST2, \ s:TEST3, \ s:TEST4 \ ] let s:repeatcount = [1, 1, 1000000, 10] let s:resultarray = [ \ "A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C 9C D0 D8 9D", \ "84 98 3E 44 1C 3B D2 6E BA AE 4A A1 F9 51 29 E5 E5 46 70 F1", \ "34 AA 97 3C D4 C4 DA A4 F6 1E EB 2B DB AD 27 31 65 34 01 6F", \ "DE A3 56 A2 CD DD 90 C7 A7 EC ED C5 EB B5 63 93 4F 46 04 52" \ ] function s:main() let sha = deepcopy(s:SHA1Context, 1) let Message_Digest = repeat([0], 20) " " Perform SHA-1 tests " for j in range(len(s:testarray)) if j == 2 echo "Test 3 will take about 1 hour. Press CTRL-C to skip." endif echo "" echo printf("Test %d: %d, '%s'", \ j+1, \ s:repeatcount[j], \ s:testarray[j]) let err = s:SHA1Reset(sha) if err echo printf("SHA1Reset Error %d.", err ) break " out of for j loop endif try for i in range(s:repeatcount[j]) let err = s:SHA1Input(sha, s:str2bytes(s:testarray[j])) if err echo printf("SHA1Input Error %d.", err ) break " out of for i loop */ endif endfor catch /^Vim:Interrupt$/ echo "Skip ..." while getchar(0) | endwhile continue endtry let err = s:SHA1Result(sha, Message_Digest) if err echo printf("SHA1Result Error %d, could not compute message digest.", err) else echo "\t" for i in range(20) echon printf("%02X ", Message_Digest[i]) endfor echo "" endif echo "Should match:" echo printf("\t%s", s:resultarray[j]) endfor " Test some error returns let err = s:SHA1Input(sha, s:str2bytes(s:testarray[1][0:0])) echo printf("\nError %d. Should be %d.", err, s:shaStateError) let err = s:SHA1Reset(0) echo printf("\nError %d. Should be %d.", err, s:shaNull) endfunction "--------------------------------------------------------------------- " misc function! s:str2bytes(str) return map(range(len(a:str)), 'char2nr(a:str[v:val])') endfunction function! s:cmp(a, b) let a = printf("%08x", a:a) let b = printf("%08x", a:b) return a < b ? -1 : a > b ? 1 : 0 endfunction function! s:uint8(n) return s:bitwise_and(a:n, 0xFF) endfunction let s:k = [ \ 0x1, 0x2, 0x4, 0x8, \ 0x10, 0x20, 0x40, 0x80, \ 0x100, 0x200, 0x400, 0x800, \ 0x1000, 0x2000, 0x4000, 0x8000, \ 0x10000, 0x20000, 0x40000, 0x80000, \ 0x100000, 0x200000, 0x400000, 0x800000, \ 0x1000000, 0x2000000, 0x4000000, 0x8000000, \ 0x10000000, 0x20000000, 0x40000000, 0x80000000, \ ] let s:and = [ \ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0], \ [0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1], \ [0x0, 0x0, 0x2, 0x2, 0x0, 0x0, 0x2, 0x2, 0x0, 0x0, 0x2, 0x2, 0x0, 0x0, 0x2, 0x2], \ [0x0, 0x1, 0x2, 0x3, 0x0, 0x1, 0x2, 0x3, 0x0, 0x1, 0x2, 0x3, 0x0, 0x1, 0x2, 0x3], \ [0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4], \ [0x0, 0x1, 0x0, 0x1, 0x4, 0x5, 0x4, 0x5, 0x0, 0x1, 0x0, 0x1, 0x4, 0x5, 0x4, 0x5], \ [0x0, 0x0, 0x2, 0x2, 0x4, 0x4, 0x6, 0x6, 0x0, 0x0, 0x2, 0x2, 0x4, 0x4, 0x6, 0x6], \ [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7], \ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8], \ [0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x8, 0x9, 0x8, 0x9, 0x8, 0x9, 0x8, 0x9], \ [0x0, 0x0, 0x2, 0x2, 0x0, 0x0, 0x2, 0x2, 0x8, 0x8, 0xA, 0xA, 0x8, 0x8, 0xA, 0xA], \ [0x0, 0x1, 0x2, 0x3, 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xA, 0xB, 0x8, 0x9, 0xA, 0xB], \ [0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x8, 0x8, 0x8, 0x8, 0xC, 0xC, 0xC, 0xC], \ [0x0, 0x1, 0x0, 0x1, 0x4, 0x5, 0x4, 0x5, 0x8, 0x9, 0x8, 0x9, 0xC, 0xD, 0xC, 0xD], \ [0x0, 0x0, 0x2, 0x2, 0x4, 0x4, 0x6, 0x6, 0x8, 0x8, 0xA, 0xA, 0xC, 0xC, 0xE, 0xE], \ [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF] \ ] let s:or = [ \ [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF], \ [0x1, 0x1, 0x3, 0x3, 0x5, 0x5, 0x7, 0x7, 0x9, 0x9, 0xB, 0xB, 0xD, 0xD, 0xF, 0xF], \ [0x2, 0x3, 0x2, 0x3, 0x6, 0x7, 0x6, 0x7, 0xA, 0xB, 0xA, 0xB, 0xE, 0xF, 0xE, 0xF], \ [0x3, 0x3, 0x3, 0x3, 0x7, 0x7, 0x7, 0x7, 0xB, 0xB, 0xB, 0xB, 0xF, 0xF, 0xF, 0xF], \ [0x4, 0x5, 0x6, 0x7, 0x4, 0x5, 0x6, 0x7, 0xC, 0xD, 0xE, 0xF, 0xC, 0xD, 0xE, 0xF], \ [0x5, 0x5, 0x7, 0x7, 0x5, 0x5, 0x7, 0x7, 0xD, 0xD, 0xF, 0xF, 0xD, 0xD, 0xF, 0xF], \ [0x6, 0x7, 0x6, 0x7, 0x6, 0x7, 0x6, 0x7, 0xE, 0xF, 0xE, 0xF, 0xE, 0xF, 0xE, 0xF], \ [0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF], \ [0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF], \ [0x9, 0x9, 0xB, 0xB, 0xD, 0xD, 0xF, 0xF, 0x9, 0x9, 0xB, 0xB, 0xD, 0xD, 0xF, 0xF], \ [0xA, 0xB, 0xA, 0xB, 0xE, 0xF, 0xE, 0xF, 0xA, 0xB, 0xA, 0xB, 0xE, 0xF, 0xE, 0xF], \ [0xB, 0xB, 0xB, 0xB, 0xF, 0xF, 0xF, 0xF, 0xB, 0xB, 0xB, 0xB, 0xF, 0xF, 0xF, 0xF], \ [0xC, 0xD, 0xE, 0xF, 0xC, 0xD, 0xE, 0xF, 0xC, 0xD, 0xE, 0xF, 0xC, 0xD, 0xE, 0xF], \ [0xD, 0xD, 0xF, 0xF, 0xD, 0xD, 0xF, 0xF, 0xD, 0xD, 0xF, 0xF, 0xD, 0xD, 0xF, 0xF], \ [0xE, 0xF, 0xE, 0xF, 0xE, 0xF, 0xE, 0xF, 0xE, 0xF, 0xE, 0xF, 0xE, 0xF, 0xE, 0xF], \ [0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF] \ ] let s:xor = [ \ [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF], \ [0x1, 0x0, 0x3, 0x2, 0x5, 0x4, 0x7, 0x6, 0x9, 0x8, 0xB, 0xA, 0xD, 0xC, 0xF, 0xE], \ [0x2, 0x3, 0x0, 0x1, 0x6, 0x7, 0x4, 0x5, 0xA, 0xB, 0x8, 0x9, 0xE, 0xF, 0xC, 0xD], \ [0x3, 0x2, 0x1, 0x0, 0x7, 0x6, 0x5, 0x4, 0xB, 0xA, 0x9, 0x8, 0xF, 0xE, 0xD, 0xC], \ [0x4, 0x5, 0x6, 0x7, 0x0, 0x1, 0x2, 0x3, 0xC, 0xD, 0xE, 0xF, 0x8, 0x9, 0xA, 0xB], \ [0x5, 0x4, 0x7, 0x6, 0x1, 0x0, 0x3, 0x2, 0xD, 0xC, 0xF, 0xE, 0x9, 0x8, 0xB, 0xA], \ [0x6, 0x7, 0x4, 0x5, 0x2, 0x3, 0x0, 0x1, 0xE, 0xF, 0xC, 0xD, 0xA, 0xB, 0x8, 0x9], \ [0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0, 0xF, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8], \ [0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7], \ [0x9, 0x8, 0xB, 0xA, 0xD, 0xC, 0xF, 0xE, 0x1, 0x0, 0x3, 0x2, 0x5, 0x4, 0x7, 0x6], \ [0xA, 0xB, 0x8, 0x9, 0xE, 0xF, 0xC, 0xD, 0x2, 0x3, 0x0, 0x1, 0x6, 0x7, 0x4, 0x5], \ [0xB, 0xA, 0x9, 0x8, 0xF, 0xE, 0xD, 0xC, 0x3, 0x2, 0x1, 0x0, 0x7, 0x6, 0x5, 0x4], \ [0xC, 0xD, 0xE, 0xF, 0x8, 0x9, 0xA, 0xB, 0x4, 0x5, 0x6, 0x7, 0x0, 0x1, 0x2, 0x3], \ [0xD, 0xC, 0xF, 0xE, 0x9, 0x8, 0xB, 0xA, 0x5, 0x4, 0x7, 0x6, 0x1, 0x0, 0x3, 0x2], \ [0xE, 0xF, 0xC, 0xD, 0xA, 0xB, 0x8, 0x9, 0x6, 0x7, 0x4, 0x5, 0x2, 0x3, 0x0, 0x1], \ [0xF, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0] \ ] function! s:bitwise_lshift(a, n) return a:a * s:k[a:n] endfunction function! s:bitwise_rshift(a, n) let a = a:a < 0 ? a:a - 0x80000000 : a:a let a = a / s:k[a:n] if a:a < 0 let a += 0x40000000 / s:k[a:n - 1] endif return a endfunction function! s:bitwise_not(a) return -a:a - 1 endfunction function! s:bitwise_and(a, b) let a = a:a < 0 ? a:a - 0x80000000 : a:a let b = a:b < 0 ? a:b - 0x80000000 : a:b let r = 0 let n = 1 while a && b let r += s:and[a % 0x10][b % 0x10] * n let a = a / 0x10 let b = b / 0x10 let n = n * 0x10 endwhile if (a:a < 0) && (a:b < 0) let r += 0x80000000 endif return r endfunction function! s:bitwise_or(a, b) let a = a:a < 0 ? a:a - 0x80000000 : a:a let b = a:b < 0 ? a:b - 0x80000000 : a:b let r = 0 let n = 1 while a || b let r += s:or[a % 0x10][b % 0x10] * n let a = a / 0x10 let b = b / 0x10 let n = n * 0x10 endwhile if (a:a < 0) || (a:b < 0) let r += 0x80000000 endif return r endfunction function! s:bitwise_xor(a, b) let a = a:a < 0 ? a:a - 0x80000000 : a:a let b = a:b < 0 ? a:b - 0x80000000 : a:b let r = 0 let n = 1 while a || b let r += s:xor[a % 0x10][b % 0x10] * n let a = a / 0x10 let b = b / 0x10 let n = n * 0x10 endwhile if (a:a < 0) != (a:b < 0) let r += 0x80000000 endif return r endfunction let &cpo = s:save_cpo unlet s:save_cpo