פונקציית ספוג

בקריפטוגרפיה, פונקציית ספוג (sponge function) היא דרך להרחיב פונקציית גיבוב לפונקציה קריפטוגרפית כללית שהקלט והפלט שלה באורך משתנה. פונקציית ספוג מיישמת מבנה ספוג (sponge structure) שהוא מבנה איטרטיבי פשוט המבוסס על תמורה או טרנספורמציה פנימית הפועלת על קלט באורך קבוע, שמקבל קלט באורך משתנה ומפיק פלט באורך משתנה. פונקציית ספוג מאוד גמישה ויכולה לשמש כצופן זרם שבו נדרש קלט קצר ופלט ארוך או כפונקציית גיבוב וקוד אימות מסרים שבהם הקלט ארוך והפלט קצר. מהיבט תאורטי פונקציית ספוג משמשת כמודל למבנה קונקרטי של פונקציית גיבוב עם גישה לזיכרון פנימי. פונקציית ספוג אקראית מקבילה לאורקל אקראי, למעט אפקט הזיכרון הסופי (התנגשויות הן בלתי נמנעות). לכן יכולה לשמש כחלופה למודל אורקל אקראי כדי לבטא טענת ביטחון. הרעיון נולד במהלך פיתוח RadioGatun שהיא פונקציית גיבוב המקבלת קלט באורך שרירותי ומפיקה פלט בכל אורך רצוי. המפתחים נתקלו בבעיה בניסיון לבטא את ביטחון האלגוריתם במונחים של סיבוכיות זמן. כאשר הפלט קבוע אפשר לטעון שפונקציית הגיבוב טובה לפחות כאורקל אקראי שהפלט שלו נחתך ל- n {\displaystyle n} סיביות. לכן בגלל התקפת יום הולדת סיבוכיות התקפה בסיסית למציאת התנגשות היא מסדר גודל של 2 n / 2 {\displaystyle 2^{n/2}} . אולם כאשר הפלט באורך משתנה אין לטענה זו משמעות, כביכול אפשר להגיע לביטחון אינסופי אם מאריכים את הפלט מאוד. לכן המפתחים הגיעו למודל שונה שבו מצהירים ביטחון במונחים של אורקל אקראי שנקרא כאן "פונקציית ספוג אקראית", שהוא מבנה תאורטי כמו אורקל אקראי למעט העובדה שהוא מוגבל בזיכרון לכן התנגשויות בלתי נמנעות. הממצאים פורסמו לראשונה ב-2007 בסמינר Dugstuhl בגרמניה ולאחר מכן בסדנת Ecrypt בברצלונה. פונקציית ספוג התגלתה ככלי יעיל לבניית פרימיטיבים קריפטוגרפיים רבים. אפשר לנצל מבנה ספוג ותאומו הנקרא "מבנה דופלקס" (duplex construction), כדי ליישם מגוון רחב של פרימיטיבים קריפטוגרפיים, כולל פונקציית גיבוב, מחולל פסאודו-אקראי, הצפנה סימטרית, אימות מסרים והצפנה מאומתת, עם ובלי וקטור אתחול ובאורכים משתנים לפי לצורך. בדרך זו נהנים מפונקציונליות רבה בפונקציית תמורה יחידה ומפשטים את תהליך הפיתוח והיישום מבלי לדאוג למרכיבים אחרים כמו תהליך הכנת מפתח. האטרקטיביות של מבנה זה נובעת מהעובדה שאפשר להתבסס על פרמוטציה מתאימה שזה יותר קל מלפתח צופן בלוקים או פונקציית דחיסה. קיימים כמה אלגוריתמים חדשים שמסתמכים על מבנה ספוג מהם Keccak, Quark, Photon, Spongent וכן Spritz. מראה כללי של מבנה ספוג הוא: הסימן ‖ {\displaystyle \|} מייצג שרשור. תחילה הקלט M {\displaystyle M} מרופד לפי כלל ריפוד מתאים (בהמשך), לאחר מכן התוצאה P {\displaystyle P} נספגת לתוך המצב הפנימי s {\displaystyle s} באמצעות הפונקציה הפנימית f {\displaystyle f} באורך r {\displaystyle r} סיביות. היא יכולה להיות כל PRP או PRF בטוח לפי בחירה. ואז הפלט Z {\displaystyle Z} נסחט בהתאם לאורך הרצוי ℓ {\displaystyle \ell } , הפלט יכול לשמש כמפתח הצפנה או ערך גיבוב. באופן כללי אמור להיות קשה למצוא מסלול מ- s {\displaystyle s} ל- P {\displaystyle P} . התנגשות פירושה ש- ABSORB ( P ) = ABSORB ( Q ) {\displaystyle {\text{ABSORB}}(P)={\text{ABSORB}}(Q)} כאשר P ≠ Q {\displaystyle P\neq Q} וכן אם מתקבל ABSORB ( P ) = ABSORB ( P   ‖   0 d r ) {\displaystyle {\text{ABSORB}}(P)={\text{ABSORB}}(P\ \|\ 0^{dr})} פירושו שהמבנה מכיל מעגליות ולכן הפלט יחזור על עצמו. היות שהקלט באורך משתנה יש להפעיל כלל ריפוד מתאים כדי לחלק את הקלט ל- x {\displaystyle x} בלוקים בגודל b {\displaystyle b} סיביות כל אחד, באופן שיהיה קל להסיר את הריפוד עם קבלת המסר בצד השני מבלי לדעת מה היה אורך המסר. סכמת הריפוד הפשוטה והנפוצה ביותר היא pad 10 ∗ {\displaystyle {\text{pad}}10^{*}} כלומר מוסיפים את הסיבית "1" בסוף הקלט ומרפדים באפסים, כאשר הכוכבית מציינת שמספר האפסים הנדרש תלוי באורך הקלט ובגודל הבלוק, כך שהאורך הכולל צריך להתחלק ב- b {\displaystyle b} . כלל הריפוד חייב לקיים שלושה תנאים: הריפוד צריך להיות קל להסרה. מחרוזת הריפוד לא יכולה להיות ריקה. הבלוק האחרון חייב להיות שונה מאפס. הסימון של כלל הריפוד עבור בלוק באורך x {\displaystyle x} סיביות מסומן בקיצור: M   ‖   pad [ x ] ( | M | ) {\displaystyle M\ \|\ {\text{pad}}[x](|M|)} מבנה ספוג הוא מבנה איטרטיבי פשוט ליצירת פונקציה SPONGE [ f , pad , r ] ( M , ℓ ) {\displaystyle {\text{SPONGE}}[f,{\text{pad}},r](M,\ell )} המקבלת קלט מהתחום Z 2 ∗ {\displaystyle \mathbb {Z} _{2}^{*}} ומפיקה פלט בטווח Z 2 ∞ {\displaystyle \mathbb {Z} _{2}^{\infty }} . היא מבוססת על תמורה או טרנספורמציה f {\displaystyle f} הפועלת על b {\displaystyle b} סיביות. b {\displaystyle b} קבוע ונקרא כאן רוחב. הוא כולל מצב פנימי (זיכרון) באורך b = r + c {\displaystyle b=r+c} סיביות, כאשר r {\displaystyle r} נקרא "קצב" (bitrate) ו- c {\displaystyle c} נקרא "קיבולת" (capacity). המצב הפנימי מאותחל באפסים, הקלט מרופד כאמור ומחולק לבלוקים של r {\displaystyle r} סיביות ומשם ממשיכים בשני שלבים: שלב הספיגה, בשלב זה הבלוקים של הקלט מועברים בפונקציה f {\displaystyle f} ומשולבים ב-XOR עם r {\displaystyle r} הסיביות הראשונות של המצב הפנימי. כאשר מסיימים לקלוט את כל הבלוקים עוברים לשלב הבא. שלב הסחיטה. בשלב זה r {\displaystyle r} הסיביות הראשונות של המצב מועברות שוב בפונקציה f {\displaystyle f} והתוצאה מוחזרת למשתמש. מספר הבלוקים שהפונקציה מחזירה תלוי במשתמש. הסימון ⌊ ⋅ ⌋ ℓ {\displaystyle \left\lfloor \cdot \right\rfloor _{\ell }} פירושו שאת פלט הפונקציה חותכים ל- ℓ {\displaystyle \ell } הסיביות הראשונות. כאשר c {\displaystyle c} הסיביות הנותרות של המצב לעולם לא מושפעות מבלוקים של הקלט ולעולם אינן נכללות בפלט במהלך הסחיטה. להלן פסאודו-קוד המתאר מבנה הספוג: S P O N G E [ f , pad , r ] {\displaystyle \mathbf {SPONGE} [f,{\text{pad}},r]} P = M   ‖   pad [ r ] ( | M | ) {\displaystyle P=M\ \|\ {\text{pad}}[r](|M|)} s = 0 b {\displaystyle s=0^{b}} For  i = 0  to  | P | r − 1  do {\displaystyle {\text{For }}i=0{\text{ to }}{|P|}_{r}-1{\text{ do}}} s = s ⊕ P i   ‖   0 b − r {\displaystyle s=s\oplus P_{i}\ \|\ 0^{b-r}} s = f ( s ) {\displaystyle s=f(s)} Z = ⌊ s ⌋ r {\displaystyle Z=\left\lfloor s\right\rfloor _{r}} While  | Z | r r < ℓ  do {\displaystyle {\text{While }}|Z|_{r}r<\ell {\text{ do}}} s = f ( s ) {\displaystyle s=f(s)} Z = Z   ‖   ⌊ s ⌋ r {\displaystyle Z=Z\ \|\ \left\lfloor s\right\rfloor _{r}} Return  ⌊ Z ⌋ ℓ {\displaystyle {\text{Return }}\left\lfloor Z\right\rfloor _{\ell }} בפונקציית גיבוב עם פלט קבוע מקובל היה בדרך כלל להשוותה מול אורקל אקראי, אולם זה השתנה בעקבות גילויים חדשים בעשור האחרון. יש לזכור שהיות שהמצב הפנימי סופי והפונקציה איטרטיבית - היא מעבדת את הקלט בלוק אחר בלוק, בהכרח שיהיו התנגשויות, זאת לעומת אורקל אקראי תאורטי שאצלו לא קיים מושג "מצב" ואין לו התנגשויות. מסיבה זו אי אפשר להשוות ישירות למודל אורקל אקראי. אלטרנטיבה טובה למודל אורקל אקראי בהקשר זה היא מבנה ספוג אקראי שהוא מבנה תאורטי שהפונקציה הפנימית שלו f {\displaystyle f} היא פרמוטציה אקראית שנבחרה באופן אחיד מטווח הפרמוטציות האפשריות מעל b {\displaystyle b} סיביות. למעט האפקט שנובע עקב מגבלת הזיכרון הסופי. מהיבט תאורטי כשמנתחים ביטחון פונקציית ספוג לפי מודל זה מביאים בחשבון גם את הפרמטרים קצב וקיבולת. במצב אידיאלי אומרים שביטחון הפונקציה הוא במונחים של הקיבולת c {\displaystyle c} , כלומר התקפה גנרית שאינה מנצלת חולשות ספציפיות בפונקציה הפנימית תהיה בסיבוכיות 2 c / 2 {\displaystyle 2^{c/2}} לפחות. במילים אחרות מוכיחים שכל התקפה מוצלחת נגד המבנה עצמו משליכה בהכרח שניתן להבחין בין תוצאת הפרמוטציה שהמבנה משתמש בה לבין מחרוזת אקראית ומכאן שהיא אינה טובה לשימוש. באופן דומה מבנה DUPLEX [ f , pad , r ] {\displaystyle {\text{DUPLEX}}[f,{\text{pad}},r]} משתמש בטרנספורמציה או תמורה פנימית f {\displaystyle f} , כלל ריפוד מתאים ופרמטר r {\displaystyle r} . אך בשונה מפונקציית ספוג שהיא חסרת מצב בין הקריאות לפונקציה, מבנה דופלקס הוא אובייקט שיכול לקבל קלט נוסף ולהפיק מחרוזת פלט שהיא תוצאה של הקלט שהתקבל עד כה. במילים אחרות מבנה דופלקס דומה לרצף קריאות חוזרות של פונקציית ספוג עם קלט שונה. אובייקט דופלקס מכיל מצב בגודל b {\displaystyle b} סיביות, בשלב האתחול המצב הפנימי מאופס, ומכאן ואילך אפשר להפעיל את הפונקציה D.duplexing ( σ , ℓ ) {\displaystyle {\text{D.duplexing}}(\sigma ,\ell )} שוב ושוב עם קלט σ {\displaystyle \sigma } שאורכו צריך להיות קצר מספיק כדי שיתקבל בלוק אחד לאחר ריפוד. הפלט הוא באורך ℓ {\displaystyle \ell } שהוא לכל היותר r {\displaystyle r} סיביות. בכל קריאה המבנה תחילה מרפד את הקלט לפי כלל הריפוד שנבחר, מחבר את הקלט ב-XOR עם חלק החיצוני של המצב הפנימי ואז מיישם את הפונקציה f {\displaystyle f} על המצב ומחזיר את ℓ {\displaystyle \ell } הסיביות הראשונות של המצב. הוכח שמבנה דופלקס בטוח כמבנה ספוג, היות שמבנה דופלקס בעצם מקביל למבנה ספוג שהקלט שלו חולק למקטעים בגודל σ {\displaystyle \sigma } שכל אחד מהם מרופד בנפרד ואז הם משורשרים לרצף אחד ארוך. להלן תיאור מבנה דופלקס: D U P L E X [ f , pad , r ] {\displaystyle \mathbf {DUPLEX} [f,{\text{pad}},r]} D . i n i t i a l i z e {\displaystyle \mathbf {D.initialize} } s = 0 b {\displaystyle s=0^{b}} D . d u p l e x i n g ( σ , ℓ )  with  ℓ ≤ r {\displaystyle \mathbf {D.duplexing} (\sigma ,\ell ){\text{ with }}\ell \leq r} P = σ   ‖   pad [ r ] ( | σ | ) {\displaystyle P=\sigma \ \|\ {\text{pad}}[r](|\sigma |)} s = s ⊕ ( P   ‖   0 b − 1 ) {\displaystyle s=s\oplus (P\ \|\ 0^{b-1})} s = f ( s ) {\displaystyle s=f(s)} Return  ⌊ s ⌋ ℓ {\displaystyle {\text{Return }}\left\lfloor s\right\rfloor _{\ell }} ערך מורחב – הצפנה מאומתת הצפנה מאומתת היא דרך להצפין ולאמת מידע יחד עם מידע נלווה המשויך אליו אם ישנו. הרעיון שימושי במיוחד בפרוטוקול תקשורת שבו חלק מחבילת מידע אמור להיות סודי בעוד שחלק אחר שנקרא בהקשר זה כותר (header) אמור להישאר קריא (משמש את השרת המקבל). המצפין רוצה להבטיח מלבד סודיות שהמסר והמידע הנלווה אליו אותנטיים וכי לא שונו על ידי גורם זר או בשל תקלה בשידור, באופן שמסכן את החלק הסודי של החבילה. אפשר ליישם הצפנה מאומתת באמצעות מבנה דופלקס. האובייקט SpongeWrap להלן, משתמש באובייקט דופלקס D עם הפרמטרים f , pad , r {\displaystyle f,{\text{pad}},r} אותו הוא מאתחל ומעביר אליו את המפתח K {\displaystyle K} . כדי להצפין ולאמת קוראים לפונקציה W.wrap עם הפרמטרים A , B , ℓ {\displaystyle A,B,\ell } כאשר A {\displaystyle A} הוא המידע הנלווה, B {\displaystyle B} הוא המסר המיועד להצפנה והפרמטר ℓ {\displaystyle \ell } מייצג את אורך תג האימות בסיביות. הפונקציה מחזירה את הטקסט המוצפן C {\displaystyle C} שהוא C i = B i ⊕ Z i {\displaystyle C_{i}=B_{i}\oplus Z_{i}} כאשר Z i {\displaystyle Z_{i}} הוא הערך החוזר מהפונקציה duplexing ואת תג האימות T {\displaystyle T} . לפענוח קוראים לפונקציה W.unwrap עם הפרמטרים A , C , T {\displaystyle A,C,T} והיא אמורה להחזיר את B {\displaystyle B} או "Error" אם אחד הערכים אינו תקין. לפני הקריאה לאובייקט D לביצוע duplexing תחילה מרפדים את כל האלמטים בסיבית אחת נוספת שנקראת frame-bit (1 חוץ מהבלוק האחרון). הערך ρ {\displaystyle \rho } נקרא קצב והוא קובע את גודל הבלוק, כלומר כמות הסיביות שאפשר להצפין ולאמת בקריאה אחת. לכן הערך המקסימלי שלו הוא ρ max ( pad , r ) − 1 {\displaystyle \rho _{\text{max}}({\text{pad}},r)-1} כי יש להביא בחשבון את הסיבית הנוספת. להלן תיאור האלגוריתם: S p o n g e W r a p [ f , pad , ρ ] {\displaystyle \mathbf {SpongeWrap} [f,{\text{pad}},\rho ]} ‎ W.initialize ( K ) ,  with  K ∈ Z 2 ∗ {\displaystyle {\text{W.initialize}}(K),{\text{ with }}K\in \mathbb {Z} _{2}^{*}} Let  K = K 0   ‖   K 1   ‖   . . .   ‖   K u  with  | K i | = ρ  for  i < u , | K u | ≤ ρ , | K u | > 0  if  u > 0 {\displaystyle {\text{Let }}K=K_{0}\ \|\ K_{1}\ \|\ ...\ \|\ K_{u}{\text{ with }}|K_{i}|=\rho {\text{ for }}i<u,|K_{u}|\leq \rho ,|K_{u}|>0{\text{ if }}u>0} D.initialize ( ) {\displaystyle {\text{D.initialize}}()} for  i = 0  to  u − 1  do {\displaystyle {\text{for }}i=0{\text{ to }}u-1{\text{ do}}} D.duplexing ( K i   ‖   1 , 0 ) {\displaystyle {\text{D.duplexing}}(K_{i}\ \|\ 1,0)} D.duplexing ( K u   ‖   0 , 0 ) {\displaystyle {\text{D.duplexing}}(K_{u}\ \|\ 0,0)} ‎ W . w r a p ( A , B , ℓ )  with  A , B ∈ Z 2 ∗ , ℓ ≥ 0 {\displaystyle \mathbf {W.wrap} (A,B,\ell ){\text{ with }}A,B\in \mathbb {Z} _{2}^{*},\ell \geq 0} Let  A = A 0   ‖   A 1   ‖   A v  with  | A i | = ρ  for  i < v  and  | A v | ≤ ρ , | A v | > 0  if  v > 0 {\displaystyle {\text{Let }}A=A_{0}\ \|\ A_{1}\ \|\ A_{v}{\text{ with }}|A_{i}|=\rho {\text{ for }}i<v{\text{ and }}|A_{v}|\leq \rho ,|A_{v}|>0{\text{ if }}v>0} Let  B = B 0   ‖   B 1   ‖   B w  with  | B i | = ρ  for  i < w  and  | B w | ≤ ρ , | B w | > 0  if  w > 0 {\displaystyle {\text{Let }}B=B_{0}\ \|\ B_{1}\ \|\ B_{w}{\text{ with }}|B_{i}|=\rho {\text{ for }}i<w{\text{ and }}|B_{w}|\leq \rho ,|B_{w}|>0{\text{ if }}w>0} for  i = 0  to  v − 1  do {\displaystyle {\text{for }}i=0{\text{ to }}v-1{\text{ do}}} D.duplexing ( A i   ‖   0 , 0 ) {\displaystyle {\text{D.duplexing}}(A_{i}\ \|\ 0,0)} Z = D.duplexing ( A v   ‖   1 , | B 0 | ) {\displaystyle Z={\text{D.duplexing}}(A_{v}\ \|\ 1,|B_{0}|)} C = B 0 ⊕ Z {\displaystyle C=B_{0}\oplus Z} for  i = 0  to  w − 1  do {\displaystyle {\text{for }}i=0{\text{ to }}w-1{\text{ do}}} Z = D.duplexing ( B i   ‖   1 , | B i + 1 | ) {\displaystyle Z={\text{D.duplexing}}(B_{i}\ \|\ 1,|B_{i+1}|)} C = C   ‖   ( B i + 1 ⊕ Z ) {\displaystyle C=C\ \|\ (B_{i+1}\oplus Z)} Z = D.duplexing ( B w   ‖   0 , ρ ) {\displaystyle Z={\text{D.duplexing}}(B_{w}\ \|\ 0,\rho )} while  | Z | < ℓ  do {\displaystyle {\text{while }}|Z|<\ell {\text{ do}}} Z = Z   ‖   D.duplexing ( 0 , ρ ) {\displaystyle Z=Z\ \|\ {\text{D.duplexing}}(0,\rho )} T = ⌊ Z ⌋ ℓ {\displaystyle T=\left\lfloor Z\right\rfloor _{\ell }} Return  ( C , T ) {\displaystyle {\text{Return }}(C,T)} ‎ W . u n w r a p ( A , C , T )  with  A , C , T ∈ Z 2 ∗ {\displaystyle \mathbf {W.unwrap} (A,C,T){\text{ with }}A,C,T\in \mathbb {Z} _{2}^{*}} Let  A = A 0   ‖   A 1   ‖   A v  with  | A i | = ρ  for  i < v  and  | A v | ≤ ρ , | A v | > 0  if  v > 0 {\displaystyle {\text{Let }}A=A_{0}\ \|\ A_{1}\ \|\ A_{v}{\text{ with }}|A_{i}|=\rho {\text{ for }}i<v{\text{ and }}|A_{v}|\leq \rho ,|A_{v}|>0{\text{ if }}v>0} Let  C = C 0   ‖   C 1   ‖   C w  with  | C i | = ρ  for  i < w  and  | C w | ≤ ρ , | C w | > 0  if  w > 0 {\displaystyle {\text{Let }}C=C_{0}\ \|\ C_{1}\ \|\ C_{w}{\text{ with }}|C_{i}|=\rho {\text{ for }}i<w{\text{ and }}|C_{w}|\leq \rho ,|C_{w}|>0{\text{ if }}w>0} Let  T = T 0   ‖   T 1   ‖   T x  with  | T i | = ρ  for  i < x  and  | T x | ≤ ρ , | T x | > 0  if  x > 0 {\displaystyle {\text{Let }}T=T_{0}\ \|\ T_{1}\ \|\ T_{x}{\text{ with }}|T_{i}|=\rho {\text{ for }}i<x{\text{ and }}|T_{x}|\leq \rho ,|T_{x}|>0{\text{ if }}x>0} for  i = 0  to  v − 1  do {\displaystyle {\text{for }}i=0{\text{ to }}v-1{\text{ do}}} D.duplexing ( A i   ‖   0 , 0 ) {\displaystyle {\text{D.duplexing}}(A_{i}\ \|\ 0,0)} Z = D.duplexing ( A v   ‖   1 , | C 0 | ) {\displaystyle Z={\text{D.duplexing}}(A_{v}\ \|\ 1,|C_{0}|)} B 0 = C 0 ⊕ Z {\displaystyle B_{0}=C_{0}\oplus Z} for  i = 0  to  w − 1  do {\displaystyle {\text{for }}i=0{\text{ to }}w-1{\text{ do}}} Z = D.duplexing ( B i   ‖   1 , | C i + 1 | ) {\displaystyle Z={\text{D.duplexing}}(B_{i}\ \|\ 1,|C_{i+1}|)} B i + 1 = C i + 1 ⊕ Z {\displaystyle B_{i+1}=C_{i+1}\oplus Z} Z = D.duplexing ( B w   ‖   0 , ρ ) {\displaystyle Z={\text{D.duplexing}}(B_{w}\ \|\ 0,\rho )} if  T = ⌊ Z ⌋ ℓ  then {\displaystyle {\text{if }}T=\left\lfloor Z\right\rfloor _{\ell }{\text{ then}}} Return  B 0   ‖ B 1   ‖   . . .   ‖   B w {\displaystyle {\text{Return }}B_{0}\ \|B_{1}\ \|\ ...\ \|\ B_{w}} else return  E r r o r {\displaystyle {\text{else return }}\mathbf {Error} } SHA-3 Cryptographic sponge functions Duplexing the sponge: single-pass authenticated encryption and other applications A. Joux, Multicollisions in iterated hash functions. Application to cascaded constructions, Advances in Cryptology - Crypto 2004 (M. Franklin, ed.), LNCS, no. 3152, Springer-Verlag, 2004, pp. 306-316. J. Kelsey and B. Schneier, Second preimages on n-bit hash functions for much less than 2^n work, Advances in Cryptology - Eurocrypt 2005 (R. Cramer, ed.), LNCS, no. 3494, Springer-Verlag, 2005, pp. 474-490. T. Kohno and J. Kelsey, Herding hash functions and the Nostradamus attack, Advances in Cryptology – Eurocrypt 2006 (S. Vaudenay, ed.), LNCS, no. 4004, Springer-Verlag, 2006, pp. 222-232.