From df63ff6208209c356d0448f90892cea56fc0e4f3 Mon Sep 17 00:00:00 2001 From: Fang Date: Thu, 19 Jul 2018 21:47:06 +0200 Subject: [PATCH] Add argon2 and blake2b to zuse --- sys/zuse.hoon | 685 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 685 insertions(+) diff --git a/sys/zuse.hoon b/sys/zuse.hoon index 2d50cfe5c..549939634 100644 --- a/sys/zuse.hoon +++ b/sys/zuse.hoon @@ -3497,6 +3497,691 @@ -- -- -- + :: + ++ blake + ~% %blake ..is ~ + |% + ::TODO generalize for both blake2 variants + ++ blake2b + ~/ %blake2b + |= [msg=byts key=byts out=@ud] + ^- @ + :: initialization vector + =/ iv=@ + 0x6a09.e667.f3bc.c908. + bb67.ae85.84ca.a73b. + 3c6e.f372.fe94.f82b. + a54f.f53a.5f1d.36f1. + 510e.527f.ade6.82d1. + 9b05.688c.2b3e.6c1f. + 1f83.d9ab.fb41.bd6b. + 5be0.cd19.137e.2179 + :: per-round constants + =/ sigma=(list (list @ud)) + :~ + :~ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 == + :~ 14 10 4 8 9 15 13 6 1 12 0 2 11 7 5 3 == + :~ 11 8 12 0 5 2 15 13 10 14 3 6 7 1 9 4 == + :~ 7 9 3 1 13 12 11 14 2 6 5 10 4 0 15 8 == + :~ 9 0 5 7 2 4 10 15 14 1 11 12 6 8 3 13 == + :~ 2 12 6 10 0 11 8 3 4 13 7 5 15 14 1 9 == + :~ 12 5 1 15 14 13 4 10 0 7 6 3 9 2 8 11 == + :~ 13 11 7 14 12 1 3 9 5 0 15 4 8 6 2 10 == + :~ 6 15 14 9 11 3 0 8 12 2 13 7 1 4 10 5 == + :~ 10 2 8 4 7 6 1 5 15 11 9 14 3 12 13 0 == + :~ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 == + :~ 14 10 4 8 9 15 13 6 1 12 0 2 11 7 5 3 == + == + => |% + ++ get-word-list + |= [h=@ w=@ud] + ^- (list @) + %- flop + =+ l=(rip 6 h) + =- (weld - l) + (reap (sub w (lent l)) 0) + :: + ++ get-word + |= [h=@ i=@ud w=@ud] + ^- @ + %+ snag i + (get-word-list h w) + :: + ++ put-word + |= [h=@ i=@ud w=@ud d=@] + ^- @ + %+ rep 6 + =+ l=(get-word-list h w) + %- flop + %+ weld (scag i l) + [d (slag +(i) l)] + :: + ++ mod-word + |* [h=@ i=@ud w=@ud g=$-(@ @)] + (put-word h i w (g (get-word h i w))) + :: + ++ pad + |= [byts len=@ud] + (lsh 3 (sub len wid) dat) + :: + ++ compress + |= [h=@ c=@ t=@ud l=?] + ^- @ + :: set up local work vector + =+ v=(add (lsh 6 8 h) iv) + :: xor the counter t into v + =. v + %- mod-word + :^ v 12 16 + (cury mix (end 0 64 t)) + =. v + %- mod-word + :^ v 13 16 + (cury mix (rsh 0 64 t)) + :: for the last block, invert v14 + =? v l + %- mod-word + :^ v 14 16 + (cury mix 0xffff.ffff.ffff.ffff) + :: twelve rounds of message mixing + =+ i=0 + =| s=(list @) + |^ + ?: =(i 12) + :: xor upper and lower halves of v into state h + =. h (mix h (rsh 6 8 v)) + (mix h (end 6 8 v)) + :: select message mixing schedule and mix v + =. s (snag (mod i 10) sigma) + =. v (do-mix 0 4 8 12 0 1) + =. v (do-mix 1 5 9 13 2 3) + =. v (do-mix 2 6 10 14 4 5) + =. v (do-mix 3 7 11 15 6 7) + =. v (do-mix 0 5 10 15 8 9) + =. v (do-mix 1 6 11 12 10 11) + =. v (do-mix 2 7 8 13 12 13) + =. v (do-mix 3 4 9 14 14 15) + $(i +(i)) + :: + ++ do-mix + |= [na=@ nb=@ nc=@ nd=@ nx=@ ny=@] + ^- @ + =- =. v (put-word v na 16 a) + =. v (put-word v nb 16 b) + =. v (put-word v nc 16 c) + (put-word v nd 16 d) + %- b2mix + :* (get-word v na 16) + (get-word v nb 16) + (get-word v nc 16) + (get-word v nd 16) + (get-word c (snag nx s) 16) + (get-word c (snag ny s) 16) + == + -- + :: + ++ b2mix + |= [a=@ b=@ c=@ d=@ x=@ y=@] + ^- [a=@ b=@ c=@ d=@] + =. x (rev 3 8 x) + =. y (rev 3 8 y) + =+ fed=~(. fe 6) + =. a :(sum:fed a b x) + =. d (ror:fed 0 32 (mix d a)) + =. c (sum:fed c d) + =. b (ror:fed 0 24 (mix b c)) + =. a :(sum:fed a b y) + =. d (ror:fed 0 16 (mix d a)) + =. c (sum:fed c d) + =. b (ror:fed 0 63 (mix b c)) + [a b c d] + -- + :: ensure inputs adhere to contraints + =. out (max 1 (min out 64)) + =. wid.msg (min wid.msg (bex 128)) + =. wid.key (min wid.key 64) + =. dat.msg (end 3 wid.msg dat.msg) + =. dat.key (end 3 wid.key dat.key) + :: initialize state vector + =+ h=iv + :: mix key length and output length into h0 + =. h + %- mod-word + :^ h 0 8 + %+ cury mix + %+ add 0x101.0000 + (add (lsh 3 1 wid.key) out) + :: keep track of how much we've compressed + =* mes dat.msg + =+ com=0 + =+ rem=wid.msg + :: if we have a key, pad it and prepend to msg + =? mes (gth wid.key 0) + (can 3 ~[rem^mes 128^(pad key 128)]) + =? rem (gth wid.key 0) + (add rem 128) + |- + :: compress 128-byte chunks of the message + ?: (gth rem 128) + =+ c=(cut 3 [(sub rem 128) 128] mes) + =. com (add com 128) + %_ $ + rem (sub rem 128) + h (compress h c com |) + == + :: compress the final bytes of the msg + =+ c=(cut 3 [0 rem] mes) + =. com (add com rem) + =. c (pad [rem c] 128) + =. h (compress h c com &) + :: produce output of desired length + %^ rsh 3 (sub 64 out) + :: do some word + %+ rep 6 + %+ turn (flop (gulf 0 7)) + |= a=@ + (rev 3 8 (get-word h a 8)) + -- ::blake + :: + ++ argon2 + ~% %argon ..is ~ + |% + :: + :: structures + :: + += argon-type ?(%d %i %id %u) + :: + :: shorthands + :: + ++ argon2-minimal + (argon2 32 %id 0x13 1 8 1 *byts *byts) + :: + ::TODO discuss and standardize? + ++ argon2-urbit + (argon2 64 %u 0x13 4 1.024 10 *byts *byts) + :: + :: argon2 proper + :: + :: main argon2 operation + ++ argon2 + :: out: desired output size in bytes + :: typ: argon2 type + :: version: argon2 version (0x10/v1.0 or 0x13/v1.3) + :: threads: amount of threads/parallelism + :: mem-cost: kb of memory to use + :: time-cost: iterations to run + :: key: optional secret + :: extra: optional arbitrary data + |= $: out=@ud + typ=argon-type + version=@ux + :: + threads=@ud + mem-cost=@ud + time-cost=@ud + :: + key=byts + extra=byts + == + ^- $-([msg=byts sat=byts] @) + :: + :: check configuration sanity + :: + ?: =(0 threads) + ~| %parallelism-must-be-above-zero + !! + ?: =(0 time-cost) + ~| %time-cost-must-be-above-zero + !! + ?: (lth mem-cost (mul 8 threads)) + ~| :- %memory-cost-must-be-at-least-threads + [threads %times 8 (mul 8 threads)] + !! + ?. |(=(0x10 version) =(0x13 version)) + ~| [%unsupported-version version %want [0x10 0x13]] + !! + :: + :: calculate constants and initialize buffer + :: + :: for each thread, there is a row in the buffer. + :: the amount of columns depends on the memory-cost. + :: columns are split into groups of four. + :: a single such quarter section of a row is a segment. + :: + :: blocks: (m_prime) + :: columns: row length (q) + :: seg-length: segment length + =/ blocks=@ud + :: round mem-cost down to the nearest multiple of 4*threads + =+ (mul 4 threads) + (mul (div mem-cost -) -) + =+ columns=(div blocks threads) + =+ seg-length=(div columns 4) + :: + =/ buffer=(list (list @)) + (reap threads (reap columns 0)) + :: + :: main function + :: + :: msg: the main input + :: sat: optional salt + ~% %argon2 ..argon2 ~ + |= [msg=byts sat=byts] + ^- @ + ?: (lth wid.sat 8) + ~| [%min-salt-length-is-8 wid.sat] + !! + :: + :: h0: initial 64-byte block + =/ h0=@ + =- (blake2b:blake - 0^0 64) + :- :(add 40 wid.msg wid.sat wid.key wid.extra) + %+ can 3 + =+ (cury (cury rev 3) 4) + :~ (prep-wid extra) + (prep-wid key) + (prep-wid sat) + (prep-wid msg) + 4^(- (type-to-num typ)) + 4^(- version) + 4^(- time-cost) + 4^(- mem-cost) + 4^(- out) + 4^(- threads) + == + :: + :: do time-cost passes over the buffer + :: + =+ t=0 + |- + ?: (lth t time-cost) + :: + :: process all four segments in the columns... + :: + =+ s=0 + |- + ?. (lth s 4) ^$(t +(t)) + :: + :: ...of every row/thread + :: + =+ r=0 + |- + ?. (lth r threads) ^$(s +(s)) + =; new=_buffer + $(buffer new, r +(r)) + %- fill-segment + :* buffer h0 + t s r + blocks columns seg-length + threads time-cost typ version + == + :: + :: mix all rows together and hash the result + :: + =+ r=0 + =| final=@ + |- + ?: =(r threads) + (hash 1.024^final out) + =- $(final -, r +(r)) + %+ mix final + (snag (dec columns) (snag r buffer)) + :: + :: per-segment computation + ++ fill-segment + |= $: buffer=(list (list @)) + h0=@ + :: + itn=@ud + seg=@ud + row=@ud + :: + blocks=@ud + columns=@ud + seg-length=@ud + :: + threads=@ud + time-cost=@ud + typ=argon-type + version=@ux + == + :: + :: fill-segment utilities + :: + => |% + ++ put-word + |= [rob=(list @) i=@ud d=@] + %+ weld (scag i rob) + [d (slag +(i) rob)] + -- + ^+ buffer + :: + :: rob: row buffer to operate on + :: do-i: whether to use prns from input rather than state + :: rands: prns generated from input, if we do-i + =+ rob=(snag row buffer) + =/ do-i=? + ?| ?=(%i typ) + &(?=(%id typ) =(0 itn) (lte seg 1)) + &(?=(%u typ) =(0 itn) (lte seg 2)) + == + =/ rands=(list (pair @ @)) + ?. do-i ~ + :: + :: keep going until we have a list of :seg-length prn pairs + :: + =+ l=0 + =+ counter=1 + |- ^- (list (pair @ @)) + ?: (gte l seg-length) ~ + =- (weld - $(counter +(counter), l (add l 128))) + :: + :: generate pseudorandom block by compressing metadata + :: + =/ random-block=@ + %+ compress 0 + %+ compress 0 + %^ lsh 3 968 + %+ rep 6 + =+ (cury (cury rev 3) 8) + :~ (- counter) + (- (type-to-num typ)) + (- time-cost) + (- blocks) + (- seg) + (- row) + (- itn) + == + :: + :: split the random-block into 64-bit sections, + :: then extract the first two 4-byte sections from each. + :: + %+ turn (flop (rip 6 random-block)) + |= a=@ + ^- (pair @ @) + :- (rev 3 4 (rsh 5 1 a)) + (rev 3 4 (end 5 1 a)) + :: + :: iterate over the entire segment length + :: + =+ sin=0 + |- + :: + :: when done, produce the updated buffer + :: + ?: =(sin seg-length) + %+ weld (scag row buffer) + [rob (slag +(row) buffer)] + :: + :: col: current column to process + =/ col=@ud + (add (mul seg seg-length) sin) + :: + :: first two columns are generated from h0 + :: + ?: &(=(0 itn) (lth col 2)) + =+ (app-num (app-num 64^h0 col) row) + =+ (hash - 1.024) + $(rob (put-word rob col -), sin +(sin)) + :: + :: c1, c2: prns for picking reference block + =+ ^- [c1=@ c2=@] ::TODO =/ w/o face + ?: do-i (snag sin rands) + =+ =- (snag - rob) + ?: =(0 col) (dec columns) + (mod (dec col) columns) + :- (rev 3 4 (cut 3 [1.020 4] -)) + (rev 3 4 (cut 3 [1.016 4] -)) + :: + :: ref-row: reference block row + =/ ref-row=@ud + ?: &(=(0 itn) =(0 seg)) row + (mod c2 threads) + :: + :: ref-col: reference block column + =/ ref-col=@ud + =- (mod - columns) + %+ add + :: starting index + ?: |(=(0 itn) =(3 seg)) 0 + (mul +(seg) seg-length) + :: pseudorandom offset + =- %+ sub (dec -) + %^ rsh 0 32 + %+ mul - + (rsh 0 32 (mul c1 c1)) + :: reference area size + ?: =(0 itn) + ?: |(=(0 seg) =(row ref-row)) (dec col) + ?: =(0 sin) (dec (mul seg seg-length)) + (mul seg seg-length) + =+ sul=(sub columns seg-length) + ?: =(ref-row row) (dec (add sul sin)) + ?: =(0 sin) (dec sul) + sul + :: + :: compress the previous and reference block + :: to create the new block + :: + =/ new=@ + %+ compress + =- (snag - rob) + :: previous index, wrap-around + ?: =(0 col) (dec columns) + (mod (dec col) columns) + :: get reference block + %+ snag ref-col + ?: =(ref-row row) rob + (snag ref-row buffer) + :: + :: starting from v1.3, we xor the new block in, + :: rather than directly overwriting the old block + :: + =? new &(!=(0 itn) =(0x13 version)) + (mix new (snag col rob)) + $(rob (put-word rob col new), sin +(sin)) + :: + :: compression function (g) + ++ compress + :: x, y: assumed to be 1024 bytes + |= [x=@ y=@] + ^- @ + :: + =+ r=(mix x y) + =| q=(list @) + :: + :: iterate over rows of r to get q + :: + =+ i=0 + |- + ?: (lth i 8) + =; p=(list @) + $(q (weld q p), i +(i)) + %- permute + =- (weld (reap (sub 8 (lent -)) 0) -) + %- flop + %+ rip 7 + (cut 10 [(sub 7 i) 1] r) + :: + :: iterate over columns of q to get z + :: + =/ z=(list @) (reap 64 0) + =. i 0 + |- + :: + :: when done, assemble z and xor it with r + :: + ?. (lth i 8) + (mix (rep 7 (flop z)) r) + :: + :: permute the column + :: + =/ out=(list @) + %- permute + :~ (snag i q) + (snag (add i 8) q) + (snag (add i 16) q) + (snag (add i 24) q) + (snag (add i 32) q) + (snag (add i 40) q) + (snag (add i 48) q) + (snag (add i 56) q) + == + :: + :: put the result into z per column + :: + =+ j=0 + |- + ?: =(8 j) ^$(i +(i)) + =- $(z -, j +(j)) + =+ (add i (mul j 8)) + %+ weld (scag - z) + [(snag j out) (slag +(-) z)] + :: + :: permutation function (p) + ++ permute + ::NOTE this function really just takes and produces + :: 8 values, but taking and producing them as + :: lists helps clean up the code significantly. + |= s=(list @) + ?> =(8 (lent s)) + ^- (list @) + :: + :: list inputs as 16 8-byte values + :: + =/ v=(list @) + %- zing + ^- (list (list @)) + %+ turn s + |= a=@ + :: rev for endianness + =+ (rip 6 (rev 3 16 a)) + (weld - (reap (sub 2 (lent -)) 0)) + :: + :: do permutation rounds + :: + =. v (do-round v 0 4 8 12) + =. v (do-round v 1 5 9 13) + =. v (do-round v 2 6 10 14) + =. v (do-round v 3 7 11 15) + =. v (do-round v 0 5 10 15) + =. v (do-round v 1 6 11 12) + =. v (do-round v 2 7 8 13) + =. v (do-round v 3 4 9 14) + :: rev for endianness + =. v (turn v (cury (cury rev 3) 8)) + :: + :: cat v back together into 8 16-byte values + :: + %+ turn (gulf 0 7) + |= i=@ + =+ (mul 2 i) + (cat 6 (snag +(-) v) (snag - v)) + :: + :: perform a round and produce updated value list + ++ do-round + |= [v=(list @) na=@ nb=@ nc=@ nd=@] + ^+ v + => |% + ++ get-word + |= i=@ud + (snag i v) + :: + ++ put-word + |= [i=@ud d=@] + ^+ v + %+ weld (scag i v) + [d (slag +(i) v)] + -- + =- =. v (put-word na a) + =. v (put-word nb b) + =. v (put-word nc c) + (put-word nd d) + %- round + :* (get-word na) + (get-word nb) + (get-word nc) + (get-word nd) + == + :: + :: perform a round (bg) and produce updated values + ++ round + |= [a=@ b=@ c=@ d=@] + ^- [a=@ b=@ c=@ d=@] + :: operate on 64 bit words + =+ fed=~(. fe 6) + =* sum sum:fed + =* ror ror:fed + =+ end=(cury (cury end 5) 1) + =. a :(sum a b :(mul 2 (end a) (end b))) + =. d (ror 0 32 (mix d a)) + =. c :(sum c d :(mul 2 (end c) (end d))) + =. b (ror 0 24 (mix b c)) + =. a :(sum a b :(mul 2 (end a) (end b))) + =. d (ror 0 16 (mix d a)) + =. c :(sum c d :(mul 2 (end c) (end d))) + =. b (ror 0 63 (mix b c)) + [a b c d] + :: + :: argon2 wrapper around blake2b (h') + ++ hash + =, blake + |= [byts out=@ud] + ^- @ + :: + :: msg: input with byte-length prepended + =+ msg=(prep-num [wid dat] out) + :: + :: if requested size is low enough, hash directly + :: + ?: (lte out 64) + (blake2b msg 0^0 out) + :: + :: build up the result by hashing and re-hashing + :: the input message, adding the first 32 bytes + :: of the hash to the result, until we have the + :: desired output size. + :: + =+ tmp=(blake2b msg 0^0 64) + =+ res=(rsh 3 32 tmp) + =. out (sub out 32) + |- + ?: (gth out 64) + =. tmp (blake2b 64^tmp 0^0 64) + =. res (add (lsh 3 32 res) (rsh 3 32 tmp)) + $(out (sub out 32)) + %+ add (lsh 3 out res) + (blake2b 64^tmp 0^0 out) + :: + :: utilities + :: + ++ type-to-num + |= t=argon-type + ?- t + %d 0 + %i 1 + %id 2 + %u 10 + == + :: + ++ app-num + |= [byts num=@ud] + ^- byts + :- (add wid 4) + %+ can 3 + ~[4^(rev 3 4 num) wid^dat] + :: + ++ prep-num + |= [byts num=@ud] + ^- byts + :- (add wid 4) + %+ can 3 + ~[wid^dat 4^(rev 3 4 num)] + :: + ++ prep-wid + |= a=byts + (prep-num a wid.a) + -- -- ::crypto :: :::: :::: ++unity :: (2c) unit promotion