RIPEMD

RIPEMD ראשי תיבות: פונקציית תמצות של פרויקט RIPE (באנגלית: RACE Integrity Primitives Evaluation Message Digest) היא משפחה של פונקציות גיבוב קריפטוגרפיות שפותחה על ידי הוועדה האירופאית RACE שהוקמה בראשית שנות התשעים של המאה ה-20 לצורך מחקר ופיתוח של טכנולוגיות תקשורת. RIPEMD הראשונה מבוססת על MD4 והיא דומה בביצועיה ל-SHA-1. לגרסה זו נוספו שיפורים אחדים וכיום קיימות כמה גרסאות מתקדמות כמו RIPEMD-160 וכן RIPEMD-128 שתיהן כלולות בתקן ISO/IEC 10118-3:2004 של ISO.

פרויקט RIPE שם לו למטרה להכין רשימה מומלצת של פונקציות קריפטוגרפיות בהתבסס על הערכה עצמאית משלו במקביל לפרויקט SHA של NIST. ב-1990 הוצעה גרסה מחוזקת של MD4 שנקראה בקיצור RIPEMD. באופן כללי RIPEMD המקורית מורכבת למעשה משתי גרסאות משופרות של MD4 הפועלות על הקלט בשני מסלולים מקבילים ונבדלות ביניהן רק בקבועי הסבבים, כאשר בסיום העבודה הפלט שלהן מאוחד לפלט הסופי של האלגוריתם. בניגוד למקבילה SHA-1 פונקציית הגיבוב RIPEMD פותחה על ידי הקהילה האקדמית באופן פומבי, היא אינה מוגנת בפטנט כלשהו אך השימוש בה פחות נפוץ מ-SHA-1. האלגוריתם היה בשימוש במערכת הבנקאות יחד עם SHA-1. בעקבות פיתוח התקפות קריפטוגרפיות חדשות ועקב גילוי חולשות באלגוריתם המקורי פותח RIPEMD-160. דור ההמשך RIPEMD-160 הוא שיפור של RIPEMD והוא פותח ב-1996 על ידי Hans Dobbertin ,Antoon Bosselaers ו-Bart Preneel מקבוצת המחקר COSIC (אבטחת מחשבים וקריפטוגרפיה מתועשת) של אוניברסיטת לוון והוא בטוח יותר מקודמו. פרוטוקול ביטקוין משתמש בין היתר ב-RIPEMD-160 כחלק מכתובת ביטקוין הכלולה בעסקה.

==רקע ומוטיבציה==

פונקציית גיבוב נחשבת לסוס עבודה של ההצפנה המודרנית. היא קיימת כמעט בכל מערכת הצפנה כחלק מחתימה דיגיטלית, קוד אימות מסרים, מחולל פסאודו אקראי וכדומה. תפקידה למפות מחרוזת סיביות באורך כלשהו למחרוזת סיביות קצרה באורך קבוע הנקראת ערך גיבוב או תג המשרת כמו טביעת אצבע. בהינתן הפונקציה <math>h</math> והקלט <math>X</math> חישוב <math>h(X)</math> קל מאוד והוא אינו אורך יותר מכמה מילישניות על מעבד נפוץ. אולם הפעולה ההופכית קשה מאוד, בהינתן פלט גיבוב מסוים אמור להיות קשה מבחינה חישובית למצוא את הקלט המקורי שאם מחשבים את הגיבוב שלו מתקבל ערך הגיבוב הזה. הגדרה נוספת אומרת שיהיה קשה למצוא קלט נוסף שממנו מופק ערך גיבוב זהה לקלט הראשון. שתי ההגדרות נקראות בקיצור "מציאת מקור ראשון" ו"מציאת מקור שני" בהתאמה. בשני המקרים קיים ערך גיבוב קבוע ותפקיד המתקיף או הקריפטואנליסט הוא למצוא מקור שיענה על התנאים האמורים. באופן אידיאלי אמור להיות שסיבוכיות מציאת מקור ראשון או שני תהיה <math>2^m</math> פעולות גיבוב עבור פונקציית גיבוב שאורך הפלט הגיבוב שלה הוא <math>m</math> סיביות בממוצע. פונקציית גיבוב חסינת התנגשויות היא פונקציית גיבוב שבנוסף לשתי ההגדרות האמורות מקיימת תנאי נוסף: יהיה קשה מאוד מבחינה חישובית למצוא כל זוג קלטים אפשריים לא בהכרח קבועים מהם מופק פלט זהה - דהיינו מציאת התנגשות. במקרה כזה, בהנחה שלא התגלו חולשות בפונקציית הגיבוב, הדרך המהירה ביותר למצוא התנגשות היא התקפת יום הולדת שדורשת בממוצע <math>2^{m/2}</math> פעולות גיבוב. 

כמו מרבית פונקציות הגיבוב RIPEMD היא איטרטיבית באופייה. פונקציה פנימית <math>f</math> שנקראת פונקציית כיווץ או פונקציית תמצות מופעלת על הקלט המחולק למקטעים בגודל קבוע הקרויים בלוקים בשיטת מרקל-דמגרד. בניסוח רשמי, עבור הקלט <math>X</math> המחולק ל-<math>t</math> בלוקים באורך קבוע (את הבלוק האחרון מרפדים בדרך מוסכמת כדי שכל הבלוקים יהיו באורך אחיד וכן מוסיפים ליתר ביטחון בלוק ריק שבו מקודדים את אורך הקלט בסיביות) הפונקציה <math>h</math> פועלת כדלהלן:
<center>
:<math>\boldsymbol{H_0=IV, H_i=f(H_{i-1},X_i), h(X)=H_t}</math>
</center>
כאשר <math>1\le i\le t</math> ו-<math>f</math> היא פונקציה חד-כיוונית או פונקציה פסאודו אקראית. הערך IV הוא ערך התחלתי קבוע הנקרא וקטור אתחול. <math>H_i</math> הוא ערך הביניים שמתקבל בין כל איטרציה ופלט הפונקציה הוא ערך הביניים האחרון <math>H_t</math>.

==RIPEMD-160==
קלט האלגוריתם הוא <math>t</math> בלוקים באורך 16 מילים כל אחד המחולקים בשיטת מרקל-דמגרד והפלט הסופי הוא ערך גיבוב באורך 160 סיביות. הפונקציה הפנימית של האלגוריתם מורכבת מחמש פונקציות בוליאניות המופעלות חמש פעמים כל אחת לסירוגין בשני מסלולים מקבילים הנקראים כאן צד ימין וצד שמאל בהתאמה כשהפלט הסופי הוא שילוב של תוצאות שניהם. הזיכרון הפנימי של הפונקציה הפנימית מורכב מחמשה אוגרים באורך 32 סיביות, בסך הכול 160 סיביות עבור כל צד. הפונקציות בשני הצדדים זהות וההבדל ביניהם הוא רק בערכים ההתחלתיים, סדר הקריאות לפונקציות הבוליאניות וסדר עיבוד המילים בתוך הבלוק.

הקלט לפונקציות הפנימיות הוא חמש מילים באורך 32 סיביות כל אחת המסומנות <math>A,B,C,D,E</math>, הקבוע <math>K</math> (לפי הטבלה להלן), בלוק הקלט הנוכחי <math>X</math> וההיסט <math>s</math> עבור ההזזה המעגלית (לפי הטבלה להלן) והן מבצעות:
<center>
:<math>A=((A+f_i(B,C,D)+X+K)\lll s) + E, C=C\lll 10</math>,
</center>
כאשר <math>f_i</math> מתייחס לאחת מחמש הפונקציות המתוארות להלן. הביטוי <math>X \lll s</math> מייצג הזזה מעגלית שמאלה של <math>X</math> בגבולות מילה באורך 32 סיביות <math>s</math> פוזיציות או צעדים. 
לאחר מכן ערכי האוגרים מתחלפים ביניהם לפי הסדר הבא: <math>T=A,A=E,E=D,D=C,C=B,B=T</math>. כדי להבדיל בין ערכי הביניים והקבועים של שני הצדדים, הערכים של הצד הימני מסומנים בגרש, כמו: <math>A',B',C',D',E'</math> וכן <math>K'</math>.

סדר עיבוד מילות הבלוק נקבע לפי שילוב של שתי פרמוטציות, הראשונה <math>\rho</math> מוגדרת לפי הטבלה:
<center>
{| class="wikitable" dir="ltr"
|-
| <math>i</math> || 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 || 12 || 13 || 14 || 15
|-
| <math>\rho(i)</math> || 7 || 4 || 13 || 1 || 10 || 6 || 15 || 3 || 12 || 0 || 9 || 5 || 2 || 14 || 11 || 8
|}
</center>

הפרמוטציה השנייה <math>\pi</math> מוגדרת לפי <math>\pi(i)=9i+5</math> מודולו 16. 

לסיכום 16 מילות הבלוק מעובדות בשני צידי האלגוריתם, שנקראים כאן ימין ושמאל בהתאמה, לפי סדר הנקבע לפי הטבלה הבאה:
<center>
{| class="wikitable"
|-
! צד !! סבב 1 !! סבב 2 !! סבב 3 !! סבב 4 !! סבב 5
|-
| שמאל || <math>id</math> || <math>\rho</math> || <math>\rho^2</math> || <math>\rho^3</math> || <math>\rho^4</math>
|-
| ימין || <math>\pi</math> || <math>\rho\pi</math> || <math>\rho^2\pi</math> || <math>\rho^3\pi</math> || <math>\rho^4\pi</math>
|}
</center>

הפונקציות הבוליאניות מוגדרות כדלהלן:
<center>
{| dir="ltr"
|-
|
:<math>f_1(x, y, z) = x \oplus y \oplus z</math>
:<math>f_2(x, y, z) = (x \land y) \lor (\neg x \land z)</math>
:<math>f_3(x, y, z) = (x \lor \neg y) \oplus z</math>
:<math>f_4(x, y, z) = (x \land z) \lor (y \land \neg z)</math>
:<math>f_5(x, y, z) = x \oplus (y \lor \neg z)</math>
|}
</center>

הסימן <math>\neg</math> הוא אופרטור השלילה, הסימן <math>\land</math> הוא אופרטור וגם והסימן <math>\lor</math> הוא האופרטור או.

השימוש בפונקציות הבוליאניות מתבצע לפי סדר המופיע בטבלה הבאה:
<center>
{| class="wikitable"
|-
! צד !! סבב 1 !! סבב 2 !! סבב 3 !! סבב 4 !! סבב 5
|-
| שמאל || <math>f_1</math> || <math>f_2</math> || <math>f_3</math> || <math>f_4</math> || <math>f_5</math>
|-
| ימין || <math>f_5</math> || <math>f_4</math> || <math>f_3</math> || <math>f_2</math> || <math>f_1</math>
|}
</center>

בשני הצדדים ההזזות המעגליות מבוצעות במרחקים קבועים לפי הטבלה הבאה:
<center>
{| class="wikitable"
|-
| סבב || <math>X_0</math> || <math>X_1</math> || <math>X_2</math> || <math>X_3</math> || <math>X_4</math> || <math>X_5</math> || <math>X_6</math> || <math>X_7</math> || <math>X_8</math> || <math>X_9</math> || <math>X_{10}</math> || <math>X_{11}</math> || <math>X_{12}</math> || <math>X_{13}</math> || <math>X_{14}</math> || <math>X_{15}</math>
|-
| 1 || 11 || 14 || 15 || 12 || 5 || 8 || 7 || 9 || 11 || 13 || 14 || 15 || 6 || 7 || 9 || 8
|-
| 2 || 12 || 13 || 11 || 15 || 6 || 9 || 9 || 7 || 12 || 15 || 11 || 13 || 7 || 8 || 7 || 7
|-
| 3 || 13 || 15 || 14 || 11 || 7 || 7 || 6 || 8 || 13 || 14 || 13 || 12 || 5 || 5 || 6 || 9
|-
| 4 || 14 || 11 || 12 || 14 || 8 || 6 || 5 || 5 || 15 || 12 || 15 || 14 || 9 || 9 || 8 || 6
|-
| 5 || 15 || 12 || 13 || 13 || 9 || 5 || 8 || 6 || 14 || 11 || 12 || 11 || 8 || 6 || 5 || 5
|}
</center>

ערכי קבועי הסבבים הם החלק השלם של המספרים הבאים:
<center>
{| class="wikitable"
|-
! צד !! סבב 1 !! סבב 2 !! סבב 3 !! סבב 4 !! סבב 5
|-
| שמאל || 0 || <math>2^{30}\cdot\sqrt{2}</math> || <math>2^{30}\cdot\sqrt{3}</math> || <math>2^{30}\cdot\sqrt{5}</math> || <math>2^{30}\cdot\sqrt{7}</math>
|-
| ימין || <math>2^{30}\cdot\sqrt[3]{2}</math> || <math>2^{30}\cdot\sqrt[3]{3}</math> || <math>2^{30}\cdot\sqrt[3]{5}</math> || <math>2^{30}\cdot\sqrt[3]{7}</math> || 0
|}
</center>

או באופן מפורש:
<center>
{| dir="ltr"
|-
! צד שמאל !! צד ימין
|-
|
:<math>K_j = \text{00000000}, \ \ (0 \le j \le 15)</math>
:<math>K_j = \text{5A827999}, \ \ (16 \le j \le 31)</math>
:<math>K_j = \text{6ED9EBA1}, \ \ (32 \le j \le 47)</math>
:<math>K_j = \text{8F1BBCDC}, \ \ (48 \le j \le 63)</math>
:<math>K_j = \text{A953FD4E}, \ \ (64 \le j \le 79)</math>
|| 
:<math>K'_j = \text{50A28BE6}, \ \ (0 \le j \le 15)</math>
:<math>K'_j = \text{5C4DD124}, \ \ (16 \le j \le 31)</math>
:<math>K'_j = \text{6D703EF3}, \ \ (32 \le j \le 47)</math>
:<math>K'_j = \text{7A6D76E9}, \ \ (48 \le j \le 63)</math>
:<math>K'_j = \text{00000000}, \ \ (64 \le j \le 79)</math>
|}
</center>

הערכים ההתחלתיים הם:
:<math>h_0=\text{0x67452301},h_1=\text{EFCDAB89},h_2=\text{98BADCFE},h_3=\text{10325476},h_4=\text{C3D2E1F0}</math>.

===פסאודו קוד===
סדר העיבוד של מילות הקלט:
<center>
{| dir="ltr"
|-
| colspan="2" align="right" | צד שמאל 
|-
| <math>r(j) </math> || <math>= 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15</math>
|-
| <math>r(16..31)</math> || <math>= 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8</math>
|-
| <math>r(32..47)</math> || <math>= 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12</math>
|-
| <math>r(48..63)</math> || <math>= 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2</math>
|-
| <math>r(64..79)</math> || <math>= 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13</math>
|-
| colspan="2" align="right" | צד ימין
|-
| <math>r'(0..15)</math> || <math>= 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12</math>
|-
| <math>r'(16..31)</math> || <math>= 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2</math>
|-
| <math>r'(32..47)</math> || <math>= 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13</math>
|-
| <math>r'(48..63)</math> || <math>= 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14</math>
|-
| <math>r'(64..79)</math> || <math>= 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11</math>
|}
</center>

ההיסטים של ההזזה המעגלית:
<center>
{| dir="ltr"
|-
| colspan="2" align="right" | צד שמאל
|-
| <math>s(0..15)</math> || <math>= 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8</math>
|-
| <math>s(16..31)</math> || <math>= 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12</math>
|-
| <math>s(32..47)</math> || <math>= 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5</math>
|-
| <math>s(48..63)</math> || <math>= 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12</math>
|-
| <math>s(64..79)</math> || <math>= 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6</math>
|-
| colspan="2" align="right" | צד ימין
|-
| <math>s'(0..15)</math> || <math>= 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6</math>
|-
| <math>s'(16..31)</math> || <math>= 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11</math>
|-
| <math>s'(32..47)</math> || <math>= 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5</math>
|-
| <math>s'(48..63)</math> || <math>= 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8</math>
|-
| <math>s'(64..79)</math> || <math>= 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11</math>
|}
</center>

הלולאה הראשית של האלגוריתם:
<center>
{| dir="ltr"
|-
|
:<math>\text{For }i=1\text{ to }t\text{ do: }</math>
:<math>\{</math>
:<math>\ \ \ \ A = h_0, B = h_1, C = h_2, D = h_3, E = h_4,</math>
:<math>\ \ \ \ A' = h_0, B' = h_1, C' = h_2, D' = h_3, E' = h_4</math>
:<math>\ \ \ \ \text{For }j=0\text{ to }79\text{ do: }</math>
:<math>\ \ \ \ \ \ \ \ \ T = \left((A \boxplus f_j(B,C,D)\boxplus X_i[r_j]\boxplus K_j)\lll s_j\right)\boxplus E,</math>
:<math>\ \ \ \ \ \ \ \ \ A = E, E = D, D = C\lll 10, C = B, B = T,</math>
:<math>\ \ \ \ \ \ \ \ \ T = ((A' \boxplus f_{(79-j)}(B',C',D')\boxplus X_i[r'_j]\boxplus K'_j)\lll s'_j)\boxplus E';</math>
:<math>\ \ \ \ \ \ \ \ \ A' = E', E' = D', D' = C'\lll 10, C' = B', B' = T,</math>
:<math>\ \ \ \ T = h_1 \boxplus C\boxplus D', h_1 = h_2\boxplus D\boxplus E', h_2 = h_3\boxplus E\boxplus A',</math>
:<math>\ \ \ \ h_3 = h_4\boxplus A\boxplus B', h_4 = h_0\boxplus B\boxplus C', h_0 = T.</math>
:<math>\}</math>
|}
</center>

הסימן <math>\boxplus</math> מייצג חיבור מודולו <math>2^{32}</math> (ברוב שפות התכנות אין צורך לדאוג לצמצום המודולרי ואפשר להתעלם ממנו כי תוצאת החיבור של שני אוגרים באורך 32 סיביות ממילא נחתכת בגבולות אוגר אחד שזה בעצם שקול לפעולת המודולו), הסימן <math>\oplus</math> מייצג XOR. הפונקציות <math>f_j</math> ו-<math>f_{(79-j)}</math> מתייחסות לסדר הקריאות לחמש הפונקציות הבוליאניות של צד ימין וצד שמאל בהתאמה. כל פונקציה מופעלת 16 פעמים על 16 מילות הבלוק הנוכחי עבור כל צד, בסך הכול מבוצעות 160 קריאות. למשל 16 המילים הראשונות של הבלוק הראשון בצד שמאל מעובדות עם הפונקציה <math>f_1</math> ובצד ימין עם הפונקציה <math>f_5</math>, וכן 16 המילים הבאות מעובדות בצד שמאל עם הפונקציה <math>f_2</math> ובצד ימין עם הפונקציה <math>f_4</math> וכן הלאה.

===וקטור בדיקה של RIPEMD-160===
{| dir="ltr"
|-
|
:<math>\text{RIPEMD-160}(\text{abc}) =\text{8eb208f7e05d987a9b044a8e98c6b087f15a0bfc}</math>
:<math>\text{RIPEMD-160}(\text{message digest}) =\text{5d0689ef49d2fae572b881b123a85ffa21595f36}</math>
:<math>\text{RIPEMD-160}(\text{abcdefghijklmnopqrstuvwxyz}) =\text{f71c27109c692c1b56bbdceb5b9d2865b3708dbc}</math>
|}

==RIPEMD-128==
פונקציית הגיבוב RIPEMD-128 דומה מאוד ל-RIPEMD-160 ההבדל העיקרי ביניהן הוא שהזיכרון הפנימי צומצם לארבע מילים באורך 32 סיביות עבור כל צד וכן מבוצעים רק ארבעה סבבים בהתאם (בהם משתמשים רק בארבע פונקציות בוליאניות לסירוגין).

פונקציית הסבב הפנימית מקבלת את ארבעת האוגרים A,B,C,D את בלוק הקלט הנוכחי <math>X</math>, את הקבוע הנוכחי <math>K</math> לפי הטבלה וכן את ההיסט <math>s</math> לפי הטבלה ומבצעת:
<center>
:<math>A = (A+f_i(B,C,D)+X+K)\lll s</math>
</center>
הפונקציה <math>f_i</math> מתייחסת לאחת מהפונקציות הבוליאניות המובאות לעיל כאשר <math>i\in\{1,2,3,4\}</math>. סדר הפעלתן זהה לפונקציה RIPEMD-160 פונקציית הסבב הפנימית השמאלית (צד שמאל) מתחילה לפי הסדר מהפונקציה הבוליאנית הראשונה ואחריה השנייה וכן הלאה. ואילו פונקציית הסבב הימנית מתחילה בסדר הפוך מהרביעית לשלישית, לשנייה וכן הלאה. 

טבלת הקבועים היא:
<center>
{| class="wikitable"
|-
! צד !! סבב 1 !! סבב 2 !! סבב 3 !! סבב 4
|-
| שמאל || 0 || <math>2^{30}\cdot\sqrt{2}</math> || <math>2^{30}\cdot\sqrt{3}</math> || <math>2^{30}\cdot\sqrt{5}</math>
|-
| ימין || <math>2^{30}\cdot\sqrt[3]{2}</math> || <math>2^{30}\cdot\sqrt[3]{3}</math> || <math>2^{30}\cdot\sqrt[3]{5}</math> || 0
|}
</center>

==הרחבות==
כאשר נדרש ערך גיבוב ארוך יותר ממה שהפונקציה מסוגלת לייצר בריצה אחת אפשר פשוט להפעיל את פונקציית הגיבוב באופן מקבילי פעמיים או יותר ואז לאחד את התוצאות לערך גיבוב באורך הרצוי. אולם טכניקה זו לא בטוחה והיא עלולה לייצר נקודת תורפה בגלל שהעובדה ששתי הפונקציות זהות לחלוטין עלולה להחדיר תלות בלתי רצויה ביניהן (עובדה שנוצלה בעבר כדי להתקיף את פונקציית הגיבוב RIPEMD המקורית). דרך בטוחה יותר היא לגרום להבדלים קלים ביניהן כמו שינוי בערכי קבועים, בסדר עיבוד מילות הקלט או בהיסטים של ההזזה המעגלית. וכן לייצר אינטראקציה כלשהי ביניהן, למשל על ידי החלפת ערכי האגורים של הזיכרון הפנימי בין שתי הפונקציות במהלך האיטרציות. טכניקות אילו יושמו בפונקציית הגיבוב RIPEMD-160 והיות שהיא כבר כוללת שני מסלולים מקבילים אפשר להרוויח פלט ארוך יותר ללא מאמץ נוסף. פשוט על ידי דילוג על השלב שבו משלבים יחד את התוצאות של שתי הפונקציות. אולם עקב כך יש צורך להוסיף אינטראקציה כשלהי בין צד ימין לצד שמאל. אפשר למשל להחליף את ערך האוגר <math>A</math> ב-<math>A'</math> אחרי הסבב הראשון ואת האוגר <math>B</math> ב-<math>B'</math> אחרי הסבב השני.

==הערות שוליים==

קטגוריה:פונקציות גיבוב קריפטוגרפיות