private void GenerateAddresses(Position position, ulong[] pseudoRands) { var buf = new ulong[QwordsInBlock * 4]; var zeroBlock = new BlockValues(buf, 0); var inputBlock = new BlockValues(buf, 1); var addressBlock = new BlockValues(buf, 2); var tmpBlock = new BlockValues(buf, 3); inputBlock[0] = (ulong)position.Pass; inputBlock[1] = (ulong)position.Lane; inputBlock[2] = (ulong)position.Slice; inputBlock[3] = (ulong)this.MemoryBlockCount; inputBlock[4] = (ulong)this.config.TimeCost; inputBlock[5] = (ulong)this.config.Type; for (int i = 0; i < this.SegmentLength; ++i) { if (i % QwordsInBlock == 0) { inputBlock[6] += 1; tmpBlock.Init(0); addressBlock.Init(0); FillBlockWithXor(zeroBlock, inputBlock, tmpBlock); FillBlockWithXor(zeroBlock, tmpBlock, addressBlock); } pseudoRands[i] = addressBlock[i % QwordsInBlock]; } }
/// <summary> /// XOR <paramref name="other"/> with this and store the result into this. /// </summary> /// <param name="other"> /// The <see cref="BlockValues"/> to XOR. /// </param> public void Xor(BlockValues other) { for (int i = 0; i < Argon2.QwordsInBlock; ++i) { this[i] ^= other[i]; } }
private void FillSegment(Position position) { bool dataIndependentAddressing = this.config.Type == Argon2Type.DataIndependentAddressing || (this.config.Type == Argon2Type.HybridAddressing && position.Pass == 0 && position.Slice < SyncPoints / 2); var pseudoRands = new ulong[this.SegmentLength]; if (dataIndependentAddressing) { this.GenerateAddresses(position, pseudoRands); } // 2 if already generated the first two blocks int startingIndex = position.Pass == 0 && position.Slice == 0 ? 2 : 0; int curOffset = (position.Lane * this.LaneLength) + (position.Slice * this.SegmentLength) + startingIndex; int prevOffset = curOffset % this.LaneLength == 0 ? curOffset + this.LaneLength - 1 : curOffset - 1; for (int i = startingIndex; i < this.SegmentLength; ++i, ++curOffset, ++prevOffset) { if (curOffset % this.LaneLength == 1) { prevOffset = curOffset - 1; } // compute index of reference block taking pseudo-random value from previous block ulong pseudoRand = dataIndependentAddressing ? pseudoRands[i] : this.Memory[prevOffset][0]; // cannot reference other lanes until pass or slice are not zero int refLane = (position.Pass == 0 && position.Slice == 0) ? position.Lane : (int)((uint)(pseudoRand >> 32) % (uint)this.config.Lanes); // compute possible number of reference blocks in lane position.Index = i; int refIndex = this.IndexAlpha(position, (uint)pseudoRand, refLane == position.Lane); BlockValues refBlock = this.Memory[(this.LaneLength * refLane) + refIndex]; BlockValues curBlock = this.Memory[curOffset]; if (this.config.Version == Argon2Version.Sixteen) { // version 1.2.1 and earlier: overwrite, not XOR FillBlock(this.Memory[prevOffset], refBlock, curBlock); } else if (position.Pass == 0) { FillBlock(this.Memory[prevOffset], refBlock, curBlock); } else { FillBlockWithXor(this.Memory[prevOffset], refBlock, curBlock); } } }
private SecureArray <byte> Final() { using (var blockhashBuffer = BestSecureArray <ulong>(BlockSize / 8)) { var blockhash = new BlockValues(blockhashBuffer.Buffer, 0); blockhash.Copy(this.Memory[this.LaneLength - 1]); // XOR last blocks for (int l = 1; l < this.config.Lanes; ++l) { blockhash.Xor(this.Memory[(l * this.LaneLength) + (this.LaneLength - 1)]); } using (var blockhashBytes = BestSecureArray <byte>(BlockSize)) { StoreBlock(blockhashBytes.Buffer, blockhash); var ret = BestSecureArray <byte>(this.config.HashLength); Blake2BLong(ret.Buffer, blockhashBytes.Buffer); PrintTag(ret.Buffer); return(ret); } } }
/// <summary> /// Copy <paramref name="other"/> into this. /// </summary> /// <param name="other"> /// The <see cref="BlockValues"/> to copy. /// </param> public void Copy(BlockValues other) { Array.Copy(other.memory, other.offset, this.memory, this.offset, Argon2.QwordsInBlock); }