Line   1:// Copyright Chris Lomont 2009-2011.                                                                                                        
Line   2:// Implements Skein version 1.3, http://www.skein-hash.info/                                                                                
Line   3:// Versions 1.0-1.2 are still possible by changing an ifdef below.                                                                          
Line   4:// For bugs or comments, contact me through www.lomont.org                                                                                  
Line   5:// C#, Visual Studio 2008, 2010                                                                                                             
Line   6:#define SKEIN13 // define this to get Skein1.3, else you have a previous version                                                            
Line   7:using System;                                                                                                                               
Line   8:using System.Diagnostics;                                                                                                                   
Line   9:using System.Collections.Generic;                                                                                                           
Line  10:using System.Security.Cryptography;                                                                                                         
Line  11:                                                                                                                                            
Line  12:namespace Lomont{ namespace Crypto                                                                                                          
Line  13:    {                                                                                                                                       
Line  14:    // todo - implement rest of spec: tree functions, etc.                                                                                  
Line  15:    // todo - make Threefish a complete .NET citizen by subclassing it properly                                                             
Line  16:    // todo - walk code looking for endian problems, use BitConverter.IsLittleEndian to fix?                                                
Line  17:    // todo - rewrite for speed                                                                                                             
Line  18:    // todo - comment thoroughly, give usage cases, polish                                                                                  
Line  19:    // todo - see JavaScript at http://www.h2database.com/skein/index.html for a way to do more in place operations                         
Line  20:    // todo -change interface uint, int, ulong, etc., to make class nicely useable                                                          
Line  21:                                                                                                                                            
Line  22:                                                                                                                                            
Line  23:    /// <summary>                                                                                                                           
Line  24:    /// The Skein hash function                                                                                                             
Line  25:    /// Create a class using internal length 256, 512, or 1024 bits                                                                         
Line  26:    /// Then use the Hash function to create hashes, usually of the                                                                         
Line  27:    /// same size.                                                                                                                          
Line  28:    /// </summary>                                                                                                                          
Line  29:    public class Skein : HashAlgorithm                                                                                                      
Line  30:    {                                                                                                                                       
Line  31:        /// <summary>                                                                                                                       
Line  32:        /// Create a Skein hash                                                                                                             
Line  33:        /// Length is 256, 512, or 1024 bits for block/key size.                                                                            
Line  34:        /// </summary>                                                                                                                      
Line  35:        /// <param name="stateSize">The length of the internal state: 256, 512, or 1024 bits.</param>                                       
Line  36:        /// <param name="outputLength">Output size in bits. Must be a multiple of 8 and greater than 0.</param>                             
Line  37:        /// todo - output length ('No' in spec) should be allowed to be any value >= 0 by the spec?                                         
Line  38:        public Skein(uint stateSize, uint outputLength)                                                                                     
Line  39:            {                                                                                                                               
Line  40:            if ((stateSize != 256) && (stateSize != 512) && (stateSize != 1024))                                                            
Line  41:                throw new ArgumentOutOfRangeException("stateSize""Must be one of 256, 512, 1024.");                                       
Line  42:            if ((outputLength <= 0) || ((outputLength&7) != 0))                                                                             
Line  43:                throw new ArgumentOutOfRangeException("outputLength""Must be a multiple of 8 and greater than 0.");                       
Line  44:            threeFishCipher = new Threefish(stateSize);                                                                                     
Line  45:            Nb = stateSize / 8;                                                                                                             
Line  46:                                                                                                                                            
Line  47:            // set configuration to default values                                                                                          
Line  48:            Configuration = new ulong[4];                                                                                                   
Line  49:            Schema = 0x33414853U; // ASCII 'SHA3' // todo - check endianess                                                                 
Line  50:            Version = 1;                                                                                                                    
Line  51:            OutputLength = outputLength;                                                                                                    
Line  52:            TreeLeafSize = 0;                                                                                                               
Line  53:            TreeFanOutSize = 0;                                                                                                             
Line  54:            TreeMaximumHeight = 0;                                                                                                          
Line  55:                                                                                                                                            
Line  56:            // set fields in base class                                                                                                     
Line  57:            HashSizeValue = (int)outputLength;                                                                                              
Line  58:            // todo - more?                                                                                                                 
Line  59:            }                                                                                                                               
Line  60:                                                                                                                                            
Line  61:        private readonly Threefish threeFishCipher;                                                                                         
Line  62:                                                                                                                                            
Line  63:        #region Configuration                                                                                                               
Line  64:                                                                                                                                            
Line  65:        /// <summary>                                                                                                                       
Line  66:        /// The 32 byte configuration data. This is modified by setting Skein parameters.                                                   
Line  67:        /// Setting these values here and reading the parameters decodes a configuration block.                                             
Line  68:        /// </summary>                                                                                                                      
Line  69:        public ulong[] Configuration { getprivate set; }                                                                                  
Line  70:                                                                                                                                            
Line  71:        /// <summary>                                                                                                                       
Line  72:        /// A schema is 4 bytes. Currently it is ASCII 'SHA3'                                                                               
Line  73:        /// </summary>                                                                                                                      
Line  74:        public uint Schema                                                                                                                  
Line  75:        {                                                                                                                                   
Line  76:            get { return (uint)Configuration[0];  }                                                                                         
Line  77:            set {                                                                                                                           
Line  78:                Configuration[0] &= ~0xFFFFFFFFUL;                                                                                          
Line  79:                Configuration[0] |= value;                                                                                                  
Line  80:            }                                                                                                                               
Line  81:        }                                                                                                                                   
Line  82:                                                                                                                                            
Line  83:        /// <summary>                                                                                                                       
Line  84:        /// Version. Currently set to 1 for Skein version 1.3                                                                               
Line  85:        /// </summary>                                                                                                                      
Line  86:        public ushort Version                                                                                                               
Line  87:        {                                                                                                                                   
Line  88:            get { return (ushort)(Configuration[0] >> 32); }                                                                                
Line  89:            set                                                                                                                             
Line  90:            {                                                                                                                               
Line  91:                Configuration[0] &= 0xFFFF0000FFFFFFFFUL;                                                                                   
Line  92:                Configuration[0] |= ((ulong)value) << 32;                                                                                   
Line  93:            }                                                                                                                               
Line  94:        }                                                                                                                                   
Line  95:        /// <summary>                                                                                                                       
Line  96:        /// The output length. Must be set in the constructor.                                                                              
Line  97:        /// </summary>                                                                                                                      
Line  98:        public ulong OutputLength                                                                                                           
Line  99:        {                                                                                                                                   
Line 100:            get { return Configuration[1]; }                                                                                                
Line 101:            private set { Configuration[1] = value; }                                                                                       
Line 102:        }                                                                                                                                   
Line 103:        /// <summary>                                                                                                                       
Line 104:        /// Tree leaf size 0-255.                                                                                                           
Line 105:        /// </summary>                                                                                                                      
Line 106:        public byte TreeLeafSize                                                                                                            
Line 107:        {                                                                                                                                   
Line 108:            get { return (byte)(Configuration[2]); }                                                                                        
Line 109:            set                                                                                                                             
Line 110:            {                                                                                                                               
Line 111:                Configuration[2] &= 0xFFFFFFFFFFFFFF00UL;                                                                                   
Line 112:                Configuration[2] |= ((ulong)value);                                                                                         
Line 113:            }                                                                                                                               
Line 114:        }                                                                                                                                   
Line 115:        /// <summary>                                                                                                                       
Line 116:        /// Tree fan factor 0-255                                                                                                           
Line 117:        /// </summary>                                                                                                                      
Line 118:        public byte TreeFanOutSize                                                                                                          
Line 119:        {                                                                                                                                   
Line 120:            get { return (byte)(Configuration[2]>>8); }                                                                                     
Line 121:            set                                                                                                                             
Line 122:            {                                                                                                                               
Line 123:                Configuration[2] &= 0xFFFFFFFFFFFF00FFUL;                                                                                   
Line 124:                Configuration[2] |= ((ulong)value)<<8;                                                                                      
Line 125:            }                                                                                                                               
Line 126:        }                                                                                                                                   
Line 127:                                                                                                                                            
Line 128:        /// <summary>                                                                                                                       
Line 129:        /// Max tree height 0-255. 255 denotes unlimited tree height.                                                                       
Line 130:        /// </summary>                                                                                                                      
Line 131:        public byte TreeMaximumHeight                                                                                                       
Line 132:        {                                                                                                                                   
Line 133:            get { return (byte)(Configuration[2]>>16); }                                                                                    
Line 134:            set                                                                                                                             
Line 135:            {                                                                                                                               
Line 136:                Configuration[2] &= 0xFFFFFFFFFF00FFFFUL;                                                                                   
Line 137:                Configuration[2] |= ((ulong)value)<<16;                                                                                     
Line 138:            }                                                                                                                               
Line 139:        }                                                                                                                                   
Line 140:                                                                                                                                            
Line 141:                                                                                                                                            
Line 142:        #endregion                                                                                                                          
Line 143:                                                                                                                                            
Line 144:        /// <summary>                                                                                                                       
Line 145:        /// Given an array of byte data, compute the hash                                                                                   
Line 146:        /// </summary>                                                                                                                      
Line 147:        /// <param name="data">The data to hash.</param>                                                                                    
Line 148:        /// <returns>The hashed byte data</returns>                                                                                         
Line 149:        byte[] HashSkein(byte[] data)                                                                                                       
Line 150:        {                                                                                                                                   
Line 151:            Debug.Assert((Nb == 32) || (Nb == 64) || (Nb == 128));                                                                          
Line 152:            var No = OutputLength*8; // number of output bits                                                                               
Line 153:            byte [] M = data;   // alias for the data                                                                                       
Line 154:                                                                                                                                            
Line 155:            var K = new ulong[Nb/8];                                                                                                        
Line 156:            var tweak = new UbiTweak();                                                                                                     
Line 157:            tweak.BlockType = UbiType.Config; // Set configuration block Tcfg                                                               
Line 158:            var G0 = UBI(K, SkeinByteConverter.WordsToBytes(Configuration), tweak, Nb * 8);                                                 
Line 159:                                                                                                                                            
Line 160:            tweak = new UbiTweak();                                                                                                         
Line 161:            tweak.BlockType = UbiType.Message; // set message block Tmsg                                                                    
Line 162:            var G1 = UBI(G0, M, tweak, 8 * (ulong)M.Length);                                                                                
Line 163:                                                                                                                                            
Line 164:            byte[] H = Output(G1, No);                                                                                                      
Line 165:            return H;                                                                                                                       
Line 166:            }                                                                                                                               
Line 167:                                                                                                                                            
Line 168:        #region Implementation                                                                                                              
Line 169:                                                                                                                                            
Line 170:        /// <summary>                                                                                                                       
Line 171:        /// Number of bytes 32, 64, or 128                                                                                                  
Line 172:        /// </summary>                                                                                                                      
Line 173:        ulong Nb = 0UL;                                                                                                                     
Line 174:                                                                                                                                            
Line 175:        /// <summary>                                                                                                                       
Line 176:        /// Perform the UBI compression on G, return compression.                                                                           
Line 177:        /// </summary>                                                                                                                      
Line 178:        /// <param name="G">From spec. Starting value of some bytes.</param>                                                                
Line 179:        /// <param name="M">Message from spec</param>                                                                                       
Line 180:        /// <param name="T">Tweak from spec. This can be modified by this function.</param>                                                 
Line 181:        /// <param name="bits">The number of bits to hash</param>                                                                           
Line 182:        /// <returns>The byte array</returns>                                                                                               
Line 183:        ulong [] UBI(ulong [] G, byte [] M, UbiTweak Ts, ulong bits)                                                                        
Line 184:            { // todo need bits <= 2^99 - 8, this only holds 2^64 - 1.                                                                      
Line 185:            //Debug.Assert((Nb == 32) || (Nb == 64) || (Nb == 128));                                                                        
Line 186:                                                                                                                                            
Line 187:            // pad message if needed. See page 12 of spec.                                                                                  
Line 188:            int B = 0;                                                                                                                      
Line 189:            byte [] Mp = M;                                                                                                                 
Line 190:            if ((bits & 7) != 0)                                                                                                            
Line 191:            {                                                                                                                               
Line 192:                B = 1;                                                                                                                      
Line 193:                Mp = new byte[M.Length];                                                                                                    
Line 194:                M.CopyTo(M, 0);                                                                                                             
Line 195:                Mp[M.Length - 1] |= (byte) (1 << (int) (7 - (bits & 7)));                                                                   
Line 196:            }                                                                                                                               
Line 197:            ulong Nm = (ulong)Mp.Length;                                                                                                    
Line 198:            ulong k = (Nm + Nb - 1) / Nb; // number of blocks of bitLength Nb                                                               
Line 199:            if (k == 0) k = 1; // at least one block                                                                                        
Line 200:            ulong [] Mpp = new ulong[k*Nb/8];                                                                                               
Line 201:            SkeinByteConverter.BytesToWords(Mp).CopyTo(Mpp, 0);                                                                             
Line 202:                                                                                                                                            
Line 203:            ulong[] H = G;                                                                                                                  
Line 204:            ulong [] temp = new ulong[Nb / 8];                                                                                              
Line 205:                                                                                                                                            
Line 206:            for (ulong i = 0; i < k ; ++i)                                                                                                  
Line 207:            {                                                                                                                               
Line 208:                // prepare tweak value                                                                                                      
Line 209:                Ts.Position = Math.Min(Nm, (i + 1) * Nb); // bitLength                                                                      
Line 210:                Ts.IsFirstBlock = i == 0;                                                                                                   
Line 211:                Ts.IsFinalBlock = i == k - 1;                                                                                               
Line 212:                if (Ts.IsFinalBlock)                                                                                                        
Line 213:                    Ts.IsPadded = B != 0;                                                                                                   
Line 214:                                                                                                                                            
Line 215:                for (ulong j = 0; j < Nb / 8; ++j)                                                                                          
Line 216:                    temp[j] = Mpp[j + i * Nb / 8];                                                                                          
Line 217:                                                                                                                                            
Line 218:                threeFishCipher.EncryptBlock(H,Ts.Value,temp,0);                                                                            
Line 219:                for (ulong j = 0; j < Nb/8; ++j)                                                                                            
Line 220:                    H[j] = temp[j] ^ Mpp[j + i * Nb / 8];                                                                                   
Line 221:                }                                                                                                                           
Line 222:                                                                                                                                            
Line 223:            return H;                                                                                                                       
Line 224:            }                                                                                                                               
Line 225:                                                                                                                                            
Line 226:        /// <summary>                                                                                                                       
Line 227:        /// The Output function from the spec.                                                                                              
Line 228:        /// Converts the internal state to the desired output size.                                                                         
Line 229:        /// </summary>                                                                                                                      
Line 230:        /// <param name="G">Internal state</param>                                                                                          
Line 231:        /// <param name="No">Number of desired output bytes</param>                                                                         
Line 232:        /// <returns>The output bytes</returns>                                                                                             
Line 233:        byte[] Output(ulong [] G, ulong No)                                                                                                 
Line 234:        {                                                                                                                                   
Line 235:            var tweak = new UbiTweak();                                                                                                     
Line 236:            tweak.BlockType = UbiType.Out;                                                                                                  
Line 237:                                                                                                                                            
Line 238:            byte [] ans = new byte[(No+7)/8];                                                                                               
Line 239:                                                                                                                                            
Line 240:            ulong bitsDone = 0;                                                                                                             
Line 241:            ulong i = 0;                                                                                                                    
Line 242:            ulong bits = 64*(ulong)G.Length;                                                                                                
Line 243:            while (bitsDone < No)                                                                                                           
Line 244:                {                                                                                                                           
Line 245:                byte [] O =                                                                                                                 
Line 246:                    SkeinByteConverter.WordsToBytes(                                                                                        
Line 247:                    UBI(G, SkeinByteConverter.ToBytes(i,8), tweak, 8*8));                                                                   
Line 248:                ulong start= bitsDone / 8;                                                                                                  
Line 249:                ulong length = Math.Min((ulong)O.Length, (ulong)ans.Length-start);                                                          
Line 250:                for (ulong index = 0; index < length; ++index)                                                                              
Line 251:                    ans[index+start] = O[index];                                                                                            
Line 252:                ++i;                                                                                                                        
Line 253:                bitsDone += bits; // todo - correct?                                                                                        
Line 254:                }                                                                                                                           
Line 255:            return ans;                                                                                                                     
Line 256:            }                                                                                                                               
Line 257:                                                                                                                                            
Line 258:        #endregion   // Implementation                                                                                                      
Line 259:                                                                                                                                            
Line 260:        protected override void HashCore(byte[] array, int ibStart, int cbSize)                                                             
Line 261:        {                                                                                                                                   
Line 262:            if ((ibStart != 0) || (array.Length != cbSize))                                                                                 
Line 263:                throw new NotImplementedException("Style of hashing not implemented");                                                      
Line 264:            base.HashValue = HashSkein(array);                                                                                              
Line 265:        }                                                                                                                                   
Line 266:                                                                                                                                            
Line 267:        protected override byte[] HashFinal()                                                                                               
Line 268:        {                                                                                                                                   
Line 269:            return HashValue;                                                                                                               
Line 270:        }                                                                                                                                   
Line 271:                                                                                                                                            
Line 272:        public override void Initialize()                                                                                                   
Line 273:        {                                                                                                                                   
Line 274:        }                                                                                                                                   
Line 275:    } // Skein                                                                                                                              
Line 276:                                                                                                                                            
Line 277:    /// <summary>                                                                                                                           
Line 278:    /// Type values from the spec, Table 6                                                                                                  
Line 279:    /// </summary>                                                                                                                          
Line 280:    public enum UbiType : ulong                                                                                                             
Line 281:    {                                                                                                                                       
Line 282:        /// <summary>                                                                                                                       
Line 283:        /// Key used for MAC and KDF                                                                                                        
Line 284:        /// </summary>                                                                                                                      
Line 285:        Key = 0,                                                                                                                            
Line 286:        /// <summary>                                                                                                                       
Line 287:        /// Configuration block                                                                                                             
Line 288:        /// </summary>                                                                                                                      
Line 289:        Config = 4,                                                                                                                         
Line 290:        /// <summary>                                                                                                                       
Line 291:        /// Personalization string                                                                                                          
Line 292:        /// </summary>                                                                                                                      
Line 293:        Personalization = 8,                                                                                                                
Line 294:        /// <summary>                                                                                                                       
Line 295:        /// Public key for digital signature hashing                                                                                        
Line 296:        /// </summary>                                                                                                                      
Line 297:        PublicKey = 12,                                                                                                                     
Line 298:        /// <summary>                                                                                                                       
Line 299:        /// Key identifier for KDF                                                                                                          
Line 300:        /// </summary>                                                                                                                      
Line 301:        KeyIdentifier = 16,                                                                                                                 
Line 302:        /// <summary>                                                                                                                       
Line 303:        /// Nonce for stream cipher or randomized hashing                                                                                   
Line 304:        /// </summary>                                                                                                                      
Line 305:        Nonce = 20,                                                                                                                         
Line 306:        /// <summary>                                                                                                                       
Line 307:        /// Message to hash                                                                                                                 
Line 308:        /// </summary>                                                                                                                      
Line 309:        Message = 48,                                                                                                                       
Line 310:        /// <summary>                                                                                                                       
Line 311:        /// Output                                                                                                                          
Line 312:        /// </summary>                                                                                                                      
Line 313:        Out = 63                                                                                                                            
Line 314:    }                                                                                                                                       
Line 315:                                                                                                                                            
Line 316:    /// <summary>                                                                                                                           
Line 317:    /// Store the values for the Tweak parameters for Threefish                                                                             
Line 318:    /// </summary>                                                                                                                          
Line 319:    public class UbiTweak                                                                                                                   
Line 320:    {                                                                                                                                       
Line 321:        /// <summary>                                                                                                                       
Line 322:        /// Create a new tweak structure                                                                                                    
Line 323:        /// </summary>                                                                                                                      
Line 324:        public UbiTweak() {Value = new ulong[2];}                                                                                           
Line 325:        /// <summary>                                                                                                                       
Line 326:        /// The 128 bit tweak value                                                                                                         
Line 327:        /// </summary>                                                                                                                      
Line 328:        public ulong[] Value { get;  private set; }                                                                                         
Line 329:        #region Helper functions                                                                                                            
Line 330:        void Set(ulong mask, bool value)                                                                                                    
Line 331:        {                                                                                                                                   
Line 332:            if (value)                                                                                                                      
Line 333:                Value[1] |= mask;                                                                                                           
Line 334:            else                                                                                                                            
Line 335:                Value[1] &= ~mask;                                                                                                          
Line 336:        }                                                                                                                                   
Line 337:        bool Get(ulong mask)                                                                                                                
Line 338:        {                                                                                                                                   
Line 339:            return (Value[1] & mask) != 0;                                                                                                  
Line 340:        }                                                                                                                                   
Line 341:        #endregion                                                                                                                          
Line 342:        /// <summary>                                                                                                                       
Line 343:        /// Is this the first block?                                                                                                        
Line 344:        /// </summary>                                                                                                                      
Line 345:        public bool IsFirstBlock                                                                                                            
Line 346:        {                                                                                                                                   
Line 347:            get { return Get(1UL<<62); }                                                                                                    
Line 348:            set{ Set(1UL<<62,value); }                                                                                                      
Line 349:        }                                                                                                                                   
Line 350:        /// <summary>                                                                                                                       
Line 351:        /// Is this the final block?                                                                                                        
Line 352:        /// </summary>                                                                                                                      
Line 353:        public bool IsFinalBlock                                                                                                            
Line 354:        {                                                                                                                                   
Line 355:            get { return Get(1UL << 63); }                                                                                                  
Line 356:            set { Set(1UL << 63, value); }                                                                                                  
Line 357:        }                                                                                                                                   
Line 358:                                                                                                                                            
Line 359:        /// <summary>                                                                                                                       
Line 360:        /// Is this block padded due to not using all bits in last byte?                                                                    
Line 361:        /// </summary>                                                                                                                      
Line 362:        public bool IsPadded                                                                                                                
Line 363:        {                                                                                                                                   
Line 364:            get { return Get(1UL << 54); }                                                                                                  
Line 365:            set { Set(1UL << 54, value); }                                                                                                  
Line 366:        }                                                                                                                                   
Line 367:                                                                                                                                            
Line 368:        /// <summary>                                                                                                                       
Line 369:        /// Get/Set tree level 0-63                                                                                                         
Line 370:        /// </summary>                                                                                                                      
Line 371:        public byte TreeLevel {                                                                                                             
Line 372:            get { return (byte) ((Value[1] >> 48) & 0x3f); }                                                                                
Line 373:            set {                                                                                                                           
Line 374:                if (value > 63)                                                                                                             
Line 375:                    throw new ArgumentOutOfRangeException("TreeLevel""TreeLevel must be in 0-63");                                        
Line 376:                Value[1] &= ~(0x3FUL << 48); // mask out                                                                                    
Line 377:                Value[1] |= ((ulong)value << 48);   // or in                                                                                
Line 378:            }                                                                                                                               
Line 379:        }                                                                                                                                   
Line 380:                                                                                                                                            
Line 381:        /// <summary>                                                                                                                       
Line 382:        /// Get/set UBI block type                                                                                                          
Line 383:        /// </summary>                                                                                                                      
Line 384:        public UbiType BlockType                                                                                                            
Line 385:        {                                                                                                                                   
Line 386:            get { return (UbiType)((Value[1] >> 56)&0x3f); }                                                                                
Line 387:            set                                                                                                                             
Line 388:            {                                                                                                                               
Line 389:                Value[1] &= ~(0x3FUL << 56);      // mask out                                                                               
Line 390:                Value[1] |= ((ulong)value << 56); // or in                                                                                  
Line 391:            }                                                                                                                               
Line 392:        }                                                                                                                                   
Line 393:                                                                                                                                            
Line 394:        /// <summary>                                                                                                                       
Line 395:        /// The bit position. TODO  - only supports 64 bits but needs to do 96 bits.                                                        
Line 396:        /// </summary>                                                                                                                      
Line 397:        public ulong Position { get { return Value[0]; } set { Value[0] = value; } }                                                        
Line 398:                                                                                                                                            
Line 399:    }                                                                                                                                       
Line 400:                                                                                                                                            
Line 401:    /// <summary>                                                                                                                           
Line 402:    /// An implementation of the Threefish encryption function.                                                                             
Line 403:    /// TODO - make it implement .NET SymmetricAlgorithm and ICryptoTransform interfaces                                                    
Line 404:    /// </summary>                                                                                                                          
Line 405:    public class Threefish                                                                                                                  
Line 406:        {                                                                                                                                   
Line 407:        /// <summary>                                                                                                                       
Line 408:        /// Create a Threefish encryption/decryption object.                                                                                
Line 409:        /// Requires bitLength in bits of key and plaintext blocks.                                                                         
Line 410:        /// Length must be one of 256, 512, or 1024.                                                                                        
Line 411:        /// </summary>                                                                                                                      
Line 412:        /// <param name="bitLength">Length in bits of key (256, 512, or 1024)</param>                                                       
Line 413:        public Threefish(uint bitLength)                                                                                                    
Line 414:            {                                                                                                                               
Line 415:            if ((bitLength != 256) && (bitLength != 512) && (bitLength != 1024))                                                            
Line 416:                throw new ArgumentOutOfRangeException("bitLength""Threefish bit length must be one of 256, 512, or 1024");                
Line 417:            Nw = bitLength / 64; // number of 64 bit words                                                                                  
Line 418:            Nr = 72;          // number of rounds                                                                                           
Line 419:            if (Nw == 16) Nr = 80;                                                                                                          
Line 420:                                                                                                                                            
Line 421:            // set up tables and functions                                                                                                  
Line 422:            if (Nw == 4)                                                                                                                    
Line 423:                {                                                                                                                           
Line 424:                R = Rtbl4;                                                                                                                  
Line 425:                Permute = Permute4;                                                                                                         
Line 426:                Unpermute = Unpermute4;                                                                                                     
Line 427:                }                                                                                                                           
Line 428:            else if (Nw == 8)                                                                                                               
Line 429:                {                                                                                                                           
Line 430:                R = Rtbl8;                                                                                                                  
Line 431:                Permute = Permute8;                                                                                                         
Line 432:                Unpermute = Unpermute8;                                                                                                     
Line 433:                }                                                                                                                           
Line 434:            else if (Nw == 16)                                                                                                              
Line 435:                {                                                                                                                           
Line 436:                R = Rtbl16;                                                                                                                 
Line 437:                Permute = Permute16;                                                                                                        
Line 438:                Unpermute = Unpermute16;                                                                                                    
Line 439:                }                                                                                                                           
Line 440:                                                                                                                                            
Line 441:            Ks = new ulong[Nw + 1]; // sub-key storage                                                                                      
Line 442:            t = new ulong[3];       // t0,t1,t2 tweak values                                                                                
Line 443:            } // constructor                                                                                                                
Line 444:                                                                                                                                            
Line 445:        /// <summary>                                                                                                                       
Line 446:        /// Encrypt a block.                                                                                                                
Line 447:        /// Requires key, plaintext, and a tweak value.                                                                                     
Line 448:        /// Returns encrypted text.                                                                                                         
Line 449:        /// </summary>                                                                                                                      
Line 450:        /// <param name="K">Key to encrypt. Must be 32, 64, or 128 bytes and same size as plaintext P.</param>                              
Line 451:        /// <param name="T">16 byte tweak value (2 ulongs). Must be the same for decryption.</param>                                        
Line 452:        /// <param name="P">Plaintext to encrypt. Must be 32, 64, or 128 bytes and same size as key K.</param>                              
Line 453:        /// <returns>The encrypted bytes.</returns>                                                                                         
Line 454:        public byte[] EncryptBlock(byte[] K, ulong[] T, byte[] P)                                                                           
Line 455:            {                                                                                                                               
Line 456:            int keylen = K.Length;                                                                                                          
Line 457:            if ((keylen != 32) && (keylen != 64) && (keylen != 128))                                                                        
Line 458:                throw new ArgumentException("Key bitLength not 32, 64, or 128 bytes.");                                                     
Line 459:            int textlen = P.Length;                                                                                                         
Line 460:            if ((textlen != 32) && (textlen != 64) && (textlen != 128))                                                                     
Line 461:                throw new ArgumentException("Plaintext bitLength not 32, 64, or 128 bytes.");                                               
Line 462:            if (keylen != textlen)                                                                                                          
Line 463:                throw new ArgumentException("Plaintext bitLength must match key bitLength.");                                               
Line 464:            if (T.Length != 2)                                                                                                              
Line 465:                throw new ArgumentException("Tweak must be 16 bytes (2 longs)");                                                            
Line 466:                                                                                                                                            
Line 467:            var P1 = SkeinByteConverter.BytesToWords(P);                                                                                    
Line 468:            EncryptBlock(SkeinByteConverter.BytesToWords(K), T, P1, 0);                                                                     
Line 469:            return SkeinByteConverter.WordsToBytes(P1);                                                                                     
Line 470:            }                                                                                                                               
Line 471:                                                                                                                                            
Line 472:        /// <summary>                                                                                                                       
Line 473:        /// Decrypt a block.                                                                                                                
Line 474:        /// Requires key, ciphertext, and a tweak value.                                                                                    
Line 475:        /// Returns decrypted text.                                                                                                         
Line 476:        /// </summary>                                                                                                                      
Line 477:        /// <param name="K">Key to decrypt. Must be 32, 64, or 128 bytes and same size as ciphertext C.</param>                             
Line 478:        /// <param name="T">16 byte tweak value (2 ulongs). Must be the same for encryption.</param>                                        
Line 479:        /// <param name="C">Ciphertext to decrypt. Must be 32, 64, or 128 bytes and same size as key K.</param>                             
Line 480:        /// <returns>The decrypted bytes.</returns>                                                                                         
Line 481:        public byte[] DecryptBlock(byte[] K, ulong [] T, byte[] C)                                                                          
Line 482:            {                                                                                                                               
Line 483:            int keylen = K.Length;                                                                                                          
Line 484:            if ((keylen != 32) && (keylen != 64) && (keylen != 128))                                                                        
Line 485:                throw new ArgumentException("Key bitLength not 32, 64, or 128 bytes.");                                                     
Line 486:            int cipherlen = C.Length;                                                                                                       
Line 487:            if ((cipherlen != 32) && (cipherlen != 64) && (cipherlen != 128))                                                               
Line 488:                throw new ArgumentException("Ciphertext bitLength not 32, 64, or 128 bytes.");                                              
Line 489:            if (keylen != cipherlen)                                                                                                        
Line 490:                throw new ArgumentException("Ciphertext bitLength must match key bitLength.");                                              
Line 491:            if (T.Length != 2)                                                                                                              
Line 492:                throw new ArgumentException("Tweak must be 16 bytes (2 ulongs)");                                                           
Line 493:                                                                                                                                            
Line 494:            ulong [] C1 = SkeinByteConverter.BytesToWords(C);                                                                               
Line 495:            DecryptBlock(SkeinByteConverter.BytesToWords(K), T, C1, 0);                                                                     
Line 496:            return SkeinByteConverter.WordsToBytes(C1);                                                                                     
Line 497:            }                                                                                                                               
Line 498:                                                                                                                                            
Line 499:                                                                                                                                            
Line 500:        #region Implementation                                                                                                              
Line 501:        /// <summary>                                                                                                                       
Line 502:        /// Number of 64 bit words per block Nw, and number of rounds Nr                                                                    
Line 503:        /// </summary>                                                                                                                      
Line 504:        uint Nw, Nr;                                                                                                                        
Line 505:        /// <summary>                                                                                                                       
Line 506:        /// The lengthened key state                                                                                                        
Line 507:        /// </summary>                                                                                                                      
Line 508:        ulong[] Ks = null;                                                                                                                  
Line 509:        /// <summary>                                                                                                                       
Line 510:        /// The lengthened tweak values                                                                                                     
Line 511:        /// </summary>                                                                                                                      
Line 512:        ulong[] t = null;                                                                                                                   
Line 513:                                                                                                                                            
Line 514:#if SKEIN13                                                                                                                                 
Line 515:        const ulong KeyScheduleConstant = 0x1BD11BDAA9FC1A22UL;                                                                             
Line 516:#else                                                                                                                                       
Line 517:        const ulong KeyScheduleConstant = 0x5555555555555555UL; // Floor[2^64 / 3]                                                          
Line 518:#endif                                                                                                                                      
Line 519:                                                                                                                                            
Line 520:                                                                                                                                            
Line 521:        /// <summary>                                                                                                                       
Line 522:        /// Encrypt a block in place. Thus P is the plaintext on input, and the cipertext on output                                         
Line 523:        /// </summary>                                                                                                                      
Line 524:        /// <param name="K">Key is 4, 8, or 16 64-bit values</param>                                                                        
Line 525:        /// <param name="T">Two 64-bit values for the tweak value.</param>                                                                  
Line 526:        /// <param name="P">Plaintext. A block of data, same bitLength as key K</param>                                                     
Line 527:        /// <param name="start">Start offset into P for encryption</param>                                                                  
Line 528:        public void EncryptBlock(ulong[] K, ulong[] T, ulong[] P, ulong start)                                                              
Line 529:            {                                                                                                                               
Line 530:            if ((K.Length != 4) && (K.Length != 8) && (K.Length != 16))                                                                     
Line 531:                throw new ArgumentOutOfRangeException("K""K must be 4,8, or 16 values in bitLength");                                     
Line 532:            if (K.Length > P.Length - (int)start)                                                                                           
Line 533:                throw new ArgumentOutOfRangeException("K and block""Block must have at least the bitLength of the key K");                
Line 534:                                                                                                                                            
Line 535:            // copy key to longer key for key scheduling                                                                                    
Line 536:            Ks[Nw] = KeyScheduleConstant;                                                                                                   
Line 537:            for (int i = 0; i < Nw; ++i)                                                                                                    
Line 538:                {                                                                                                                           
Line 539:                Ks[i] = K[i];                                                                                                               
Line 540:                Ks[Nw] ^= K[i];                                                                                                             
Line 541:                }                                                                                                                           
Line 542:                                                                                                                                            
Line 543:            // more key schedule parameters                                                                                                 
Line 544:            t[0] = T[0];                                                                                                                    
Line 545:            t[1] = T[1];                                                                                                                    
Line 546:            t[2] = T[0] ^ T[1];                                                                                                             
Line 547:                                                                                                                                            
Line 548:            for (uint d = 0; d < Nr; ++d) // d is round number as in spec                                                                   
Line 549:                {                                                                                                                           
Line 550:                if ((d & 3) == 0)                                                                                                           
Line 551:                    AddSubkey(d / 4, P, start);                                                                                             
Line 552:                // apply MIX to data two words at a time                                                                                    
Line 553:                for (uint j = 0; j < Nw / 2; ++j) // i is word number as in spec                                                            
Line 554:                    {                                                                                                                       
Line 555:                    MIX(P,2*j+start,R[d&7,j]);                                                                                              
Line 556:                    }                                                                                                                       
Line 557:                Permute(P, start);                                                                                                          
Line 558:                }                                                                                                                           
Line 559:                                                                                                                                            
Line 560:            // final cipertext                                                                                                              
Line 561:            AddSubkey(Nr / 4, P, start);                                                                                                    
Line 562:            } // EncryptBlock                                                                                                               
Line 563:                                                                                                                                            
Line 564:        /// <summary>                                                                                                                       
Line 565:        /// Decrypt a block in place. Thus C is the ciphertext on input, and the plaintext on output                                        
Line 566:        /// </summary>                                                                                                                      
Line 567:        /// <param name="K">Key, 4,8, or 16 64-bit values</param>                                                                           
Line 568:        /// <param name="T">2 64-bit values</param>                                                                                         
Line 569:        /// <param name="C">Ciphertext. A block of data, same bitLength as key K</param>                                                    
Line 570:        protected void DecryptBlock(ulong[] K, ulong[] T, ulong[] C, ulong start)                                                           
Line 571:            {                                                                                                                               
Line 572:            if ((K.Length != 4) && (K.Length != 8) && (K.Length != 16))                                                                     
Line 573:                throw new ArgumentOutOfRangeException("K""K must be 4,8, or 16 values in bitLength");                                     
Line 574: &nbs