! Copyright (C) 2008 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: kernel splitting grouping math sequences namespaces make io.binary math.bitwise checksums checksums.common sbufs strings combinators.smart math.ranges fry combinators accessors locals checksums.stream multiline literals generalizations ; IN: checksums.sha SINGLETON: sha1 INSTANCE: sha1 stream-checksum SINGLETON: sha-224 SINGLETON: sha-256 INSTANCE: sha-224 stream-checksum INSTANCE: sha-256 stream-checksum TUPLE: sha1-state < checksum-state K H W word-size ; CONSTANT: initial-H-sha1 { HEX: 67452301 HEX: efcdab89 HEX: 98badcfe HEX: 10325476 HEX: c3d2e1f0 } CONSTANT: K-sha1 $[ 20 HEX: 5a827999 20 HEX: 6ed9eba1 20 HEX: 8f1bbcdc 20 HEX: ca62c1d6 4 { } nappend-as ] TUPLE: sha2-state < checksum-state K H word-size ; TUPLE: sha2-short < sha2-state ; TUPLE: sha2-long < sha2-state ; TUPLE: sha-224-state < sha2-short ; TUPLE: sha-256-state < sha2-short ; M: sha2-state clone call-next-method [ clone ] change-H [ clone ] change-K ; ( -- sha1-state ) sha1-state new-checksum-state 64 >>block-size K-sha1 >>K initial-H-sha1 >>H 4 >>word-size ; : ( -- sha2-state ) sha-224-state new-checksum-state 64 >>block-size K-256 >>K initial-H-224 >>H 4 >>word-size ; : ( -- sha2-state ) sha-256-state new-checksum-state 64 >>block-size K-256 >>K initial-H-256 >>H 4 >>word-size ; M: sha1 initialize-checksum-state drop ; M: sha-224 initialize-checksum-state drop ; M: sha-256 initialize-checksum-state drop ; : s0-256 ( x -- x' ) [ [ -7 bitroll-32 ] [ -18 bitroll-32 ] [ -3 shift ] tri ] [ bitxor ] reduce-outputs ; inline : s1-256 ( x -- x' ) [ [ -17 bitroll-32 ] [ -19 bitroll-32 ] [ -10 shift ] tri ] [ bitxor ] reduce-outputs ; inline : S0-256 ( x -- x' ) [ [ -2 bitroll-32 ] [ -13 bitroll-32 ] [ -22 bitroll-32 ] tri ] [ bitxor ] reduce-outputs ; inline : S1-256 ( x -- x' ) [ [ -6 bitroll-32 ] [ -11 bitroll-32 ] [ -25 bitroll-32 ] tri ] [ bitxor ] reduce-outputs ; inline : s0-512 ( x -- x' ) [ [ -1 bitroll-64 ] [ -8 bitroll-64 ] [ -7 shift ] tri ] [ bitxor ] reduce-outputs ; inline : s1-512 ( x -- x' ) [ [ -19 bitroll-64 ] [ -61 bitroll-64 ] [ -6 shift ] tri ] [ bitxor ] reduce-outputs ; inline : S0-512 ( x -- x' ) [ [ -28 bitroll-64 ] [ -34 bitroll-64 ] [ -39 bitroll-64 ] tri ] [ bitxor ] reduce-outputs ; inline : S1-512 ( x -- x' ) [ [ -14 bitroll-64 ] [ -18 bitroll-64 ] [ -41 bitroll-64 ] tri ] [ bitxor ] reduce-outputs ; inline : prepare-M-256 ( n seq -- ) { [ [ 16 - ] dip nth ] [ [ 15 - ] dip nth s0-256 ] [ [ 7 - ] dip nth ] [ [ 2 - ] dip nth s1-256 w+ w+ w+ ] [ ] } 2cleave set-nth ; inline : prepare-M-512 ( n seq -- ) { [ [ 16 - ] dip nth ] [ [ 15 - ] dip nth s0-512 ] [ [ 7 - ] dip nth ] [ [ 2 - ] dip nth s1-512 w+ w+ w+ ] [ ] } 2cleave set-nth ; inline : ch ( x y z -- x' ) [ bitxor bitand ] keep bitxor ; inline : maj ( x y z -- x' ) [ [ bitand ] [ bitor ] 2bi ] dip bitand bitor ; inline : slice3 ( n seq -- a b c ) [ dup 3 + ] dip first3 ; inline GENERIC: pad-initial-bytes ( string sha2 -- padded-string ) :: T1-256 ( n M H sha2 -- T1 ) n M nth n sha2 K>> nth + e H slice3 ch w+ e H nth S1-256 w+ h H nth w+ ; inline : T2-256 ( H -- T2 ) [ a swap nth S0-256 ] [ a swap slice3 maj w+ ] bi ; inline :: T1-512 ( n M H sha2 -- T1 ) n M nth n sha2 K>> nth + e H slice3 ch w+ e H nth S1-512 w+ h H nth w+ ; inline : T2-512 ( H -- T2 ) [ a swap nth S0-512 ] [ a swap slice3 maj w+ ] bi ; inline : update-H ( T1 T2 H -- ) h g pick exchange g f pick exchange f e pick exchange pick d pick nth w+ e pick set-nth d c pick exchange c b pick exchange b a pick exchange [ w+ a ] dip set-nth ; inline : prepare-message-schedule ( seq sha2 -- w-seq ) [ word-size>> [ be> ] map ] [ block-size>> [ 0 pad-tail 16 ] keep [a,b) over '[ _ prepare-M-256 ] each ] bi ; inline :: process-chunk ( M block-size cloned-H sha2 -- ) block-size [ M cloned-H sha2 T1-256 cloned-H T2-256 cloned-H update-H ] each sha2 [ cloned-H [ w+ ] 2map ] change-H drop ; inline M: sha2-short checksum-block [ prepare-message-schedule ] [ [ block-size>> ] [ H>> clone ] [ ] tri process-chunk ] bi ; : seq>byte-array ( seq n -- string ) '[ _ >be ] map B{ } join ; : sha1>checksum ( sha2 -- bytes ) H>> 4 seq>byte-array ; : sha-224>checksum ( sha2 -- bytes ) H>> 7 head 4 seq>byte-array ; : sha-256>checksum ( sha2 -- bytes ) H>> 4 seq>byte-array ; : pad-last-short-block ( state -- ) [ bytes>> t ] [ bytes-read>> pad-last-block ] [ ] tri [ checksum-block ] curry each ; PRIVATE> M: sha-224-state get-checksum clone [ pad-last-short-block ] [ sha-224>checksum ] bi ; M: sha-256-state get-checksum clone [ pad-last-short-block ] [ sha-256>checksum ] bi ; M: sha-224 checksum-stream ( stream checksum -- byte-array ) drop [ ] dip add-checksum-stream get-checksum ; M: sha-256 checksum-stream ( stream checksum -- byte-array ) drop [ ] dip add-checksum-stream get-checksum ; : sha1-W ( t seq -- ) { [ [ 3 - ] dip nth ] [ [ 8 - ] dip nth bitxor ] [ [ 14 - ] dip nth bitxor ] [ [ 16 - ] dip nth bitxor 1 bitroll-32 ] [ ] } 2cleave set-nth ; : prepare-sha1-message-schedule ( seq -- w-seq ) 4 [ be> ] map 80 0 pad-tail 16 80 [a,b) over '[ _ sha1-W ] each ; inline : sha1-f ( B C D n -- f_nbcd ) 20 /i { { 0 [ [ over bitnot ] dip bitand [ bitand ] dip bitor ] } { 1 [ bitxor bitxor ] } { 2 [ 2dup bitand [ pick bitand [ bitand ] dip ] dip bitor bitor ] } { 3 [ bitxor bitxor ] } } case ; :: inner-loop ( n H W K -- temp ) a H nth :> A b H nth :> B c H nth :> C d H nth :> D e H nth :> E [ A 5 bitroll-32 B C D n sha1-f E n K nth n W nth ] sum-outputs 32 bits ; :: process-sha1-chunk ( bytes H W K state -- ) 80 [ H W K inner-loop d H nth e H set-nth c H nth d H set-nth b H nth 30 bitroll-32 c H set-nth a H nth b H set-nth a H set-nth ] each state [ H [ w+ ] 2map ] change-H drop ; inline M:: sha1-state checksum-block ( bytes state -- ) bytes prepare-sha1-message-schedule state (>>W) bytes state [ H>> clone ] [ W>> ] [ K>> ] tri state process-sha1-chunk ; M: sha1-state get-checksum clone [ pad-last-short-block ] [ sha-256>checksum ] bi ; M: sha1 checksum-stream ( stream checksum -- byte-array ) drop [ ] dip add-checksum-stream get-checksum ;