! Copyright (C) 2008 Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: accessors checksums checksums.common checksums.stream combinators combinators.smart fry generalizations grouping io.binary kernel literals locals make math math.bitwise math.ranges multiline namespaces sbufs sequences sequences.generalizations sequences.private splitting strings ; 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 { 0x67452301 0xefcdab89 0x98badcfe 0x10325476 0xc3d2e1f0 } CONSTANT: K-sha1 $[ 20 0x5a827999 20 0x6ed9eba1 20 0x8f1bbcdc 20 0xca62c1d6 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-unsafe ] [ [ 15 - ] dip nth-unsafe s0-256 ] [ [ 7 - ] dip nth-unsafe ] [ [ 2 - ] dip nth-unsafe s1-256 w+ w+ w+ ] [ ] } 2cleave set-nth-unsafe ; inline : prepare-M-512 ( n seq -- ) { [ [ 16 - ] dip nth-unsafe ] [ [ 15 - ] dip nth-unsafe s0-512 ] [ [ 7 - ] dip nth-unsafe ] [ [ 2 - ] dip nth-unsafe s1-512 w+ w+ w+ ] [ ] } 2cleave set-nth-unsafe ; 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-unsafe n sha2 K>> nth-unsafe + e H slice3 ch w+ e H nth-unsafe S1-256 w+ h H nth-unsafe w+ ; inline : T2-256 ( H -- T2 ) [ a swap nth-unsafe S0-256 ] [ a swap slice3 maj w+ ] bi ; inline :: T1-512 ( n M H sha2 -- T1 ) n M nth-unsafe n sha2 K>> nth-unsafe + e H slice3 ch w+ e H nth-unsafe S1-512 w+ h H nth-unsafe w+ ; inline : T2-512 ( H -- T2 ) [ a swap nth-unsafe S0-512 ] [ a swap slice3 maj w+ ] bi ; inline : update-H ( T1 T2 H -- ) h g pick exchange-unsafe g f pick exchange-unsafe f e pick exchange-unsafe pick d pick nth-unsafe w+ e pick set-nth-unsafe d c pick exchange-unsafe c b pick exchange-unsafe b a pick exchange-unsafe [ w+ a ] dip set-nth-unsafe ; 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-integer 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{ } concat-as ; : 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-unsafe ] [ [ 8 - ] dip nth-unsafe bitxor ] [ [ 14 - ] dip nth-unsafe bitxor ] [ [ 16 - ] dip nth-unsafe bitxor 1 bitroll-32 ] [ ] } 2cleave set-nth-unsafe ; : 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-unsafe :> A b H nth-unsafe :> B c H nth-unsafe :> C d H nth-unsafe :> D e H nth-unsafe :> E [ A 5 bitroll-32 B C D n sha1-f E n K nth-unsafe n W nth-unsafe ] sum-outputs 32 bits ; :: process-sha1-chunk ( bytes H W K state -- ) 80 [ H W K inner-loop d H nth-unsafe e H set-nth-unsafe c H nth-unsafe d H set-nth-unsafe b H nth-unsafe 30 bitroll-32 c H set-nth-unsafe a H nth-unsafe b H set-nth-unsafe a H set-nth-unsafe ] each-integer 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 ;