~/bend-docscommunity

src/crypto/argon2/memory.bend source

src/crypto/argon2/memory.bend on the hub · documented module

import Baseimport ./types.bend as Aimport ./sub.bend as SB# The Argon2 memory: a packed Array<U32> of 2^(8 + k) words, block b at words# 256 b .. 256 b + 255 (lane n of the block at words 256 b + 2 n, low half,# and 256 b + 2 n + 1, high half). Blocks are read and written word by word# with Base's Array.get and Array.set, which the compiler turns into O(1)# accesses of the packed buffer.# Words i - n .. i, prepended to acc: pair holds the memory and word i.def rd(n: Nat, +i: Nat, acc: List<&2, U32>, pair: Array<U32> & U32) -> Array<U32> & List<&2, U32>:  match n pair:    case 0n Tuple{a, w}:      (a, w <> acc)    case 1n+p Tuple{a, w}:      +j = Nat.sub(i, 1n)      rd(p, j, w <> acc, Array.get(U32, a, U32.from_nat(j)))def read_fin(pair: Array<U32> & List<&2, U32>) -> Array<U32> & A.Block:  (a, ws) = pair  (a, SB.rows8(ws))# Block b; the memory is handed back.def get(+b: Nat, a: Array<U32>) -> Array<U32> & A.Block:  +last = Nat.add(Nat.mul(b, 256n), 255n)  read_fin(rd(255n, last, Nil{}, Array.get(U32, a, U32.from_nat(last))))# The words stored from word i on.def wr(ws: List<&2, U32>, +i: Nat, a: Array<U32>) -> Array<U32>:  match ws:    case Nil{}:      a    case w <> rest:      wr(rest, Nat.add(i, 1n), Array.set(U32, a, U32.from_nat(i), w))# The memory with block b replaced by v.def set(+b: Nat, v: A.Block, a: Array<U32>) -> Array<U32>:  wr(SB.words(v), Nat.mul(b, 256n), a)def pw(k: Nat) -> Nat:  match k:    case 0n:      1n    case 1n+p:      Nat.double(pw(p))# The smallest k >= k0 with 2^k >= n.def levels_go(fuel: Nat, +n: Nat, +k: Nat, done: Bool) -> Nat:  match fuel done:    case _ True{}:      k    case 0n False{}:      k    case 1n+f False{}:      levels_go(f, n, 1n+k, Nat.is_le(n, pw(1n+k)))def levels(+n: Nat) -> Nat:  levels_go(32n, n, 0n, Nat.is_le(n, 1n))# A zeroed memory of 2^k blocks.def new(+k: Nat) -> Array<U32>:  Array.new(U32, Nat.add(8n, k), 0)