def _generateRandomID( self, c1 = constants.CRYPTO_CHALLENGE_C1, c2 = constants.CRYPTO_CHALLENGE_C2): """Generates the NodeID by solving two cryptographic puzzles.""" # Solve the static cryptographic puzzle. rsaKey = None p = 0x1 # non-zero value pub = None randomStream = Crypto.Random.new().read while not util.hasNZeroBitPrefix(p, c1): rsaKey = Crypto.PublicKey.RSA.generate(constants.RSA_BITS, randomStream) pub = str(rsaKey.n) + str(rsaKey.e) p = util.hsh2int(Crypto.Hash.SHA.new(Crypto.Hash.SHA.new(pub).digest())) # created correct NodeID self.rsaKey = rsaKey nodeID = Crypto.Hash.SHA.new(pub) # Solve the dynamic cryptographic puzzle. p, x = 0x1, None while not util.hasNZeroBitPrefix(p, c2): x = util.bin2int(util.generateRandomString(constants.ID_LENGTH)) # This is madness! p = util.hsh2int( Crypto.Hash.SHA.new( util.int2bin( (util.hsh2int(nodeID) ^ x)))) # Found a correct value of X and nodeID self.x = x return nodeID.digest()
def _verifyID(self, nodeID, x): '''Verifies if a user's ID has been generated using the ''' p1 = util.hsh2int(Crypto.Hash.SHA.new(nodeID)) p2 = util.hsh2int(Crypto.Hash.SHA.new( util.int2bin((util.bin2int(nodeID) ^ x)))) # check preceeding c_i bits in P1 and P2 using sharesXPrefices. return ( util.hasNZeroBitPrefix(p1, constants.CRYPTO_CHALLENGE_C1) and util.hasNZeroBitPrefix(p2, constants.CRYPTO_CHALLENGE_C2))
def nandmultiply(): '''Generates a NAND program. Outputs the string representation of a NAND program that takes in inputs x_0, ..., x_{127} and multiplies it with C mod 2^n. The output of the NAND program should be stored in variables y_0, ..., y_{127}. The first digit will be the least significant digit (ex: 110001 --> 35). Good luck!''' # creates a blank NAND program with n inputs and n outputs. prog = NANDProgram(PSET_DIM, PSET_DIM) # now add lines to your NAND program by calling python functions like # prog.NAND() or prog.OR() or other helper functions. For an example, take # a look at the stuff after if __name__ == '__main__': or the nand adder # function that we implemented. C_bin = util.int2bin(C, PSET_DIM) #column_carry = "" #for i in range(0, PSET_DIM): #column_sum = nand.allocate() #for j in range(0, i): #column_value = nand.allocate() #input_index = j #c_index = i - j #nand.AND(column_value, prog.input_var(input_index), C_bin[c_index]) #nand.ADD_3(column_sum, column_sum, column_value, "0") prog.ONE("ONE") prog.ZERO("ZERO") prog.ONE("1") prog.ZERO("0") sum = ["ZERO"] * PSET_DIM for i in range(0, PSET_DIM): row = ["ZERO"] * i for j in range(0, PSET_DIM): elem = prog.allocate() prog.AND(elem, prog.input_var(i), C_bin[j]) row.append(elem) row = row[:PSET_DIM] new_sum = mynandadder(PSET_DIM, prog, sum + row) for i in range(0, PSET_DIM): sum[i] = new_sum[i] for k in range(0, PSET_DIM): prog.OR(prog.output_var(k), "ZERO", sum[k]) print(sum) # "compiles" your completed program as a NAND program string. return str(prog)
def nandmultiply(): '''Generates a NAND program. Outputs the string representation of a NAND program that takes in inputs x_0, ..., x_{127} and multiplies it with C mod 2^n. The output of the NAND program should be stored in variables y_0, ..., y_{127}. The first digit will be the least significant digit (ex: 110001 --> 35). Good luck!''' # creates a blank NAND program with n inputs and n outputs. prog = NANDProgram(PSET_DIM, PSET_DIM) # now add lines to your NAND program by calling python functions like # prog.NAND() or prog.OR() or other helper functions. For an example, take # a look at the stuff after if __name__ == '__main__': or the nand adder # function that we implemented. C_bin = util.int2bin(C, PSET_DIM) prog.ZERO("0") prog.ONE("1") # Need to allocate a variable to store the carry digits from previous # additions. zero_lst = [] for i in range(0, PSET_DIM): zero_lst.append(prog.ZERO("0")) acc_lst = [] for x in range(0, PSET_DIM): output = prog.CREATE(x, C_bin, PSET_DIM) if x == 0: acc_lst = prog.ADDER(zero_lst, output, PSET_DIM - 1) if x != 0: acc_lst = prog.ADDER(acc_lst, output, PSET_DIM - 1) for j in range(0, len(acc_lst)): prog.OR(prog.output_var(j), acc_lst[j], "0") # prog.OR(prog.output_var(PSET_DIM - 1), prog.ZERO("0"), prog.ONE("1")) # "compiles" your completed program as a NAND program string. # print(prog) return str(prog)
def getDigest(self, n = 10): """Gets latest n updates from friends.""" digest = {} for f in self.friends: # update post cache lastKnownPost = max([0] + self.postCache[f].keys()) # Do eventual update of cache # Note: unfortunaly we can't block and wait for updates, so make do self.getUpdates(f, lastKnownPost) for f in self.friends: for k in self.postCache[f].keys()[-n:]: postID = self.postCache[f][k]['id'] if postID in self.sharingKeys: self.postCache[f][k].update({'key': self.sharingKeys[postID]}) self.postCache[f][k].update({'postp': self._decryptPost( self.sharingKeys[postID], util.int2bin(k, nbytes = constants.NONCE_LENGTH), self.postCache[f][k]['post'])}) else: sharingKeyName = ('%s:share:%s' % (postID, self.node.id)) sharingKeyID = self.node.getNameID(sharingKeyName) def _createClosureForPSKR(postID): def _processSharingKeyResult(result): if type(result) == dict: for r in result: if not isinstance(result[r], entangled.kademlia.contact.Contact): self.sharingKeys[postID] = self.node.rsaKey.decrypt( result[r][0]) else: print('Could not find sharing key for: %s : %s' % ( util.bin2hex(postID), util.bin2hex(self.node.id), )) return _processSharingKeyResult self.node.iterativeFindValue(sharingKeyID).addCallback( _createClosureForPSKR(postID)) # get last n from this friend digest[f] = self.postCache[f].items()[-n:][::-1] return digest
def post(self, content): """ Post some resource to the network. Ask the network to store some (encrypted) resource. Note: This should be encrypted with a symmetric key which will be private until shared through the above share() method. """ newSequenceNumber = self._getSequenceNumber() postKey = util.generateRandomString(constants.SYMMETRIC_KEY_LENGTH) #nonce = util.generateRandomString(constants.NONCE_LENGTH) # Use sequence number as nonce - that way we dont need to include it nonce = util.int2bin(newSequenceNumber, nbytes = constants.NONCE_LENGTH) encryptedContent = self._encryptPost(postKey, nonce, content) postName = ('%s:post:%s' % (self.node.id, newSequenceNumber)) postID = self.node.getNameID(postName) # We need to remember post keys used so we can issue sharing keys later self.sharingKeys[postID] = postKey postDefer = self.node.publishData(postName, encryptedContent) # update our latest sequence number latestName = ('%s:latest' % (self.node.id)) latestDefer = self.node.publishData(latestName, newSequenceNumber) # store post key by sharing the post with ourself postDefer.addCallback(lambda result: self.share(postID, self.node.id))
return str(nand) if __name__ == '__main__': # Generate the string representation of a NAND prog. that adds numbers addtwo = str(nandadder(2)) print(EVAL(addtwo, '1111')) # 0 + 1 = 1 mod 2 print(EVAL(addtwo, '1010')) # 1 + 1 = 2 mod 2 addfive = str(nandadder(10)) # Input Number 1: 11110 --> 15 # Input Number 2: 10110 --> 13 1111010110 # Expected Output: 28 --> 001110 #816 0000110011 #877 1011011011 # 10111001011 # You should test your implementation. # Again, note that the binary strings have the least significant digit first # Or, you can submit to gradescope and run the automatic test cases. prog = nandmultiply() for test_integer in [0, 100, 123123123]: print("Testing C * {}".format(test_integer)) ans = (test_integer * C) % (2**PSET_DIM) print("Answer should be: {} with binary:\n{}".format( ans, util.int2bin(ans, PSET_DIM))) print("Program Output") print(EVAL(prog, util.int2bin(test_integer, PSET_DIM))) print("-" * 80)
if __name__ == '__main__': # Generate the string representation of a NAND prog. that adds numbers #addtwo = str(nandadder(2)) #print(EVAL(addtwo, '0010')) # 0 + 1 = 1 mod 2 #print(EVAL(addtwo, '1010')) # 1 + 1 = 2 mod 2 #addfive = str(nandadder(10)) # Input Number 1: 11110 --> 15 # Input Number 2: 10110 --> 13 1111010110 # Expected Output: 28 --> 001110 #816 0000110011 #877 1011011011 # 10111001011 #print(EVAL(addfive,'00001100111011011011')) # You should test your implementation. # Again, note that the binary strings have the least significant digit first # Or, you can submit to gradescope and run the automatic test cases. prog = nandmultiply() for test_integer in [0, 1, 100, 123123]: print("Testing C * {}".format(test_integer)) ans = (test_integer * C) % (2 ** PSET_DIM) print("Answer should be: {} with binary:\n{}".format(ans, util.int2bin(ans, PSET_DIM))) print("Program Output") print(EVAL(prog, util.int2bin(test_integer, PSET_DIM))) print("-" * 80)