def getSignatures(message, circle):
    signatures = []

    hashMessage = encryptionUtilities.getHashofInput(message)

    for agent in circle:
        signatures.append({agent : encryptionUtilities.signMessage(hashMessage, agentPriKeys[agent])})

    return signatures
def validateInstruction(instruction):
  returnValue = {
        'message': f'Instruction Accepted',
        'return': True
    }

  body = instruction['instruction']
  hash = instruction['instructionHash']
  sign = instruction['signature']
  sender = body['sender']

  if redisUtilities.getInstructionLuaHash(body['name']) == None:
      returnValue['message'] = f"Instruction name: {body['name']} in invalid"
      returnValue['return'] = False
      return returnValue

  #TODO add check for lua hash matching, args list matching and keys list matching

  if encryptionUtilities.getHashofInput(body) != hash:
      logging.info(f'hash of instruction does not match: {encryptionUtilities.getHashofInput(body)}')
      returnValue['message'] = f'Incorrect hash for Instruction at {hash}'
      returnValue['return'] = False
      return returnValue

  publicKey = redisUtilities.getPublicKey(sender)

  logging.debug(f'publicKey is {publicKey}')

  # if getPubKey of sender is None, we dont know the sender (not on chain).  We deny them
  if publicKey == None:
      logging.info(f'Sender not known, reject')
      returnValue['message'] = f'Public Key of sender not registered on chain'
      returnValue['return'] = False
      return returnValue

  # TODO confirm signature - if this is false then reject (sohuld we untrust sender?)
  if encryptionUtilities.verifyMessage(hash, sign, publicKey) != True:
      logging.info(f'Instruction for {hash} not verified - signature {sign} for {publicKey} pkey incorrect')
      returnValue['message'] = f'Signature does not match'
      returnValue['return'] = False

  return returnValue
Exemplo n.º 3
0
    def __init__(self, blockID, entityInstructions):

        self.block = redisUtilities.getCandidateBlock(blockID)

        logging.debug(f'in parseBlock')
        self.blockHash = self.block['blockHash']
        logging.debug(f'Block Hash is {self.blockHash}')
        self.blockHeader = self.block['blockHeader']
        self.convergenceHeader = self.blockHeader['convergenceHeader']
        self.consensusCircle = self.blockHeader['consensusCircle']
        self.blockSignatures = self.blockHeader['blockSignatures']
        self.instructionCount = self.convergenceHeader['instructionCount']
        self.instructionsMerkleRoot = self.convergenceHeader[
            'instructionsMerkleRoot']
        self.previousBlock = self.convergenceHeader['previousBlock']
        self.blockHeight = self.convergenceHeader['blockHeight']
        self.randomNumbers = self.convergenceHeader[
            'randomNumbers']  # Need to parse by circle for convergence matrix
        self.instructions = self.block['instructions']

        self.randomMatrix = []
        self.ccKeys = []
        self.blockSigs = []

        self.instructionHashes = []
        self.instructionBodies = []

        self.blockPass = True
        self.blockComment = 'Block Conforms'

        logging.debug(f'checking block not on chain {self.blockHash}')
        if (redisUtilities.blockExists(self.blockHash)):
            self.blockPass = False
            self.blockComment = "this block is already on the chain"

        logging.debug(f'checking previous block {self.previousBlock} exists')
        if not (redisUtilities.blockExists(self.previousBlock)):
            self.blockPass = False
            self.blockComment = "previous block is not known to this agent"

        logging.debug(
            f'checking the block height is correct relative to the identified previous block'
        )
        if (self.blockHeight !=
            (redisUtilities.getBlockHeight(self.previousBlock) + 1)):
            self.blockPass = False
            self.blockComment = "block height incorrect"
            logging.info(
                f'block height is not valid. was: {self.blockHeight}, should be: {redisUtilities.getBlockHeight()+1}'
            )

        logging.debug(f'random Numbers are {self.randomNumbers}')
        for e in self.randomNumbers:
            for f in e.values():
                self.randomMatrix.append(f)

        for e in self.consensusCircle:
            self.ccKeys.append(e['agentID'])

        logging.info(f'randomMatrix is {self.randomMatrix}')

        # Now do checks:
        # Is blockhash the same
        # TODO confirm json.dumps is deterministic.  If order changes then hash will change.  May need more reliable approach
        # TODO use orderedDict for loading: https://stackoverflow.com/questions/2774361/json-output-sorting-in-python
        self.calculatedHash = encryptionUtilities.getHashofInput(
            self.blockHeader)
        logging.info(
            f'blockhash is: \n{self.blockHash}\nCalculated:\n{self.calculatedHash}\n'
        )
        if self.blockHash != self.calculatedHash:
            self.blockPass = False
            self.blockComment = 'blockHash is not correct'
            return

        # Are the instructions hashed and signed?
        for e in self.instructions:
            validInstruction = blockUtilities.validateInstruction(e)
            if not validInstruction['return']:
                self.blockPass = False
                self.blockComment = validInstruction['message']
                return
            self.instructionHashes.append(e['instructionHash'])

        # Check instruction count is the same from header
        if self.instructionCount != len(self.instructionHashes):
            self.blockPass = False
            self.blockComment = f'instructionCount is not same as number instructions'
            return

        # Does the merkleroot of the instructions map to the header?
        if encryptionUtilities.returnMerkleRoot(
                self.instructionHashes) != self.instructionsMerkleRoot:
            self.blockPass = False
            logging.info(
                f'merkle root does not match got {encryptionUtilities.returnMerkleRoot(self.instructionHashes)} expected {self.instructionsMerkleRoot}'
            )
            self.blockComment = f'instruction merkle root of {self.instructionsMerkleRoot} != calculated merkle root of {encryptionUtilities.returnMerkleRoot(self.instructionHashes)}'
            return

        # Check consensus circle has signed off on the convergenceHeader
        logging.debug(f'parsing  blockSig {self.blockSignatures}')
        for e in self.blockSignatures:
            self.blockSigs.append(list(e.values())[0])

        rlen, clen, blen, j, i = len(self.randomMatrix), len(self.ccKeys), len(
            self.blockSigs), 0, 0

        # Check Lengths
        if rlen != clen:
            selfblockPass = False
            self.blockComment = 'array length of random Numbers not same as consensusCircle'
            return

        if blen != clen:
            selfblockPass = False
            self.blockComment = 'length of block Signatures not same as consensusCircle'
            return

        hashConvergenceHeader = encryptionUtilities.getHashofInput(
            self.convergenceHeader)
        logging.info(
            f'\nhash of convergenceHeader is {hashConvergenceHeader}\n')
        while i < clen:
            if encryptionUtilities.verifyMessage(
                    hashConvergenceHeader, self.blockSigs[i],
                    redisUtilities.getPublicKey(self.ccKeys[i])) != True:
                self.blockPass = False
                self.blockComment = f'signature for Circle at {i} is not valid'
                return
            i += 1

        # Converge the Matrix
        self.outputMatrix = [
            g for g in encryptionUtilities.converge(self.randomMatrix, 2**256)
        ]
        logging.info(f'Converged Matrix is {self.outputMatrix}')

        self.circleDistance = encryptionUtilities.returnCircleDistance(
            redisUtilities.getOutputMatrix(self.previousBlock), self.ccKeys,
            self.instructionCount, entityInstructions)

        # remove anything that there is duplicates of for printing
        del self.block
        del self.convergenceHeader
        del self.consensusCircle
        del self.blockSignatures
        del self.instructionCount
        del self.instructionsMerkleRoot
        del self.previousBlock
        del self.blockHeight
        del self.randomNumbers
        del self.randomMatrix

        return
        "level":
        "protector",
        "agentID":
        "031a3a259e059ec67971841a267528af2fc42bfcc1271259164b822fedf86102"
    }, {
        "level":
        "protector",
        "agentID":
        "5aebce47cab0ff962b7bfde34949f557e5826ccf0a8a572e2f8c8769deb8e58b"
    }],
    "blockSignatures": [{
        "180cedac0f95b45ec18cdcd473d14d44b512ef16fc065e6c75c769b544d06675":
        "3046022100d2db6c6b50e45d35ef61f7ab23423b64faafee5875ae08766eaabe7db9c15d3d022100f8a9c062b2ad1b57b0f469d78d70624bd2247ea7c92f6f11d8660936f9bfb70b"
    }, {
        "2efb6ec38d1f9ccfa4b1b88bd98ab9b09c4a484496a5713af177b971ccfb922b":
        "304502205e1aed5f901131dd31751e1c24557921f1bcbeb05651b7ab5a862db7accc88f8022100e3e3ab08f3c197e479464c3792259fdd07f4b089d36ba30044abbfcb4e491872"
    }, {
        "2c24af4bd0889b10e325733c9b468779db7b2a82e9052df3b46a8aa1078262ea":
        "3046022100ce6a49d5eb25ab0cb273eb0a6850cd8d85eb2e1dcb7a742a31acaf800f6202e2022100fa1b985cc01b74baa5e3070d7961e39460713241baddd0ab0372073dcf0141ff"
    }, {
        "031a3a259e059ec67971841a267528af2fc42bfcc1271259164b822fedf86102":
        "304502204b34e301739a03337144edd9082983d9a9b0c37ccc00faf6077157fff87129c9022100d5e99b30fa6b0bc6534e599c7c418772908453a799b0939b985f09fa172f8e64"
    }, {
        "5aebce47cab0ff962b7bfde34949f557e5826ccf0a8a572e2f8c8769deb8e58b":
        "30450221008596db19f7f309014c89710cde90bf870f17b5102b9c615ee6d07c15a435bc82022045a863a55cff29ba6b52c4614484bb438ddbd641528fc338f33139ada0865e59"
    }]
}

print('Block hash:')
print(getHashofInput(blockHeader))
Exemplo n.º 5
0
def generateNextCircle():

    logging.debug("in generateNextCircle")

    # should always be the latest block that you are generating the next circle from
    circle = nextCircle(redisUtilities.getOutputMatrix(
    ))  # No excluded agents for now, get matrix of last block

    logging.debug(f'next circle outputMatrix is {circle}')

    # Am I in the circle?

    if not (redisUtilities.getMyID() in circle):
        # what should happen if not in next circle?
        logging.info("I AM NOT IN THE NEXT CIRCLE.")
        return

    logging.debug("Agent is in next circle")
    # gather and check instructions
    possibleInstructions = redisUtilities.getInstructionHashes()
    logging.debug(f'possible instructions are {possibleInstructions}')
    validInstructions = []
    validInstructionHashes = []
    # TODO here: clear any mining pool from previous iterations.  (clearMining.lua script).  Hardcoded for now but put in redisUtilities
    luaHash = 'b5ef661e48d6306417d1f645c358f3d98a6148a1'
    red.evalsha(luaHash, 0)
    # TODO catch around this.  If instruction fails on a non matching script it should be removed.
    for instructionHash in possibleInstructions:
        if blockUtilities.tryInstruction(instructionHash):
            logging.debug('instruction was valid')
            validInstructionHashes.append(instructionHash)
            validInstructions.append(
                redisUtilities.getInstruction(instructionHash))

    logging.debug(f'valid instructions are: {validInstructionHashes}')
    if len(validInstructionHashes) == 0:
        logging.info("there are no valid instructions and so, no valid block")
        # TODO - do we broadcast no valid block?  Or do we pause and retry in 10s?
        return

    # TODO: global static (in Redis?) for random number size, agents in the CIRCLE
    myRandoms = [g for g in encryptionUtilities.getRandomNumbers(32, 5)]
    logging.debug(f'myRandoms are {myRandoms}')

    mySeed = encryptionUtilities.getRandomNumber(32)
    logging.debug(f'mySeed is {mySeed}')

    mySeededRandomHash = encryptionUtilities.getHashWithSeed(myRandoms, mySeed)
    logging.debug(f'seeded hash is {mySeededRandomHash}')

    convergenceHeader = {
        "previousBlock":
        redisUtilities.getBlockHash(),
        "instructionsMerkleRoot":
        encryptionUtilities.returnMerkleRoot(validInstructionHashes),
        "instructionCount":
        len(validInstructions),
        "blockHeight": (redisUtilities.getBlockHeight() + 1),
        "randomNumberHash":
        mySeededRandomHash
    }

    logging.debug(f'convergenceHeader is {convergenceHeader}')

    signature = encryptionUtilities.signMessage(
        encryptionUtilities.getHashofInput(convergenceHeader),
        redisUtilities.getMyPrivKey())

    logging.debug(f'signature is {signature}')

    blockSignatures = [{redisUtilities.getMyID(): signature}]
    logging.debug(f'blockSignatures is {blockSignatures}')
    proposedBlock = {
        "convergenceHeader": json.dumps(convergenceHeader),
        "blockSignatures": blockSignatures,
        "instructions": json.dumps(validInstructions),
        "broadcaster": redisUtilities.getMyID()
    }

    logging.info(f'Proposed Block for initial convergence is {proposedBlock}')

    # Write these to blockchain?  (or after all done?)

    # TODO setup signature for convergence header

    # TODO create proposedBlock and convergence header.  Broadcast proposed block. Need to lookup addresses of the

    # TODO also update consensus emulator to emit new block type structure.

    # TODO update NODE to accumulate latest block (same convergence header) with all the random numbers

    # GREG: I think this is where we emulate the full block creation?
    approval = consensusEmulator.proposeConvergenceHeader(
        proposedBlock, circle)
    # (proposedBlock, broadcaster, signature, circle, randomHashes)

    convergenceHeader = approval['header']
    signatures = approval['signatures']
    broadcaster = approval['broadcaster']
    validInstruction = approval['validInstructions']
    circleAgents = approval['agentInfo']

    # GREG: Do in a Lucid Chart on how the circle converges
    # Setup the candidate structure and post to our convergenceProcessor to kick off the convergence process
    candidate = {}
    #
    candidate['blocksize'] = 0  #TODO
    candidate['blockHeader'] = {
        "version": "entityVersionUsed",  #TODO
        "staticHeight": "height below which a fork is not allowed",  #TODO
        "convergenceHeader": convergenceHeader,
        "consensusCircle": circleAgents,
        "blockSignatures": signatures,
    }
    candidate["blockHash"] = encryptionUtilities.getHashofInput(
        candidate['blockHeader'])
    candidate["blockOriginatedAgent"] = broadcaster
    candidate["instructions"] = validInstructions

    logging.debug(f'candidate = {candidate}')

    # writing out a file doesnt work because in the rq worker container
    distributeBlock(candidate)

    return