thewar_client/Client/Assets/Best HTTP/Source/SecureProtocol/crypto/digests/Blake3Digest.cs

1052 lines
30 KiB
C#

#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using System.Collections.Generic;
#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER || UNITY_2021_2_OR_NEWER
using System.Runtime.CompilerServices;
#endif
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Digests
{
public sealed class Blake3Digest
: IDigest, IMemoable, IXof
{
/**
* Already outputting error.
*/
private const string ERR_OUTPUTTING = "Already outputting";
/**
* Number of Words.
*/
private const int NUMWORDS = 8;
/**
* Number of Rounds.
*/
private const int ROUNDS = 7;
/**
* Buffer length.
*/
private const int BLOCKLEN = NUMWORDS * Integers.NumBytes * 2;
/**
* Chunk length.
*/
private const int CHUNKLEN = 1024;
/**
* ChunkStart Flag.
*/
private const int CHUNKSTART = 1;
/**
* ChunkEnd Flag.
*/
private const int CHUNKEND = 2;
/**
* Parent Flag.
*/
private const int PARENT = 4;
/**
* Root Flag.
*/
private const int ROOT = 8;
/**
* KeyedHash Flag.
*/
private const int KEYEDHASH = 16;
/**
* DeriveContext Flag.
*/
private const int DERIVECONTEXT = 32;
/**
* DeriveKey Flag.
*/
private const int DERIVEKEY = 64;
/**
* Chaining0 State Locations.
*/
private const int CHAINING0 = 0;
/**
* Chaining1 State Location.
*/
private const int CHAINING1 = 1;
/**
* Chaining2 State Location.
*/
private const int CHAINING2 = 2;
/**
* Chaining3 State Location.
*/
private const int CHAINING3 = 3;
/**
* Chaining4 State Location.
*/
private const int CHAINING4 = 4;
/**
* Chaining5 State Location.
*/
private const int CHAINING5 = 5;
/**
* Chaining6 State Location.
*/
private const int CHAINING6 = 6;
/**
* Chaining7 State Location.
*/
private const int CHAINING7 = 7;
/**
* IV0 State Locations.
*/
private const int IV0 = 8;
/**
* IV1 State Location.
*/
private const int IV1 = 9;
/**
* IV2 State Location.
*/
private const int IV2 = 10;
/**
* IV3 State Location.
*/
private const int IV3 = 11;
/**
* Count0 State Location.
*/
private const int COUNT0 = 12;
/**
* Count1 State Location.
*/
private const int COUNT1 = 13;
/**
* DataLen State Location.
*/
private const int DATALEN = 14;
/**
* Flags State Location.
*/
private const int FLAGS = 15;
/**
* Message word permutations.
*/
private static readonly byte[] SIGMA = { 2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8 };
/**
* Blake3 Initialization Vector.
*/
private static readonly uint[] IV = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
/**
* The byte input/output buffer.
*/
private readonly byte[] m_theBuffer = new byte[BLOCKLEN];
/**
* The key.
*/
private readonly uint[] m_theK = new uint[NUMWORDS];
/**
* The chaining value.
*/
private readonly uint[] m_theChaining = new uint[NUMWORDS];
/**
* The state.
*/
private readonly uint[] m_theV = new uint[NUMWORDS << 1];
/**
* The message Buffer.
*/
private readonly uint[] m_theM = new uint[NUMWORDS << 1];
/**
* The indices.
*/
private readonly byte[] m_theIndices = new byte[NUMWORDS << 1];
/**
* The chainingStack.
*/
private readonly List<uint[]> m_theStack = new List<uint[]>();
/**
* The default digestLength.
*/
private readonly int m_theDigestLen;
/**
* Are we outputting?
*/
private bool m_outputting;
/**
* How many more bytes can we output?
*/
private long m_outputAvailable;
/**
* The current mode.
*/
private int m_theMode;
/**
* The output mode.
*/
private int m_theOutputMode;
/**
* The output dataLen.
*/
private int m_theOutputDataLen;
/**
* The block counter.
*/
private long m_theCounter;
/**
* The # of bytes in the current block.
*/
private int m_theCurrBytes;
/**
* The position of the next byte in the buffer.
*/
private int m_thePos;
public Blake3Digest()
: this((BLOCKLEN >> 1) * 8)
{
}
/// <param name="pDigestSize">the default digest size (in bits)</param>
public Blake3Digest(int pDigestSize)
{
m_theDigestLen = pDigestSize / 8;
Init(null);
}
/**
* Constructor.
*
* @param pSource the source digest.
*/
public Blake3Digest(Blake3Digest pSource)
{
/* Copy default digest length */
m_theDigestLen = pSource.m_theDigestLen;
/* Initialise from source */
Reset(pSource);
}
public int GetByteLength() => BLOCKLEN;
public string AlgorithmName => "BLAKE3";
public int GetDigestSize() => m_theDigestLen;
/**
* Initialise.
*
* @param pParams the parameters.
*/
public void Init(Blake3Parameters pParams)
{
/* Access key/context */
byte[] myKey = pParams?.GetKey();
byte[] myContext = pParams?.GetContext();
/* Reset the digest */
Reset();
/* If we have a key */
if (myKey != null)
{
/* Initialise with the key */
InitKey(myKey);
Arrays.Fill(myKey, 0);
/* else if we have a context */
}
else if (myContext != null)
{
/* Initialise for deriving context */
InitNullKey();
m_theMode = DERIVECONTEXT;
/* Derive key from context */
BlockUpdate(myContext, 0, myContext.Length);
DoFinal(m_theBuffer, 0);
InitKeyFromContext();
Reset();
/* Else init null key and reset mode */
}
else
{
InitNullKey();
m_theMode = 0;
}
}
public void Update(byte b)
{
/* Check that we are not outputting */
if (m_outputting)
throw new InvalidOperationException(ERR_OUTPUTTING);
/* If the buffer is full */
int blockLen = m_theBuffer.Length;
int remainingLength = blockLen - m_thePos;
if (remainingLength == 0)
{
/* Process the buffer */
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
CompressBlock(m_theBuffer);
#else
CompressBlock(m_theBuffer, 0);
#endif
/* Reset the buffer */
Arrays.Fill(m_theBuffer, 0);
m_thePos = 0;
}
/* Store the byte */
m_theBuffer[m_thePos] = b;
m_thePos++;
}
public void BlockUpdate(byte[] pMessage, int pOffset, int pLen)
{
/* Ignore null operation */
if (pMessage == null)
return;
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
BlockUpdate(pMessage.AsSpan(pOffset, pLen));
#else
if (pLen == 0)
return;
/* Check that we are not outputting */
if (m_outputting)
throw new InvalidOperationException(ERR_OUTPUTTING);
/* Process any bytes currently in the buffer */
int remainingLen = 0; // left bytes of buffer
if (m_thePos != 0)
{
/* Calculate space remaining in the buffer */
remainingLen = BLOCKLEN - m_thePos;
/* If there is sufficient space in the buffer */
if (remainingLen >= pLen)
{
/* Copy data into buffer and return */
Array.Copy(pMessage, pOffset, m_theBuffer, m_thePos, pLen);
m_thePos += pLen;
return;
}
/* Fill the buffer */
Array.Copy(pMessage, pOffset, m_theBuffer, m_thePos, remainingLen);
/* Process the buffer */
CompressBlock(m_theBuffer, 0);
/* Reset the buffer */
m_thePos = 0;
Arrays.Fill(m_theBuffer, 0);
}
/* process all blocks except the last one */
int messagePos;
int blockWiseLastPos = pOffset + pLen - BLOCKLEN;
for (messagePos = pOffset + remainingLen; messagePos < blockWiseLastPos; messagePos += BLOCKLEN)
{
/* Process the buffer */
CompressBlock(pMessage, messagePos);
}
/* Fill the buffer with the remaining bytes of the message */
int len = pLen - messagePos;
Array.Copy(pMessage, messagePos, m_theBuffer, 0, pOffset + len);
m_thePos += pOffset + len;
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public void BlockUpdate(ReadOnlySpan<byte> input)
{
if (input.IsEmpty)
return;
/* Check that we are not outputting */
if (m_outputting)
throw new InvalidOperationException(ERR_OUTPUTTING);
int pLen = input.Length;
/* Process any bytes currently in the buffer */
int remainingLen = 0; // left bytes of buffer
if (m_thePos != 0)
{
/* Calculate space remaining in the buffer */
remainingLen = BLOCKLEN - m_thePos;
/* If there is sufficient space in the buffer */
if (remainingLen >= pLen)
{
/* Copy data into buffer and return */
input.CopyTo(m_theBuffer.AsSpan(m_thePos));
m_thePos += pLen;
return;
}
/* Fill the buffer */
input[..remainingLen].CopyTo(m_theBuffer.AsSpan(m_thePos));
/* Process the buffer */
CompressBlock(m_theBuffer);
/* Reset the buffer */
m_thePos = 0;
Arrays.Fill(m_theBuffer, 0);
}
/* process all blocks except the last one */
int messagePos;
int blockWiseLastPos = pLen - BLOCKLEN;
for (messagePos = remainingLen; messagePos < blockWiseLastPos; messagePos += BLOCKLEN)
{
/* Process the buffer */
CompressBlock(input[messagePos..]);
}
/* Fill the buffer with the remaining bytes of the message */
input[messagePos..].CopyTo(m_theBuffer);
m_thePos += pLen - messagePos;
}
#endif
public int DoFinal(byte[] pOutput, int pOutOffset)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
return OutputFinal(pOutput.AsSpan(pOutOffset, GetDigestSize()));
#else
return OutputFinal(pOutput, pOutOffset, GetDigestSize());
#endif
}
public int OutputFinal(byte[] pOut, int pOutOffset, int pOutLen)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
return OutputFinal(pOut.AsSpan(pOutOffset, pOutLen));
#else
/* Reject if we are already outputting */
if (m_outputting)
throw new InvalidOperationException(ERR_OUTPUTTING);
/* Build the required output */
int length = Output(pOut, pOutOffset, pOutLen);
/* reset the underlying digest and return the length */
Reset();
return length;
#endif
}
public int Output(byte[] pOut, int pOutOffset, int pOutLen)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
return Output(pOut.AsSpan(pOutOffset, pOutLen));
#else
/* If we have not started outputting yet */
if (!m_outputting)
{
/* Process the buffer */
CompressFinalBlock(m_thePos);
}
/* Reject if there is insufficient Xof remaining */
if (pOutLen < 0 || (m_outputAvailable >= 0 && pOutLen > m_outputAvailable))
throw new ArgumentException("Insufficient bytes remaining");
/* If we have some remaining data in the current buffer */
int dataLeft = pOutLen;
int outPos = pOutOffset;
if (m_thePos < BLOCKLEN)
{
/* Copy data from current hash */
int dataToCopy = System.Math.Min(dataLeft, BLOCKLEN - m_thePos);
Array.Copy(m_theBuffer, m_thePos, pOut, outPos, dataToCopy);
/* Adjust counters */
m_thePos += dataToCopy;
outPos += dataToCopy;
dataLeft -= dataToCopy;
}
/* Loop until we have completed the request */
while (dataLeft > 0)
{
/* Calculate the next block */
NextOutputBlock();
/* Copy data from current hash */
int dataToCopy = System.Math.Min(dataLeft, BLOCKLEN);
Array.Copy(m_theBuffer, 0, pOut, outPos, dataToCopy);
/* Adjust counters */
m_thePos += dataToCopy;
outPos += dataToCopy;
dataLeft -= dataToCopy;
}
/* Adjust outputAvailable */
m_outputAvailable -= pOutLen;
/* Return the number of bytes transferred */
return pOutLen;
#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
public int DoFinal(Span<byte> output)
{
return OutputFinal(output[..GetDigestSize()]);
}
public int OutputFinal(Span<byte> output)
{
/* Reject if we are already outputting */
if (m_outputting)
throw new InvalidOperationException(ERR_OUTPUTTING);
/* Build the required output */
int length = Output(output);
/* reset the underlying digest and return the length */
Reset();
return length;
}
public int Output(Span<byte> output)
{
/* If we have not started outputting yet */
if (!m_outputting)
{
/* Process the buffer */
CompressFinalBlock(m_thePos);
}
int pOutOffset = 0, pOutLen = output.Length;
/* Reject if there is insufficient Xof remaining */
if (pOutLen < 0 || (m_outputAvailable >= 0 && pOutLen > m_outputAvailable))
throw new ArgumentException("Insufficient bytes remaining");
/* If we have some remaining data in the current buffer */
int dataLeft = pOutLen;
int outPos = pOutOffset;
if (m_thePos < BLOCKLEN)
{
/* Copy data from current hash */
int dataToCopy = System.Math.Min(dataLeft, BLOCKLEN - m_thePos);
m_theBuffer.AsSpan(m_thePos, dataToCopy).CopyTo(output[outPos..]);
/* Adjust counters */
m_thePos += dataToCopy;
outPos += dataToCopy;
dataLeft -= dataToCopy;
}
/* Loop until we have completed the request */
while (dataLeft > 0)
{
/* Calculate the next block */
NextOutputBlock();
/* Copy data from current hash */
int dataToCopy = System.Math.Min(dataLeft, BLOCKLEN);
m_theBuffer.AsSpan(0, dataToCopy).CopyTo(output[outPos..]);
/* Adjust counters */
m_thePos += dataToCopy;
outPos += dataToCopy;
dataLeft -= dataToCopy;
}
/* Adjust outputAvailable */
m_outputAvailable -= pOutLen;
/* Return the number of bytes transferred */
return pOutLen;
}
#endif
public void Reset()
{
ResetBlockCount();
m_thePos = 0;
m_outputting = false;
Arrays.Fill(m_theBuffer, 0);
}
public void Reset(IMemoable pSource)
{
/* Access source */
Blake3Digest mySource = (Blake3Digest)pSource;
/* Reset counter */
m_theCounter = mySource.m_theCounter;
m_theCurrBytes = mySource.m_theCurrBytes;
m_theMode = mySource.m_theMode;
/* Reset output state */
m_outputting = mySource.m_outputting;
m_outputAvailable = mySource.m_outputAvailable;
m_theOutputMode = mySource.m_theOutputMode;
m_theOutputDataLen = mySource.m_theOutputDataLen;
/* Copy state */
Array.Copy(mySource.m_theChaining, 0, m_theChaining, 0, m_theChaining.Length);
Array.Copy(mySource.m_theK, 0, m_theK, 0, m_theK.Length);
Array.Copy(mySource.m_theM, 0, m_theM, 0, m_theM.Length);
/* Copy stack */
m_theStack.Clear();
foreach (var element in mySource.m_theStack)
{
m_theStack.Add(Arrays.Clone(element));
}
/* Copy buffer */
Array.Copy(mySource.m_theBuffer, 0, m_theBuffer, 0, m_theBuffer.Length);
m_thePos = mySource.m_thePos;
}
public IMemoable Copy()
{
return new Blake3Digest(this);
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
private void CompressBlock(ReadOnlySpan<byte> block)
{
/* Initialise state and compress message */
InitChunkBlock(BLOCKLEN, false);
InitM(block);
Compress();
/* Adjust stack if we have completed a block */
if (m_theCurrBytes == 0)
{
AdjustStack();
}
}
private void InitM(ReadOnlySpan<byte> block)
{
/* Copy message bytes into word array */
Pack.LE_To_UInt32(block, m_theM);
}
#else
/**
* Compress next block of the message.
*
* @param pMessage the message buffer
* @param pMsgPos the position within the message buffer
*/
private void CompressBlock(byte[] pMessage, int pMsgPos)
{
/* Initialise state and compress message */
InitChunkBlock(BLOCKLEN, false);
InitM(pMessage, pMsgPos);
Compress();
/* Adjust stack if we have completed a block */
if (m_theCurrBytes == 0)
{
AdjustStack();
}
}
/**
* Initialise M from message.
*
* @param pMessage the source message
* @param pMsgPos the message position
*/
private void InitM(byte[] pMessage, int pMsgPos)
{
/* Copy message bytes into word array */
Pack.LE_To_UInt32(pMessage, pMsgPos, m_theM);
}
#endif
/**
* Adjust the stack.
*/
private void AdjustStack()
{
/* Loop to combine blocks */
long myCount = m_theCounter;
while (myCount > 0)
{
/* Break loop if we are not combining */
if ((myCount & 1) == 1)
break;
/* Build the message to be hashed */
uint[] myLeft = m_theStack[m_theStack.Count - 1];
m_theStack.RemoveAt(m_theStack.Count - 1);
Array.Copy(myLeft, 0, m_theM, 0, NUMWORDS);
Array.Copy(m_theChaining, 0, m_theM, NUMWORDS, NUMWORDS);
/* Create parent block */
InitParentBlock();
Compress();
/* Next block */
myCount >>= 1;
}
/* Add back to the stack */
m_theStack.Add(Arrays.CopyOf(m_theChaining, NUMWORDS));
}
/**
* Compress final block.
*
* @param pDataLen the data length
*/
private void CompressFinalBlock(int pDataLen)
{
/* Initialise state and compress message */
InitChunkBlock(pDataLen, true);
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
InitM(m_theBuffer);
#else
InitM(m_theBuffer, 0);
#endif
Compress();
/* Finalise stack */
ProcessStack();
}
/**
* Process the stack.
*/
private void ProcessStack()
{
/* Finalise stack */
while (m_theStack.Count > 0)
{
/* Build the message to be hashed */
uint[] myLeft = m_theStack[m_theStack.Count - 1];
m_theStack.RemoveAt(m_theStack.Count - 1);
Array.Copy(myLeft, 0, m_theM, 0, NUMWORDS);
Array.Copy(m_theChaining, 0, m_theM, NUMWORDS, NUMWORDS);
/* Create parent block */
InitParentBlock();
if (m_theStack.Count < 1)
{
SetRoot();
}
Compress();
}
}
/**
* Perform compression.
*/
private void Compress()
{
/* Initialise the buffers */
InitIndices();
/* Loop through the rounds */
for (int round = 0; round < ROUNDS - 1; round++)
{
/* Perform the round and permuteM */
PerformRound();
PermuteIndices();
}
PerformRound();
AdjustChaining();
}
/**
* Perform a round.
*/
#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER || UNITY_2021_2_OR_NEWER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
private void PerformRound()
{
/* Apply to columns of V */
MixG(0, CHAINING0, CHAINING4, IV0, COUNT0);
MixG(1, CHAINING1, CHAINING5, IV1, COUNT1);
MixG(2, CHAINING2, CHAINING6, IV2, DATALEN);
MixG(3, CHAINING3, CHAINING7, IV3, FLAGS);
/* Apply to diagonals of V */
MixG(4, CHAINING0, CHAINING5, IV2, FLAGS);
MixG(5, CHAINING1, CHAINING6, IV3, COUNT0);
MixG(6, CHAINING2, CHAINING7, IV0, COUNT1);
MixG(7, CHAINING3, CHAINING4, IV1, DATALEN);
}
/**
* Adjust Chaining after compression.
*/
private void AdjustChaining()
{
/* If we are outputting */
if (m_outputting)
{
/* Adjust full state */
for (int i = 0; i < NUMWORDS; i++)
{
m_theV[i] ^= m_theV[i + NUMWORDS];
m_theV[i + NUMWORDS] ^= m_theChaining[i];
}
/* Output state to buffer */
Pack.UInt32_To_LE(m_theV, m_theBuffer, 0);
m_thePos = 0;
/* Else just build chain value */
}
else
{
/* Combine V into Chaining */
for (int i = 0; i < NUMWORDS; i++)
{
m_theChaining[i] = m_theV[i] ^ m_theV[i + NUMWORDS];
}
}
}
/**
* Mix function G.
*
* @param msgIdx the message index
* @param posA position A in V
* @param posB position B in V
* @param posC position C in V
* @param posD poistion D in V
*/
#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER || UNITY_2021_2_OR_NEWER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
private void MixG(int msgIdx, int posA, int posB, int posC, int posD)
{
/* Determine indices */
int msg = msgIdx << 1;
/* Perform the Round */
m_theV[posA] += m_theV[posB] + m_theM[m_theIndices[msg++]];
m_theV[posD] = Integers.RotateRight(m_theV[posD] ^ m_theV[posA], 16);
m_theV[posC] += m_theV[posD];
m_theV[posB] = Integers.RotateRight(m_theV[posB] ^ m_theV[posC], 12);
m_theV[posA] += m_theV[posB] + m_theM[m_theIndices[msg]];
m_theV[posD] = Integers.RotateRight(m_theV[posD] ^ m_theV[posA], 8);
m_theV[posC] += m_theV[posD];
m_theV[posB] = Integers.RotateRight(m_theV[posB] ^ m_theV[posC], 7);
}
/**
* initialise the indices.
*/
private void InitIndices()
{
for (byte i = 0; i < m_theIndices.Length; i++)
{
m_theIndices[i] = i;
}
}
/**
* PermuteIndices.
*/
private void PermuteIndices()
{
for (byte i = 0; i < m_theIndices.Length; i++)
{
m_theIndices[i] = SIGMA[m_theIndices[i]];
}
}
/**
* Initialise null key.
*/
private void InitNullKey()
{
Array.Copy(IV, 0, m_theK, 0, NUMWORDS);
}
/**
* Initialise key.
*
* @param pKey the keyBytes
*/
private void InitKey(byte[] pKey)
{
/* Copy message bytes into word array */
Pack.LE_To_UInt32(pKey, 0, m_theK);
m_theMode = KEYEDHASH;
}
/**
* Initialise key from context.
*/
private void InitKeyFromContext()
{
Array.Copy(m_theV, 0, m_theK, 0, NUMWORDS);
m_theMode = DERIVEKEY;
}
/**
* Initialise chunk block.
*
* @param pDataLen the dataLength
* @param pFinal is this the final chunk?
*/
private void InitChunkBlock(int pDataLen, bool pFinal)
{
/* Initialise the block */
Array.Copy(m_theCurrBytes == 0 ? m_theK : m_theChaining, 0, m_theV, 0, NUMWORDS);
Array.Copy(IV, 0, m_theV, NUMWORDS, NUMWORDS >> 1);
m_theV[COUNT0] = (uint)m_theCounter;
m_theV[COUNT1] = (uint)(m_theCounter >> Integers.NumBits);
m_theV[DATALEN] = (uint)pDataLen;
m_theV[FLAGS] = (uint)(m_theMode
+ (m_theCurrBytes == 0 ? CHUNKSTART : 0)
+ (pFinal ? CHUNKEND : 0));
/* * Adjust block count */
m_theCurrBytes += pDataLen;
if (m_theCurrBytes >= CHUNKLEN)
{
IncrementBlockCount();
m_theV[FLAGS] |= CHUNKEND;
}
/* If we are single chunk */
if (pFinal && m_theStack.Count < 1)
{
SetRoot();
}
}
/**
* Initialise parent block.
*/
private void InitParentBlock()
{
/* Initialise the block */
Array.Copy(m_theK, 0, m_theV, 0, NUMWORDS);
Array.Copy(IV, 0, m_theV, NUMWORDS, NUMWORDS >> 1);
m_theV[COUNT0] = 0;
m_theV[COUNT1] = 0;
m_theV[DATALEN] = BLOCKLEN;
m_theV[FLAGS] = (uint)(m_theMode | PARENT);
}
/**
* Initialise output block.
*/
private void NextOutputBlock()
{
/* Increment the counter */
m_theCounter++;
/* Initialise the block */
Array.Copy(m_theChaining, 0, m_theV, 0, NUMWORDS);
Array.Copy(IV, 0, m_theV, NUMWORDS, NUMWORDS >> 1);
m_theV[COUNT0] = (uint)m_theCounter;
m_theV[COUNT1] = (uint)(m_theCounter >> Integers.NumBits);
m_theV[DATALEN] = (uint)m_theOutputDataLen;
m_theV[FLAGS] = (uint)m_theOutputMode;
/* Generate output */
Compress();
}
/**
* IncrementBlockCount.
*/
private void IncrementBlockCount()
{
m_theCounter++;
m_theCurrBytes = 0;
}
/**
* ResetBlockCount.
*/
private void ResetBlockCount()
{
m_theCounter = 0;
m_theCurrBytes = 0;
}
/**
* Set root indication.
*/
private void SetRoot()
{
m_theV[FLAGS] |= ROOT;
m_theOutputMode = (int)m_theV[FLAGS];
m_theOutputDataLen = (int)m_theV[DATALEN];
m_theCounter = 0;
m_outputting = true;
m_outputAvailable = -1;
Array.Copy(m_theV, 0, m_theChaining, 0, NUMWORDS);
}
}
}
#pragma warning restore
#endif