123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- \ Elsie-Four (LC4), Copyright 2018 etb, License: GPLv3+
- CREATE K 36 ALLOT \ Key buffer
- CREATE S 36 ALLOT \ State buffer
- CREATE M 0 , \ Marker
- : ->INT ( c -- n)
- DUP [CHAR] # = IF DROP 0 ELSE
- DUP [CHAR] _ = IF DROP 1 ELSE
- DUP [CHAR] 2 >= OVER [CHAR] 9 <= AND IF [ CHAR 2 2 - ]L - ELSE
- DUP [CHAR] a >= OVER [CHAR] z <= AND IF [ CHAR a 10 - ]L - ELSE
- DUP [CHAR] A >= OVER [CHAR] Z <= AND IF [ CHAR A 10 - ]L - ELSE
- ." Warning: mapping '" EMIT ." ' to '_'" CR 1
- THEN THEN THEN THEN THEN ;
- : ->CHAR ( n -- c) >R
- S" #_23456789abcdefghijklmnopqrstuvwxyz" R@ <
- IF [CHAR] * ELSE R@ + C@ THEN R> DROP ;
- CREATE BUF 256 ALLOT CREATE B BUF ,
- : B0 BUF B ! ; : .B BUF B @ BUF - TYPE ;
- : B, B @ C! [ 1 CHARS ]L B +! ;
- CREATE A 0 ,
- : C@A+ ( -- c) A @ C@ 1 CHARS A +! ;
- : A-C! ( c --) A @ 1 CHARS - TUCK C! A ! ;
- : RIGHT-ROTATE ( row --) 6 * S + A !
- C@A+ C@A+ C@A+ C@A+ C@A+ C@A+ >R
- A-C! A-C! A-C! A-C! A-C! R> A-C! ;
- : C@A6+ ( -- c) A @ C@ 6 CHARS A +! ;
- : A6-C! ( c --) A @ 6 CHARS - TUCK C! A ! ;
- : DOWN-ROTATE ( col --) S + A !
- C@A6+ C@A6+ C@A6+ C@A6+ C@A6+ C@A6+ >R
- A6-C! A6-C! A6-C! A6-C! A6-C! R> A6-C! ;
- : S[] ( n -- c) S + C@ ;
- : SFIND ( c -- n) >R
- 0 BEGIN DUP S[] R@ <> WHILE CHAR+ REPEAT R> DROP ;
- : +S ( n n' -- n'') \ Add indices within the state matrix
- 6 /MOD ROT 6 /MOD ROT
- + 6 MOD 6 * >R + 6 MOD R> + ;
- : -S ( n n' -- n'') \ Subtract indices within the state matrix
- 6 /MOD ROT 6 /MOD ROT
- - 6 MOD 6 * >R SWAP - 6 MOD R> + ;
- \ Rather than maintain row and column indices for various markers,
- \ just keep track of the character, and search, via SFIND, for the
- \ index in S when needed.
- : UPDATE ( C P --)
- SFIND 6 / RIGHT-ROTATE \ rotate row of P
- DUP SFIND 6 MOD DOWN-ROTATE \ rotate column of C
- M @ SFIND +S S[] M ! ; \ adjust marker
- : CIPHER ( c --) ->INT
- DUP SFIND M @ ( P P' M)
- +S ( P C') S[] TUCK ( C P C)
- ->CHAR B, UPDATE ;
- : PLAIN ( c --) ->INT
- DUP SFIND M @ ( C C' M)
- -S ( C P') S[] DUP ( C P P)
- ->CHAR B, UPDATE ;
- : (ENCRYPT) ( c-addr u) BOUNDS ?DO I C@ CIPHER LOOP ;
- : (DECRYPT) ( c-addr u) BOUNDS ?DO I C@ PLAIN LOOP ;
- : RESET K S 36 CMOVE 0 S[] M ! ; \ Reset the state matrix and marker
- : ENCRYPT ( nonce u1 header u2 plaintext u3 sig u4)
- RESET
- 2>R 2>R 2SWAP \ save plaintext/sig for later, setup nonce
- (ENCRYPT) B0 \ encrypt the nonce and ignore
- (ENCRYPT) B0 \ encrypt header, if any, and ignore
- 2R> 2R> 2SWAP \ restore sig/plaintext
- (ENCRYPT) \ encrypt the plaintext
- (ENCRYPT) \ append the encrypted sig
- CR ." Ciphertext: " .B CR ;
- : DECRYPT ( nonce u1 header u2 ciphertext u3)
- RESET
- 2SWAP 2ROT \ save ciphertext for later, setup nonce
- (ENCRYPT) B0 \ encrypt the nonce and ignore
- (ENCRYPT) B0 \ encrypt header, if any, and ignore
- (DECRYPT) \ decrypt the ciphertext
- CR ." Plaintext: " .B CR ;
- : S. S A ! 6 0 DO 6 0 DO C@A+ ->CHAR EMIT LOOP SPACE LOOP ;
- : M. SPACE M @ SFIND 6 /MOD . SPACE . SPACE ;
- : TRACE ( c-addr u) CR RESET
- ." State" 38 SPACES ." i j pt ct" CR
- S. M. CR BOUNDS ?DO
- I C@ CIPHER
- S. M. I C@ EMIT 2 SPACES B @ 1 CHARS - C@ EMIT CR
- LOOP ;
- \ Convenience syntax
- : SEND
- BL PARSE \ nonce
- BL PARSE \ header
- BL PARSE \ plaintext
- BL PARSE \ sig
- ENCRYPT ;
- : RECEIVE
- BL PARSE \ nonce
- BL PARSE \ header
- BL PARSE \ ciphertext
- DECRYPT ;
- : PRIV-KEY ( " ccc" --)
- BL WORD COUNT
- 36 <> IF DROP ." ERROR: Key must have length 36" CR QUIT THEN
- A ! 36 0 DO C@A+ ->INT K I + C! LOOP ; IMMEDIATE
- PRIV-KEY XV7YDQ#OPAJ_39RZUT8B45WCSGEHMIKNF26L
- RESET
|