internal async Task <Argon2Lane[]> InitializeLanes(byte[] password) { var blockHash = Initialize(password); var lanes = new Argon2Lane[DegreeOfParallelism]; // adjust memory size if needed so that each segment has // an even size var segmentLength = MemorySize / (lanes.Length * 4); MemorySize = segmentLength * 4 * lanes.Length; var blocksPerLane = MemorySize / lanes.Length; if (blocksPerLane < 4) { throw new InvalidOperationException($"Memory should be enough to provide at least 4 blocks per {nameof(DegreeOfParallelism)}"); } Task[] init = new Task[lanes.Length * 2]; for (var i = 0; i < lanes.Length; ++i) { lanes[i] = new Argon2Lane(blocksPerLane); int taskIndex = i * 2; int iClosure = i; init[taskIndex] = Task.Run(() => { var stream = new LittleEndianActiveStream(); stream.Expose(blockHash); stream.Expose(0); stream.Expose(iClosure); ModifiedBlake2.Blake2Prime(lanes[iClosure][0], stream); }); init[taskIndex + 1] = Task.Run(() => { var stream = new LittleEndianActiveStream(); stream.Expose(blockHash); stream.Expose(1); stream.Expose(iClosure); ModifiedBlake2.Blake2Prime(lanes[iClosure][1], stream); }); } await Task.WhenAll(init).ConfigureAwait(false); Array.Clear(blockHash, 0, blockHash.Length); return(lanes); }
private byte[] Finalize(Argon2Lane[] lanes) { XorLanes(lanes); var ds = new LittleEndianActiveStream(); ds.Expose(lanes[0][lanes[0].BlockCount - 1]); ModifiedBlake2.Blake2Prime(lanes[0][1], ds, _tagLine); var result = new byte[_tagLine]; var tmp = MemoryMarshal.Cast <ulong, byte>(lanes[0][1].Span).Slice(0, result.Length); tmp.CopyTo(result); return(result); }
private byte[] Finalize(Argon2Lane[] lanes) { XorLanes(lanes); var ds = new LittleEndianActiveStream(); ds.Expose(lanes[0][lanes[0].BlockCount - 1]); ModifiedBlake2.Blake2Prime(lanes[0][1], ds, _tagLine); var result = new byte[_tagLine]; var stream = new Argon2Memory.Stream(lanes[0][1]); stream.Read(result, 0, _tagLine); return(result); }