Frecon code: sha.pal
From PROSE Programming Language - Wiki
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % SHA256 Routines for Frecon % Author: Mark R. Bannister % Date: 19/Dec/2017 % % Provides routines for calculating SHA-256 checksums % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ~Module EQUS {[frecon]} ~square_prime EQUD { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 } ~cube_prime EQUD { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 } ._init attr/load P0, [psString], P1, [psPointer] func/def [sha256], &[.sha256], P0, P1, [file] func/def [sha256_convert], &[.sha256_convert], P0, P0, [bin] error/def [BadFileObject], [Argument is not a file object] local/rtn %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Calculate SHA-256 checksum of given file object % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .sha256 var/addr P10, [file] attr/addr P10, P10, [psPointer] % % Check that this is a psFile object and that % it has the psStatUnix class % class/load P8, [psStatUnix] class/test P10, [psFile], P8 reg/jmplt &[.bad_file], SFLG, #2 ne: class/add P10, P8 % % Only possible for regular files % attr/index A, P10, [statMode] opa/and #0170000 reg/jmpeq &[.init_hash], A, #0100000 reg/copy P10, [] reg/save P10, (#64) func/rtn P10 .init_hash % % Initialise hash values h0 to h7 (P0-P7) from square_prime data segment % attr/load P8, [psIndex] reg/load P12, (&[~square_prime]) reg/load P0, (P12) reg/load P1, (P12) reg/load P2, (P12) reg/load P3, (P12) reg/load P4, (P12) reg/load P5, (P12) reg/load P6, (P12) reg/load P7, (P12) % % Initialise array k from cube_prime data segment % mtx/local P14, P8, [w], #64 mtx/local P15, P8, [k], #64 reg/clr A reg/load P12, (&[~cube_prime]) .init_loop reg/load P13, (P12) reg/jmpeq &[.read_file], P13, NULL mtx/set P15, A, P13 op/incr reg/jmplt &[.init_loop], A, #64 .read_file % % Process file in 512-bit chunks % obj/edit P10, P10 class/add P10, [psStreamOpen] attr/add P10, [psStreamMode], [r], [psStreamBufferSize], #1048576, % buffer in 1MB blocks [psStreamReadSize], #64 obj/commitref P10, P10 attr/load P11, [psByteStream] attr/def P8, [psInteger], #0 % length of original message in bits .process reg/jmpne &[.read_next], P8, NULL % read from file if not reached EOF reg/jmpeq &[.digest], PEEK, LOCK % finished, compute digest stack/pull P12 % pull last chunk from stack local/jmp &[.process_chunk] .read_next % % Read next 512 bits from input file % attr/copy P12, P10, P11 reg/jmpeq &[.append_bits_eof], P12, NULL reg/xload P13, (P12) op/mult PUSH, P13, #8 % convert to number of bits opx/add P8, P8, PULL % add onto message length counter reg/jmplt &[.append_bits], P13, #64 .process_chunk % % Copy first 16 words into work array w % At this point, register P12 will contain exactly 512 bits of data % reg/clr A reg/load P13, A .copy16 reg/load PUSH, (P12, A) % read 32 bits at offset A, push to stack mtx/set P14, P13, PULL % store in w[0..15] opa/add #4 % increment A by 32 bits op/incr P13 % increment array index reg/jmplt &[.copy16], P13, #16 % continue while array index < 16 % % Extend first 16 words into remaining 48 words of the work array % .extend % for i (P13) from 16 to 63 reg/load A, P13 opa/sub #15 mtx/get P9, P14, A % w[i-15] attr/index P9, P9 % convert XVALUE to raw index op/ror PUSH, P9, #7 % rightrotate 7, push to stack op/ror PUSH, P9, #18 % rightrotate 18, push to stack op/shr PUSH, P9, #3 % rightshift 3, push to stack op/xor PUSH, PULL, PULL, PULL % xor top 3 items on stack and push back reg/load A, P13 opa/sub #2 mtx/get P9, P14, A % w[i-2] attr/index P9, P9 % convert XVALUE to raw index op/ror PUSH, P9, #17 % rightrotate 17, push to stack op/ror PUSH, P9, #19 % rightrotate 19, push to stack op/shr PUSH, P9, #10 % rightshift 10, push to stack op/xor PUSH, PULL, PULL, PULL % xor top 3 items on stack and push back reg/load A, P13 opa/sub #16 mtx/get P9, P14, A % w[i-16] attr/index PUSH, P9 % convert XVALUE to raw index and push reg/load A, P13 opa/sub #7 mtx/get P9, P14, A % w[i-7] attr/index PUSH, P9 % convert XVALUE to raw index and push op/add PUSH, PULL, PULL, PULL, PULL mtx/set P14, P13, PULL % w[i] = sum of top 4 items on stack op/incr P13 reg/jmplt &[.extend], P13, #64 % loop while i < 64 % % Save current hash value % reg/load PUSH, P7, PUSH, P6, PUSH, P5, PUSH, P4, PUSH, P3, PUSH, P2, PUSH, P1, PUSH, P0 % % Compression loop % stack/push P10 % save P10 reg/clr A .compress op/ror PUSH, P4, #6 % e rightrotate 6, push to stack op/ror PUSH, P4, #11 % e rightrotate 11, push to stack op/ror PUSH, P4, #25 % e rightrotate 25, push to stack op/xor PUSH, PULL, PULL, PULL % xor top 3 items on stack and push back op/and PUSH, P4, P5 % e and f op/not PUSH, P4 % not e op/and PUSH, PULL, P6 % and g op/xor PUSH, PULL, PULL % xor top 2 items on stack and push back mtx/get PUSH, P15, A % k[i] attr/index PUSH, PULL % convert XVALUE to raw index mtx/get PUSH, P14, A % w[i] attr/index PUSH, PULL % convert XVALUE to raw index op/add P9, P7, PULL, PULL, % temp1 (P9) = sum of h with top PULL, PULL % 4 items on stack op/ror PUSH, P0, #2 % a rightrotate 2 op/ror PUSH, P0, #13 % a rightrotate 13 op/ror PUSH, P0, #22 % a rightrotate 22 op/xor PUSH, PULL, PULL, PULL % xor top 3 items on stack and push back op/and PUSH, P0, P1 % a and b op/and PUSH, P0, P2 % a and c op/and PUSH, P1, P2 % b and c op/xor PUSH, PULL, PULL, PULL % xor top 3 items on stack and push back op/add P10, PULL, PULL % temp2 (P10) = sum of top 2 stack items reg/roll #-1, #8 % roll registers P0-P7 right op/add P0, P9, P10 % a = temp1 + temp2 op/add P4, P4, P9 % e += temp1 op/incr reg/jmplt &[.compress], A, #64 % loop while i < 64 stack/pull P10 % restore register P10 % % Add the compressed chunk to the current hash value pushed on stack earlier % op/add P0, P0, PULL op/add P1, P1, PULL op/add P2, P2, PULL op/add P3, P3, PULL op/add P4, P4, PULL op/add P5, P5, PULL op/add P6, P6, PULL op/add P7, P7, PULL local/jmp &[.process] .append_bits_eof % % Reached EOF with no new data, we now require 0x80 % followed by 55 null bytes then the length of the % original message as a 64-bit big endian integer % reg/copy P12, [] reg/save P12, (#64) % set-up new zeroed 512-bit chunk reg/save P12, (#0x80000000, #0) % set the first bit .end_chunk attr/export PUSH, P8, #9 % export data size in bits as big endian reg/copy PUSH, (PULL, #1) % discard the sign byte reg/save P12, (PULL, #56) % write to end of 512-bit chunk reg/load P8, NULL % set P8 to NULL to indicate last chunk local/jmp &[.process_chunk] .append_bits % % Reached final chunk of file which is less than 512 bits % % If there are at least 9 bytes remaining before the end of the chunk % then we write 0x80 ... null bytes ... 64-bit integer (message length) % and finish, otherwise we write 0x80 ... null bytes ... and go round again % reg/save P12, (#64) % expand current chunk to 512 bits reg/save P12, (#0x80000000, P13) % set the first bit of the expansion reg/jmple &[.end_chunk], P13, #55 % last chunk to process .two_more_chunks attr/export PUSH, P8, #64 % push 2nd chunk to stack for later reg/load P8, NULL % set P8 to NULL to indicate last chunk local/jmp &[.process_chunk] .digest % % Generate the final hash value % reg/copy P8, [] reg/save P8, (#32) reg/save P8, (P0, #0x00) reg/save P8, (P1, #0x04) reg/save P8, (P2, #0x08) reg/save P8, (P3, #0x0c) reg/save P8, (P4, #0x10) reg/save P8, (P5, #0x14) reg/save P8, (P6, #0x18) reg/save P8, (P7, #0x1c) func/rtn P8 .bad_file error/now ![.prose.error.frecon.BadFileObject] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Convert SHA-256 in binary format to a hexadecimal string % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .sha256_convert var/addr P0, [bin] attr/copy P0, P0, [psString] reg/copy P1, [] reg/save P1, (#64) attr/load P15, [psIndex] reg/clr A .convert_loop reg/copy P2, (P0, A, #4) attr/import P3, P15, P2 attr/index P3, P3 reg/conv P3, P3, #16 op/shl P4, A, #1 reg/save P1, (P3, P4) opa/add #4 reg/jmplt &[.convert_loop], A, #32 func/rtn P1