bool CheckSig(ScriptStack stack, byte[] sigHash) { var publicKey = stack.PopPublicKey(); var signature = stack.PopSignature(); var result = publicKey.Verify(sigHash, signature); return(result); }
IList <Signature> PopSignatures(ScriptStack stack, BigInteger count) { var signatures = new List <Signature>(); while (count-- > 0) { signatures.Add(stack.PopSignature()); } return(signatures); }
IList <PublicKey> PopKeys(ScriptStack stack, BigInteger count) { var publicKeys = new List <PublicKey>(); while (count-- > 0) { publicKeys.Add(stack.PopPublicKey()); } return(publicKeys); }
bool Evaluate(OpCode opCode, ScriptStack stack, byte[] sigHash) { switch (opCode) { case OpCode.OP_CHECKSIG: return(stack.Push(CheckSig(stack, sigHash))); case OpCode.OP_CHECKMULTISIG: return(stack.Push(CheckMultiSig(stack, sigHash))); default: throw new NotImplementedException(); } }
bool CheckMultiSig(ScriptStack stack, byte[] sigHash) { var publicKeys = PopKeys(stack, stack.PopInt()); var signatures = PopSignatures(stack, stack.PopInt()); stack.PopInt(); // Satoshi off-by-one var keyIndex = 0; foreach (var signature in signatures) { while (!publicKeys[keyIndex++].Verify(sigHash, signature)) { if (keyIndex >= publicKeys.Count) { return(false); } } } return(true); }
bool Evaluate(OpCode opCode, ScriptStack stack, ScriptStack altStack) { throw new NotImplementedException(); }
bool Evaluate(OpCode opCode, ScriptStack stack, IEnumerable <object> commands) { throw new NotImplementedException(); }
public bool Evaluate(IEnumerable <object> scriptCommands, byte[]?sigHash = null) { var commands = new Queue <object>(scriptCommands ?? throw new ArgumentNullException(nameof(scriptCommands))); var stack = new ScriptStack(); var altStack = new ScriptStack(); while (commands.Count > 0) { if (IsPayToScriptHash(commands)) { var redeemScript = DecodeRedeemScript((byte[])commands.Dequeue()); commands = new Queue <object>(redeemScript.Commands); } var command = commands.Dequeue(); if (command is byte[] bytes) { stack.Push(bytes); } else if (command is OpCode opCode) { var result = false; try { switch (GetOpertationType(opCode)) { case OpertationType.Stack: result = Evaluate(opCode, stack); break; case OpertationType.SigHash: result = Evaluate(opCode, stack, sigHash ?? throw new ArgumentNullException(nameof(sigHash))); break; case OpertationType.Commands: result = Evaluate(opCode, stack, commands); break; case OpertationType.AltStack: result = Evaluate(opCode, stack, altStack); break; } } catch (FormatException ex) { if (throwOnFailure) { throw new VerificationException("Bad format", ex); } } catch (InvalidOperationException ex) { if (throwOnFailure) { throw new VerificationException("Bad operation", ex); } } if (!result) { if (throwOnFailure) { throw new VerificationException("Script evaluation false"); } return(false); } } else { throw new InvalidOperationException("Invalid command type"); } } return(stack.Count > 0 && stack.Pop().Length > 0); }
bool Evaluate(OpCode opCode, ScriptStack stack) { switch (opCode) { case OpCode.OP_0: return(stack.Push(0)); case OpCode.OP_1NEGATE: return(stack.Push(-1)); case OpCode.OP_1: case OpCode.OP_2: case OpCode.OP_3: case OpCode.OP_4: case OpCode.OP_5: case OpCode.OP_6: case OpCode.OP_7: case OpCode.OP_8: case OpCode.OP_9: case OpCode.OP_10: case OpCode.OP_11: case OpCode.OP_12: case OpCode.OP_13: case OpCode.OP_14: case OpCode.OP_15: case OpCode.OP_16: return(stack.Push((int)opCode - (int)OpCode.OP_1 + 1)); case OpCode.OP_NOP: case OpCode.OP_NOP1: case OpCode.OP_NOP4: case OpCode.OP_NOP5: case OpCode.OP_NOP6: case OpCode.OP_NOP7: case OpCode.OP_NOP8: case OpCode.OP_NOP9: case OpCode.OP_NOP10: return(true); case OpCode.OP_DUP: return(stack.Push(stack.Peek())); case OpCode.OP_2DUP: var d1 = stack.Pop(); var d2 = stack.Peek(); stack.Push(d1); stack.Push(d2); return(stack.Push(d1)); case OpCode.OP_SWAP: var s1 = stack.Pop(); var s2 = stack.Pop(); stack.Push(s1); return(stack.Push(s2)); case OpCode.OP_VERIFY: return(stack.Pop().Length > 0); case OpCode.OP_EQUALVERIFY: return(stack.Pop().SequenceEqual(stack.Pop())); case OpCode.OP_HASH160: return(stack.Push(Cipher.Hash160(stack.Pop()))); case OpCode.OP_SHA1: return(stack.Push(Cipher.Sha1(stack.Pop()))); case OpCode.OP_ADD: return(stack.Push(stack.PopInt() + stack.PopInt())); case OpCode.OP_MUL: return(stack.Push(stack.PopInt() * stack.PopInt())); case OpCode.OP_EQUAL: return(stack.Push(stack.Pop().SequenceEqual(stack.Pop()) ? 1 : 0)); case OpCode.OP_NOT: return(stack.Push(stack.Pop().Length == 0 ? 1 : 0)); default: throw new InvalidOperationException("Unknown operation: " + opCode); } }