SignatureHash
[NovacoinLibrary.git] / Novacoin / ScriptCode.cs
index 6d69349..6f50fc0 100644 (file)
@@ -167,6 +167,17 @@ namespace Novacoin
         TX_NULL_DATA,
     };
 
+    /// <summary>
+    /// Signature hash types/flags
+    /// </summary>
+    public enum sigflag
+    {
+        SIGHASH_ALL = 1,
+        SIGHASH_NONE = 2,
+        SIGHASH_SINGLE = 3,
+        SIGHASH_ANYONECANPAY = 0x80,
+    };
+
     public static class ScriptCode
     {
 
@@ -661,7 +672,7 @@ namespace Novacoin
                 typeRet = txnouttype.TX_SCRIPTHASH;
 
                 // Take 20 bytes with offset of 2 bytes
-                IEnumerable<byte> hashBytes = scriptPubKey.Enumerable.Skip(2).Take(20);
+                IEnumerable<byte> hashBytes = scriptPubKey.Bytes.Skip(2).Take(20);
                 solutions.Add(hashBytes);
 
                 return true;
@@ -673,7 +684,7 @@ namespace Novacoin
                 typeRet = txnouttype.TX_PUBKEYHASH;
 
                 // Take 20 bytes with offset of 3 bytes
-                IEnumerable<byte> hashBytes = scriptPubKey.Enumerable.Skip(3).Take(20);
+                IEnumerable<byte> hashBytes = scriptPubKey.Bytes.Skip(3).Take(20);
                 solutions.Add(hashBytes);
 
                 return true;
@@ -722,8 +733,8 @@ namespace Novacoin
 
                 IEnumerable<byte> args1, args2;
 
-                byte last1 = script1.Enumerable.Last();
-                byte last2 = script2.Enumerable.Last();
+                byte last1 = script1.Bytes.Last();
+                byte last2 = script2.Bytes.Last();
 
                 while (true)
                 {
@@ -820,5 +831,85 @@ namespace Novacoin
 
             return false;
         }
+
+        public static Hash256 SignatureHash(CScript scriptCode, CTransaction txTo, int nIn, int nHashType)
+        {
+            if (nIn >= txTo.vin.Length)
+            {
+                StringBuilder sb = new StringBuilder();
+                sb.AppendFormat("ERROR: SignatureHash() : nIn={0} out of range\n", nIn);
+                throw new ArgumentOutOfRangeException("nIn", sb.ToString());
+            }
+
+            CTransaction txTmp = new CTransaction(txTo);
+
+            // In case concatenating two scripts ends up with two codeseparators,
+            // or an extra one at the end, this prevents all those possible incompatibilities.
+            scriptCode.RemovePattern(new byte[] { (byte)opcodetype.OP_CODESEPARATOR });
+
+            // Blank out other inputs' signatures
+            for (int i = 0; i < txTmp.vin.Length; i++)
+            {
+                txTmp.vin[i].scriptSig = new CScript();
+            }
+            txTmp.vin[nIn].scriptSig = scriptCode;
+
+            // Blank out some of the outputs
+            if ((nHashType & 0x1f) == (int)sigflag.SIGHASH_NONE)
+            {
+                // Wildcard payee
+                txTmp.vout = null;
+
+                // Let the others update at will
+                for (int i = 0; i < txTmp.vin.Length; i++)
+                {
+                    if (i != nIn)
+                    {
+                        txTmp.vin[i].nSequence = 0;
+                    }
+                }
+            }
+            else if ((nHashType & 0x1f) == (int)sigflag.SIGHASH_SINGLE)
+            {
+                // Only lock-in the txout payee at same index as txin
+                int nOut = nIn;
+                if (nOut >= txTmp.vout.Length)
+                {
+                    StringBuilder sb = new StringBuilder();
+                    sb.AppendFormat("ERROR: SignatureHash() : nOut={0} out of range\n", nOut);
+                    throw new ArgumentOutOfRangeException("nOut", sb.ToString());
+                }
+                Array.Resize(ref txTmp.vout, nOut + 1);
+
+                for (int i = 0; i < nOut; i++)
+                {
+                    txTmp.vout[i] = new CTxOut();
+                }
+
+                // Let the others update at will
+                for (int i = 0; i < txTmp.vin.Length; i++)
+                {
+                    if (i != nIn)
+                    {
+                        txTmp.vin[i].nSequence = 0;
+                    }
+                }
+            }
+
+            // Blank out other inputs completely, not recommended for open transactions
+            if ((nHashType & (int)sigflag.SIGHASH_ANYONECANPAY) != 0)
+            {
+                txTmp.vin[0] = txTmp.vin[nIn];
+                Array.Resize(ref txTmp.vin, 1);
+            }
+
+            // Serialize and hash
+            List<byte> b = new List<byte>();
+            b.AddRange(txTmp.Bytes);
+            b.AddRange(BitConverter.GetBytes(nHashType));
+
+            return Hash256.Compute256(b);
+        }
+
     };
 }