-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathans
executable file
·84 lines (76 loc) · 2.8 KB
/
ans
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#!/usr/bin/perl
use strict;
my $def_lpw = 6;
my $def_len = 10;
my $def_key = chr(0) x 64;
my $usage = "usage: ans [-k str] [-n#] [-p] [-w#] [-c] [query]\n".
" -k Key string (may use \"\\x##\" hex sequences) (default ".length($def_key)." zeros)\n".
" -n Chars in answer; should be even (default $def_len)\n".
" -p Do not prompt when reading query from stdin\n".
" -w Letters per word. 0 = no word divisions (default $def_lpw)\n".
" -c Use CVC syllables\n";
use Getopt::Std;
my %opt;
# -----------------------------------------------------------------
main();
sub main {
die $usage if not getopts('ck:n:puw:', \%opt);
my $query = join ' ', @ARGV;
if (not defined $query) {
print '>' unless $opt{p};
$query = <>;
chomp $query;
}
my $len = ($opt{n} or $def_len);
my $key = $def_key;
if ($opt{k}) {
$key = $opt{k};
$key =~ s/\\x([\da-f][\d-af])/chr(hex($1))/eg; # Convert "\xNN" to char with that value
}
my $lpw = (defined $opt{w}) ? $opt{w} : $def_lpw;
print ans($query, $len, $key, $lpw), "\n";
}
# -----------------------------------------------------------------
# Each 2-char syllable is created from one byte of a hash value.
# The hash value is derived from the key k and query q:
# for i < hash.len, the hash used is H0 = sha(k|q).
# for i < 2*hash.len, the hash used is H1 = sha(k|H0)
# for i < 3*hash.len, the hash used is H2 = sha(k|H1)
# etc.
use Digest::SHA;
sub ans {
my ($query, $len, $key, $lpw) = @_;
my $lps = $opt{c} ? 3 : 2; # letters per syllable
my $cons = 'bdfghkmprstvwyz';
my $vowel = 'aeio';
while ($lpw % $lps) { ++$lpw; } # make lpw multiple of lps
while ($len % $lps) { ++$len; }
my $ans = '';
my $h = newh($key, $query);
for (my $ax = 0; $ax < $len; $ax += $lps) {
# Generate syllable from one byte of hash
my $num = hbyte($h);
$ans .= substr($cons, $num % length($cons), 1);
$ans .= substr($vowel, ($num / length($cons)) % length($vowel), 1) if $ax+1 < $len;
if ($lps > 2) {
$num = hbyte($h);
$ans .= substr($cons, $num % length($cons), 1);
}
# Add space if current word has $lpw letters and we're not at end of output.
$ans .= ' ' if $lpw >= $lps and $ax % $lpw == $lpw - $lps and $ax + $lps < $len;
}
return $ans;
}
sub newh {
my ($key, $query) = @_;
return { 'index'=> 0, 'hash'=> '', 'key'=> $key, 'query'=> $query };
}
sub hbyte {
my ($h) = @_;
if ($h->{index} >= length($h->{hash})) {
my $data = (length($h->{hash}) > 0) ? $h->{hash} : $h->{query};
$h->{hash} = Digest::SHA::sha256($h->{key}.'|'.$data);
$h->{index} = 0;
}
return ord(substr($h->{hash}, $h->{index}++, 1));
}