Main step of GOST 28147-89

Implemented to match explanation on Discussion page:

# sboxes from http://en.wikipedia.org/wiki/GOST_(block_cipher)
constant sbox =
    [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];

sub infix:<rol³²>(\y, \n) { (y +< n) % 2**32 +| (y +> (32 - n)) }

sub ГОСТ-round(\R, \K) {
    my \a = (R + K) % 2**32;
    my \b = :16[ sbox[$_][(a +> (4 * $_)) % 16] for 7...0 ];
    b rol³² 11;
}

sub feistel-step(&F, \L, \R, \K) { R, L +^ F(R, K) }

my @input = 0x21, 0x04, 0x3B, 0x04, 0x30, 0x04, 0x32, 0x04;
my @key   = 0xF9, 0x04, 0xC1, 0xE2;

my ($L,$R) = @input.reverse.map: { :256[$^a,$^b,$^c,$^d] }
my ($K   ) = @key\ .reverse.map: { :256[$^a,$^b,$^c,$^d] }

($L,$R) = feistel-step(&ГОСТ-round, $L, $R, $K);

say [ ($L +< 32 + $R X+> (0, 8 ... 56)) X% 256 ].fmt('%02X');

Output:

1F 88 CF 07 21 04 3B 04