From f124498dff43502bf5915d559ee26582b67d03b7 Mon Sep 17 00:00:00 2001 From: rtrimana Date: Thu, 14 Jul 2016 10:23:18 -0700 Subject: [PATCH] Revised client algorithm - part that gets slots from server --- doc/iotcloud.tex | 333 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 237 insertions(+), 96 deletions(-) diff --git a/doc/iotcloud.tex b/doc/iotcloud.tex index 5a362c9..eb6fca1 100644 --- a/doc/iotcloud.tex +++ b/doc/iotcloud.tex @@ -2,7 +2,6 @@ \newcommand{\tuple}[1]{\ensuremath \langle #1 \rangle} \usepackage{color} \usepackage{amsthm} -\usepackage{amsmath} \usepackage{algpseudocode}% http://ctan.org/pkg/algorithmicx \newtheorem{theorem}{Theorem} \newtheorem{defn}{Definition} @@ -52,11 +51,15 @@ client's last entry from the queue. This is kept in the slot until the entry owner inserts a newer update into the queue.} \item Queue state entry: Includes queue size \newline {The purpose of this is for the client to tell if the server lies about the number -of slots in the queue, e.g. if there are 2 queue state entries in the queue, +of slots in the queue, e.g. if there are 2 queue state entry in the queue, e.g. 50 and 70, the client knows that when it sees 50, it should expect at most 50 slots in the queue and after it sees 70, it should expect 50 slots before that queue state entry slot 50 and at most 70 slots. The queue state entry slot 70 is counted as slot number 51 in the queue.} +\item Collision resolution entry: Machine id + message identifier of +collision winner +\newline {The purpose of this is to keep keep track of the winner of +all the collisions until all clients have seen the particular entry.} \end{enumerate} \subsection{Live status} @@ -72,6 +75,9 @@ or user-level data) is dead if there is a newer slot from the same machine. {In the case of queue state entries 50 and 70, this means that queue state entry 50 is dead and 70 is live. However, not until the number of slots reaches 70 that queue state entry 50 will be expunged from the queue.} + +\item Collision resolution entry is dead if there this entry has been seen +by all clients after a collision happens. \end{enumerate} When data is at the end of the queue ready to expunge, if: @@ -171,109 +177,244 @@ $SlotVal(\tuple{s, sv})=sv$ \\ \end{algorithmic} \subsection{Client Algorithm} +\textbf{Data Entry} \\ +$de$ is a data entry \\ +$k$ is key of entry \\ +$v$ is value of entry \\ +$kv$ is a key-value entry $\tuple{k,v}$, $kv \in D$ \\ +$ss$ is a slot sequence entry $\tuple{id,s_{last}}$, +id + last s of a machine, $ss \in D$ \\ +$qs$ is a queue state entry, $qs \in D$ \\ +$D = \{kv,ss,qs\}$ \\ +$DE = \{de \mid de \in D\}$ \\ \\ +$s \in SN$ is a sequence number set\\ +$id$ is a machine ID\\ +$hmac_p$ is the HMAC value of the previous slot \\ +$hmac_c$ is the HMAC value of the current slot \\ +$Dat_s = \tuple{s,id,hmac_p,DE,hmac_c}$ \\ +$sv_s = \tuple{s, E(Dat_s)} = +\tuple{s, E(\tuple{s,id,hmac_p,DE,hmac_c})}$ \\ \\ + +\textbf{States} \\ +\textit{DT = set of $\tuple{k,v}$ on client} \\ +\textit{MS = set of $\tuple{id, s_{last}}$ of all clients on client +(initially empty)} \\ +\textit{$MS_c$ = set MS to save all $\tuple{id, s_{last}}$ pairs while +traversing DT after a request to server (initially empty)} \\ +\textit{$max_c$ = maximum number of slots (initially $max_c > 0$)} \\ +\textit{m = number of slots on client (initially $m = 0 \mid m \leq n$)} \\ +\textit{$hmac_p$ = the HMAC value of the previous slot ($hmac_p = \emptyset$ +for the first slot)} \\ +\textit{$id_{self}$ = machine Id of this client} \\ +\textit{SK = Secret Key} \\ \\ +\textbf{Helper Functions} \\ +$MaxSlot(SL_s)= \tuple{s, sv} \mid \tuple{s, sv} +\in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \geq s_s$ \\ +$MinSlot(SL_s)= \tuple{s, sv} \mid \tuple{s, sv} +\in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \leq s_s$ \\ +$SeqN(\tuple{s, sv})=s$ \\ +$SlotVal(\tuple{s, sv})=sv$ \\ +$Decrypt(SK_s,sv_s)=Dat_s=\tuple{s,id,hmac_p,DE,hmac_c}$ \\ +$ComputeHash(bit_s)$ is a hash function that generates hash value on $bit_s$ \\ +$ComputeHmac(bit_s,SK_s)$ is a HMAC function that generates HMAC value on $bit_s$ +based on key $SK_s$\\ +$GetSeqN(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=s$ \\ +$GetMacId(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=id$ \\ +$GetPrevHmac(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=hmac_p$ \\ +$GetCurrHmac(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=hmac_c$ \\ +$GetDatEnt(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=DE$ \\ +$GetQS(de_s \mid de_s \in D \land de_s = qs)=qs$ \\ +$GetSS(de_s \mid de_s \in D \land de_s = ss)=ss$ \\ +$GetKV(de_s \mid de_s \in D \land de_s = kv)=kv=\tuple{k,v}$ \\ +$GetLastSeqN(MS_s,id_s)= s_{last} \mid \tuple{id, s_{last}} +\in MS_s \wedge \forall \tuple{id_s, s_{s_{last}}} \in MS_s, +id = id_s$ \\ +$GetKey(\tuple{k, v})=k$ \\ +$GetVal(\tuple{k, v})=v$ \\ +$GetKeyVal(DT_s,k_s)= \tuple{k, v} \mid \tuple{k, v} +\in DT_s \wedge \forall \tuple{k_s, v_s} \in DT_s, k = k_s$ \\ + \begin{algorithmic}[1] -\Function{CallClient}{$uid,pw,d,m,max,s,Data*,Result*$} -\textit{ -\newline{// uid = user identification} -\newline{// pw = password} -\newline{// d = new data for write} -\newline{// m = client message (read/write/resize)} -\newline{// max = maximum number of slots (input only for resize message)} -\newline{// n = number of slots} -\newline{// s = sequence number for server request} -\newline{// t = sequence numbers of slots on server} -\newline{// mid = machine identification} -\newline{// seq = sequence number inside slot} -\newline{// newSlot = new slot} -\newline{// expSlot = expunged/expired slot} -\newline{// slotSeqE = slot sequence entry} -\newline{// M = list of all machines/devices with their respective latest s on client} -\newline{// Data = array of slots written/read (input only for write)} -\newline{// Result = array of decrypted and valid slots after a read} -\newline{// Slot = one data slot)} -\newline{// DSlot = one decrypted data slot)} -} -\State $SK = Hash(uid + pw)$ -\If{$m = read$} - \State $Data \gets CallServer(m,max,s,Data)$ - \If{$Data = \emptyset$} - \State $ReportError(\emptyset,read)$ - \Else - \If{$\neg HasCurrentQueueStateEntry(Data)$} - \State $ReportError(DSlot_i,read)$ - \EndIf - \ForAll{$Slot_i \in Data$} - \State $DSlot_i \gets Decrypt(SK,Slot_i)$\Comment{Check s and HMAC} - \If{$\neg (ValidSeqN(DSlot_i) \land ValidHmac(DSlot_i) \land $\\ - \push[1] $ValidPrevHmac(DSlot_i))$} - \State $ReportError(DSlot_i,read)$ - \Else\Comment{Check only live entries} - \If{$IsLiveSlotSequenceEntry(DSlot_i)$} - \State $lastS \gets LastSeqN(DSlot_i)$ - \State $lastMid \gets LastMachineId(DSlot_i)$ - \If{$lastS \neq LastSeqN(lastMid,M)$} - \State $ReportError(DSlot_i,read)$ - \EndIf - \ElsIf{$IsLiveKeyValueEntry(DSlot_i)$} - \State $mid \gets MachineId(DSlot_i)$ - \State $seq \gets SeqN(DSlot_i)$ - \If{$IsOwnMid(mid)$} - \If{$IsLastS(mid,seq,Data) \land $\\ - \push[1] $(seq \neq LastSeqN(mid,M))$} - \State $ReportError(DSlot_i,read)$ - \EndIf - \Else\Comment{Check s for other machines} - \If{$IsLastS(mid,seq,Data) \land $\\ - \push[1] $(seq < LastSeqN(mid,M))$} - \State $ReportError(DSlot_i,read)$ - \EndIf - \EndIf\Comment{Check queue state entry} - \ElsIf{$IsLiveQueueStateEntry(DSlot_i)$} - \If{$IsCurrentQueueState(DSlot_i)$} - \If{$Length(Data) > QueueLength(DSlot_i)$} - \State $ReportError(DSlot_i,read)$ - \EndIf - \EndIf - \Else - \State $ReportError(DSlot_i,read)$ - \EndIf - \EndIf - \State $Result \gets Concat(Result, DSlot_i)$ - \EndFor - \EndIf +\Function{CreateSK}{$uid,pw$} +\State $SK = ComputeHash(uid + pw)$ +\State \Return{$SK$} +\EndFunction +\end{algorithmic} + +\begin{algorithmic}[1] +\Function{Hmac}{$Dat_s,SK_s$} +\State \Return{$ComputeHmac(Dat_s,SK_s)$} +\EndFunction +\end{algorithmic} + +\begin{algorithmic}[1] +\Function{ValidHmac}{$Dat_s,SK_s$} +\State $hmac_{stored} \gets GetCurrHmac(Dat_s)$ +\State $hmac_{computed} \gets \Call{Hmac}{Dat_s,SK_s}$ +\If{$hmac_{stored} = hmac_{computed}$} + \State \Return{$true$} +\Else + \State \Return{$false$} +\EndIf +\EndFunction +\end{algorithmic} -\ElsIf{$m = write$} - \State $newSlot \gets CreateSlot(d)$ - \State $Data[1] \gets Encrypt(SK,newSlot)$ - \State $Data \gets CallServer(m,max,s,Data)$ - \If{$Data = \emptyset$} - \State $ReportError(\emptyset,write)$ - \Else\Comment Check for valid return value from server - \If{$\neg ValidOldLastEntry(Data[1])$} - \State $ReportError(Data[1],write)$ - \Else\Comment{Check if we need slot sequence entry} - \If{$Length(Data) = 2$} - \State $expSlot \gets Decrypt(SK,Data[2])$ - \State $mid \gets MachineId(expSlot)$ - \State $seq \gets SeqN(expSlot)$ - \If{$seq = LastSeqN(mid,M)$}\Comment{Liveness check} - \State $slotSeqE \gets CreateSlotSeqE(mid,seq)$ - \State $Data[1] \gets Encrypt(SK,slotSeqE)$ - \State $Data \gets CallServer(m,max,s,Data)$ - \EndIf +\begin{algorithmic}[1] +\Function{ValidPrevHmac}{$Dat_s,hmac_{p_s}$} +\If{$hmac_{p_s} = \emptyset$}\Comment{First slot - no previous HMAC} + \State \Return{$true$} +\EndIf +\State $hmac_{stored} \gets GetPrevHmac(Dat_s)$ +\If{$hmac_{stored} = hmac_{p_s}$} + \State \Return{$true$} +\Else + \State \Return{$false$} +\EndIf +\EndFunction +\end{algorithmic} + +\begin{algorithmic}[1] +\Function{GetQueSta}{$Dat_s$} +\State $DE_s \gets GetDatEnt(Dat_s)$ +%\State $qs_{ret} \gets max_s$ +%\ForAll{$de_i \in DE_s$} +% \If{$de_i \mid de_i \in D \land de_i = qs$} +% \State $qs_i \gets GetQS(de_i)$ +% \If{$qs_i > qs_{ret}$} +% \State $qs_{ret} \gets qs_i$ +% \EndIf +% \EndIf +%\EndFor +\State $de_{qs} \gets de_s \mid de_s \in DE_s, de_s \in D \land de_s = qs$ +\State $qs_{ret} \gets GetQS(de_{qs})$ +%\If{$qs_{ret} > max_s$} +%\State $qs_{ret} \gets qs_i$ +%\EndIf +\State \Return{$qs_{ret}$} +\EndFunction +\end{algorithmic} + +\begin{algorithmic}[1] +\Function{GetSlotSeq}{$Dat_s$} +\State $DE_s \gets GetDatEnt(Dat_s)$ +%\ForAll{$de_i \in DE_s$} + %\If{$de_i \mid de_i \in D \land de_i = ss$} + %\State $\tuple{id_{ret},s_{last_{ret}}} \gets GetSS(de_i)$ + %\EndIf +%\EndFor +\State $de_{ss} \gets de_s \mid de_s \in DE_s, de_s \in D \land de_s = ss$ +\State $\tuple{id_{ret},s_{last_{ret}}} \gets GetSS(de_{ss})$ +\State \Return{$\tuple{id_{ret},s_{last_{ret}}}$} +\EndFunction +\end{algorithmic} + +\begin{algorithmic}[1] +\Function{UpdateLastSeqN}{$id_s,s_s,MS_s$} +\State $s_t \gets GetLastSeqN(MS_s,id_s)$ +\If{$s_t = \emptyset$} + \State $MS_s \gets MS_s \cup \{\tuple{id_s,s_s}\}$\Comment{First occurrence} +\Else + \If{$s_s > s_t$}\Comment{Update entry with a later s} + \State $MS_s \gets (MS_s - \{\tuple{id_s,s_t}\}) \cup + \{\tuple{id_s,s_s}\}$ + \EndIf +\EndIf +\State \Return{$MS_s$} +\EndFunction +\end{algorithmic} + +\begin{algorithmic}[1] +\Function{CheckLastSeqN}{$MS_s,MS_t$}\Comment{Check $MS_t$ based on $MS_s$} +\ForAll{$\tuple{id_t,s_{t_{last}}} \in MS_t$} + \State $s_{s_{last}} \gets GetLastSeqN(MS_s,id_t)$ + \If{$s_{s_{last}} \neq \emptyset$} + \If{$id_t = id_{self}$} + \If{$s_{s_{last}} \neq s_{t_{last}}$} + \State $error \gets$ 'Invalid last $s$ for this machine' + \State \Return{error} + \EndIf + \Else + \If{$s_{s_{last}} \geq s_{t_{last}}$} + \State $MS_s \gets (MS_s - \{\tuple{id_t,s_{t_{last}}}\}) \cup + \{\tuple{id_t,s_{s_{last}}}\}$ \Else - \State $ReportError(Data,write)$ + \State $error \gets$ 'Invalid last $s$ for machine $id_t$' + \State \Return{error} \EndIf \EndIf \EndIf +\EndFor +\State \Return{$\emptyset$} +\EndFunction +\end{algorithmic} + +\begin{algorithmic}[1] +\Function{UpdateDT}{$DT_s,Dat_s$} +\State $DE_s \gets GetDatEnt(Dat_s)$ +\ForAll{$de_i \in DE_s$} + \If{$de_i \mid de_i \in D \land de_i = kv$} + \State $\tuple{k_s,v_s} \gets GetKV(de_i)$ + \State $k_s \gets GetKey(\tuple{k_s,v_s})$ + \State $\tuple{k_s,v_t} \gets GetKeyVal(DT_s,k_s)$ + \If{$\tuple{k_s,v_t} = \emptyset$} + \State $DT_s \gets DT_s \cup \{\tuple{k_s,v_s}\}$ + \Else + \State $DT_s \gets (DT_s - \{\tuple{k_s,v_t}\}) \cup + \{\tuple{k_s,v_s}\}$ + \EndIf + \EndIf +\EndFor +\State \Return{$DT_s$} +\EndFunction +\end{algorithmic} -\ElsIf{$m = resize$} - \State $Data \gets CallServer(m,max,s,Data)$ - \If{$Data = \emptyset$} - \State $ReportError(\emptyset,resize)$ +\begin{algorithmic}[1] +\Function{GetKVPairs}{$s$} +\State $SL_c \gets \Call{GetSlot}{s}$ +\State $MS_c \gets \emptyset$ +\ForAll{$\tuple{s_i,sv_i} \in SL_c$} + \State $s_i \gets SeqN(\tuple{s_i,sv_i})$ + \State $sv_i \gets SlotVal(\tuple{s,sv_i})$ + \State $Dat_i \gets Decrypt(SK,sv_i)$ + \State $s_s \gets GetSeqN(Dat_s)$ + \If{$s_i \neq s_s$} + \State $error \gets$ 'Invalid sequence number' + \EndIf + \If{$\Call{ValidPrevHmac}{Dat_i,hmac_p} = false$} + \State $error \gets$ 'Invalid previous HMAC value' \EndIf + \If{$\Call{ValidHmac}{Dat_i,SK} = false$} + \State $error \gets$ 'Invalid current HMAC value' + \EndIf + \State $hmac_p \gets \Call{Hmac}{Dat_i,SK}$\Comment{Update $hmac_p$ for next slot check} + %\State $max_c \gets \Call{GetQueSta}{Dat_i,max_c}$\Comment{Handle qs} + \State $qs_c \gets \Call{GetQueSta}{Dat_i}$\Comment{Handle qs} + \If{$qs_c > max_c$} + \State $max_c \gets qs_c$ + \EndIf + %Check for last s in Dat + \State $id_i \gets GetMacId(Dat_i)$\Comment{Handle last s} + \State $MS_c \gets \Call{UpdateLastSeqN}{id_i,s_i,MS_c}$ + %Check for last s in DE in Dat + \State $\tuple{id_j,s_{j_{last}}} \gets \Call{GetSlotSeq}{Dat_i}$\Comment{Handle ss} + \State $MS_c \gets \Call{UpdateLastSeqN}{id_j,s_{j_{last}},MS_c}$ + \State $DT \gets \Call{UpdateDT}{DT,Dat_i}$ +\EndFor +\If{$m + |SL_c| \leq max_c$}\Comment{Check actual size against $max_c$} + \State $m \gets m + |SL_c|$ +\Else + \State $error \gets$ 'Actual queue size exceeds $max_c$' \EndIf -\State \Return{$Result$} + \State $error \gets \Call{CheckLastSeqN}{MS_c,MS}$ +\State \Return{$DT$} +\EndFunction +\end{algorithmic} + +\begin{algorithmic}[1] +\Function{GetValFromKey}{$k_g$} +\State $\tuple{k_s,v_s} \gets \tuple{k,v} \mid \tuple{k,v} \in DT \land k = k_g$ +\State $v_s \gets GetVal(\tuple{k_s,v_s})$ +\State \Return{$v_s$} \EndFunction \end{algorithmic} -- 2.34.1