class OrchestratorProtocol(pb.Root): #------------------------------------------------- def __init__(self): log.startLogging(sys.stdout) log.msg("Server Running...") self.orchestrator = Orchestrator() #------------------------------------------------- # Send group is set message to all users in the group def groupIsSet(self, groupID): participants = self.orchestrator.getParticipants(groupID) for user in participants: params = self.orchestrator.getGroupIsSetParameters(user, groupID) log.msg('sending groupIsSet message to {0}'.format(user)) self.orchestrator.getUserRef(user).callRemote \ ( "groupIsSet", groupID.encode(), params[0], params[1], params[2] ) return #-------------------------------------------------- # operations available to remote in this section #-------------------------------------------------- # Register user with Orchestrator def remote_register(self, username, ref): self.orchestrator.register(username, ref) #------------------------------------------------- def remote_createGroup(self, proposer, m, n): try: results = self.orchestrator.createGroup(proposer, m, n) except Exception as inst: raise OrchestratorError(inst.args) groupId = results[0] inviteList = results[1] for invitee in inviteList: invitee.callRemote("invite", groupId).addCallback \ (self.acceptInviteCallback) return groupId #------------------------------------------------- # This sends a request for data to all participants of group def remote_sharePublicKey(self, user, groupId, calcType): groupId = groupId.decode() self.orchestrator.setCalcType(groupId, calcType.decode()) if not self.orchestrator.validGroup(groupId): errMsg = 'Group Id is not valid: {0}'.format(groupId) raise OrchestratorError(errMsg) if self.orchestrator.isLocked(groupId): errMsg = 'Group Id is locked, try again later: {0}'.format(groupId) raise OrchestratorError(errMsg) self.orchestrator.lock(groupId) participants = self.orchestrator.getParticipants(groupId) if user not in participants: errMsg = 'user is not in the group: {0}'.format(user) raise OrchestratorError(errMsg) userRefs = self.orchestrator.getUserReferences(groupId) calcType = self.orchestrator.calcType(groupId) for ref in userRefs: ref.callRemote("requestData", groupId, calcType).addCallback \ (self.collateDataCallback) return #------------------------------------------------- def remote_sharePublicKeyCompleted(self, groupId, user): groupId = groupId.decode() self.orchestrator.unLock(groupId) #------------------------------------------------- def remote_initiatePresigning(self, user, groupId, number): groupId = groupId.decode() if self.orchestrator.isLocked(groupId): errMsg = 'Group Id is locked, try again later: {0}'.format(groupId) raise OrchestratorError(errMsg) self.orchestrator.lock(groupId) return [user, groupId, number] #------------------------------------------------- # This sends a request for data to all participants of group def remote_presigning(self, user, groupId, calcType): groupId = groupId.decode() calcType = calcType.decode() self.orchestrator.setCalcType(groupId, calcType) log.msg("presigning: user={0}, groupId={1}, calcType={2}".format( user, groupId, calcType)) if not self.orchestrator.validGroup(groupId): errMsg = 'Group Id is not valid: {0}'.format(groupId) raise OrchestratorError(errMsg) participants = self.orchestrator.getParticipants(groupId) if user not in participants: errMsg = 'user is not in the group: {0}'.format(user) raise OrchestratorError(errMsg) userRefs = self.orchestrator.getUserReferences(groupId) for ref in userRefs: ref.callRemote("requestData", groupId, calcType).addCallback \ (self.collateDataCallback) return #------------------------------------------------- def remote_presigningCompleted(self, groupId): groupId = groupId.decode() if not self.orchestrator.validGroup(groupId): errMsg = 'Group Id is not valid: {0}'.format(groupId) raise OrchestratorError(errMsg) self.orchestrator.unLock(groupId) #------------------------------------------------- def remote_collateVWData(self, groupId, ordinal, data): log.msg("Collating VW Data") groupId = groupId.decode() if self.orchestrator.collateVWData(groupId, ordinal, data): collatedData = self.orchestrator.getCollatedVWData(groupId) # send the public data out to all group participants userRefs = self.orchestrator.getUserReferences(groupId) for ref in userRefs: ref.callRemote("sharedVWData", groupId, collatedData) #------------------------------------------------- def remote_ephemeralKeyCompleted(self, groupId, user): groupId = groupId.decode() log.msg("EphemeralKey has been completed, groupId = {0}, user = {1}".format \ (groupId, user)) if self.orchestrator.allEphemeralKeysCompleted(user, groupId): # send the public data out to all group participants userRefs = self.orchestrator.getUserReferences(groupId) for ref in userRefs: ref.callRemote("completed", groupId) #------------------------------------------------- # This sends a request for data to all participants of group def remote_sign(self, user, groupId, index, msg): log.msg("remote_sign") groupId = groupId.decode() msg = msg.decode() log.msg("sign: user={0}, groupId={1}, msg={2}".format( user, groupId, msg)) if not self.orchestrator.validGroup(groupId): errMsg = 'Group Id is not valid: {0}'.format(groupId) raise OrchestratorError(errMsg) if self.orchestrator.isLocked(groupId): errMsg = 'Group Id is locked, try again later: {0}'.format(groupId) raise OrchestratorError(errMsg) self.orchestrator.lock(groupId) participants = self.orchestrator.getParticipants(groupId) # check the user is in the group, then set the signer if user not in participants: errMsg = 'user is not in the group: {0}'.format(user) raise OrchestratorError(errMsg) self.orchestrator.setSigner(groupId, user) userRefs = self.orchestrator.getUserReferences(groupId) for ref in userRefs: ref.callRemote("requestSignatureData", groupId, index, msg).addCallback \ (self.signingCallback) return #------------------------------------------------- # routes eval (f_x) through from the fromOridnal, to toOrdinal def remote_routeEvals(self, gid, user, toOrdinal, fromOrdinal, f_x): groupId = gid.decode() log.msg("routeEvals. toOrdinal={0}, fromOrdinal={1}, f_x={2}".format( toOrdinal, fromOrdinal, f_x)) # go from ordinal to user refDict = self.orchestrator.getPtpReferences(user, groupId) refDict[toOrdinal].callRemote("distributeEvals", \ groupId, toOrdinal, fromOrdinal, f_x) return #------------------------------------------------- # called when a Player has received all their Evals def remote_receivedAllEvals(self, gid, ordinal): log.msg("receivedAllEvals") groupId = gid.decode() # if all Players have received their Eval data then continue if self.orchestrator.allEvalsReceived(groupId, ordinal): collatedData = self.orchestrator.getCollatedData(groupId) # send the public data out to all group participants userRefs = self.orchestrator.getUserReferences(groupId) for ref in userRefs: ref.callRemote( "createSecret", groupId, self.orchestrator.calcType(groupId), collatedData[0], collatedData[1])\ .addCallbacks(self.secretVerificationCallback, self.verificationErrorCallback) #-------------------------------------------------- # Callback operations available in this section #-------------------------------------------------- def acceptInviteCallback(self, data): user = data[0] groupID = data[1] acceptance = data[2] if self.orchestrator.acceptInvite(user, groupID, acceptance): self.groupIsSet(groupID) #------------------------------------------------- # collate data def collateDataCallback(self, data): #JAS # TODO : can remove user from this as not used here! log.msg('collateDataCallback') groupId = data[0] ordinal = data[1] user = data[2] hiddenPoly = data[3] hiddenEvals = data[4] # if True then ready to distribute data if self.orchestrator.collateData(groupId, ordinal, hiddenPoly, hiddenEvals): # Call the shareEvals, pass in a different set of ordinal:refs for each userRefs = self.orchestrator.getUserReferences(groupId) participants = self.orchestrator.getParticipants(groupId) for p, ref in zip(participants, userRefs): newUserRefs = self.orchestrator.getPtpReferences(p, groupId) toOrdinals = [] for key, value in newUserRefs.items(): toOrdinals.append(key) log.msg(toOrdinals) ref.callRemote("shareEvals", groupId, toOrdinals) log.msg('finished in collateDataCallback') # // following part is the orig #collatedData = self.orchestrator.getCollatedData(groupId) # send the public data out to all group participants #userRefs = self.orchestrator.getUserReferences( groupId ) #for ref in userRefs : # ref.callRemote( "createSecret", groupId, self.orchestrator.calcType(groupId), collatedData[0], collatedData[1], collatedData[2])\ # .addCallbacks(self.secretVerificationCallback, self.verificationErrorCallback) #------------------------------------------------- # Receives verification from all group members def secretVerificationCallback(self, data): user = data[0] groupId = data[1] if self.orchestrator.secretVerification(user, groupId): calcType = self.orchestrator.calcType(groupId) log.msg("secretVerification complete for: {0}".format(calcType)) # contact all the group participants with verification success userRefs = self.orchestrator.getUserReferences(groupId) for ref in userRefs: ref.callRemote("groupIsVerified", groupId, calcType) #------------------------------------------------- def verificationErrorCallback(self, data): l = data.value.split("'")[1::2] user = l[0] groupId = l[1] reason = l[2] log.msg ("Verification Error: groupId = {0}, user = {1}, reason = {2}".format\ ( groupId, user, reason )) # contact all the group participants to delete group userRefs = self.orchestrator.getUserReferences(groupId) for ref in userRefs: ref.callRemote("deleteGroup", groupId) #------------------------------------------------- # Signing callback with data: def signingCallback(self, data): log.msg("signingCallback") groupId = data[0] ordinal = data[1] sig = data[2] msg = data[3] # if True then ready to distribute data if self.orchestrator.signature(groupId, ordinal, sig): signatureData = self.orchestrator.getSignatureData(groupId) # send the signature data out to the signer userRef = self.orchestrator.getSignerReference(groupId) userRef.callRemote( "readyToSign", groupId, msg, signatureData) \ .addCallbacks(self.signingCompletedCallback, self.signingErrorCallback) #-------------------------------------------------- def signingCompletedCallback(self, groupId): log.msg("signingCompletedCallback: groupId = {0}".format(groupId)) self.orchestrator.clearSignatureSetFlag(groupId) self.orchestrator.unLock(groupId) #-------------------------------------------------- def signingErrorCallback(self, groupId): log.msg("signingErrorCallback: groupId = {0}".format(groupId))
class OrchestratorProtocol( rpc.TSServiceServicer ) : def __init__( self ) : print('in OrchestratorProtocol:__init__') self.orchestrator = Orchestrator( ) #------------------------------------------------- # Send group is set message to all users in the group def groupIsSet(self, gid): userRefs = self.orchestrator.getUserReferences( gid ) participants = self.orchestrator.getParticipants(gid) print('gid = {0}, participants = {1}'.format(gid, participants)) t = self.orchestrator.getDegree( gid ) counter = 1 participantList = [] for user in participants : ref = self.orchestrator.getUserRef(user) print('user {0} : ref {1} '.format(user, ref) ) player = stub.Player( name=user, port=ref[1] ) aParticipant = stub.GroupIsSetRequest.Participant( ordinal=counter, playerId=player) participantList.append( aParticipant ) counter = counter + 1 gReq = stub.GroupIsSetRequest( groupId=gid, degree=t, participants=participantList ) for user in participants : print ('sending groupIsSet message to {0}'.format(user)) ref = self.orchestrator.getUserRef(user) response = ref[0].CallGroupIsSet( gReq ) return #-------------------------------------------------- # operations available to remote in this section #-------------------------------------------------- # Register user with Orchestrator def CallRegister(self, request, context): player = request.playerId client_port = str(player.port) print('client_port = {0}'.format(client_port)) # create a gRPC channel + stub client_channel = grpc.insecure_channel('localhost' + ':' + str(client_port)) client_conn = rpc.TSServiceStub( client_channel ) self.orchestrator.register( player.name, (client_conn, client_port) ) return stub.RegisterReply( success = True ) #------------------------------------------------- def CallCreateGroup(self, request, context) : print('user = {0}, m = {1}, n = {2} '.format \ ( request.userId, request.m, request.n ) ) results = None try : results = self.orchestrator.createGroup(request.userId, request.m, request.n) except Exception as inst: #raise OrchestratorError( inst.args ) print('ERROR in OrchestratorProtocol:CallCreateGroup') gid = results[0] inviteList = results[1] for invitee in inviteList : idMsg = stub.IdentityMessage( groupId=gid ) call_future = invitee[0].CallInvite.future( stub.InviteRequest ( id=idMsg ) ) call_future.add_done_callback( self.acceptInviteCallback ) idMsg = stub.IdentityMessage( userId=request.userId, groupId=gid ) print('returning a creategroupreply') return stub.CreateGroupReply( id=idMsg ) #------------------------------------------------- # This sends a request for data to all participants of group def CallShareSecret( self, request, context ) : print('in CallShareSecret') gid = request.id.groupId self.orchestrator.setCalcType (gid, request.calculation ) if not self.orchestrator.validGroup(gid) : errMsg = 'Group Id is not valid: {0}'.format(gid) #raise OrchestratorError( errMsg ) print('ERROR in OrchestratorProtocol:CallShareSecret') print(errMsg) if self.orchestrator.isLocked(gid) : errMsg = 'Group Id is locked, try again later: {0}'.format(gid) #raise OrchestratorError( errMsg ) print('ERROR in OrchestratorProtocol:CallShareSecret') print(errMsg) self.orchestrator.lock(gid) participants = self.orchestrator.getParticipants(gid) if request.id.userId not in participants : errMsg = 'user is not in the group: {0}'.format(request.id.userId) #raise OrchestratorError( errMsg ) print('ERROR in OrchestratorProtocol:CallShareSecret') print(errMsg) userRefs = self.orchestrator.getUserReferences(gid) calcType = self.orchestrator.calcType( gid ) idMsg = stub.IdentityMessage( userId=request.id.userId, groupId=gid ) for ref in userRefs : print('calling request data...') call_future = ref[0].CallShareSecretData.future( stub.ShareSecretDataRequest( id=idMsg )) call_future.add_done_callback( self.collateDataCallback ) return stub.ShareSecretReply( id=idMsg, success=True ) #------------------------------------------------- def CallInitiatePresign(self, request, context) : gid = request.id.groupId if self.orchestrator.isLocked(gid) : errMsg = 'Group Id is locked, try again later: {0}'.format(gid) #raise OrchestratorError( errMsg ) print('ERROR: ' + errMsg ) self.orchestrator.lock( gid ) idMsg = stub.IdentityMessage( userId=request.id.userId, groupId=gid ) return stub.InitPresignReply \ ( id=idMsg, number=request.number ) #------------------------------------------------- def CallPresigning (self, request, context) : user = request.id.userId gid = request.id.groupId calcType = request.calculation self.orchestrator.setCalcType( gid, calcType ) print("presigning: user={0}, groupId={1}, calcType={2}".format \ (user, gid, calcType) ) if not self.orchestrator.validGroup(gid) : errMsg = 'Group Id is not valid: {0}'.format(gid) #raise OrchestratorError( errMsg ) print('ERROR: ' + errMsg ) participants = self.orchestrator.getParticipants(gid) if user not in participants : errMsg = 'user is not in the group: {0}'.format(user) #raise OrchestratorError( errMsg ) print('ERROR: ' + errMsg ) userRefs = self.orchestrator.getUserReferences(gid) for ref in userRefs : print('calling request data...') idMsg = stub.IdentityMessage( userId=user, groupId=gid ) call_future = ref[0].CallShareSecretData.future \ ( stub.ShareSecretDataRequest( id=idMsg )) call_future.add_done_callback( self.collateDataCallback ) return stub.PresigningReply( success=True ) #------------------------------------------------- def CallShareVW(self, request, context) : gid = request.id.groupId user = request.id.userId print("Collating VW Data") # orchestrator expects a tuple () data = ( request.data.v, request.data.w ) idMsg = stub.IdentityMessage( userId=user, groupId=gid ) if self.orchestrator.collateVWData( gid, request.data.ordinal, data ) : collatedData = self.orchestrator.getCollatedVWData( gid ) vwList = [] for ordinal, vw in collatedData.items() : vwdata = stub.VWData( ordinal=ordinal, v=vw[0], w=vw[1] ) vwList.append( vwdata ) # send the public data out to all group participants userRefs = self.orchestrator.getUserReferences( gid ) for ref in userRefs : ref[0].CallCollatedVWShare( stub.CollatedVWShareRequest \ ( id=idMsg, data=vwList ) ) return stub.ShareVWDataMessageReply( id=idMsg, success=True ) #------------------------------------------------- def CallPubKeyComplete(self, request, context) : print('Sharing public key completed: {0}'.format(request.groupId)) self.orchestrator.unLock( request.groupId ) return stub.GenericReply( success=True ) #------------------------------------------------- def CallEphemKeyComplete(self, request, context) : print("EphemeralKey has been completed, groupId = {0}, user = {1}".format \ (request.groupId, request.userId)) if self.orchestrator.allEphemeralKeysCompleted( request.userId, request.groupId ) : # send the public data out to all group participants userRefs = self.orchestrator.getUserReferences( request.groupId ) for ref in userRefs : ref[0].CallCompleted( stub.IdentityMessage \ ( groupId=request.groupId ) ) return stub.GenericReply( success=True ) #------------------------------------------------- def CallPresignComplete(self, request, context) : groupId = request.groupId if not self.orchestrator.validGroup(groupId) : errMsg = 'Group Id is not valid: {0}'.format(groupId) #raise OrchestratorError( errMsg ) print('ERROR: CallPresignComplete ' + errMsg ) self.orchestrator.unLock( groupId ) return stub.GenericReply( success=True ) #------------------------------------------------- # This sends a request for data to all participants of group def CallInitSignature(self, request, context) : gid = request.id.groupId msg = request.message userId = request.id.userId print("sign: user={0}, groupId={1}, msg={2}".format(userId, gid, msg)) if not self.orchestrator.validGroup(gid) : errMsg = 'Group Id is not valid: {0}'.format(gid) #raise OrchestratorError( errMsg ) print('ERROR: ' + msg) if self.orchestrator.isLocked(gid) : errMsg = 'Group Id is locked, try again later: {0}'.format(gid) #raise OrchestratorError( errMsg ) print('ERROR: ' + msg) self.orchestrator.lock(gid) participants = self.orchestrator.getParticipants(gid) # check the user is in the group, then set the signer if userId not in participants : errMsg = 'user is not in the group: {0}'.format(useId) #raise OrchestratorError( errMsg ) print( 'ERROR: ' + msg ) self.orchestrator.setSigner(gid, userId) userRefs = self.orchestrator.getUserReferences(gid) for ref in userRefs : call_future = ref[0].CallShareOfSignature.future( stub.ShareOfSigRequest \ ( groupId=gid, message=msg ) ) call_future.add_done_callback( self.signingCallback ) #ref.callRemote("requestSignatureData", groupId, msg).addCallback \ # (self.signingCallback) # return stub.InitSignatureReply( success=True ) #-------------------------------------------------- # Callback operations available in this section #-------------------------------------------------- def acceptInviteCallback (self, call_future ) : res = call_future.result() if self.orchestrator.acceptInvite(res.id.userId, res.id.groupId, res.acceptance) : self.groupIsSet(res.id.groupId) print('acceptInviteCallback: group is set!') #-------------------------------------------------- def collateDataCallback (self, call_future ) : res = call_future.result() print('collateDataCallback') # if True then ready to distribute data if self.orchestrator.collateData( res.id.groupId, res.ordinal, res.hiddenPoly, res.hiddenEvals) : # Call the shareEvals, pass in a different set of ordinal:refs for each userRefs = self.orchestrator.getUserReferences( res.id.groupId ) participants = self.orchestrator.getParticipants( res.id.groupId ) idMsg = stub.IdentityMessage( groupId=res.id.groupId ) for ref in userRefs : ref[0].CallInitShareEvals( stub.InitShareEvalsRequest ( id=idMsg ) ) #--------------------------------------------------- def CallReceivedAllEvals ( self, request, context ) : gid = request.id.groupId ord = request.ordinal print('receivedAllEvals') # if all Players have received their Eval data then continue if self.orchestrator.allEvalsReceived( gid, ord ) : collatedData = self.orchestrator.getCollatedData( gid) # send the public data out to all group participants userRefs = self.orchestrator.getUserReferences( gid ) # get hiddenPoly into suitable format hpList = [] for ordinalB, coeffs in collatedData[0].items() : hp = stub.hiddenPolynomial(ordinal=ordinalB,coefficients=coeffs) hpList.append(hp) # get hidden evals into a suitable format hidEvalList = [] for ordinalC, evals in collatedData[1].items() : l_of_hep = stub.listOfPolynomials() l_of_hep.ordinal = ordinalC for e in evals : l_of_hep.ep.add(ordinal=e.ordinal, f_x=e.f_x) hidEvalList.append(l_of_hep) idMsg = stub.IdentityMessage( groupId=gid ) for ref in userRefs : print('calling createsecret...') call_future = ref[0].CallCollatedSecretShare.future( stub.CollatedSecretRequest( \ id=idMsg, calculation=self.orchestrator.calcType(gid), \ hiddenPolys=hpList, hiddenEvals=hidEvalList )) call_future.add_done_callback( self.secretVerificationCallback ) print('returning True from CallReceivedAllEvals') return stub.RxAllEvalsReply( success=True ) #-------------------------------------------------- def secretVerificationCallback (self, call_future ) : res = call_future.result() gid = res.id.groupId user = res.id.userId print('secretVerificationCallback: ') idMsg = stub.IdentityMessage( userId=user, groupId=gid ) if self.orchestrator.secretVerification(user, gid) : calcType = self.orchestrator.calcType(gid) print("secretVerification complete for: {0}".format(calcType)) # contact all the group participants with verification success userRefs = self.orchestrator.getUserReferences(gid) for ref in userRefs : ref[0].CallGroupIsVerified( stub.GroupIsVerifiedRequest \ ( id=idMsg, calculation=calcType ) ) #-------------------------------------------------- def signingCallback (self, call_future ) : res = call_future.result() gid = res.id.groupId ordinal = res.ordinal sig = res.signature msg = res.message # if True then ready to distribute data if self.orchestrator.signature( gid, ordinal, sig) : signatureDict = self.orchestrator.getSignatureData(gid) sigList = [] for ord, sig in signatureDict.items() : sigData = stub.SigData( ordinal=ord, signature=sig ) sigList.append(sigData) # send the signature data out to the signer userRef = self.orchestrator.getSignerReference( gid ) idMsg = stub.IdentityMessage( userId=res.id.userId, groupId=gid ) call_future = userRef[0].CallSignMessage.future( stub.SignDataMessage \ ( id=idMsg, message=msg, signatures=sigList ) ) call_future.add_done_callback( self.signingCompletedCallback ) #-------------------------------------------------- def signingCompletedCallback (self, call_future ) : res = call_future.result() print(res) self.orchestrator.clearSignatureSetFlag(res.id.groupId) self.orchestrator.unLock(res.id.groupId)