Criptografia binária

11

Isso é baseado no xkcd # 153 .

Crie um programa ou função nomeada com dois parâmetros, cada um dos quais é uma sequência de caracteres ou uma lista ou matriz de bytes ou caracteres. O segundo parâmetro conterá apenas caracteres extraídos lrfu(ou os bytes ASCII equivalentes). Deve ser interpretado como uma série de instruções a serem executadas em uma sequência de bits representada pelo primeiro parâmetro.

O processamento realizado deve ser equivalente ao seguinte:

  1. Converta o primeiro parâmetro em uma única cadeia de bits formada concatenando os bits de cada caractere (interpretado como um dos ASCII de 7 bits, um ASCII estendido de 8 bits ou uma codificação Unicode padrão). Por exemplo, se o primeiro parâmetro for "AB", esse seria um de 10000011000010(7 bits), 0100000101000010(8 bits ou UTF-8) 00000000010000010000000001000010ou 01000001000000000100001000000000(UTF-16 nas duas endiannesses), etc.
  2. Para cada caractere no segundo parâmetro, em ordem, execute a instrução correspondente:
    • lgira a sequência de bits da esquerda. Por exemplo, 10000011000010torna-se 00000110000101.
    • rgira a sequência de bits certa. Por exemplo, 10000011000010torna-se 01000001100001.
    • fvira (ou inverte) cada bit na cadeia de bits. Por exemplo, 10000011000010torna-se 01111100111101.
    • uinverte a cadeia de bits. Por exemplo, 10000011000010torna-se 01000011000001.
  3. Converta a sequência de bits em uma sequência ASCII que usa um caractere por bit. Por exemplo, 10000011000010torna-se "10000011000010". Isso ocorre porque nem todos os conjuntos de 7/8 bits têm um caractere atribuído a eles.

Exemplo (em Python):

>>> f("b", "rfu")
01110011

Ele se transforma "b"em sua representação binária ASCII de 8 bits 01100010, gira-o para a direita ( 00110001), vira cada bit ( 11001110) e o inverte ( 01110011).

Flexibilidade

Outros caracteres podem ser usados em vez dos personagens l, r, f, e u, mas eles devem ser claramente documentados.

Placar

Agradecemos ao @Optimizer por criar o seguinte snippet de código. Para usar, clique em "Mostrar trecho de código", role para baixo e clique em "► Executar trecho de código".


fonte
3
Qual pode ser o segundo parâmetro? Pode ser "rrfrburb"? Além disso, quando alguém muda ou reverte os bits, o faz para cada letra individual ou para a cadeia como um todo? Mais casos de teste tornariam isso mais claro.
Xnor
1
Você quer dizer mudar ou girar? um deslocamento à esquerda em C resultará na perda do bit mais à esquerda e do bit mais à direita que se tornará zero. Para uma mudança de direitos em um número não assinado, o inverso acontece. Para um número assinado, não tenho certeza se existe um comportamento definido universalmente para o que é transferido para números negativos (é 0 ou 1?) De qualquer maneira, as informações são sempre perdidas quando uma mudança é realizada, o que não é o caso para rodar.
Level River St
2
FWIW existe uma pergunta com base nesse XKCD .
Peter Taylor
2
@flawr, eu não acho que teria qualquer vantagem sobre a capacidade existente para procurar 'xkcd'
Peter Taylor
1
@KSFT Acho que vou ter que dizer não a isso. Faça uma string juntando-a.

Respostas:

1

CJam, 34 32 bytes

1l+256b2b1>l{~"11W:mm%!<>">4%~}/

Ele usa os seguintes caracteres para obter instruções:

0: left rotation
1: right rotation
2: reverse
3: flip

A entrada é retirada de STDIN com a palavra na primeira linha e a sequência de instruções na segunda linha.

Teste aqui.

Explicação

Obter a sequência de bits é realmente apenas uma questão de interpretar os códigos de caracteres como os dígitos de um número de base 256 (e obter sua representação de base 2). O difícil é que a última conversão de base não irá preencher o resultado com 0s à esquerda. Portanto, adiciono um 1 inicial à entrada inicial e, em seguida, separo esse 1 novamente na representação binária. Como exemplo, se for a entrada ab, transformo isso em uma matriz [1 'a 'b], interpreto isso como base-256 (os caracteres são convertidos automaticamente em códigos de caracteres), que é 90466e a base-2, que é [1 0 1 1 0 0 0 0 1 0 1 1 0 0 0 1 0]. Agora, se eu remover essa liderança 1, tenho o fluxo de bits que estou procurando.

É isso que essa parte do código faz:

1l+256b2b1>

Agora, leio a lista de instruções e executo um bloco para cada caractere na sequência de instruções:

l{...}/

A primeira coisa a fazer é avaliar o caráter e inteiros reais 0, 1, 2ou 3. Agora, a verdadeira mágica do golfe ... dependendo da instrução, quero executar um pequeno pedaço de código que implementa a operação:

Integer:  Code  Operation
0         1m<   "Left rotation";
1         1m>   "Right rotation";
2         W%    "Reverse";
3         :!    "Flip each bit";

Eu poderia armazená-los em uma matriz de blocos e escolher o bloco certo para executar, mas codificá-los em uma string é realmente mais curto:

"11W:mm%!<>">4%~

Primeiro, eu uso o número inteiro associado à instrução para cortar o início da string. Portanto, para rotação à esquerda, a string não é alterada; para rotação à direita, o primeiro caractere é descartado e assim por diante. Então eu seleciono cada quarto caractere da string, começando do primeiro, com 4%. Observe como os quatro trechos de código são distribuídos por toda a cadeia. Finalmente, apenas avalio a string como código ~.

A sequência de bits é impressa automaticamente no final do programa.

Martin Ender
fonte
Por 1m<que ao invés de (+? Você está trabalhando em uma matriz e não em um número, não está?
Peter Taylor
@ Peter oh certo, obrigado. Eu vou consertar isso mais tarde.
Martin Ender
2

CJam, 34 bytes

Outra abordagem no CJam.

1l+256b2b1>l_S/,1&@f=_,,@f{W%~}\f=

O texto de entrada está na primeira linha e as instruções estão na segunda linha.

Instruções:

)        Rotate left.
(        Rotate right.
 (space) Flip.
~        Reverse.
jimmy23013
fonte
1
Isso é bem inteligente. Uma pena que f~não foi implementada, não é? ;)
Martin Ender
2

Pitão 33

jku@[+eGPG+tGhG_Gms!dG)sHwsmjCk2z

Usos:

0    : rotate right
1    : rotate left
2    : reverse order
3    : flip values

Pyth github

Experimente online aqui.

Este é um programa que aceita a cadeia de caracteres como seu primeiro argumento e a cadeia de comandos como o segundo argumento. Na versão online, você deve fornecer as strings separadas por uma nova linha, assim:

AbC
0321

Explicação:

                                    : z=input() (implicit)
jk                                  : join("", ...)
  u@[                 )sHw          : reduce(select from [...] the value at int(H), input(), ...)
     +eGPG                          : [ G[-1] + G[:1],
          +tGhG                     : G[1:] + G[1],
               _G                   : G[::-1],
                 ms!dG              : map(lambda d: int(not(d)), G) ]
                          smjCk2z   : first arg = sum(map(lambda k:convert_to_base(ord(k),2),z)

Algo que eu não conseguia entender: o Pyth reduceusa automaticamente Gpara o valor anterior e Hpara o próximo valor.

FryAmTheEggman
fonte
Perdendo seu toque? Apenas 1 byte menor que CJam?
Optimizer
@Optimizer Na verdade, eu posso superar isso usando as mesmas instruções. Mas não achei que isso seria válido porque o desafio diz "Outras letras podem ser usadas em vez de lrfu, mas devem ser claramente documentadas". (ênfase minha)
Martin Ender
1

Scala - 192

def f(i:String,l:String)=(i.flatMap(_.toBinaryString).map(_.toInt-48)/:l){
case(b,'l')⇒b.tail:+b.head
case(b,'r')⇒b.last+:b.init
case(b,'f')⇒b.map(1-_)
case(b,'u')⇒b.reverse}.mkString
Gilad Hoch
fonte
1

Matlab (166 bytes)

Isso usa letras em abcdvez de lrfurespectivamente.

function D=f(B,C)
D=dec2bin(B,8)';
D=D(:);
g=@circshift;
for c=C
switch c-97
case 0
D=g(D,-1);
case 1
D=g(D,1);
case 2
D=char(97-D);
case 3
D=flipud(D);
end
end
D=D';

Alguns truques usados ​​aqui para economizar espaço:

  • Usando abcdletras me permite subtrair 97uma vez, e, em seguida, as letras tornam-se 0, 1, 2, 3. Isso economiza espaço nas cláusulas switch- case.
  • Definir circshiftcomo uma função anônima de uma letra também economiza espaço, pois é usada duas vezes.
  • Como Dconsiste em '0'e '1'caracteres (códigos ASCII 48e 49), a instrução D=char(97-D)corresponde à inversão entre '0'e '1'valores. Observe que isso 97não tem nada a ver com o mencionado acima.
  • A transposição do conjugado complexo 'é usada em vez da transposição .'.
Luis Mendo
fonte
0

Python 2 - 179

b="".join([bin(ord(i))[2:]for i in input()])
for i in input():b=b[-1]+b[:-1]if i=="r"else b[1:]+b[0]if i=="l"else[str("10".find(j))for j in b]if i=="f"else b[::-1]
print"".join(b)
KSFT
fonte
0

C #, 418 bytes

using System;using System.Collections.Generic;using System.Linq;class P{string F(string a,string o){var f=new Dictionary<char,Func<string,IEnumerable<char>>>{{'l',s=>s.Substring(1)+s[0]},{'r',s=>s[s.Length-1]+s.Substring(0,s.Length-1)},{'u',s=>s.Reverse()},{'f',s=>s.Select(c=>(char)(97-c))}};return o.Aggregate(string.Join("",a.Select(c=>Convert.ToString(c,2).PadLeft(8,'0'))),(r,c)=>new string(f[c](r).ToArray()));}}

Formatado:

using System;
using System.Collections.Generic;
using System.Linq;

class P
{
    string F(string a, string o)
    {
        // define string operations
        var f = new Dictionary<char, Func<string, IEnumerable<char>>>
        {
            {'l', s => s.Substring(1) + s[0]},
            {'r', s => s[s.Length - 1] + s.Substring(0, s.Length - 1)},
            {'u', s => s.Reverse()},
            {'f', s => s.Select(c => (char) (97 - c))}
        };
        // for each operation invoke f[?]; start from converted a
        return o.Aggregate(
            // convert each char to binary string, pad left to 8 bytes and join them
            string.Join("", a.Select(c => Convert.ToString(c, 2).PadLeft(8, '0'))),
            // invoke f[c] on result of prev operation
            (r, c) => new string(f[c](r).ToArray())
        );
    }
}
Krzysztof
fonte
0

J, 164

([: >@:}. (([: }. >&{.) ; >@:{.@:>@:{. 128!:2 >@:}.)^:({.@:$@:>@:{.))@:(>@:((<;._1 ' 1&|."1 _1&|."1 -. |."1') {~ 'lrfu' i. 0&({::)@:]) ; ;@:([: (8$2)&#: a. i. 1&({::)))

Formatado:

nextop=:([: }. >&{.)
exec=: (>@:{.@:>@:{.) apply"1 >@:}.
times=: ({.@:$@:>@:{.)
gapply=: [: >@:}. (nextop ; exec)^:(times) f.

tobin=: ;@:([: (8#2)&#:(a.i.1&{::))
g=:'1&|.';'_1&|.';'-.';'|.'
tog =:  g {~ ('lrfu' i. 0&{::@:])
golf=: gapply @: (>@:tog;tobin)  f.

Exemplo

golf ('rfu';'b')
0 1 1 1 0 0 1 1


golf ('lruuff';'b')
0 1 1 0 0 0 1 0

(8#2)#: 98
0 1 1 0 0 0 1 0

golf ('lruuff';'AB')
0 1 0 0 0 0 0 1 0 1 0 0 0 0 1 0

tobin '';'AB'
0 1 0 0 0 0 0 1 0 1 0 0 0 0 1 0
joebo
fonte
0

JavaScript (E6), 163 167

Totalmente usando a flexibilidade de entrada, uma função nomeada com 2 parâmetros de matriz.

  • Primeiro parâmetro, matriz de bytes correspondente aos códigos de caracteres de 7 bits
  • Segundo parâmetro, matriz de bytes correspondente aos caracteres ascii 'F', 'L', 'R', 'U' -> 70, 76, 82, 85

A função retorna uma sequência de caracteres composta de '1' e '0'

F=(a,s,r='')=>
  a.map(c=>r+=(128|c).toString(2).slice(-7))-
  s.map(c=>a=c<71?a.map(c=>1-c):c<77?a.concat(a.shift):c<83?[a.pop(),...a]:a.reverse(),a=[...r])
  ||a.join('')

Exemplo de f("b", "rfu") conversão para F([98],[82,70,85]), resultado é0111001

Observe que o uso de cadeias de caracteres é muito mais longo em javascript! Contagem de bytes 186

F=(a,s,r='')=>
  [for(c of a)r+=(128|c.charCodeAt()).toString(2).slice(-7)]-
  [for(c of(a=[...r],s))a=c<'G'?a.map(c=>1-c):c<'M'?a.concat(a.shift):c<'S'?[a.pop(),...a]:a.reverse()]
  ||a.join('')

Exemplo F("b", "RFU") , resultado é 0111001novamente

edc65
fonte
0

Ruby, 151

f=->i,s{s.chars.inject(i.unpack("B*")[0]){|a,c|
a.reverse! if c==?u
a.tr!"01","10" if c==?f
a<<a.slice!(1..-1) if c==?l
a<<a.slice!(0..-2) if c==?r
a}}

Bastante direto. Loops através dos personagens se executam uma ação para qualquer um deles.

britishtea
fonte
0

Python 2, 142

j="".join
f=lambda S,I:reduce(lambda s,i:[s[1:]+s[0],s[-1]+s[:-1],s[::-1],j([`1^int(c)`for c in s])][int(i)],I,j([bin(ord(c))[2:]for c in S]))

Semelhante à minha resposta pyth na abordagem: eu construo uma lista de todas as seqüências de caracteres e o indexo com base no valor da sequência de instruções que eu itero usando usando reduzir.

Usos:

0  ->  Rotate left
1  ->  Rotate right
2  ->  Reverse order
3  ->  Invert bits
FryAmTheEggman
fonte