Skip to content

Commit

Permalink
Add secrets exercise for bit manipulation
Browse files Browse the repository at this point in the history
  • Loading branch information
kahgoh committed Nov 12, 2023
1 parent 60f14ff commit 0d4947a
Show file tree
Hide file tree
Showing 11 changed files with 331 additions and 5 deletions.
8 changes: 4 additions & 4 deletions concepts/bit-manipulation/about.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,14 @@ Otherwise, it is 0.

### Bitwise NOT(`~`)

Lastly, the bitwise NOT operator (`~`) flips each bit in the value.
Lastly, the bitwise NOT operator (`~`) flips each of the value's bits.
Unlike the other binary operators, this is a unary operator, operating on only on the value to the right.

```crystal
~0b1110_0010
# => 0b0001_1101
```

[integers]: https://crystal-lang.org/api/1.10.1/Int.html
[shift]: https://crystal-lang.org/reference/1.10/syntax_and_semantics/operators.html#shifts
[binary]: https://crystal-lang.org/reference/1.10/syntax_and_semantics/operators.html#binary
[integers]: https://crystal-lang.org/api/Int.html
[shift]: https://crystal-lang.org/reference/syntax_and_semantics/operators.html#shifts
[binary]: https://crystal-lang.org/reference/syntax_and_semantics/operators.html#binary
2 changes: 1 addition & 1 deletion concepts/bit-manipulation/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Otherwise, it is 0.

### Bitwise NOT(`~`)

Lastly, the bitwise NOT operator (`~`) flips each bit in the value.
Lastly, the bitwise NOT operator (`~`) flips each of the value's bits.
Unlike the other binary operators, this is a unary operator, operating on only on the value to the right.

```crystal
Expand Down
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,14 @@
"concepts": ["binary-octal-hexadecimal"],
"prerequisites": ["string"],
"status": "wip"
},
{
"slug": "secrets",
"name": "Secrets",
"uuid": "b8b96139-53b9-4f3d-b528-7d82fc76c4c6",
"concepts": ["bit-manipulation"],
"prerequisites": ["binary-octal-hexadecimal"],
"status": "wip"
}
],
"practice": [
Expand Down
19 changes: 19 additions & 0 deletions exercises/concept/secrets/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Hints

## 1. Shift back the bits
- Crystal has an [operator][shifts] for left shifting bits.

## 2. Apply a bit mask
- Crystal has a [bitwise AND][binary] operator.

## 3. Set some bits
- Crystal has a [bitwise OR][binary] operator.

## 4. Reverse XOR
- An XOR can be reversed by applying an XOR on the same value.
- Crystal has operators for [bitwise NOT][not] and bitwise [XOR][xor].

[shifts]: https://crystal-lang.org/reference/syntax_and_semantics/operators.html#shifts
[binary]: https://crystal-lang.org/reference/syntax_and_semantics/operators.html#binary
[not]: https://crystal-lang.org/reference/syntax_and_semantics/operators.html#other-unary-operators
[xor]: https://crystal-lang.org/reference/syntax_and_semantics/operators.html#binary
55 changes: 55 additions & 0 deletions exercises/concept/secrets/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Instructions

Your has just sent you a message with an important secret.
Not wanting to make it easy for others to read it, the message has been encrypted using a series of bit manipulations.
You will need to write a program to help decrypt the message.

## 1. Shift back the bits

The first step in decrypting the message is to undo the shifting from the encryption process by shifting the bits back to the left.
The number of places to shift can vary between messages.

Implement the method `Secrets.shift_back` that takes a value and the number of places to shift left.

```crystal
Secrets.shift_back(0b0001, 2)
# => 0b0100
```

## 2. Apply a bit mask

The next step is apply a bit mask to extract the value of certain bits.
The mask is applied by performing a bitwise AND between the value and the mask.

Implement the method `Secrets.apply_mask` that takes a value and applies a mask.

```crystal
Secrets.apply_mask(0b0110, 0b0101)
# => 0b0100
```

## 3. Set some bits

Shifting bits to the left has added some new 0 bits.
Some of these new bits need to be set to 1.
The bitwise OR is useful for setting certain bits to 1 while preserving the rest.

Implement the method `Secrets.set_bits` that takes two values and performs a bitwise OR.

```crystal
Secrets.set_bits(0b0110, 0b0101)
# => 0b111
```

## 4. Reverse XOR

Part of the encryption process applies a XOR with an agreed value.
To get back to the original value, the encrypted value can simply be XOR again with the agreed value.
However, due to a misunderstanding, your friend flipped the agreed value's bits (i.e. applied a bitwise NOT to the agreed value) before applying the XOR.

Implement the `Secrets.reverse_xor` method that takes the encrypted and agreed values and calculates the original value.

```crystal
Secrets.reverse_xor(0b1100, 0b0101)
# => 0b(0110)
```
101 changes: 101 additions & 0 deletions exercises/concept/secrets/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Bit Manipulation

Crystal has bitwise operators for manipulating [`Integers`][integers] at the binary level.

## Shift operators

Crystal has [shift operators][shift] for shifting bits to the left (`<<`) or the right (`>>`).

### Shift left(`<<`)

The shift left operator (`<<`) shifts the bits to the left.
The value to shift is specified on the left side and the number of places to shift is on the right.

```crystal
0b0010 << 1
# => 0b0100
0b0010 << 2
# => 0b1000
```

If the number is negative, it will shift to the right instead.

```crystal
0b0010 << -1
# => 0b0001
```

### Shift right(`>>`)

The shift right operator (`>>`) shifts the bits to the right.
Like the shift left operator, the value to shift is specified on the left and number of places to shift is on the right.

```crystal
0b0100 >> 1
# => 0b0010
0b0100 >> 2
# => 0b0001
```

And similarly, the operator will shift to the left if the number is negative.

```crystal
0b0100 >> -1
# => 0b1000
```

## Binary operators

Crystal has 3 [binary operators][binary] (`&`, `|`, `^`) and a `~` operator for performing bitwise operations.

### Bitwise AND(`&`)

The binary AND operator (`&`) performs a bitwise AND on two values.
It compares each bit in the first value against the bit in the same position in the second value.
The resulting bit is set to 1 if both bits are 1.
Otherwise, it is set to 0.

```crystal
0b0011 & 0b1010
# => 0b0010
```

### Bitwise OR(`|`)

The binary OR operator (`|`) performs a bitwise OR on two values.
It also compares each bit in the first value against the bit in the same position in the second value.
If either bit is 1, the resulting bit is set 1.
Otherwise, it is set to 0.

```crystal
0b0011 | 0b1010
# => 0b1011
```

### Bitwise XOR(`^`)

The binary XOR operator (`^`) performs a bitwise XOR.
Like the bitwise AND and bitwise OR operators, it compares each bit from the first value against the bit in the same position in the second value.
If _only one_ of them is 1, the resulting bit is 1.
Otherwise, it is 0.

```crystal
0b0011 ^ 0b1010
# => 0b1001
```

### Bitwise NOT(`~`)

Lastly, the bitwise NOT operator (`~`) flips each of the value's bits.
Unlike the other binary operators, this is a unary operator, operating on only on the value to the right.

```crystal
~0b1110_0010
# => 0b0001_1101
```

[integers]: https://crystal-lang.org/api/Int.html
[shift]: https://crystal-lang.org/reference/syntax_and_semantics/operators.html#shifts
[binary]: https://crystal-lang.org/reference/syntax_and_semantics/operators.html#binary
21 changes: 21 additions & 0 deletions exercises/concept/secrets/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"authors": [
"kahgoh"
],
"files": {
"solution": [
"src/secrets.cr"
],
"test": [
"spec/secrets_spec.cr"
],
"exemplar": [
".meta/src/exemplar.cr"
]
},
"forked_from": [
"elixir/secrets"
],
"icon": "secrets",
"blurb": "Learn about bit manipulation by writing a program to decrypt a message."
}
22 changes: 22 additions & 0 deletions exercises/concept/secrets/.meta/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
## Goal

The goal of this exercise is to teach the student about bitwise operations in Crystal.

## Learning objectives

- Learn about the bitwise operators <<, >>, &, |, ^ and ~

## Concepts

`bit-operators`:

- `>>`
- `<<`
- `&`
- `|`
- `^`
- `~`

## Prerequisites

- Binary, Octal, and Hexadecimal
17 changes: 17 additions & 0 deletions exercises/concept/secrets/.meta/src/exemplar.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Secrets
def shift_back(value : UInt8, numberOfPlaces : UInt8) : UInt8
value << numberOfPlaces
end

def apply_mask(value : UInt8, mask : UInt8) : UInt8
value & mask
end

def set_bits(value1 : UInt8, value2 : UInt8) : UInt8
value1 | value2
end

def reverse_xor(value : UInt8, agreedValue : UInt8) : UInt8
value ^ ~agreedValue
end
end
66 changes: 66 additions & 0 deletions exercises/concept/secrets/spec/secrets_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
require "spec"
require "../src/*"

include Secrets

describe "Secrets" do
describe "shift_back" do
it "should be able to shift 0 places" do
shift_back(15, 0).should eq 15
end

it "should be able to shift 1 place to the left" do
shift_back(7, 1).should eq 14
end

it "should be able to shift 4 places to the left" do
shift_back(5, 4).should eq 80
end

it "should be able to shift bits off" do
shift_back(96, 4).should eq 0
end
end

describe "apply_mask" do
it "should be able to AND value with mask bits all 1" do
apply_mask(101, 255).should eq 101
end

it "should be able to AND value with mask bits all 0" do
apply_mask(101, 0).should eq 0
end

it "should be able to AND value with some bits 1" do
apply_mask(62, 85).should eq 20
end
end

describe "set_bits" do
it "should be able to OR value with 0s" do
set_bits(107, 0).should eq 107
end

it "should be able to OR with with 1s" do
set_bits(107, 255).should eq 255
end

it "should be able to set some bits" do
set_bits(62, 85).should eq 127
end
end

describe "reverse_xor" do
it "should be able to reverse with all 1s" do
reverse_xor(106, 255).should eq 106
end

it "should be able to reverse with all 0s" do
reverse_xor(106, 0).should eq 149
end

it "should be able to reverse with mix of 1s and 0s" do
reverse_xor(62, 85).should eq 148
end
end
end
17 changes: 17 additions & 0 deletions exercises/concept/secrets/src/secrets.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Secrets
def shift_back(value : UInt8, numberOfPlaces : UInt8) : UInt8
raise "Please implement the Secrets::shift_back method"
end

def apply_mask(value : UInt8, mask : UInt8) : UInt8
raise "Please implement the Secrets::apply_mask method"
end

def set_bits(value1 : UInt8, value2 : UInt8) : UInt8
raise "Please implement the Secrets::set_bits method"
end

def reverse_xor(value : UInt8, agreedValue : UInt8) : UInt8
raise "Please implement the Secrets::reverse_xor method"
end
end

0 comments on commit 0d4947a

Please sign in to comment.