internal Argon2Lane[] InitializeLanes(byte[] password) { byte[] blockHash = Initialize(password); Argon2Lane[] lanes = new Argon2Lane[1]; // Adjust memory size if needed so that each segment has an even size int segmentLength = MemorySize / (lanes.Length * 4); MemorySize = segmentLength * 4 * lanes.Length; int blocksPerLane = MemorySize / lanes.Length; if (blocksPerLane < 4) { throw new InvalidOperationException($"Memory should be enough to provide at least 4 blocks"); } Action[] init = new Action[lanes.Length * 2]; for (int i = 0; i < lanes.Length; ++i) { lanes[i] = new Argon2Lane(blocksPerLane); int taskIndex = i * 2; int iClosure = i; init[taskIndex] = () => { LittleEndianActiveStream stream = new LittleEndianActiveStream(); stream.Expose(blockHash); stream.Expose(0); stream.Expose(iClosure); ModifiedBlake2.Blake2Prime(lanes[iClosure][0], stream); }; init[taskIndex + 1] = () => { LittleEndianActiveStream stream = new LittleEndianActiveStream(); stream.Expose(blockHash); stream.Expose(1); stream.Expose(iClosure); ModifiedBlake2.Blake2Prime(lanes[iClosure][1], stream); }; } foreach (Action t in init) { t(); } Array.Clear(blockHash, 0, blockHash.Length); return(lanes); }
private byte[] Finalize(Argon2Lane[] lanes) { XorLanes(lanes); LittleEndianActiveStream ds = new LittleEndianActiveStream(); ds.Expose(lanes[0][lanes[0].BlockCount - 1]); ModifiedBlake2.Blake2Prime(lanes[0][1], ds, TagLine); byte[] result = new byte[TagLine]; Argon2Memory memory = lanes[0][1]; memory.GetBuffer(result); return(result); }
internal static void Compress(Argon2Memory dest, Argon2Memory refb, Argon2Memory prev) { ulong[] tmpblock = new ulong[dest.Length]; for (int n = 0; n < 128; ++n) { tmpblock[n] = refb[n] ^ prev[n]; dest[n] ^= tmpblock[n]; } for (int i = 0; i < 8; ++i) { ModifiedBlake2.DoRoundColumns(tmpblock, i); } for (int i = 0; i < 8; ++i) { ModifiedBlake2.DoRoundRows(tmpblock, i); } for (int n = 0; n < 128; ++n) { dest[n] ^= tmpblock[n]; } }