GOST 28147-89 is a standard symmetric encryption based on a Feistel network.



The structure of the algorithm consists of three levels:

   encryption modes - simple replacement, application range, imposing a range of feedback and authentication code generation;
   cycles - 32-З, 32-Р and 16-З, is a repetition of the main step;
   main step, a function that takes a 64-bit block of text and one of the eight 32-bit encryption key elements, and uses the replacement table (8x16 matrix of 4-bit values), and returns encrypted block.


Task

Implement the main step of this encryption algorithm.




with javascript_semantics
constant cbrf = {
      { 4, 10,  9,  2, 13,  8,  0, 14,  6, 11,  1, 12,  7, 15,  5,  3},
      {14, 11,  4, 12,  6, 13, 15, 10,  2,  3,  8,  1,  0,  7,  5,  9},
      { 5,  8,  1, 13, 10,  3,  4,  2, 14, 15, 12,  7,  6,  0,  9, 11},
      { 7, 13, 10,  1,  0,  8,  9, 15, 14,  4,  6, 12, 11,  2,  5,  3},
      { 6, 12,  7,  1,  5, 15, 13,  8,  4, 10,  9, 14,  0,  3, 11,  2},
      { 4, 11, 10,  0,  7,  2,  1, 13,  3,  6,  8,  5,  9, 12, 15, 14},
      {13, 11,  4,  1,  3, 15,  5,  9,  0, 10, 14,  7,  6,  8,  2, 12},
      { 1, 15, 13,  0,  5,  7, 10,  4,  9,  2,  3, 14,  6, 11,  8, 12}}
 
function generate(integer k)
    sequence res = repeat(0,256)
    for i=1 to length(res) do
        integer hdx = floor((i-1)/16)+1,
                ldx = and_bits(i-1,#F)+1
        res[i] = or_bits(cbrf[k][hdx]*#10,cbrf[k-1][ldx])
    end for
    return res
end function
 
constant k87 = generate(8),
         k65 = generate(6),
         k43 = generate(4),
         k21 = generate(2)
 
function r32(atom a)
    if a<0 then a+=#100000000 end if
    return remainder(a,#100000000)
end function
 
function mainstep(sequence input, atom key)
    atom s = r32(input[1]+key)
    s = r32(or_all({k87[and_bits(floor(s/#1000000),#FF)+1]*#1000000,
                    k65[and_bits(floor(s/#0010000),#FF)+1]*#0010000,
                    k43[and_bits(floor(s/#0000100),#FF)+1]*#0000100,
                    k21[and_bits(floor(s/#0000001),#FF)+1]*#0000001}))
    s = r32(s*power(2,11))+floor(s/power(2,32-11))
    s = xor_bits(s,input[2])
    return {s,input[1]}
end function
 
sequence res = mainstep({#043B0421, #04320430}, #E2C104F9)
printf(1,"%08x %08x\n",res)
--or, for other-endian:
sequence s = sprintf("%08x",res[1]),
         t = sprintf("%08x",res[2])
s = reverse(split(join_by(s,1,2,""," ")))
t = reverse(split(join_by(t,1,2,""," ")))
?{s,t}
