<?php

function split_hash($hash, $sizes) {
    $cnt = count($sizes);                   // количество словарей
    $partSize = floor(128/4/$cnt);          // размер части хэша в тетрадах
    $result = array();
    foreach($sizes as $size) {
        $tmp = substr($hash, 0, $partSize); // разбиваем хэш по тетрадам на равные части
        $hash = substr($hash, $partSize);   
        $result[] = gmp_intval(gmp_mod(gmp_init($tmp, 16), $size)); // возвращаем остаток от деления фрагмента хэша 
                                                                    // на размер словаря
    }
    return $result;
}

function R($hash, $dicts) {
    $sizes = array_map(function($val){return count($val);}, $dicts); // получаем размеры каждого словаря
    $indices = split_hash($hash, $sizes);
    $result = '';
    foreach($indices as $dictNumber=>$index) {
        $result .= $dicts[$dictNumber][$index]; // сцепляем слово из частей
    }
    return $result;
}

function make_chain($start, $length, $dicts) {
    for($i = 0; $i < $length; ++$i) {
        $hash = md5($start);
        echo $hash . ' : ' . $start . PHP_EOL;
        $start = R($hash, $dicts);
    }
}

make_chain('свинособака', 10, array(
      array('свино',  'овце', 'тигро', 'косатко', 'зубро', 'волко', 'кото'),
      array('собака', 'бык',  'лев',   'дельфин', 'бизон')
));
