ZUC

**ZUC** הוא צופן זרם שפותח ב-2010 על ידי האקדמיה הסינית למדע עבור טכנולוגיית LTE. זהו צופן זרם סינכרוני, מותאם לחומרה ותוכנה כאחד, פועל ברמת מילים באורך 32 סיביות, מקבל מפתח הצפנה באורך 128 סיביות, וקטור אתחול באורך 128 סיביות ומייצר מילים פסאודו-אקראיות באורך 32 סיביות המשמשות חלק מזרם מפתח להצפנה ופענוח של המידע מילה אחר מילה. ZUC שוכן בליבת תקן 3GPP להצפנה מאומתת של שיחה סלולרית באלגוריתמים EEA3 להצפנה ו-EIA3 לאימות. הצופן קרוי על שמו של המתמטיקאי הסיני זו צ'אנגזי שחי במאה החמישית לספירה.

## תיאור הצופן
540px|ממוזער|שמאל|תרשים סכמטי של צופן ZUC המתאר את שלוש השכבות (הקווים המקווקווים); השכבה הראשונה LFSR מייצגת את אוגר הזיזה בעל 16 המצבים, שכבת סידור הסיביות מחדש BitReorganization נמצאת באמצע ומתחתה שכבת הפונקציה הליניארית.
ZUC מחולק לשני מצבי הפעלה, מצב הכנה ומצב העבודה. בשלב הראשון מפתח ההצפנה ווקטור האתחול נטענים לתוך המצב הפנימי והצופן מופעל (clocked) ללא יצירת פלט. בשלב השני בכל פעימת שעון נוצרת מילה פסאודו אקראית באורך 32 סיביות.
בהמרות ממילים לבתים מתייחסים לכל הערכים כאל מספרים שלמים לפי סדר בתים קטן. לדוגמה אם a=\text{0x1234} ו-b=\text{0x5678} אז c=a\ \| \ b=\text{0x12345678}. הסימן "\lll_n" מייצג הזזה מעגלית לשמאל בגבולות מילה באורך n סיביות.הסימנים "\ll" ו-"\gg" מייצגים הזזה (shift) של סיביות לימין או לשמאל בהתאמה, במספר פוזיציות לפי הערך המופיע לאחר הסימן. הסימן \boxplus מייצג חיבור מודולו 2^{32}. הסימן \oplus הוא XOR. ל-ZUC שלוש שכבות כמתואר בתרשים משמאל:

* שכבה עליונה - LFSR בעל 16 מצבים (Taps).
* שכבה אמצעית - סידור מחדש ברמה של סיביות.
* שכבה תחתונה - פונקציה אי-ליניארית.

### LFSR
בשכבה העליונה הצופן מכיל אוגר זיזה ממושב ליניארי הכולל 16 כניסות באורך 31 סיביות כל אחת המסומנות (s_0,s_1,...,s_{15}) כאשר s_i\in\{1,2,3,...,2^{31}-1\}. בכל פעימה תכולת האוגר מוזזת צעד אחד לימין כלומר תכולת כל תא מועתקת לתא הבא שלימינו והתא הראשון (s_{15}) מתעדכן לפי הפונקציה להלן. בשלב האתחול האוגר מקבל מילה אחת u באורך 31 סיביות המתקבלת על ידי הסרת הסיבית הימנית (הכי פחות משמעותית) של הפלט W של הפונקציה האי-ליניארית, כלומר u=W\gg 1. בשלב האתחול בהינתן הקלט u מתבצעים המהלכים הבאים:
# v=2^{15}s_{15}+2^{17}s_{13}+2^{21}s_{10}2^{20}s_4+(1+2^8)s_0\text{ mod }(2^{31}-1);
# s_{16}=(v+u)\text{ mod }(2^{31}-1);
# \text{If }s_{16}=0\text{ then set }s_{16}=2^{31}-1;
# (s_1,s_2,...,s_{15},s_{16})\rightarrow(s_0,s_1,...,s_{14},s_{15}).
במצב עבודה ה-LFSR אינו מקבל קלט ופועל כדלהלן:
# s_{16}=2^{15}s_{15}+2^{17}s_{13}+2^{21}s_{10}2^{20}s_4+(1+2^8)s_0\text{ mod }(2^{31}-1);
# \text{If }s_{16}=0\text{ then set }s_{16}=2^{31}-1;
# (s_1,s_2,...,s_{15},s_{16})\rightarrow(s_0,s_1,...,s_{14},s_{15}).
מהיבט פרקטי כפל האלמנט s_j  בחזקות i של 2 מעל השדה GF(2^{31}-1) מתבצע על ידי הזזה מעגלית של s_j לשמאל i סיביות. לכן במהלך 1 לעיל כל שנדרש הוא חיבור מודולו 2^{31}-1 לאחר סדרה של כמה הזזות. ההזזה המעגלית בקוד נראית כך:
:((s_j \ll i) \lor (s_j \gg (31 - i))) \land \text{0x7FFFFFFF}.

ובאופן כללי מהלך 1 המתואר לעיל ניתן לביצוע בתוכנה באופן הבא:
:v=(s_{15}\lll_{31}15)+(s_{13}\lll_{31}17)+(s_{10}\lll_{31}21)+(s_{4}\lll_{31}20)+(s_{0}\lll_{31}8)+(s_{0}\text{ mod }2^{31}-1)).

חיבור שני אלמנטים a ו-b מעל השדה GF(2^{31}-1) ניתן לביצוע באופן הבא: תחילה מחשבים את v=a+b ואם מתרחשת גלישה כלומר סיבית הנשא היא 1 מבצעים בנוסף v=v+1.  התנאי שבודק אם הסיבית העליונה היא '1' פותח פתח ל**התקפת תיזמון** - סוג של התקפת ערוץ צדדי, כיוון שכעת מהירות פעולת החיבור תלויה בסיבית זו לכן ניתן לבצע ניתוח סטטיסטי של מהירות החישוב כדי לחשוף סיביות. כדי לעקוף בעיה זו מבצעים באופן קבוע כך: תחילה מחשבים את w=a+b כאשר w הוא ערך באורך 32 סיביות ואז v שווה 31 הסיביות הכי פחות משמעותיות של w וכעת נוטלים את הסיבית הכי משמעותית של w מזיזים אותה להתחלה ומחברים עם v הקוד נראה כך:
:w=a+b,v=(w\land\text{0x7FFFFFFF})+(w\gg 31)

### סידור מחדש (BitReorganization)
בשכבה האמצעית של האלגוריתם הנקראת בקיצור BR, מחלצים 128 סיביות משמונה תאים של ה-LFSR במיקומים המתוארים להלן ומהם מרכיבים ארבע מילים באורך 32 סיביות. שלוש המילים הראשונות ישמשו קלט לפונקציה האי-ליניארית להלן ואילו המילה הרביעית משתתפת ביצירת מילת פלט אחת של זרם המפתח. המיקומים ב-LFSR מהם נוטלים סיביות הם: s_0,s_2,s_5,s_7,s_9,s_{11},s_{14},s_{15}. ארבע המילים האמורות מיוצגות על ידי X_0,X_1,X_2,X_3 אותם מרכיבים על ידי  חצאי הקלט לפי הסדר הבא: 
# X_0=s_{15H}\ \| \ s_{14L};
# X_1=s_{11L}\ \| \ s_{9H};
# X_2=s_{7L}\ \| \ s_{5H};
# X_3=s_{2L}\ \| \ s_{0H}.
הסמלים H ו-L מייצגים את החצי העליון והחצי התחתון של המילה בהתאמה. למשל s_{iH} פירושו הסיביות 30...15 ולא 31...16 של s_i היות ש-s_i מוגדר באורך 31 סיביות. לדוגמה בשורה 1 לעיל הערך של X_0 הוא שרשור של 16 הסיביות המשמעותיות ביותר של s_{15} החל מהסיבית במיקום ה-15 ועד הסיבית ה-30 עם 16 הסיביות הפחות משמעותיות של s_{14} החל מהסיבית במיקום ה-0 ועד הסיבית ה-15.

### פונקציה אי-ליניארית
השכבה התחתונה כוללת פונקציה F המכילה שני תאי זיכרון R_1 ו-R_2 באורך 32 סיביות כל אחד. הקלט הוא X_0,X_1,X_2 שהם פלט השכבה הקודמת והפלט הוא מילה W באורך 32 סיביות. ביתר פירוט:
# W=(X_0\oplus R_1)\boxplus R_2;
# W_1=R_1\boxplus X_1;
# W_2=R_2\oplus X_2;
# R_1=S(L_1(W_{1L}\ \| \ W_{2H}));
# R_2=S(L_2(W_{2L}\ \| \ W_{1H})).
הפונקציה S היא תיבות החלפה S-box בגודל 32x32 סיביות והפונקציות L_1 ו-L_2 הן פונקציות ליניאריות כמתואר להלן.

### תיבות החלפה
S הוא תיבת החלפה s-box בגודל 32x32 המורכבת מארבע תיבות S=(S_0,S_1,S_2,S_3) שהן פונקציות אי-ליניאריות קבועות בצורת ארבע טבלאות בגודל 8x8 (המכילות 256 כניסות בגודל 8 סיביות). כאשר S_2=S_0 וכן S_3=S_1. והטבלאות S_0 ו-S_1 מובאות להלן. הפונקציה S_i מקבלת את הקלט x=h\| l בגודל בית אחד ומחזירה את הערך הנמצא בכניסה הנמצאת בשורה h ובעמודה l בטבלה וכן לגבי יתר הבתים של מילת הקלט (בסך הכול ארבעה בתים במילה), X=x_0\|x_1\|x_2\|x_3, ו-Y=y_0\|y_1\|y_2\|y_3 כאשר x_i ו-y_i הם בתים. הפונקציה S אם כן מוגדרת כך: y_i=S_i(x_i) כאשר i=0,1,2,3.





### טרנספורמציה ליניארית
ישנן שתי פונקציות ליניאריות L_1 ו-L_2 הפועלות על קלט של מילים באורך 32 סיביות ומפיקות פלט של מילים באורך 32 סיביות והן מוגדרות כדלהלן:
:L_1(X)=X\oplus (X\lll_{32}2)\oplus (X\lll_{32}10)\oplus (X\lll_{32}18)\oplus (X\lll_{32}24),
:L_2(X)=X\oplus (X\lll_{32}8)\oplus (X\lll_{32}14)\oplus (X\lll_{32}22)\oplus (X\lll_{32}30).

### הכנת מפתח
תהליך ההכנה מקבל את המפתח הראשוני המסופק על ידי המשתמש מחולק ל-16 בתים k=k_0\|k_1\|...\|k_{15} (128 סיביות) וכן וקטור האתחול iv=iv_0\|iv_1\|...\|iv_{15} (16 בתים), וטוען אותם לתוך 16 הכניסות של אוגר ה-LFSR בתוספת קבוע D באורך 240 סיביות המובא להלן, המחולק ל-16 מקטעים באורך 15 סיביות כל אחד D=d_0\|d_1\|...\|d_{15}. הערך ההתחלתי של כל כניסה באוגר הוא שרשור של שלושת הערכים: קטע אחד מהמפתח, חלק אחד מהקבוע D להלן וחלק מווקטור האתחול, כך: 
:s_i=k_i\ \| \ d_i\ \| \ iv_i עבור 0\le i \le 15.

הקבוע D הוא:
:d_0=\text{44D7}, d_1=\text{26BC}, d_2=\text{626B}, d_3=\text{135E}, d_4=\text{5789}, d_5=\text{35E2}, d_6=\text{7135}, d_7=\text{09AF},
:d_8=\text{4D78}, d_9=\text{2F13}, d_{10}=\text{6BC4}, d_{11}=\text{1AF1}, d_{12}=\text{5E26}, d_{13}=\text{3C4D}, d_{14}=\text{789A}, d_{15}=\text{47AC}.

## הצפנה ופענוח
לשימוש בצופן ZUC בפעם הראשונה מפעילים אותו 32 פעימות במצב אתחול, פעימה אחת במצב סרק ולאחר מכן עוברים למצב עבודה רגיל. בשלב האתחול הצופן מבצע תחילה את פרוצדורת טעינת המפתח כמתואר לעיל ומאפס את האוגרים R_1 ו-R_2 ואז מתבצעות שלוש הפעולות הבאות 32 פעמים:
# \text{BitReorganization}() (סידור סיביות מחדש),
# w=F(X_0,X_1,X_2) (טרנספורמציה ליניארית),
# \text{LFSRInitialisationMode}(w\gg 1) (הפעלת אוגר ה-LFSR).

שים לב שבשלב זה אוגר ה-LFSR בשורה 3 מקבל את הפרמטר w שהופק מהפונקציה האי-ליניארית, כלומר פלט הפונקציה האי-ליניארית מוזן בחזרה ל-LFSR בלולאה סגורה. לאחר מכן מתבצע מהלך סרק אחד שבו לא משתמשים בפלט הצופן אלא מתעלמים ממנו:
# \text{BitReorganization}() (סידור סיביות מחדש),
# F(X_0,X_1,X_2) (טרנספורמציה ליניארית),
# \text{LFSRWorkingMode}() (הפעלת אוגר ה-LFSR).

מכאן ואילך בכל פעימה של הצופן מתבצעות שלוש הפעולות הבאות שבסיומן מופקת מילה פסאודו-אקראית אחת:
# \text{BitReorganization}() (סידור סיביות מחדש),
# Z=F(X_0,X_1,X_2)\oplus X_3 (טרנספורמציה ליניארית),
# \text{LFSRWorkingMode}() (הפעלת אוגר ה-LFSR).

בניגוד לשלב האתחול הפעלת אוגר ה-LFSR חסרת פרמטרים במצב עבודה. פלט הצופן בכל פעימה הוא Z באורך 32 סיביות והוא משמש חלק מזרם המפתח להצפנת או פענוח המידע.

## ביטחון
ZUC הוא צופן חדש יחסית והוא בעצם שיפור של הצופן SNOW. חוקרים גילו שהצופן בגרסה המקורית (1.4) היה פגיע להתקפת מוצפן נבחר על וקטור האתחול. במקרים מסוימים הבדלים בווקטור האתחול הניבו מפתח הצפנה זהה מה שמצמצם את אורך המפתח האפקטיבי לכ-100 סיביות במקום 128. בצופן זרם שימוש במפתח הצפנה זהה להצפנת חלקים מהנתונים מהווה פגיעה הרסנית במיוחד בביטחון ההצפנה. כדי למנוע התקפה זו הם המליצו להחליף את ה-XOR בחיבור (\boxplus) מודולו 2^{31}-1 בביטוי (v+u) בשלב האתחול, גרסה זו של הצופן נקראת 1.6 והיא מעודכנת בתיאור הצופן לעיל. ZUC הוא צופן מהיר מאוד בהשוואה לצפנים כמו SNOW. הוא למעשה מהמהירים ביותר הקיימים כיום וכן בשל המפתח הארוך ווקטור האתחול הארוך (128 סיביות כל אחד) מספק הגנה מספיק טובה מפני כמה התקפות ידועות כמו: התקפת מפתח חלש, התקפות ניחוש, התקפה אלגברית, התקפות תיזמון, התקפה דיפנרציאלית והתקפת קירוב ליניארי. הצופן אינו מספק הגנה טובה מפני התקפת ערוץ צדדי המתמקדת בגרף צריכת האנרגיה שלו במהלך הצפנה או פענוח. חוקרים הראו שההתקפה הנקראת DPA קיצור של Differential Power Analysis אפשרית נגד הצופן במידה שלתוקף יכולת למדוד את צריכת האנרגיה במחשב בו מבוצעת ההצפנה.

## וקטור בדיקה
לדוגמה אם המפתח הוא:
:k=\text{3D 4C 4B E9 6A 82 FD AE B5 8F 64 1D B1 7B 45 5B}
וקטור האתחול הוא:
:iv=\text{84 31 9A A8 DE 69 15 CA 1F 6B DA 6B FB D8 C7 66}

המילה הראשונה של פלט הצופן צריכה להיות: \text{14F1C272}.

## קוד לדוגמה


```cpp
typedef unsigned char byte;
typedef unsigned int uint;

uint LFSR[16];
uint F_R1;
uint F_R2;
uint BRC[4];

byte S0[256] = {
	0x3e,0x72,0x5b,0x47,0xca,0xe0,0x00,0x33,0x04,0xd1,0x54,0x98,0x09,0xb9,0x6d,0xcb,
	0x7b,0x1b,0xf9,0x32,0xaf,0x9d,0x6a,0xa5,0xb8,0x2d,0xfc,0x1d,0x08,0x53,0x03,0x90,
	0x4d,0x4e,0x84,0x99,0xe4,0xce,0xd9,0x91,0xdd,0xb6,0x85,0x48,0x8b,0x29,0x6e,0xac,
	0xcd,0xc1,0xf8,0x1e,0x73,0x43,0x69,0xc6,0xb5,0xbd,0xfd,0x39,0x63,0x20,0xd4,0x38,
	0x76,0x7d,0xb2,0xa7,0xcf,0xed,0x57,0xc5,0xf3,0x2c,0xbb,0x14,0x21,0x06,0x55,0x9b,
	0xe3,0xef,0x5e,0x31,0x4f,0x7f,0x5a,0xa4,0x0d,0x82,0x51,0x49,0x5f,0xba,0x58,0x1c,
	0x4a,0x16,0xd5,0x17,0xa8,0x92,0x24,0x1f,0x8c,0xff,0xd8,0xae,0x2e,0x01,0xd3,0xad,
	0x3b,0x4b,0xda,0x46,0xeb,0xc9,0xde,0x9a,0x8f,0x87,0xd7,0x3a,0x80,0x6f,0x2f,0xc8,
	0xb1,0xb4,0x37,0xf7,0x0a,0x22,0x13,0x28,0x7c,0xcc,0x3c,0x89,0xc7,0xc3,0x96,0x56,
	0x07,0xbf,0x7e,0xf0,0x0b,0x2b,0x97,0x52,0x35,0x41,0x79,0x61,0xa6,0x4c,0x10,0xfe,
	0xbc,0x26,0x95,0x88,0x8a,0xb0,0xa3,0xfb,0xc0,0x18,0x94,0xf2,0xe1,0xe5,0xe9,0x5d,
	0xd0,0xdc,0x11,0x66,0x64,0x5c,0xec,0x59,0x42,0x75,0x12,0xf5,0x74,0x9c,0xaa,0x23,
	0x0e,0x86,0xab,0xbe,0x2a,0x02,0xe7,0x67,0xe6,0x44,0xa2,0x6c,0xc2,0x93,0x9f,0xf1,
	0xf6,0xfa,0x36,0xd2,0x50,0x68,0x9e,0x62,0x71,0x15,0x3d,0xd6,0x40,0xc4,0xe2,0x0f,
	0x8e,0x83,0x77,0x6b,0x25,0x05,0x3f,0x0c,0x30,0xea,0x70,0xb7,0xa1,0xe8,0xa9,0x65,
	0x8d,0x27,0x1a,0xdb,0x81,0xb3,0xa0,0xf4,0x45,0x7a,0x19,0xdf,0xee,0x78,0x34,0x60
};

byte S1[256] = {
	0x55,0xc2,0x63,0x71,0x3b,0xc8,0x47,0x86,0x9f,0x3c,0xda,0x5b,0x29,0xaa,0xfd,0x77,
	0x8c,0xc5,0x94,0x0c,0xa6,0x1a,0x13,0x00,0xe3,0xa8,0x16,0x72,0x40,0xf9,0xf8,0x42,
	0x44,0x26,0x68,0x96,0x81,0xd9,0x45,0x3e,0x10,0x76,0xc6,0xa7,0x8b,0x39,0x43,0xe1,
	0x3a,0xb5,0x56,0x2a,0xc0,0x6d,0xb3,0x05,0x22,0x66,0xbf,0xdc,0x0b,0xfa,0x62,0x48,
	0xdd,0x20,0x11,0x06,0x36,0xc9,0xc1,0xcf,0xf6,0x27,0x52,0xbb,0x69,0xf5,0xd4,0x87,
	0x7f,0x84,0x4c,0xd2,0x9c,0x57,0xa4,0xbc,0x4f,0x9a,0xdf,0xfe,0xd6,0x8d,0x7a,0xeb,
	0x2b,0x53,0xd8,0x5c,0xa1,0x14,0x17,0xfb,0x23,0xd5,0x7d,0x30,0x67,0x73,0x08,0x09,
	0xee,0xb7,0x70,0x3f,0x61,0xb2,0x19,0x8e,0x4e,0xe5,0x4b,0x93,0x8f,0x5d,0xdb,0xa9,
	0xad,0xf1,0xae,0x2e,0xcb,0x0d,0xfc,0xf4,0x2d,0x46,0x6e,0x1d,0x97,0xe8,0xd1,0xe9,
	0x4d,0x37,0xa5,0x75,0x5e,0x83,0x9e,0xab,0x82,0x9d,0xb9,0x1c,0xe0,0xcd,0x49,0x89,
	0x01,0xb6,0xbd,0x58,0x24,0xa2,0x5f,0x38,0x78,0x99,0x15,0x90,0x50,0xb8,0x95,0xe4,
	0xd0,0x91,0xc7,0xce,0xed,0x0f,0xb4,0x6f,0xa0,0xcc,0xf0,0x02,0x4a,0x79,0xc3,0xde,
	0xa3,0xef,0xea,0x51,0xe6,0x6b,0x18,0xec,0x1b,0x2c,0x80,0xf7,0x74,0xe7,0xff,0x21,
	0x5a,0x6a,0x54,0x1e,0x41,0x31,0x92,0x35,0xc4,0x33,0x07,0x0a,0xba,0x7e,0x0e,0x34,
	0x88,0xb1,0x98,0x7c,0xf3,0x3d,0x60,0x6c,0x7b,0xca,0xd3,0x1f,0x32,0x65,0x04,0x28,
	0x64,0xbe,0x85,0x9b,0x2f,0x59,0x8a,0xd7,0xb0,0x25,0xac,0xaf,0x12,0x03,0xe2,0xf2
};

uint EK_d[16] = {
	0x44D7, 0x26BC, 0x626B, 0x135E, 0x5789, 0x35E2, 0x7135, 0x09AF,
	0x4D78, 0x2F13, 0x6BC4, 0x1AF1, 0x5E26, 0x3C4D, 0x789A, 0x47AC
};
// c = a + b mod (2^31 – 1)
uint AddM(uint a, uint b)
{
	uint c = a + b;
	return (c & 0x7FFFFFFF) + (c >> 31);
}

#define MulByPow2(x, k) ((((x) << k) | ((x) >> (31 - k))) & 0x7FFFFFFF)

void LFSRWithInitialisationMode(uint u)
{
	uint f = LFSR[0];
	uint v = MulByPow2(LFSR[0], 8);
	f = AddM(f, v);
	v = MulByPow2(LFSR[4], 20);
	f = AddM(f, v);
	v = MulByPow2(LFSR[10], 21);
	f = AddM(f, v);
	v = MulByPow2(LFSR[13], 17);
	f = AddM(f, v);
	v = MulByPow2(LFSR[15], 15);
	f = AddM(f, v);
	f = AddM(f, u);
	for (int i = 0; i < 15; i++)
		LFSR[i] = LFSR[i + 1];
	LFSR[15] = f;
}

void LFSRWithWorkMode()
{
	uint f = LFSR[0];
	uint v = MulByPow2(LFSR[0], 8);
	f = AddM(f, v);
	v = MulByPow2(LFSR[4], 20);
	f = AddM(f, v);
	v = MulByPow2(LFSR[10], 21);
	f = AddM(f, v);
	v = MulByPow2(LFSR[13], 17);
	f = AddM(f, v);
	v = MulByPow2(LFSR[15], 15);
	f = AddM(f, v);
	for (int i = 0; i < 15; i++)
		LFSR[i] = LFSR[i + 1];
	LFSR[15] = f;
}

void BitReorganization()
{
	BRC[0] = ((LFSR[15] & 0x7FFF8000) << 1) | (LFSR[14] & 0xFFFF);
	BRC[1] = ((LFSR[11] & 0xFFFF) << 16) | (LFSR[9] >> 15);
	BRC[2] = ((LFSR[7] & 0xFFFF) << 16) | (LFSR[5] >> 15);
	BRC[3] = ((LFSR[2] & 0xFFFF) << 16) | (LFSR[0] >> 15);
}

#define ROT(a, k) (((a) << k) | ((a) >> (32 - k)))

uint L1(uint X)
{
	return (X ^ ROT(X, 2) ^ ROT(X, 10) ^ ROT(X, 18) ^ ROT(X, 24));
}

uint L2(uint X)
{
	return (X ^ ROT(X, 8) ^ ROT(X, 14) ^ ROT(X, 22) ^ ROT(X, 30));
}

#define MAKEU32(a, b, c, d) (((uint)(a) << 24) | ((uint)(b) << 16) | ((uint)(c) << 8) | ((uint)(d)))

uint F()
{
	uint W = (BRC[0] ^ F_R1) + F_R2;
	uint W1 = F_R1 + BRC[1];
	uint W2 = F_R2 ^ BRC[2];
	uint u = L1((W1 << 16) | (W2 >> 16));
	uint v = L2((W2 << 16) | (W1 >> 16));
	F_R1 = MAKEU32(S0[u >> 24], S1[(u >> 16) & 0xFF], S0[(u >> 8) & 0xFF], S1[u & 0xFF]);
	F_R2 = MAKEU32(S0[v >> 24], S1[(v >> 16) & 0xFF], S0[(v >> 8) & 0xFF], S1[v & 0xFF]);
	return W;
}

#define MAKEU31(a, b, c) (((uint)(a) << 23) | ((uint)(b) << 8) | (uint)(c))

void Initialization(byte* k, byte* iv)
{
	LFSR[0] = MAKEU31(k[0], EK_d[0], iv[0]);
	LFSR[1] = MAKEU31(k[1], EK_d[1], iv[1]);
	LFSR[2] = MAKEU31(k[2], EK_d[2], iv[2]);
	LFSR[3] = MAKEU31(k[3], EK_d[3], iv[3]);
	LFSR[4] = MAKEU31(k[4], EK_d[4], iv[4]);
	LFSR[5] = MAKEU31(k[5], EK_d[5], iv[5]);
	LFSR[6] = MAKEU31(k[6], EK_d[6], iv[6]);
	LFSR[7] = MAKEU31(k[7], EK_d[7], iv[7]);
	LFSR[8] = MAKEU31(k[8], EK_d[8], iv[8]);
	LFSR[9] = MAKEU31(k[9], EK_d[9], iv[9]);
	LFSR[10] = MAKEU31(k[10], EK_d[10], iv[10]);
	LFSR[11] = MAKEU31(k[11], EK_d[11], iv[11]);
	LFSR[12] = MAKEU31(k[12], EK_d[12], iv[12]);
	LFSR[13] = MAKEU31(k[13], EK_d[13], iv[13]);
	LFSR[14] = MAKEU31(k[14], EK_d[14], iv[14]);
	LFSR[15] = MAKEU31(k[15], EK_d[15], iv[15]);
	F_R1 = 0;
	F_R2 = 0;
	uint nCount = 32, w;
	while (nCount > 0)
	{
		BitReorganization();
		w = F();
		LFSRWithInitialisationMode(w >> 1);
		nCount--;
	}
}
void GenerateKeystream(uint* pKeystream, int KeystreamLen)
{
	BitReorganization();
	F(); // discard the output of F
	LFSRWithWorkMode();

	for (int i = 0; i < KeystreamLen; i++)
	{
		BitReorganization();
		pKeystream[i] = F() ^ BRC[3];
		LFSRWithWorkMode();
	}
}
```


## ראו גם
* צופן זרם
* GSM
* SNOW

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

קטגוריה:צפני זרם