Crystal برای دستکاری Int در سطح دودویی، عملگرهای بیتی دارد.
Crystal عملگرهای جابهجایی دارد که بیتها را به چپ (<<) یا راست (>>) جابهجا میکنند.
<<)عملگر جابهجایی به چپ (<<) بیتها را به چپ جابهجا میکند.
مقداری که باید جابهجا شود در سمت چپ و تعداد مکانهای جابهجایی در سمت راست مشخص میشود.
0b0010 << 1
# => 0b0100
0b0010 << 2
# => 0b1000
اگر عدد منفی باشد، در عوض به راست جابهجا میشود.
0b0010 << -1
# => 0b0001
>>)عملگر جابهجایی به راست (>>) بیتها را به راست جابهجا میکند.
مانند عملگر جابهجایی به چپ، مقداری که باید جابهجا شود در سمت چپ و تعداد مکانهای جابهجایی در سمت راست مشخص میشود.
0b0100 >> 1
# => 0b0010
0b0100 >> 2
# => 0b0001
و به همین ترتیب، اگر عدد منفی باشد، عملگر به چپ جابهجا میشود.
0b0100 >> -1
# => 0b1000
Crystal سه عملگر دوتایی (&، |، ^) و یک عملگر ~ برای انجام عملیات بیتی دارد.
&)عملگر دوتایی «و» (&) یک عملیات «و» بیتی روی دو مقدار انجام میدهد.
هر بیت در مقدار اول را با بیت در همان موقعیت در مقدار دوم مقایسه میکند.
اگر هر دو بیت ۱ باشند، بیت حاصل روی ۱ تنظیم میشود.
در غیر این صورت، روی ۰ تنظیم میشود.
0b0011 & 0b1010
# => 0b0010
|)عملگر دوتایی «یا» (|) یک عملیات «یا» بیتی روی دو مقدار انجام میدهد.
همچنین هر بیت در مقدار اول را با بیت در همان موقعیت در مقدار دوم مقایسه میکند.
اگر هر یک از بیتها ۱ باشد، بیت حاصل روی ۱ تنظیم میشود.
در غیر این صورت، روی ۰ تنظیم میشود.
0b0011 | 0b1010
# => 0b1011
^)عملگر دوتایی «یا انحصاری» (^) یک عملیات «یا انحصاری» بیتی انجام میدهد.
مانند عملگرهای بیتی «و» و «یا»، هر بیت از مقدار اول را با بیت در همان موقعیت در مقدار دوم مقایسه میکند.
اگر فقط یکی از آنها ۱ باشد، بیت حاصل ۱ است.
در غیر این صورت، ۰ است.
0b0011 ^ 0b1010
# => 0b1001
~)در نهایت، عملگر نقیض بیتی (~) هر یک از بیتهای مقدار را معکوس میکند.
برخلاف سایر عملگرهای دوتایی، این یک عملگر یکانی است که فقط روی مقدار سمت راست عمل میکند.
~0b1110_0010
# => 0b0001_1101
دوستتان همین حالا پیامی همراه با یک راز مهم برایتان فرستاده است. چون نمیخواهد خواندنش برای دیگران آسان باشد، پیام با یک رشته دستکاری بیتی رمزنگاری شده است. باید برنامهای بنویسید که به رمزگشایی پیام کمک کند.
اولین گام در رمزگشایی پیام این است که جابهجایی انجامشده در فرایند رمزنگاری را با جابهجا کردن بیتها به سمت چپ خنثی کنیم. تعداد جاهایی که باید جابهجا شوند، از پیامی به پیام دیگر میتواند متفاوت باشد.
متد Secrets.shift_back را پیادهسازی کنید که یک مقدار و تعداد جاهای جابهجایی به سمت چپ را میگیرد.
Secrets.shift_back(0b0001, 2)
# => 0b0100
گام بعدی، اعمال یک ماسک بیتی برای استخراج مقدار بیتهای مشخصی است. ماسک با انجام یک AND بیتی میان مقدار و ماسک اعمال میشود.
متد Secrets.apply_mask را پیادهسازی کنید که یک مقدار میگیرد و ماسکی را اعمال میکند.
Secrets.apply_mask(0b0110, 0b0101)
# => 0b0100
جابهجا کردن بیتها به سمت چپ، چند بیت ۰ تازه اضافه کرده است. بعضی از این بیتهای تازه باید به ۱ تبدیل شوند. OR بیتی برای تبدیل بیتهای خاصی به ۱ و در همان حال حفظ بقیه به کار میآید.
متد Secrets.set_bits را پیادهسازی کنید که دو مقدار میگیرد و یک OR بیتی انجام میدهد.
Secrets.set_bits(0b0110, 0b0101)
# => 0b111
بخشی از فرایند رمزنگاری، یک XOR با یک مقدار توافقشده اعمال میکند. برای بازگشت به مقدار اصلی، کافی است مقدار رمزنگاریشده را دوباره با همان مقدار توافقشده XOR کنیم. اما به دلیل یک سوءتفاهم، دوستتان پیش از اعمال XOR بیتهای مقدار توافقشده را وارونه کرده است (یعنی یک NOT بیتی روی مقدار توافقشده اعمال کرده است).
متد Secrets.reverse_xor را پیادهسازی کنید که مقدار رمزنگاریشده و مقدار توافقشده را میگیرد و مقدار اصلی را محاسبه میکند.
Secrets.reverse_xor(0b1100, 0b0101)
# => 0b(0110)