Hi Gabriel,
I created a paste with your code at
https://paste.factorcode.org/paste?id=2949 so that long snippets of code
can be posted there instead of the mailing list.
Here's what I would change at first glance:
- "rot-word" is similar to "rotate" in sequences.extras, maybe use that one
instead
- "1 tail" is "rest" in sequences.
- "11 0 <array> 0x01 [ drop xtime ] accumulate nip" -> use "replicate" and
keep the value on the stack
- "4 iota [ X ] 2map" -> [ X ] map-index (and 4 head if the first sequence
is longer than 4 elements)
- [ [ xtime ] times 0 ? ] with map-index -> you are doing the computation
and thowing the result away for unset bits. did you intend to do it to
simplify the stack shuffling ?
Otherwise, it looks pretty idiomatic.
Cheers,
Jon
On Sun, May 26, 2013 at 8:42 PM, Gabriel Kerneis <[email protected]>
wrote:
>
> Dear all,
>
> I've just started (re)learning Factor. As an exercise, I implemented AES
(the
> crypto.aes library has never been finished). Since I still have so much
to
> learn about Factor, I'd be grateful if you could review the code and give
me
> some hints about style, efficiency, etc.
>
> Preliminary note: it would be much more efficient to use lookup tables
(such as
> t-table and d-table provided by crypto.aes), but that wouldn't make a
very good
> exercise. This implementation follows as closely as possible the AES
(FIPS 197)
> standard <http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf>.
>
> Many thanks,
> Gabriel
>
> ! Copyright (C) 2013 Gabriel Kerneis
> ! See http://factorcode.org/license.txt for BSD license.
> USING: kernel sequences grouping math math.order math.parser math.bitwise
> math.bits strings locals arrays make crypto.aes tools.test ;
> IN: fips197
>
> ! Words are represented as arrays of 4 bytes.
> ! A representation based on uint32 would certainly be more
> ! efficient, but [shift-rows] would need significant changes.
>
> : sub-word ( word -- word )
> [ sbox nth ] map ;
>
> : rot-word ( word n -- word )
> cut-slice prepend ;
>
> : xor-word ( word word -- word )
> [ bitxor ] 2map ;
>
> : key-step ( key rcon -- next-key )
> { 0 0 0 } swap prefix
> over last 1 rot-word sub-word
> xor-word
> [ xor-word ] accumulate swap suffix 1 tail ;
>
> : expand-key ( key -- round-keys )
> ! XXX rcon is broken in crypto.aes, missing last round;
> ! let's build directly the values we need here
> 11 0 <array> 0x01 [ drop xtime ] accumulate nip swap
> [ key-step ] accumulate nip ;
>
> : sub-bytes ( state -- state )
> [ sub-word ] map ;
>
> : shift-rows ( state -- state )
> flip 4 iota [ rot-word ] 2map flip ;
>
> ! See FIPS 4.2.1 for the details -- this is very inefficient,
> ! the same operations are performed many times. Fast exponentiation
> ! should be doable with accumulate or produce, instead of map-index.
>
> : nxtime ( x y -- x' )
> make-bits
> [ [ xtime ] times 0 ? ] with map-index
> 0 [ bitxor ] reduce ;
>
> : word-product ( word word -- byte )
> [ nxtime ] 2map
> 0 [ bitxor ] reduce ;
>
> : matrix-product ( word matrix -- word )
> [ word-product ] with map ;
>
> : mix-column ( word -- word )
> { { 2 3 1 1 }
> { 1 2 3 1 }
> { 1 1 2 3 }
> { 3 1 1 2 } } matrix-product ;
>
> : mix-columns ( state -- state )
> [ mix-column ] map ;
>
> : add-round-key ( round-key state -- state )
> [ xor-word ] 2map ;
>
> : aes-round ( round-key state -- state )
> sub-bytes shift-rows mix-columns add-round-key ;
>
>
> : aes-128-encrypt ( expanded-key block -- block )
> [ unclip ] dip add-round-key
> [ unclip-last swap ] dip
> [ swap aes-round ] reduce
> sub-bytes shift-rows add-round-key ;
>
> ! Inverse transformations for decrypt
>
> : inv-shift-rows ( state -- state )
> flip { 0 3 2 1 } [ rot-word ] 2map flip ;
>
> : inv-sub-bytes ( state -- state )
> [ [ inv-sbox nth ] map ] map ;
>
> : inv-mix-column ( word -- word )
> { { 0xe 0xb 0xd 0x9 }
> { 0x9 0xe 0xb 0xd }
> { 0xd 0x9 0xe 0xb }
> { 0xb 0xd 0x9 0xe } } matrix-product ;
>
> : inv-mix-columns ( state -- state )
> [ inv-mix-column ] map ;
>
> : inv-aes-round ( round-key state -- state )
> inv-shift-rows inv-sub-bytes add-round-key inv-mix-columns ;
>
> : aes-128-decrypt ( expanded-key block -- block )
> [ reverse ] dip
> [ unclip ] dip add-round-key
> [ unclip-last swap ] dip
> [ swap inv-aes-round ] reduce
> inv-shift-rows inv-sub-bytes add-round-key ;
>
> ! Example use: decrypt some AES ECB string
> ! XXX Do not use for real-world code; ECB mode is NOT secure.
>
> : cut-padding ( seq -- seq )
> dup last head* ;
>
> : aes-128-ecb-decrypt ( key cipher -- cleartext )
> [ 4 group expand-key ] dip
> 2 [ 4 group ] times
> [ aes-128-decrypt ] with map
> concat concat
> cut-padding ;
>
> ! I also have some unit tests, not shown here.
>
>
>
------------------------------------------------------------------------------
> Try New Relic Now & We'll Send You this Cool Shirt
> New Relic is the only SaaS-based application performance monitoring
service
> that delivers powerful full stack analytics. Optimize and monitor your
> browser, app, & servers with just a few lines of code. Try New Relic
> and get this awesome Nerd Life shirt! http://p.sf.net/sfu/newrelic_d2d_may
> _______________________________________________
> Factor-talk mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/factor-talk
------------------------------------------------------------------------------
Try New Relic Now & We'll Send You this Cool Shirt
New Relic is the only SaaS-based application performance monitoring service
that delivers powerful full stack analytics. Optimize and monitor your
browser, app, & servers with just a few lines of code. Try New Relic
and get this awesome Nerd Life shirt! http://p.sf.net/sfu/newrelic_d2d_may
_______________________________________________
Factor-talk mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/factor-talk