Considérez que vous avez une fonction de hachage qui prend des chaînes de longueur et renvoie des chaînes de longueur et a la belle propriété d'être résistante aux collisions , c'est-à-dire qu'il est difficile de trouver deux chaînes différentes avec le même hachage .
Vous souhaitez maintenant construire une nouvelle fonction de hachage qui prend des chaînes de longueur arbitraire et les mappe sur des chaînes de longueur , tout en étant résistant aux collisions.
Heureusement pour vous, déjà en 1979, une méthode maintenant connue sous le nom de construction Merkle – Damgård a été publiée et permet d'atteindre exactement ce résultat.
La tâche de ce défi sera d'implémenter cet algorithme, nous allons donc d'abord regarder une description formelle de la construction Merkle – Damgård, avant de passer par un exemple étape par étape qui devrait montrer que l'approche est plus simple que cela pourrait apparaître au premier abord.
Étant donné un entier , une fonction de hachage comme décrit ci-dessus et une chaîne d'entrée de longueur arbitraire, la nouvelle fonction de hachage fait ce qui suit:
- Réglez , la longueur de , et fractionnez en morceaux de longueur , remplissant le dernier morceau avec des zéros de fin si nécessaire. Cela donne nombreux morceaux étiquetés.
- Ajoutez un morceau de tête et un morceau de fin et , où est une chaîne composée de zéros et est en binaire, avec des zéros non significatifs à la longueur .
- Appliquons maintenant de manière itérative au morceau courant ajouté au résultat précédent : , où . (Cette étape pourrait être plus claire après avoir examiné l'exemple ci-dessous.)
- La sortie de est le résultat final .
La tâche
Ecrivez un programme ou une fonction qui prend en entrée un entier positif , une fonction de hachage comme boîte noire et une chaîne non vide et renvoie le même résultat que sur les mêmes entrées.
Il s'agit de code-golf , donc la réponse la plus courte dans chaque langue l'emporte.
Exemple
Disons que , notre fonction de hachage donnée prend des chaînes de longueur 10 et renvoie des chaînes de longueur 5.
- Étant donné une entrée de , nous obtenons les morceaux suivants: , , et . Notez que devait être complété à la longueur 5 avec un zéro à la fin.
- est juste une chaîne de cinq zéros et est cinq en binaire ( ), complété par deux zéros non significatifs.
- Maintenant, les morceaux sont combinés avec :
- is our output.
Let's have a look how this output would look depending on some choices1 for :
- If , i.e. just returns every second character, we get:
So needs to be the output if such a is given as black box function. - If simply returns the first 5 chars of its input, the output of is . Similarly if returns the last 5 chars, the output is .
- If multiplies the character codes of its input and returns the first five digits of this number, e.g. , then .
1 For simplicity, those are actually not collision resistant, though this does not matter for testing your submission.
omgPzzles0
. Well chosen example input!Réponses:
Haskell,
919086 bytesTry it online!
Explanation
Just assigns the stringn times) to
"00...0"
('0'
a
The functionn ), n characters of
?
implements the recursive application ofh
:c
is the hash we have obtained so far (lengthz
is the rest of the string. Ifz
is empty then we simply returnc
, otherwise we take the firstz
(possibly padding with zeros froma
), prependc
and applyh
. This gives the new hash, and then we call?
recursively on this hash and the remaining characters ofz
.The functionn .
!
is the one actually solving the challenge. It takesn
,h
ands
(implicit) as inputs. We computea?s
, and all we have to do is appendn
in binary and applyh
once more.mapM(:"1")a!!n
returns the binary representation ofla source
let
in a guard is shorter than usingwhere
: Try it online!mapM(\_->"01")a
can bemapM(:"1")a
.R,
159154 bytesTry it online!
Yuck! Answering string challenges in R is never pretty, but this is horrible. This is an instructive answer on how not to write "normal" R code...
Thanks to nwellnhof for fixing a bug, at a cost of 0 bytes!
Thanks to J.Doe for swapping the operator aliasing to change the precedence, good for -4 bytes.
The explanation below is for the previous version of the code, but the principles remain the same.
la source
0*(n-(?s)%%n)
doesn't work if n divides s evenly. But0*-((?s)%%-n)
should work.seq
has1
as itsfrom
argument by default.C (gcc), 251 bytes
Try it online!
Not as clean as the bash solution, and highly improvable.
The function is
f
takingH
as a function that replaces its string input with that string's hash,n
as in the description, andx
the input string and output buffer.Description:
la source
Ruby, 78 bytes
Try it online!
How it works:
la source
Jelly, 23 bytes
Try it online!
AcceptsH at the line above it, s as its left argument, and n as its right argument.
la source
Bash, 127-ε bytes
Try it online!
This works as a program/function/script/snippet. H must be resolveable to a program or function that will perform the hashing. N is the argument. Example call:
Description:
This creates a string of
$1
zeroes. This works by calling printf and telling it to print an integer padded to extra argument width. That extra argument we pass is$1
, the argument to the program/function/script which stores n.This merely copies Z, our zero string, to R, our result string, in preparation for the hashing loop.
This loops over the input every
$1
(n) characters loading the read characters into c. If the input ends then c merely ends up too short. Ther
option ensures that any special characters in the input don't get bash-interpreted. This is the-ε
in the title - thatr
isn't strictly necessary, but makes the function more accurately match the input.This concatenates the n characters read from input to R along with zeroes for padding (too many zeroes for now).
This uses a here string as input to the hash function. The contents
${R::2*$1}
are a somewhat esoteric bash parameter substitution which reads: R, starting from 0, only 2n characters.Here the loop ends and we finish with:
Here the same format string trick is used to 0 pad the number.
bc
is used to convert it to binary by setting the output base (obase) to 2. The result is passed to the hash function/program whose output is not captured and thus is shown to the user.la source
r
flag. I figured 1 byte doesn't really matter, but if pushed I could shave it.read
command?Pyth, 24 bytes
Since Pyth doesn't allow H to be used for a function name, I use
y
instead.Try it online! Example is with the "every second character" version of H.
la source
Perl 6,
7968 bytesTry it online!
Explanation
la source
Clean, 143 bytes
Try it online!
la source
Python 2,
126113 bytesTry it online!
-13 thanks to Triggernometry.
Yeah, this is an abomination, why can't I just use a built-in to split a string into chunks...? :-(
la source
while
loop is the best builtin I could hope for. 104 bytes'0'*~-n
instead of'0'*(len(s)%n)
is shorter (and actually correct for shorter inputs).Programming Puzz
(16 chars). Replacing'0'*(len(s)%n)
with'0'*~-n
fixes that and saves 7 bytes.Python 2,
106102 bytesFor once, the function outgolfs the lambda. -4 bytes for simple syntax manipulation, thanks to Jo King.
Try it online!
la source
Japt, 27 bytes
Try it!
I haven't found any capability for Japt to take functions directly as an input, so this takes a string which is interpreted as Japt code and expects it to define a function. Specifically,H that takes characters at odd indexes, while this one is the "multiply char-codes and take the 5 highest digits" example.
OvW
takes the third input and interprets it as Japt, theng
calls it. Replacing that withOxW
allows input as a Javascript function instead, or if the function were (somehow) already stored in W it could just beW
and save 2 bytes. The link above has the worked example ofDue to the way Japt takes inputs,s will be n will be H will be
U
,V
, andW
Explanation:
la source
GolfScript, 47 bytes
Try it online!
la source
oK, 41 bytes
Try it online!
la source