Example #1
0
    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))
Example #2
0
    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"))
Example #3
0
    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))
Example #4
0
    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)))
Example #5
0
    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())
Example #6
0
    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)
Example #7
0
    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())
Example #8
0
    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()))
Example #9
0
    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())
Example #10
0
    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())