aboutsummaryrefslogtreecommitdiff
path: root/main.sts
blob: 627aeeb572244cdbf73d5b9f3f2a6fe9012c2247 (plain)
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
module ia32/elf/begin.sts
module ia32/float/float.sts
module cipher.sts
module keygen.sts
module freq.sts

[ sd 0 swap drop ]

defword nicedist
    3e9eb852 float_fload
exit

defword calcdist ; distance from ideal as sqrt sum square diff
    1b ref as calcdist.textfr
    local calcdist.fr
    0 do dup 1a = until
        dup word_size mul dup dup
                calcdist.fr + @ float_fload
                calcdist.textfr + @ float_fload
            float_sub float_fstore dup float_fload float_fload
        float_mul float_fstore swap calcdist.fr + !
    1 + od
    0 do dup 19 = until
        swap float_fload swap float_fload float_add float_fstore swap
    1 + od drop
    float_fload float_sqrt nicedist float_less
exit

defword checktext
    as checktext.length
    local checktext.text
        ; Count frequencies:
    ; 26 latin letters:
    0 0 0 0 0  0 0 0 0 0  0 0 0
    0 0 0 0 0  0 0 0 0 0  0 0 0 local checktext.fr
    ; count how much of each letter is in text:
    0 local checktext.count
    checktext.length do 1 -
        dup word_size mul checktext.text + @
        dup dup 'z' > 0 = swap 'a' < 0 = mul if
            dup 'z' swap - word_size mul checktext.fr + dup @ 1 + swap !
            checktext.count 1 + as checktext.count
        fi dup dup 'Z' > 0 = swap 'A' < 0 = mul if
            dup 'Z' swap - word_size mul checktext.fr + dup @ 1 + swap !
            checktext.count 1 + as checktext.count
        fi dup dup 8 > 0 = swap 1 < 0 = mul if drop drop drop
            'x' sys_write_err
            drop drop drop drop drop  drop drop drop drop drop  drop drop drop
            drop drop drop drop drop  drop drop drop drop drop  drop drop drop
        0 exit fi dup dup 1f > 0 = swap e < 0 = mul if drop drop drop
            'U' sys_write_err
            drop drop drop drop drop  drop drop drop drop drop  drop drop drop
            drop drop drop drop drop  drop drop drop drop drop  drop drop drop
        0 exit fi drop
    dup 0 = untilod drop
    ; At least 1/4 characters in text should be alphabetical:
    checktext.count @ float_iload checktext.length float_iload float_div
    1 float_iload 4 float_iload float_div float_more if drop
        drop drop drop drop drop  drop drop drop drop drop  drop drop drop
        drop drop drop drop drop  drop drop drop drop drop  drop drop drop
    0 exit fi
    ; normalize:
    0 do dup 1a = until
            dup word_size mul checktext.fr + dup @ float_iload
            checktext.count @ float_iload
        float_div float_fstore swap !
    1 + od drop
        ; Decide if text is real:
    freq_eng calcdist if 1 else
    0 fi
        ; Remove frequencies from stack:
    sd
    sd sd sd sd sd  sd sd sd sd sd  sd sd sd
    sd sd sd sd sd  sd sd sd sd sd  sd sd sd
exit

set_entry float_init ; this is program with floats
    ; read file into stack
    0 do sys_read 0 = until
        swap 1 +
    od drop as length
    local ciphertext

    0 ; initial key is empty
    do
        ; generate next key to try
        keygen as keylen local key
        '.' sys_write_err

        ; decipher text (length is the same as for ciphertext)
        keylen 1 - length do 1 -
            as textpos local pos
                textpos word_size mul ciphertext + @
                key
                keylen
                pos
            cipher
            swap textpos
        dup 0 = untilod drop drop
        local plaintext

        ; check deciphering attempt, exit if Ok or keylen = max (4)
    keylen 4 = if eeeee else length checktext fi dup until drop
        ; else remove the text from stack and place keylen back
        0 do dup length = until
            swap drop 1 +
        od drop keylen
    od as langcode drop

    ; output language
    langcode 1 = if
        'e' sys_write_err
        'n' sys_write_err
        'g' sys_write_err
        'l' sys_write_err
        'i' sys_write_err
        's' sys_write_err
        'h' sys_write_err
    fi langcode 2 = if
        'd' sys_write_err
        'u' sys_write_err
        't' sys_write_err
        'c' sys_write_err
        'h' sys_write_err
    fi langcode 3 = if
        'g' sys_write_err
        'e' sys_write_err
        'r' sys_write_err
        'm' sys_write_err
        'a' sys_write_err
        'n' sys_write_err
    fi langcode 4 = if
        'f' sys_write_err
        'r' sys_write_err
        'e' sys_write_err
        'n' sys_write_err
        'c' sys_write_err
        'h' sys_write_err
    fi langcode 5 = if
        's' sys_write_err
        'p' sys_write_err
        'a' sys_write_err
        'n' sys_write_err
        'i' sys_write_err
        's' sys_write_err
        'h' sys_write_err
    fi langcode 6 = if
        'i' sys_write_err
        't' sys_write_err
        'a' sys_write_err
        'l' sys_write_err
        'i' sys_write_err
        'a' sys_write_err
        'n' sys_write_err
    fi langcode eeeee = if
        'e' sys_write_err
        'r' sys_write_err
        'r' sys_write_err
        'o' sys_write_err
        'r' sys_write_err
    fi newline sys_write_err

    ; output text
    length do 1 -
        dup word_size mul plaintext + @ sys_write
    dup 0 = untilod drop
    length do 1 -
        swap drop
    dup 0 = untilod drop

    ; output key
    keylen do 1 -
        swap sys_write_err
    dup 0 = untilod drop newline sys_write_err
sys_exit

module ia32/elf/end.sts