context: using System;
  
  using Org.BouncyCastle.Utilities;
  
  namespace Org.BouncyCastle.Crypto.Digests
  {
      /// <remarks>
      /// <p>Implementation of RipeMD256.</p>
      /// <p><b>Note:</b> this algorithm offers the same level of security as RipeMD128.</p>
      /// </remarks>
      public class RipeMD256Digest
  		: GeneralDigest
      {
          public override string AlgorithmName
  		{
  			get { return "RIPEMD256"; }
  		}
  
  		public override int GetDigestSize()
  		{
  			return DigestLength;
  		}
  
  		private const int DigestLength = 32;
  
  		private int H0, H1, H2, H3, H4, H5, H6, H7; // IV's
  
  		private int[] X = new int[16];
          private int xOff;
  
          /// <summary> Standard constructor</summary>
          public RipeMD256Digest()
          {
              Reset();
          }
  
          /// <summary> Copy constructor.  This will copy the state of the provided
          /// message digest.
          /// </summary>
          public RipeMD256Digest(RipeMD256Digest t):base(t)
          {
  			CopyIn(t);
  		}
  
  		private void CopyIn(RipeMD256Digest t)
  		{
  			base.CopyIn(t);
  
              H0 = t.H0;
              H1 = t.H1;
              H2 = t.H2;
              H3 = t.H3;
              H4 = t.H4;
              H5 = t.H5;
              H6 = t.H6;
              H7 = t.H7;
  
              Array.Copy(t.X, 0, X, 0, t.X.Length);
              xOff = t.xOff;
          }
  
          internal override void ProcessWord(
              byte[] input,
              int inOff)
          {
              X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
                  | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
  
              if (xOff == 16)
              {
                  ProcessBlock();
              }
          }
  
          internal override void ProcessLength(
              long bitLength)
          {
              if (xOff > 14)
              {
                  ProcessBlock();
              }
  
              X[14] = (int)(bitLength & 0xffffffff);
              X[15] = (int)((ulong)bitLength >> 32);
          }
  
          private void UnpackWord(
              int word,
              byte[] outBytes,
              int outOff)
          {
              outBytes[outOff] = (byte)(uint)word;
              outBytes[outOff + 1] = (byte)((uint)word >> 8);
              outBytes[outOff + 2] = (byte)((uint)word >> 16);
              outBytes[outOff + 3] = (byte)((uint)word >> 24);
          }
  
          public override int DoFinal(byte[] output, int outOff)
          {
              Finish();
  
              UnpackWord(H0, output, outOff);
              UnpackWord(H1, output, outOff + 4);
              UnpackWord(H2, output, outOff + 8);
              UnpackWord(H3, output, outOff + 12);
              UnpackWord(H4, output, outOff + 16);
              UnpackWord(H5, output, outOff + 20);
              UnpackWord(H6, output, outOff + 24);
              UnpackWord(H7, output, outOff + 28);
  
              Reset();
  
              return DigestLength;
          }
  
          /// <summary> reset the chaining variables to the IV values.</summary>
          public override void  Reset()
          {
              base.Reset();
  
              H0 = unchecked((int)0x67452301);
              H1 = unchecked((int)0xefcdab89);
              H2 = unchecked((int)0x98badcfe);
              H3 = unchecked((int)0x10325476);
              H4 = unchecked((int)0x76543210);
              H5 = unchecked((int)0xFEDCBA98);
              H6 = unchecked((int)0x89ABCDEF);
              H7 = unchecked((int)0x01234567);
  
              xOff = 0;
  
              for (int i = 0; i != X.Length; i++)
              {
                  X[i] = 0;
              }
          }
  
          /*
          * rotate int x left n bits.
          */
          private int RL(
              int x,
              int n)
          {
              return (x << n) | (int)((uint)x >> (32 - n));
          }
  
          /*
          * f1,f2,f3,f4 are the basic RipeMD128 functions.
          */
  
          /*
          * F
          */
          private int F1(int x, int y, int z)
          {
              return x ^ y ^ z;
          }
  
          /*
          * G
          */
          private int F2(int x, int y, int z)
          {
              return (x & y) | (~ x & z);
          }
  
          /*
          * H
          */
          private int F3(int x, int y, int z)
          {
              return (x | ~ y) ^ z;
          }
  
          /*
          * I
          */
          private int F4(int x, int y, int z)
          {
              return (x & z) | (y & ~ z);
          }
  
          private int F1(int a, int b, int c, int d, int x, int s)
          {
              return RL(a + F1(b, c, d) + x, s);
          }
  
          private int F2(int a, int b, int c, int d, int x, int s)
          {
              return RL(a + F2(b, c, d) + x + unchecked((int)0x5a827999), s);
          }
  
          private int F3(int a, int b, int c, int d, int x, int s)
          {
              return RL(a + F3(b, c, d) + x + unchecked((int)0x6ed9eba1), s);
          }
  
          private int F4(int a, int b, int c, int d, int x, int s)
          {
              return RL(a + F4(b, c, d) + x + unchecked((int)0x8f1bbcdc), s);
          }
  
          private int FF1(int a, int b, int c, int d, int x, int s)
          {
              return RL(a + F1(b, c, d) + x, s);
          }
  
          private int FF2(int a, int b, int c, int d, int x, int s)
          {
              return RL(a + F2(b, c, d) + x + unchecked((int)0x6d703ef3), s);
          }
  
          private int FF3(int a, int b, int c, int d, int x, int s)
          {
              return RL(a + F3(b, c, d) + x + unchecked((int)0x5c4dd124), s);
          }
  
          private int FF4(int a, int b, int c, int d, int x, int s)
          {
              return RL(a + F4(b, c, d) + x + unchecked((int)0x50a28be6), s);
          }
  
          internal override void ProcessBlock()
          {
              int a, aa;
              int b, bb;
              int c, cc;
              int d, dd;
              int t;
  
              a = H0;
              b = H1;
              c = H2;
              d = H3;
              aa = H4;
              bb = H5;
              cc = H6;
              dd = H7;
  
              //
              // Round 1
              //
  
              a = F1(a, b, c, d, X[0], 11);
              d = F1(d, a, b, c, X[1], 14);
              c = F1(c, d, a, b, X[2], 15);
              b = F1(b, c, d, a, X[3], 12);
              a = F1(a, b, c, d, X[4], 5);
              d = F1(d, a, b, c, X[5], 8);
              c = F1(c, d, a, b, X[6], 7);
              b = F1(b, c, d, a, X[7], 9);
              a = F1(a, b, c, d, X[8], 11);
              d = F1(d, a, b, c, X[9], 13);
              c = F1(c, d, a, b, X[10], 14);
              b = F1(b, c, d, a, X[11], 15);
              a = F1(a, b, c, d, X[12], 6);
              d = F1(d, a, b, c, X[13], 7);
              c = F1(c, d, a, b, X[14], 9);
              b = F1(b, c, d, a, X[15], 8);
  
              aa = FF4(aa, bb, cc, dd, X[5], 8);
              dd = FF4(dd, aa, bb, cc, X[14], 9);
              cc = FF4(cc, dd, aa, bb, X[7], 9);
              bb = FF4(bb, cc, dd, aa, X[0], 11);
              aa = FF4(aa, bb, cc, dd, X[9], 13);
              dd = FF4(dd, aa, bb, cc, X[2], 15);
              cc = FF4(cc, dd, aa, bb, X[11], 15);
              bb = FF4(bb, cc, dd, aa, X[4], 5);
              aa = FF4(aa, bb, cc, dd, X[13], 7);
              dd = FF4(dd, aa, bb, cc, X[6], 7);
              cc = FF4(cc, dd, aa, bb, X[15], 8);
              bb = FF4(bb, cc, dd, aa, X[8], 11);
              aa = FF4(aa, bb, cc, dd, X[1], 14);
              dd = FF4(dd, aa, bb, cc, X[10], 14);
              cc = FF4(cc, dd, aa, bb, X[3], 12);
              bb = FF4(bb, cc, dd, aa, X[12], 6);
  
              t = a; a = aa; aa = t;
  
              //
              // Round 2
              //
              a = F2(a, b, c, d, X[7], 7);
              d = F2(d, a, b, c, X[4], 6);
              c = F2(c, d, a, b, X[13], 8);
              b = F2(b, c, d, a, X[1], 13);
  
gt:             a = F2(a, b, c, d, X[10], 11);