Сделал все байты. Увы, с распаралеливанием у меня совсем никак... % не стал выводить, ибо чтобы их посчитать делить надо каждую итерацию... По нажатию любой клавиши выводится текущий пароль и число уже проверенных. Если найдет правильный пароль - выведет его в ascii и в hex .
Tronix Знаете, что надо еще? чтобы можно было продолжить с заданной итерации. И почему бы не выводить при нажатии на энтер % да надо делить, но я не буду тыкать без умолку). Хотя если ты напишешь продолжение с определенного номера, то и разбить по потоком не должно быть проблемой) вообще я сам мало верю в возможность перебора, просто интересно посмотреть до куда дойдет.
Да, вот что значит отвечать после 11-часового рабочего дня. Конечно в моем посте выше следует читать "система из 256 переменных", и далее : "Если пароль автора 32 символа или меньше, он будет определен однозначно за миллисекунды. Если пароль был длиннее 32 символов, алгоритм даст какую-то 32-байтную строку, ..." Любой циклический код является линейным (здесь в терминах операции сложения по модулю "2"). То есть любой выходной бит можно представить в виде суммы по модулю 2 некоторых входных бит (исходного заполнения и строки пароля). Выходной объем информации в данном кракми - 8х32 бит (256 бит), следовательно, имеем линейную систему из 256 уравнений. Т.к. система линейна и, я полагаю, независима, то она будет однозначно определяема при ровно 256 неизвестных (32-байтном или более коротком пароле), а при большем количестве неизвестных - она станет переопределенной, т.е. будут возможны разные наборы являющиеся решениями. По-прежнему утверждаю, что решение линейной системы из 256 неизвестных по модулю 2 занимает миллисекунды на современной компьютерной технике.
Попытаюсь привести пример на 3-битном коде на основе полинома 101, старший бит слева, сдвиг производим слева направо. Начальное состояние CRC : (c; b; a) Добавляем один бит из обрабатываемой строки "p0" и на основании значения "(крайний правый бит) XOR p0", т.е. "(a) XOR p0" изменяем 2-ой и 0-ой биты (те которые равны "1" в образующем полиноме 101) (биты "предыдущего" значения CRC при этом сдвинулись на 1 позицию вправо): (a XOR p0; c; b XOR a XOR p0) Добавляем следующий бит из обрабатываемой строки "p1" и на основании значения "(b XOR a XOR p0) XOR p1" изменяем 2-ой и 0-ой биты : (b XOR a XOR p0 XOR p1; a XOR p0; c XOR b XOR a XOR p0 XOR p1) Добавляем последний бит из обрабатываемой строки "p2" и на основании значения "(c XOR b XOR a XOR p0 XOR p1) XOR p2" изменяем 2-ой и 0-ой биты : (c XOR b XOR a XOR p0 XOR p1 XOR p2; b XOR a XOR p0 XOR p1; a XOR p0 XOR c XOR b XOR a XOR p0 XOR p1 XOR p2) Пусть итоговое значение было равно 110. Имеем : c XOR b XOR a XOR p0 XOR p1 XOR p2 = 1 b XOR a XOR p0 XOR p1 = 1 a XOR p0 XOR c XOR b XOR a XOR p0 XOR p1 XOR p2 = 0 Не забываем, что мы знаем начальное заполнение (c; b; a). Например, 000. Тогда : p0 XOR p1 XOR p2 = 1 p0 XOR p1 = 1 p1 XOR p2 = 0 дает нам линейную систему из 3 уравнений с 3 неизвестными в матричном виде : 1 1 1 | 1 1 1 0 | 1 0 1 1 | 0 которая решается единственным образом : p0=1, p1=0, p2=0. В данном кракми нужно проделать тоже самое для матрицы в 256 бит (естественно определяя номера бит не вручную, а алгоритмически). Линейную систему для решения проще всего привести к треугольному виду.
Алгоритм решения уже рассказал OLS. В случае, когда разрешены любые значения символов в строке, при 32 символах решение единственно, при меньших значениях решений нет, а дальше число решений начинает расти, умножаясь на 256 с каждым новым байтом. Решение из 32 символов в hex-виде: DF 88 04 11 E4 3E 7C 7E 65 AC 62 65 E1 EE AC E8 FB 6D A4 F6 FB EF 73 B2 F0 7E F7 A4 F6 FF 73 F8 Если ограничиться только символами из первой половины ASCII-таблицы, то принцип решения тот же, только из каждого байта возникает не 8, а только 7 битовых переменных. Ситуация здесь несколько интереснее из-за того, что матрица системы вырождается, в результате чего решение может существовать только при определённых размерах строк (поскольку инициализация CRC здесь традиционная из 0xFFFFFFFF, то свободный член в уравнениях зависит от длины строки) - в данном случае длина должна быть 36. При этом есть 28 свободных бит и, соответственно, 2^28 решений с нулевым старшим битом во всех байтах. Если, например, взять все решения, состоящие только из букв A-Z,a-z, цифр 0-9 и пробела, получается следующий список (полный): jebe wnty1syb6bett1rnb6kizt eye1dbtb jtse wneh1bys6bete rns6kxkt1tyt dbeb ifbf wmwy1sza5beww1qmb6kiyw fze2dbwa jfaf wnwz2pyb5betw2qna6hizt eye1data ieae wmtz2pza6bewt2rma6hiyw fze2dawb jdcd wnux0ryb7betu0snc6jizt eye1dctc kuse wodh0bxs6beud ros6jyku0txu dceb lebc whty1uyd0bert1thd0mizt eye1bdrd ltsc wheh1dyu0bere thu0mxkt1tyt bdcd ldcb whux0tyd1beru0uhe0lizt eye1bere ogca wkvx0tzg2beqv0vke0liyw fze2beqf musc widh0dxu0besd tiu0lyku0txu becd oeac wktz2vzg0beqt2tkg0niyw fze2bgqd mtbs wiey eht bese1dit lxze1eht1rebt mess with the best die like the rest kgce wovx0pzc6beuv0roa4hiyw fze2faub ofac wkwz2uyg0beqw2tkd3mizt eye1adqd lgcb whvx0wzd1berv0uhf3oiyw fze2afre odca wkux0wyg2bequ0vkf3oizt eye1afqf lfbc whwy1vzd0berw1thg3niyw fze2agrd jusd wndh0cxr7betd snr7kyku0txu ebdc kdce woux0syc6beuu0rob7kizt eye1ebub ktsd woeh1cyr7beue sor7jxkt1tyt ecdc kebd woty1ryc7beut1soc7jizt eye1ecuc lusb whdh0ext1berd uht1myku0txu cdbe mdcc wiux0uye0besu0tid1mizt eye1cdsd neab wjtz2wzf1bept2ujf1oiyw fze2cfpe mfaa wiwz2wye2besw2vif1oizt eye1cfsf nfba wjwy1tzf2bepw1vje1liyw fze2cepf mtsb wieh1eyt1bese uit1lxkt1tyt cebe mebb wity1tye1best1uie1lizt eye1cese jeaf wntz2szb5bett2qnb5kiyw fze2gbta ifae wmwz2sya6beww2rmb5kizt eye1gbwb jfbe wnwy1pzb6betw1rna5hiyw fze2gatb itsf wmeh1ayp5bewe qmp5hxkt1tyt gafa iebf wmty1pya5bewt1qma5hizt eye1gawa Внимательный читатель, несомненно, выделит один из вариантов, который явно был исходным паролем, но подходит любой из вышеприведённых.
diamond,OLS - Браво! Тоже пытаюсь систему уравнений составить - возник вопрос (знаний не хватает в этой области): Как учесть тот факт, что Код (Text): table[BYTE(crc32[i] xor longint(ord(pwd[n])))] - выбираемый элемент полинома зависит от предыдущего значения crc и текущего значения байта из пароля. Пока на ум лезет только такая система уравнений: Код (Text): CRC(10) = 0xFFFFFFFF CRC(11) = (CRC(10)>>8)^T[CRC(10)^pwd(1)] CRC(12) = (CRC(11)>>8)^T[CRC(11)^pwd(2)] ... CRC(1N) = (CRC(1N-1)>>8)^T[CRC(1N-1)^pwd(N)] = ~073EE641 = F8C119BE; (отсюда можно найти, кстати, по F8 номер полинома - F862AE69, т.е. BYTE(CRC(1N-1)^pwd(N)) = 0xDE ) CRC(20) = 0xFFFFFFFF CRC(21) = (CRC(20)>>8)^T[CRC(20)^pwd'(1)] CRC(22) = (CRC(21)>>8)^T[CRC(21)^pwd'(2)] ... CRC(2N) = (CRC(2N-1)>>8)^T[CRC(2N-1)^pwd'(N)] = ~6E40EADF; (pwd'(1) - циклический сдвиг вправо pwd(1) на один бит) ... - и так для CRC1-CRC8 - 8 независимых уравнений...
Дело в том, что табличный алгоритм вычисления CRC, который обычно используется в программах, является по существу оптимизацией, обрабатывающей по 8 бит сообщения за раз. Как и многие оптимизации, он затуманивает смысл происходящего. Неоптимизированная версия, обрабатывающая по биту за раз, могла бы выглядеть так: вместо Код (Text): crc32:=$ffffffff; for n:=1 to length(pwd) do begin crc32:=table[BYTE(crc32 xor longint(ord(pwd[n])))] xor (crc32[i] shr 8); end; crc32:=not crc32; тот же самый результат даёт код Код (Text): crc32:=$ffffffff; for n:=1 to length(pwd) do for bit:=0 to 7 do begin if ((crc32 and 1) xor ((ord(pwd[n]) shr bit) and 1)) = 1 then crc32:=(crc32 shr 1) xor $EDB88320 else crc32:=crc32 shr 1 end; crc32:=not crc32; Табличный вариант весь внутренний цикл по битам ужимает в одно обращение к таблице. Теория, кстати, подробно изложена на сайте в разделе "Документы", http://www.wasm.ru/docs/5/crc.zip .
Да, конечно, в моем описании теории решения тоже имеется в виду неоптимизированный побитный алгоритм - в точности так, как приведено выше diamond-ом. Код (Text): fillchar(ucrc32, sizeof(ucrc32), $FF); for n:=1 to length(pwd) do begin for i:=0 to 7 do begin x:=ord(pwd[n]); for b:=0 to 7 do begin if (ucrc32[i] xor x) and 1 = 1 then ucrc32[i]:=(ucrc32[i] shr 1) xor $EDB88320 else ucrc32[i]:=(ucrc32[i] shr 1); x:=x shr 1 end; pwd[n]:=chr((ord(pwd[n]) shr 1) or ((ord(pwd[n]) and 1) shl 7)) end; end; for i:=0 to 7 do ucrc32[i]:=not ucrc32[i];
Вот щас и проверим, кто умеет обращать crc32, а кто тупо брутфорсит с начала до конца и так каждый раз. Задачка =))) есть строка из 100 млн. символов 'a'. Нужно пропатчить ее четырьмя символами подряд из множества a..z,A..Z,0..9 чтобы получить 55555555h. Первое решение это адрес 1F0h строка 'givN' - типа я сам умею =))) Нужно получить следущее за ним реШение o:
Появилось несколько свободных часов времени - решил для себя прояснить реверс CRC32...Может кому тоже будет интересно. CRC32 представляет собой множество 2^32 - соответственно, входная последовательность 32 бит полностью отображается на множестве CRC32. Т.е. любая CRC32 может быть получена из некой последовательности 32 бит. Ниже я приведу два решения реверса CRC32. Задача: по известной CRC32 получить последовательность 32 бит, КС которых соответствует входной(заданной) CRC32. Получим для CRC32 побитовый алгоритм обработки входных данных (см. #27 и #29): Код (Text): CRC32 = 0xFFFFFFFF; // for(i=0;i<NumBits;i++) { l = (CRC32^(pInpBit[i]))&0x01; if(l) CRC32=(CRC32>>1)^dwPoly; else CRC32=(CRC32>>1); } // CRC32 = 0xFFFFFFFF^CRC32; где pInpBit - i-й бит из последовательности входных данных, dwPoly - полином CRC32 (0xEDB88320). Запишем вышеприведенный алгоритм в более простой форме: Код (Text): CRC32 = 0xFFFFFFFF; // for(i=0;i<32;i++) { //l = (CRC32^(pInpBit[i]))&0x01; l = (CRC32^(dwPass>>i))&0x01;//-если входная последовательность - dwPass(32 бит) CRC32=(CRC32>>1); if(l) CRC32=CRC32^dwPoly; } // CRC32 = 0xFFFFFFFF^CRC32; Кстати, из теории - старший бит полинома CRC (dwPoly) равен 1. Предложим первый вариант реверса, основанный на графах. Итак, рассмотрим строки алгоритма: Код (Text): CRC32=(CRC32>>1); if(l) CRC32=CRC32^dwPoly; Отсюда следует - если старший бит результирующей CRC32 равен 1, то на данном шаге выполнялась операция CRC32=CRC32^dwPoly; Причем, информация о старшем бите CRC32 сохраняется на "глубину" 32 шагов - следовательно входная последовательность из 32 бит может быть полностью восстановлена. Далее, привожу пример на С реверса CRC32 (1 вариант). Код (Text): void GraphRevers(DWORD CRC32_Inp) { int i; const DWORD dwPoly = 0xEDB88320; DWORD dwPassRec; DWORD pwd[32]; #define PassBits 32 //reverce printf("\nGraphRevers - %08X\n",CRC32_Inp); //1 DWORD CRC32 = 0xFFFFFFFF^CRC32_Inp; //dwPassRec = 0; //2 for(i=PassBits-1;i>=0;i--) { pwd[i] = CRC32>>31;//теория - вытаскиваем инфорацию //был ли XOR dwPoly на i-ом шаге вычисления CRC32 if(pwd[i]) { //был XOR dwPoly CRC32=CRC32^dwPoly; } // CRC32 = CRC32<<1; } //3 восстанавливаем входную последовательность (32 бит) - dwPassRec dwPassRec = 0; CRC32 = 0xFFFFFFFF; for(i=0;i<PassBits;i++) { //Восстанавливаем i-й бит последовательности dwPassRec|=((pwd[i]^CRC32)&0x01)<<i; CRC32=(CRC32>>1); if(pwd[i]) CRC32=CRC32^dwPoly; } // CRC32 = 0xFFFFFFFF^CRC32; //Здесь можно проверить, что CRC32==CRC32_Inp //if(CRC32==CRC32_Inp) printf("GraphRevers-pass: %08X\n",dwPassRec); }; Пример работы программы: Код (Text): GraphRevers - E951A406 GraphRevers-pass: 01020304 В следующем посте я опишу второй способ реверса CRC32 (общий алгоритм которого был описан OLS в #23 и #24) - составление битовой матрицы уравнений (32х33) и ее решение. Тоже приведу пример кода.
Итак - второй способ реверса CRC32 (общий алгоритм которого был описан OLS в #23 и #24) - составление битовой матрицы уравнений (32х33) и ее решение. Для составления битовой матрицы уравнений для CRC32 в качестве шаблона будем использовать алгоритм вычисления CRC32, приведенный в посте #32: Код (Text): CRC32 = 0xFFFFFFFF; // for(i=0;i<NumBits;i++) { l = (CRC32^(pInpBit[i]))&0x01; CRC32=(CRC32>>1); if(l) CRC32=CRC32^dwPoly; } // CRC32 = 0xFFFFFFFF^CRC32; Сами уравнения p0^p1^p2^...^p(NumBits-1)^P представим в виде битовой строки, где p0,...p(NumBits-1) - есть биты входной последовательности(искомые). Их наличие/отсутствие в уравнении определяется соответствующим битом (1/0) строки, а P - свободный член уравнения тоже определяется соответствующим битом (1/0) строки. Уравнения составляем для каждого бита CRC32 отдельно. Алгоритм решения делится на 2 части: 1)Составляем побитовые уравнения CRC32; 2)Решаем полученную систему уравнений. В коде используются функции, реализующие элементарные операции над битовыми строками: AllocBitString - выделить память под строку; SetBit - установить значение конкретного бита в строке; GetBit - получить значение конкретного бита в строке; XorStrings - выполнить операцию XOR над двумя строками; CopyString - копирование строки; ShowString - визуализация строки. Код этих функций: Код (Text): //Битовое представление: #define BITS_ALLOC 32+1 #define DWORD_ALLOC 2 PDWORD AllocBitString() { return( (PDWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,DWORD_ALLOC*sizeof(DWORD)) ); } BOOL SetBit(PDWORD pdwBitsString,DWORD dwNumBit,DWORD dwBitSet) { DWORD dwNumDWord; DWORD dwNumBitDW; // // if(dwNumBit>=BITS_ALLOC) return FALSE; // dwNumDWord = dwNumBit/(sizeof(DWORD)*8); dwNumBitDW = dwNumBit%(sizeof(DWORD)*8); // pdwBitsString[dwNumDWord]&=~((0x01)<<dwNumBitDW); // if(dwBitSet) pdwBitsString[dwNumDWord]|=(0x01)<<dwNumBitDW; // return TRUE; } DWORD GetBit(PDWORD pdwBitsString,DWORD dwNumBit) { DWORD dwNumDWord; DWORD dwNumBitDW; // DWORD dwBit; // if(dwNumBit>=BITS_ALLOC) return 0; // dwNumDWord = dwNumBit/(sizeof(DWORD)*8); dwNumBitDW = dwNumBit%(sizeof(DWORD)*8); // dwBit=(pdwBitsString[dwNumDWord]>>dwNumBitDW)&0x01; // return dwBit; } void XorStrings(PDWORD pdwBitsString1,PDWORD pdwBitsString2,PDWORD pdwBitsStringRes) { for(DWORD i=0;i<DWORD_ALLOC;i++) { pdwBitsStringRes[i] = pdwBitsString1[i]^pdwBitsString2[i]; } } void CopyString(PDWORD pdwBitsString,PDWORD pdwBitsStringRes) { for(DWORD i=0;i<DWORD_ALLOC;i++) { pdwBitsStringRes[i] = pdwBitsString[i]; } } // void ShowString(PDWORD pdwBitsString) { printf("\n"); for(DWORD n=0;n<BITS_ALLOC;n++)// if(GetBit(pdwBitsString,n)) printf("1"); else printf("0"); } Далее код реверса на С с комментариями: Код (Text): void BitsSytem(DWORD CRC32_Inp) { //Представление уравнений в виде строки: //p0^p1^p2^...^p(n-1)^p(n)^1 //где p0,...p(n) - есть биты входной последовательности(искомые) //Их наличие/отсутствие в уравнении определяется соответствующим битом (1/0) строки //^1 - свободный член уравнения тоже определяется соответствующим битом (1/0) строки // //--------------------------------------------------------------------- //Предварительные объявления: #define MATRIX_SIZE 32 int i,j,k; const DWORD dwPoly = 0xEDB88320; PDWORD pArrayPolinomsCRCs[MATRIX_SIZE]; //Уравнения CRC побитно (указатели на битовые строки) PDWORD pStrNull = AllocBitString(); //Строка с нулевыми битами PDWORD pStrNewBit = AllocBitString(); //Строка для вычисления l = (CRC32^(dwPass>>i))&0x01; crc(0bit)^p(i) for(i=0;i<MATRIX_SIZE;i++) pArrayPolinomsCRCs[i] = AllocBitString(); // //p0^p1^p2^...^p30^p31^1 // printf("\nBitRevers - %08X\n",CRC32_Inp); //--------------------------------------------------------------------- // Составляем побитные уравнения CRC //1) CRC32 = 0xFFFFFFFF; for(i=0;i<MATRIX_SIZE;i++) SetBit(pArrayPolinomsCRCs[i],32,1);//Свободный бит уравнений устанавливаем в 1 //2) for(i=0;i<MATRIX_SIZE;i++)//Количество раундов вычисления CRC (число неизвестных бит): for(i=0;i<32;i++) { //2.1 l = (CRC32^(dwPass>>i))&0x01; -- crc(0bit)^p(i) = pArrayPolinomsCRCs[0]^p(i) CopyString(pArrayPolinomsCRCs[0],pStrNewBit); SetBit(pStrNewBit,i,1); //2.2 CRC32=(CRC32>>1); for(j=0;j<32-1;j++)// { CopyString(pArrayPolinomsCRCs[j+1],pArrayPolinomsCRCs[j]); } CopyString(pStrNull,pArrayPolinomsCRCs[32-1]);//Старший бит CRC обнуляется //2.3 if(l) CRC32=CRC32^dwPoly; for(j=0;j<32;j++)// { if((dwPoly>>j)&0x1) XorStrings(pArrayPolinomsCRCs[j],pStrNewBit,pArrayPolinomsCRCs[j]); } } //3) заносим биты CRC32_Inp для решения в нашу систему (XOR со свободным членом) CRC32_Inp = ~CRC32_Inp; // XorStrings(pStrNewBit,pStrNewBit,pStrNewBit); SetBit(pStrNewBit,32,1); for(i=0;i<32;i++) { if((CRC32_Inp>>i)&0x01) XorStrings(pArrayPolinomsCRCs[i],pStrNewBit,pArrayPolinomsCRCs[i]); } // //Отображаем систему printf("\nSystem:\n"); for(i=0;i<MATRIX_SIZE;i++) ShowString(pArrayPolinomsCRCs[i]); // //--------------------------------------------------------------------- //Решаем полученную систему уравнений (Гаусс) BYTE pArrNumBits[MATRIX_SIZE];//Номера битов (перестановка уравнений) for(i=0;i<MATRIX_SIZE;i++) pArrNumBits[i]=(BYTE)i; //1 Приводим к верхнетреугольному виду for(i=0;i<MATRIX_SIZE;i++) { for(j=i;j<MATRIX_SIZE;j++) { if(GetBit(pArrayPolinomsCRCs[j],i)) { //перестановка уравнений //запоминаем истинное расположение уравнений BYTE bBuf = pArrNumBits[j]; pArrNumBits[j] = pArrNumBits[i]; pArrNumBits[i] = bBuf; //перестановка уравнений CopyString(pArrayPolinomsCRCs[j],pStrNewBit); CopyString(pArrayPolinomsCRCs[i],pArrayPolinomsCRCs[j]); CopyString(pStrNewBit,pArrayPolinomsCRCs[i]); // //Обнуление нижних элементов i-го столбца путем XOR-а уравнений for(k=i+1;k<MATRIX_SIZE;k++) if(GetBit(pArrayPolinomsCRCs[k],i)) XorStrings(pArrayPolinomsCRCs[k],pArrayPolinomsCRCs[i],pArrayPolinomsCRCs[k]); // break; } } // } // //Отображаем систему printf("\nGauss(1 step):\n"); for(i=0;i<MATRIX_SIZE;i++) { ShowString(pArrayPolinomsCRCs[i]); printf(" (%d-bit)",pArrNumBits[i]); } // //2 Обратный ход for(i=MATRIX_SIZE-1;i>=0;i--) { for(j=i-1;j>=0;j--) { if(GetBit(pArrayPolinomsCRCs[j],i)) XorStrings(pArrayPolinomsCRCs[j],pArrayPolinomsCRCs[i],pArrayPolinomsCRCs[j]); } } // //Отображаем систему printf("\nGauss(2 step)\n"); for(i=0;i<MATRIX_SIZE;i++) { ShowString(pArrayPolinomsCRCs[i]); printf(" (%d-bit)",pArrNumBits[i]); } // //Отображаем биты CRC, согласно их истинному расположению (pArrNumBits) CRC32_Inp = 0; for(i=0;i<MATRIX_SIZE;i++) { if(GetBit(pArrayPolinomsCRCs[(pArrNumBits[i])],32)) CRC32_Inp|=(0x01<<i); } // printf("\nBitRevers-pass:%08X\n",CRC32_Inp); } Пример работы программы: Код (Text): BitRevers - E951A406 System: 111110111000000010001011001000000 011111011100000001000101100100001 101111101110000000100010110010000 010111110111000000010001011001001 001011111011100000001000101100101 100101111101110000000100010110010 101100000110111010001001000011000 010110000011011101000100100001100 101011000001101110100010010000111 101011011000110101011010000000011 101011010100011000100110001000000 010101101010001100010011000100001 001010110101000110001001100010001 100101011010100011000100110001001 110010101101010001100010011000101 011001010110101000110001001100010 010010010011010110010011101110001 001001001001101011001001110111000 100100100100110101100100111011101 110010010010011010110010011101110 100111110001001111010010000110111 101101000000100101100010001011010 001000011000010000111010001101100 100100001100001000011101000110110 001100111110000110000101101011010 011000100111000001001001111101100 001100010011100000100100111110110 111000110001110010011001010111011 100010100000111011000111100011100 110001010000011101100011110001110 000110010000001100111010110000111 111101110000000100010110010000011 Gauss(1 step): 111110111000000010001011001000000 (0-bit) 011111011100000001000101100100001 (1-bit) 001110001010000011101100011110001 (2-bit) 000110100001000010111000100011001 (3-bit) 000011010000100001011100010001101 (4-bit) 000001101000010000101110001000111 (5-bit) 000000111000011011110111100000101 (6-bit) 000000011100001101111011110000010 (7-bit) 000000001110000110111101111000001 (8-bit) 000000000101010110000011100000110 (9-bit) 000000000010101011000001110000010 (10-bit) 000000000001101011111100010100101 (11-bit) 000000000000110111000110100011110 (14-bit) 000000000000010000000001110111001 (15-bit) 000000000000001011100010100110110 (12-bit) 000000000000000101110001010011011 (13-bit) 000000000000000011100010011101011 (16-bit) 000000000000000001110001001110101 (17-bit) 000000000000000000110001001001110 (19-bit) 000000000000000000010011011101000 (18-bit) 000000000000000000001011111001111 (20-bit) 000000000000000000000111101011101 (21-bit) 000000000000000000000011110101111 (22-bit) 000000000000000000000001111010111 (23-bit) 000000000000000000000000100101001 (24-bit) 000000000000000000000000011101000 (26-bit) 000000000000000000000000001010110 (25-bit) 000000000000000000000000000100110 (28-bit) 000000000000000000000000000010110 (29-bit) 000000000000000000000000000001000 (27-bit) 000000000000000000000000000000110 (31-bit) 000000000000000000000000000000010 (30-bit) Gauss(2 step) 100000000000000000000000000000000 (0-bit) 010000000000000000000000000000000 (1-bit) 001000000000000000000000000000001 (2-bit) 000100000000000000000000000000000 (3-bit) 000010000000000000000000000000000 (4-bit) 000001000000000000000000000000000 (5-bit) 000000100000000000000000000000000 (6-bit) 000000010000000000000000000000000 (7-bit) 000000001000000000000000000000001 (8-bit) 000000000100000000000000000000001 (9-bit) 000000000010000000000000000000000 (10-bit) 000000000001000000000000000000000 (11-bit) 000000000000100000000000000000000 (14-bit) 000000000000010000000000000000000 (15-bit) 000000000000001000000000000000000 (12-bit) 000000000000000100000000000000000 (13-bit) 000000000000000010000000000000000 (16-bit) 000000000000000001000000000000001 (17-bit) 000000000000000000100000000000000 (19-bit) 000000000000000000010000000000000 (18-bit) 000000000000000000001000000000000 (20-bit) 000000000000000000000100000000000 (21-bit) 000000000000000000000010000000000 (22-bit) 000000000000000000000001000000000 (23-bit) 000000000000000000000000100000001 (24-bit) 000000000000000000000000010000000 (26-bit) 000000000000000000000000001000000 (25-bit) 000000000000000000000000000100000 (28-bit) 000000000000000000000000000010000 (29-bit) 000000000000000000000000000001000 (27-bit) 000000000000000000000000000000100 (31-bit) 000000000000000000000000000000010 (30-bit) BitRevers-pass:01020304 Приведенный алгоритм с минимальными доработками можно использовать для решения задачи, изложенной в #1 посте.