def test_multisig_verify_helper_verification(self): engine = test_engine() message = vm.ByteStringStackItem(b'hello') kp1 = cryptography.KeyPair(private_key=b'\x01' * 32) kp2 = cryptography.KeyPair(private_key=b'\x02' * 32) sig1 = cryptography.sign(message.to_array(), kp1.private_key) sig2 = cryptography.sign(message.to_array(), kp2.private_key) # quick pre-check the verify_signature function actually passes self.assertTrue( cryptography.verify_signature(message.to_array(), sig1, kp1.public_key.encode_point(False), cryptography.ECCCurve.SECP256R1)) self.assertTrue( cryptography.verify_signature(message.to_array(), sig2, kp2.public_key.encode_point(False), cryptography.ECCCurve.SECP256R1)) # first do a check on regular data (meaning; check sig1 with pub_key1, sig2 with pub_key2) public_keys = [ kp1.public_key.encode_point(False), kp2.public_key.encode_point(False) ] signatures = [sig1, sig2] self.assertTrue( _check_multisig(engine, message, public_keys, signatures, cryptography.ECCCurve.SECP256R1)) # same as previous, but supplying the keys out of order public_keys = [ kp2.public_key.encode_point(False), kp1.public_key.encode_point(False) ] signatures = [sig1, sig2] self.assertFalse( _check_multisig(engine, message, public_keys, signatures, cryptography.ECCCurve.SECP256R1)) # now validate it will try all available public keys for a given signature (for 1-of-2, 3-of-5 like contracts) public_keys = [ kp2.public_key.encode_point(False), kp1.public_key.encode_point(False) ] signatures = [sig1] self.assertTrue( _check_multisig(engine, message, public_keys, signatures, cryptography.ECCCurve.SECP256R1)) # test handling an exception caused by an invalid public key public_keys = [b''] signatures = [sig1] self.assertFalse( _check_multisig(engine, message, public_keys, signatures, cryptography.ECCCurve.SECP256R1))
def test_is_allowed_based_on_group(self): # We test the group permissions where all methods are allowed to be called # if the 'groups' member is valid. private_key = b'\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' keypair = cryptography.KeyPair(private_key) dummy_contract_hash = types.UInt160.from_string("01" * 20) contract_state = contracts.ContractState(1, contracts.NEF(), contracts.ContractManifest(), 0, dummy_contract_hash) signature = cryptography.sign(contract_state.hash.to_array(), keypair.private_key) contract_state.manifest.groups = [ contracts.ContractGroup(keypair.public_key, signature) ] cpd = contracts.ContractPermissionDescriptor(group=keypair.public_key) cp = contracts.ContractPermission( contract=cpd, methods=contracts.WildcardContainer.create_wildcard()) self.assertTrue(cp.is_allowed(contract_state, "dummy_method")) # now modify the manifest to have a different `groups` attribute such that validation fails public_key = cryptography.ECPoint.deserialize_from_bytes( b'\x00') # ECPoint.Infinity contract_state.manifest.groups = [ contracts.ContractGroup(public_key, signature) ] self.assertFalse(cp.is_allowed(contract_state, "dummy_method"))
def test_is_valid(self): # create a contract cm = contracts.ContractManifest("test_contract") method1 = contracts.ContractMethodDescriptor( name="main_entry", offset=0, parameters=[], return_type=contracts.ContractParameterType.INTEGER, safe=True) cm.abi.methods = [method1] # A contract hash is normally created from a combination of transaction sender (UInt160), NEF checksum and manifest.name # For this test we'll keep it simple and pretend that hash is all zeros dummy_contract_hash = types.UInt160.zero() # a "default" contract has no groups data, which is the same as always allow self.assertTrue(cm.is_valid(dummy_contract_hash)) # now try to add a malicious group member (meaning; the member did not actually sign the ABI) private_key = b'\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' keypair = cryptography.KeyPair(private_key) bad_signature = bytes(64) cm.groups = [ contracts.ContractGroup(keypair.public_key, bad_signature) ] # this time validation should fail self.assertFalse(cm.is_valid(dummy_contract_hash)) # Finally test with a group member that did sign the ABI good_signature = cryptography.sign(dummy_contract_hash.to_array(), keypair.private_key) cm.groups = [ contracts.ContractGroup(keypair.public_key, good_signature) ] self.assertTrue(cm.is_valid(dummy_contract_hash))
def test_is_valid(self): """ var private_key = new byte[] { 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1 }; var bad_signature = new byte[] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; var kp = new KeyPair(private_key); var cg = new ContractGroup() { PubKey = kp.PublicKey, Signature = bad_signature}; Console.Write(cg.ToJson()); """ bad_signature = b'\x00' * 64 cg = contracts.ContractGroup(self.keypair.public_key, bad_signature) self.assertFalse(cg.is_valid(types.UInt160.zero())) # finally test is_valid() with a keypair we know the private key off contract_hash = b'\x01' * 20 signature = cryptography.sign(contract_hash, self.keypair.private_key) cg2 = contracts.ContractGroup(self.keypair.public_key, signature) self.assertTrue(cg2.is_valid(types.UInt160(contract_hash)))
def test_verify_secp256r1(self): """ var privkey = new byte[] { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; var message = new byte[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; var signature = new byte[] { 56,70,104,22,234,182,23,161,111,25,71,188,12,5,54,28,99,189,8,47,4,82,62,150,57,216,25,130,217,25,123,118,89,149,217,130,12,109,34,125,176,189,142,119,154,140,116,16,32,209,214,87,178,248,214,39,248,29,214,10,205,153,146,111}; var kp = new KeyPair(privkey); Console.WriteLine(Crypto.VerifySignature(message, signature, kp.PublicKey.EncodePoint(false), ECCurve.Secp256r1)); """ message = b'\x01' * 32 priv_key = b'\x02' + b'\x00' * 30 + b'\x01' sig = cryptography.sign(message, priv_key) # from ecdsa import VerifyingKey, SigningKey, curves as ecdsa_curves # import hashlib # sk = SigningKey.from_string(priv_key, curve=ecdsa_curves.NIST256p, hashfunc=hashlib.sha256) # sig = sk.sign(message, hashfunc=hashlib.sha256) kp = cryptography.KeyPair(priv_key) sb = vm.ScriptBuilder() sb.emit_push(sig) sb.emit_push(kp.public_key.encode_point(False)) sb.emit_push(message) sb.emit_syscall( syscall_name_to_int("Neo.Crypto.VerifyWithECDsaSecp256r1")) engine = test_engine() script = vm.Script(sb.to_array()) engine.load_script(script) # first test with an invalid interop item. They must be IVerifiable engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) self.assertEqual(vm.BooleanStackItem(True), engine.result_stack.pop())
def sign(self, data: bytes, password: str) -> bytes: """ Sign arbitrary data using the SECP256R1 curve. Args: data: data to be signed password: the password to decrypt the private key Returns: signature of the signed data """ if self.is_watchonly: raise ValueError( "Cannot sign transaction using a watch only account") # mypy can't infer that the is_watchonly check ensures encrypted_key has a value private_key = self.private_key_from_nep2( self.encrypted_key.decode("utf-8"), password) # type: ignore return cryptography.sign(data, private_key)
def test_check_multisig_with_ECDSA_Secp256r1(self): engine = test_engine() message = vm.ByteStringStackItem(b'hello') kp1 = cryptography.KeyPair(private_key=b'\x01' * 32) sig1 = cryptography.sign(message.to_array(), kp1.private_key) sb = vm.ScriptBuilder() sb.emit_syscall( syscall_name_to_int("Neo.Crypto.CheckMultisigWithECDsaSecp256r1")) script = vm.Script(sb.to_array()) engine.load_script(script) # setup the stack for the syscall signatures = vm.ArrayStackItem(engine.reference_counter) signatures.append(vm.ByteStringStackItem(sig1)) public_keys = vm.ArrayStackItem(engine.reference_counter) public_keys.append( vm.ByteStringStackItem(kp1.public_key.encode_point(False))) engine.push(signatures) engine.push(public_keys) engine.push(message) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) self.assertEqual(vm.BooleanStackItem(True), engine.result_stack.pop()) # do the same but change the message such that the signature and key are wrong engine = test_engine() engine.load_script(script) engine.push(signatures) engine.push(public_keys) engine.push(vm.ByteStringStackItem(b'badmessage')) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) self.assertEqual(vm.BooleanStackItem(False), engine.result_stack.pop())
def test_is_valid(self): # create a default contract cm = contracts.ContractManifest() # a default contract uses a UInt160.zero as contract hash self.assertTrue(cm.is_valid(types.UInt160.zero())) self.assertFalse(cm.is_valid(types.UInt160.from_string("11" * 20))) # now try to add a malicious group member (meaning; the member did not actually sign the ABI) private_key = b'\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' keypair = cryptography.KeyPair(private_key) bad_signature = bytes(64) cm.groups = [ contracts.ContractGroup(keypair.public_key, bad_signature) ] # this time validation should fail self.assertFalse(cm.is_valid(types.UInt160.zero())) # Finally test with a group member that did sign the ABI good_signature = cryptography.sign(cm.abi.contract_hash.to_array(), keypair.private_key) cm.groups = [ contracts.ContractGroup(keypair.public_key, good_signature) ] self.assertTrue(cm.is_valid(types.UInt160.zero()))
def test_checkwitness_custom_groups(self): """ We need to setup 2 contracts 1) caller_contract: uses a System.Contract.Call to call callee_contract. This will set the calling script hash on the ExecutionContext of the callee_contract 2) callee_contract: uses a System.Runtime.CheckWitness """ engine = test_engine(has_snapshot=True, default_script=False) tx = test_tx() engine.script_container = tx ''' Create the callee contract, which does a checkwitness on its caller. Checkwitness shall only pass if the caller == "caller_contract" as defined by CustomGroup ''' sb = vm.ScriptBuilder() sb.emit_syscall( syscall_name_to_int("System.Runtime.GetCallingScriptHash") ) # get script hash of "caller_contract" sb.emit_syscall(syscall_name_to_int("System.Runtime.CheckWitness")) callee_contract_script = sb.to_array() callee_nef = contracts.NEF(script=callee_contract_script) callee_contract_name = "callee_contract" callee_manifest = contracts.ContractManifest(callee_contract_name) callee_manifest.abi.methods = [ contracts.ContractMethodDescriptor( "test_func", 0, [], contracts.ContractParameterType.ANY, True) ] callee_contract_hash = contract_hash(tx.sender, callee_nef.checksum, callee_contract_name) callee_contract = contracts.ContractState(1, callee_nef, callee_manifest, 0, callee_contract_hash) sb = vm.ScriptBuilder() sb.emit_dynamic_call(callee_contract.hash, "test_func") caller_script = sb.to_array() caller_nef = contracts.NEF(script=caller_script) caller_contract_name = "caller_contract" caller_manifest = contracts.ContractManifest(caller_contract_name) keypair = cryptography.KeyPair(private_key=b'\x01' * 32) signature = cryptography.sign(caller_script, keypair.private_key) caller_manifest.groups = [ contracts.ContractGroup(public_key=keypair.public_key, signature=signature) ] caller_contract_hash = contract_hash(tx.sender, caller_nef.checksum, caller_contract_name) caller_contract = contracts.ContractState(2, caller_nef, caller_manifest, 0, caller_contract_hash) engine.snapshot.contracts.put(caller_contract) engine.snapshot.contracts.put(callee_contract) engine.load_script(vm.Script(caller_script)) tx.signers[0].scope = payloads.WitnessScope.CUSTOM_GROUPS tx.signers[0].allowed_groups = [keypair.public_key] engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertTrue(item.to_boolean()) # now try again but make sure it fails if the public key is not listed in the allowed groups engine = test_engine(has_snapshot=True, default_script=False) tx = test_tx() engine.script_container = tx engine.snapshot.contracts.put(caller_contract) engine.snapshot.contracts.put(callee_contract) engine.load_script(vm.Script(caller_script)) tx.signers[0].scope = payloads.WitnessScope.CUSTOM_GROUPS keypair = cryptography.KeyPair(private_key=b'\x02' * 32) tx.signers[0].allowed_groups = [keypair.public_key] engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertFalse(item.to_boolean())
def test_checkwitness_custom_groups(self): """ We need to setup 2 contracts 1) caller_contract: uses a System.Contract.Call to call callee_contract. This will set the calling script hash on the ExecutionContext of the callee_contract 2) callee_contract: uses a System.Runtime.CheckWitness """ engine = test_engine(has_snapshot=True, default_script=False) tx = test_tx() engine.script_container = tx sb = vm.ScriptBuilder() sb.emit_push(tx.sender.to_array()) sb.emit_syscall(syscall_name_to_int("System.Runtime.CheckWitness")) callee_contract_script = sb.to_array() callee_manifest = contracts.ContractManifest( contract_hash=to_script_hash(callee_contract_script)) callee_manifest.abi.methods = [ contracts.ContractMethodDescriptor( "test_func", 0, [], contracts.ContractParameterType.ANY) ] callee_contract = storage.ContractState(callee_contract_script, callee_manifest) sb = vm.ScriptBuilder() sb.emit(vm.OpCode.NEWARRAY0) # args (empty array) sb.emit_push('test_func') # target method name sb.emit_push(callee_contract.script_hash().to_array()) # contract hash sb.emit_syscall(syscall_name_to_int("System.Contract.Call")) caller_script = sb.to_array() caller_manifest = contracts.ContractManifest( contract_hash=to_script_hash(caller_script)) keypair = cryptography.KeyPair(private_key=b'\x01' * 32) signature = cryptography.sign(caller_script, keypair.private_key) caller_manifest.groups = [ contracts.ContractGroup(public_key=keypair.public_key, signature=signature) ] caller_contract = storage.ContractState(caller_script, caller_manifest) engine.snapshot.contracts.put(caller_contract) engine.snapshot.contracts.put(callee_contract) engine.load_script(vm.Script(caller_script)) tx.signers[0].scope = payloads.WitnessScope.CUSTOM_GROUPS tx.signers[0].allowed_groups = [keypair.public_key] engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertTrue(item.to_boolean()) # now try again but make sure it fails if the public key is not listed in the allowed groups engine = test_engine(has_snapshot=True, default_script=False) tx = test_tx() engine.script_container = tx engine.snapshot.contracts.put(caller_contract) engine.snapshot.contracts.put(callee_contract) engine.load_script(vm.Script(caller_script)) tx.signers[0].scope = payloads.WitnessScope.CUSTOM_GROUPS keypair = cryptography.KeyPair(private_key=b'\x02' * 32) tx.signers[0].allowed_groups = [keypair.public_key] engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(1, len(engine.result_stack)) item = engine.result_stack.pop() self.assertFalse(item.to_boolean())