From 5b1507b89b3c688cf92a6c303ec0bf7d5648309a Mon Sep 17 00:00:00 2001 From: Matthias Andreas Benkard Date: Thu, 23 Feb 2012 11:12:47 +0100 Subject: Commit the dormant Threefish implementation. --- cubehash.rkt | 4 +- threefish.rkt | 132 ++++++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 97 insertions(+), 39 deletions(-) diff --git a/cubehash.rkt b/cubehash.rkt index 3aed1f3..9eb8a84 100644 --- a/cubehash.rkt +++ b/cubehash.rkt @@ -61,8 +61,8 @@ (define (cubehash init-rounds rounds/block block-size fin-rounds output-bits) - (λ: ([msg : Bytes]) - (let*: ([state : (Vectorof Word) + (λ: ([msg : Bytes]) + (let*: ([state : (Vectorof Word) (make-vector 32 #x0)] [msg-pad : Bytes (bytes-append msg diff --git a/threefish.rkt b/threefish.rkt index f09ef4c..a9cd8d0 100644 --- a/threefish.rkt +++ b/threefish.rkt @@ -19,7 +19,7 @@ (require "util.rkt") -(provide: [threefish (Bytes Bytes Bytes -> Bytes)]) +(provide: [threefish (Bytes Bytes Bytes (U 'encrypt 'decrypt) -> Bytes)]) (define-type Long Exact-Nonnegative-Integer) @@ -27,6 +27,10 @@ (define (l+ a b) (bitwise-and (+ a b) #xffffffffffffffff)) +(: l- (Long Long -> Long)) +(define (l- a b) + (bitwise-and (- a b) #xffffffffffffffff)) + (: lxor (Long Long -> Long)) (define lxor bitwise-xor) @@ -36,7 +40,14 @@ (bitwise-ior (bitwise-and ash #xffffffffffffffff) (arithmetic-shift ash -64)))) -(define (threefish key tweak plaintext) +(: rrot (Long Exact-Nonnegative-Integer -> Long)) +(define (rrot a e) + (bitwise-ior (arithmetic-shift a (- 64 e)) + (arithmetic-shift a (- e)))) + +(define (threefish key tweak plaintext mode) + (assert (= (bytes-length key) (bytes-length plaintext))) + (assert (= (bytes-length tweak) 16)) (let*: ([size (bytes-length key)] [words (quotient size 8)] [rounds (case size @@ -48,7 +59,7 @@ [(32) #(0 3 2 1)] [(64) #(2 1 4 7 6 5 0 3)] [(128) #(0 9 2 13 6 11 4 15 10 7 12 3 14 5 8 1)] - [else (error "Invalid key size")])] + [else (error "Invalid key size")])] [mixbox : (Vectorof (Vectorof Long)) (case size [(32) #(#( 5 56) @@ -58,7 +69,25 @@ #(26 20) #(53 35) #(11 42) - #(59 50))] + #(59 50)) + #; + #(#(14 16) + #(52 57) + #(23 40) + #( 5 37) + #(25 33) + #(46 12) + #(58 22) + #(32 32)) + #; + #(#(32 32) + #(58 22) + #(46 12) + #(25 33) + #( 5 37) + #(23 40) + #(52 57) + #(14 16))] [(64) #(#(38 30 50 53) #(48 20 43 31) #(34 14 15 27) @@ -77,33 +106,45 @@ #(47 49 27 58 37 48 53 56))] [else (error "Invalid key size")])] [mix - (λ: ([d : Integer] [j : Integer] [x0 : Long] [x1 : Long]) - (let*: ([y0 : Long (l+ x0 x1)] - [y1 : Long - (lxor (lrot x1 - (vector-ref (vector-ref mixbox (modulo d 8)) - j)) - y0)]) - (values y0 y1)))] + (lambda: ([d : Integer] [j : Integer] [x0 : Long] [x1 : Long]) + (let ([rotnum (vector-ref (vector-ref mixbox (if (eq? mode 'encrypt) + (modulo d 8) + (- 8 (modulo d 8)))) + j)]) + (if (eq? mode 'encrypt) + (let*: ([y0 : Long + (l+ x0 x1)] + [y1 : Long + (lxor (lrot x1 rotnum) + y0)]) + (values y0 y1)) + (let*: ([y1 : Long + (rrot (lxor x0 x1) + rotnum)] + [y0 : Long + (l- x0 y1)]) + (values y0 y1)))))] [words->bytes : ((Vectorof Long) -> Bytes) - (λ (v) + (lambda (v) (bytes-append* (reverse (for/fold: ([blocks : (Listof Bytes) '()]) - ([i : Exact-Nonnegative-Integer (in-range words)]) + ([i : Exact-Nonnegative-Integer (in-range (vector-length v))]) (cons (integer->bytes/size (vector-ref v i) 'little-endian 8) blocks)))))] [bytes->word-list : (Bytes -> (Listof Long)) - (λ (b) + (lambda (b) (for/fold: ([words : (Listof Long) '()]) - ([i : Exact-Nonnegative-Integer (in-range words)]) + ([i : Exact-Nonnegative-Integer (in-range (quotient + (bytes-length b) + 8))]) (cons (bytes->integer/le (subbytes b (* i 8) (* (add1 i) 8))) words)))] [bytes->words : (Bytes -> (Vectorof Long)) - (λ (b) + (lambda (b) (list->vector (reverse (bytes->word-list b))))] [key-words : (Vectorof Long) (let ([ks (bytes->word-list key)]) @@ -113,41 +154,49 @@ (foldl lxor (quotient (expt 2 64) 3) ks) ks))))] [tweak-words : (Vectorof Long) - (let ([t0 (bytes->integer/le (subbytes key 0 8))] - [t1 (bytes->integer/le (subbytes key 8 16))]) + (let ([t0 (bytes->integer/le (subbytes tweak 0 8))] + [t1 (bytes->integer/le (subbytes tweak 8 16))]) (vector t0 t1 (lxor t0 t1)))] [key-schedule : (Long Long -> Long) ;; XXX memoize? - (λ: ([s : Long] [i : Long]) + (lambda: ([s : Long] [i : Long]) (let ([k (vector-ref key-words (modulo (l+ s i) (l+ words 1)))]) - (cond - [(= i (- words 1)) - (l+ k s)] - [(= i (- words 2)) - (l+ k (vector-ref tweak-words (modulo (l+ s 1) 3)))] - [(= i (- words 3)) - (l+ k (vector-ref tweak-words (modulo s 3)))] - [else - k])))] + (assert (< i words)) + (l+ k + (cond + [(= i (- words 1)) + s] + [(= i (- words 2)) + (vector-ref tweak-words (modulo (l+ s 1) 3))] + [(= i (- words 3)) + (vector-ref tweak-words (modulo s 3))] + [else + 0]))))] [make-subkey : (Long -> (Vectorof Long)) - (λ: ([s : Long]) + (lambda: ([s : Long]) (list->vector (reverse (for/fold: ([words : (Listof Long) '()]) ([i : Exact-Nonnegative-Integer (in-range words)]) (cons (key-schedule s i) words)))))] [state (bytes->words plaintext)]) + (printf "size: ~a, words: ~a, rounds: ~a~%" size words rounds) (for: ([round : Exact-Nonnegative-Integer (in-range rounds)]) + (printf "Round ~a: ~s~%" round (words->bytes state)) + ;;(printf ".") (let: ([e : (Vectorof Long) (if (zero? (modulo round 4)) - (vector-map l+ + (begin ;;(printf "PLUS!\n") + (vector-map l+ state (make-subkey (quotient round 4))) + ) (vector-copy state))]) - (for: ([j : Exact-Nonnegative-Integer (in-range (quotient words 2))]) + (for: ([j : Exact-Nonnegative-Integer (in-range (quotient words 2))]) + ;;(printf "Mix.\n") (let-values ([(f0 f1) (mix round j @@ -155,11 +204,20 @@ (vector-ref e (add1 (* 2 j))))]) (vector-set! e (* 2 j) f0) (vector-set! e (add1 (* 2 j)) f1))) + ;;(printf "~s~%" (words->bytes e)) (for: ([i : Exact-Nonnegative-Integer (in-range words)]) + ;;(printf "Permute.\n") (vector-set! state i (vector-ref e (vector-ref pbox i)))))) - (for: ([i : Exact-Nonnegative-Integer (in-range words)]) - (vector-set! state - i - (l+ (vector-ref state i) - (key-schedule (quotient rounds 4) i)))) + (vector-map! l+ state (make-subkey (quotient rounds 4))) + ;;(vector-map! lxor state (bytes->words plaintext)) + (vector-map (lambda (x) (printf "~x " x)) state) (words->bytes state))) + +;;; Test vector from the PySkein documentation. +(threefish #"key of 32,64 or 128 bytes length" + ;;(integer->bytes/size #x00 'big-endian 32) + ;;(integer->bytes/size #x00 'big-endian 8) + ;;(integer->bytes/size #x00 'big-endian 32) + #"tweak: 16 bytes " + #"block of data,same length as key" + 'encrypt) -- cgit v1.2.3