public void can_always_recover_pubkey_from_signature_when_stopping_at_null() { var rand = new Random(); for (int i = 0; i < 1000; i++) { var key = new Key(); PosBlock block = new PosBlock(new BlockHeader() { Time = (uint)rand.Next() }); ECDSASignature signature = key.Sign(block.GetHash()); block.BlockSignature = new BlockSignature { Signature = signature.ToDER() }; Assert.True(key.PubKey.Verify(block.GetHash(), new ECDSASignature(block.BlockSignature.Signature))); signature = ECDSASignature.FromDER(block.BlockSignature.Signature); bool match = false; for (int recId = 0; !match; recId++) { PubKey pubKeyForSig = PubKey.RecoverFromSignature(recId, signature, block.GetHash(), true); if (pubKeyForSig == null) { break; } match = pubKeyForSig == key.PubKey; } Assert.True(match); } }
/// <summary> /// Checks if block signature is valid. /// </summary> /// <param name="block">The block.</param> /// <returns><c>true</c> if the signature is valid, <c>false</c> otherwise.</returns> private bool CheckBlockSignature(PosBlock block) { if (BlockStake.IsProofOfWork(block)) { bool res = block.BlockSignature.IsEmpty(); this.Logger.LogTrace("(-)[POW]:{0}", res); return(res); } if (block.BlockSignature.IsEmpty()) { this.Logger.LogTrace("(-)[EMPTY]:false"); return(false); } TxOut txout = block.Transactions[1].Outputs[1]; if (PayToPubkeyTemplate.Instance.CheckScriptPubKey(txout.ScriptPubKey)) { PubKey pubKey = PayToPubkeyTemplate.Instance.ExtractScriptPubKeyParameters(txout.ScriptPubKey); bool res = pubKey.Verify(block.GetHash(), new ECDSASignature(block.BlockSignature.Signature)); this.Logger.LogTrace("(-)[P2PK]:{0}", res); return(res); } // Block signing key also can be encoded in the nonspendable output. // This allows to not pollute UTXO set with useless outputs e.g. in case of multisig staking. List <Op> ops = txout.ScriptPubKey.ToOps().ToList(); if (!ops.Any()) // script.GetOp(pc, opcode, vchPushValue)) { this.Logger.LogTrace("(-)[NO_OPS]:false"); return(false); } if (ops.ElementAt(0).Code != OpcodeType.OP_RETURN) // OP_RETURN) { this.Logger.LogTrace("(-)[NO_OP_RETURN]:false"); return(false); } if (ops.Count != 2) { this.Logger.LogTrace("(-)[INVALID_OP_COUNT]:false"); return(false); } byte[] data = ops.ElementAt(1).PushData; if (data.Length > MaxPushDataSize) { this.Logger.LogTrace("(-)[PUSH_DATA_TOO_LARGE]:false"); return(false); } if (!ScriptEvaluationContext.IsCompressedOrUncompressedPubKey(data)) { this.Logger.LogTrace("(-)[NO_PUSH_DATA]:false"); return(false); } bool verifyRes = new PubKey(data).Verify(block.GetHash(), new ECDSASignature(block.BlockSignature.Signature)); return(verifyRes); }
/// <summary> /// Checks if block signature is valid. /// </summary> /// <param name="block">The block.</param> /// <returns><c>true</c> if the signature is valid, <c>false</c> otherwise.</returns> bool CheckBlockSignature(PosBlock block) { if (BlockStake.IsProofOfWork(block)) { var res = block.BlockSignature.IsEmpty(); this.Logger.LogTrace("(-)[POW]:{0}", res); return(res); } var consensusRules = (PosConsensusRuleEngine)this.Parent; return(consensusRules.StakeValidator.CheckStakeSignature(block.BlockSignature, block.GetHash(), block.Transactions[1])); }