Danger
Nothing here should be used for any security purposes.
Utility functions¶
This module is imported with:
import toy_crypto.utils
- toy_crypto.utils.digit_count(n: int, base: int = 10) int ¶
returns the number of digits (base b) of integer n.
- Raises:
ValueError – if base < 2
TypeError – if n is not an integer
- Parameters:
- Return type:
Coding this is a math problem, not a string representation problem. Idetally the solution would be to use
but that leads to erroneous results due to the precision limitations
of math.log()
.
>>> from toy_crypto.utils import digit_count
>>> digit_count(999)
3
>>> digit_count(1000)
4
>>> digit_count(1001)
4
>>> digit_count(9999999999999998779999999999999999999999999999999999999999999)
61
>>> digit_count(9999999999999999999999999999999999999999999999999999999999999)
61
>>> digit_count(10000000000000000000000000000000000000000000000000000000000000)
62
>>> digit_count(0)
1
>>> digit_count(-10_000)
5
- toy_crypto.utils.lsb_to_msb(n: int) Iterator[int] ¶
0s and 1s representing bits of n, starting with the least significant bit.
- Raises:
TypeError – if n is not an integer.
ValueError – if n is negative.
- Parameters:
n (int)
- Return type:
lsb_to_msb()
is used by
scaler_multiply()
and would be used by modular exponentiation
for implementations of those that leak the bits of the scalar (or exponent)
through side channels.
>>> from toy_crypto.utils import lsb_to_msb
>>> list(lsb_to_msb(13))
[1, 0, 1, 1]
- toy_crypto.utils.hamming_distance(a: bytes, b: bytes) int ¶
Hamming distance between byte sequences of equal length.
- Raises:
ValueError – if len(a) != len(b).
- Parameters:
- Return type:
Let’s illustrate with an example from Cryptopals.
>>> from toy_crypto.utils import hamming_distance
>>> s1 = b"this is a test"
>>> s2 = b"wokka wokka!!!"
>>> hamming_distance(s1, s2)
37
xor¶
The utils.xor()
and the class utils.Xor
provide utilities for xoring strings of bytes together. There is some assymetry between the two arguments. The message
can be an collections.abc.Iterator
as well as bytes
. The pad
arguement on the other hand, is expected to be bytes
only (in this version.) The pad
argument is will be repeated if it is shorter than the message.
Warning
The Byte
type is just a type alias for int
. There is no run time nor type checking mechanism that prevents you from passing an Iterator[Byte]
message that contains integers outside of the range that would be expected for a byte.
If you do so, bad things will happen. If you are lucky some exception from the bowels of Python will be raised in a way that will help you identify the error. If you are unlucky, you will silently get garbage results.
- class toy_crypto.utils.Xor(message: Iterator[int] | bytes, pad: bytes)¶
Iterator that spits out xor of message with (repeated) pad.
The iterator will run through successful bytes of message xor-ing those with successive bytes of pad, repeating pad if pad is shorter than message.
Each iteration returns a non-negative int less than 256.
- toy_crypto.utils.xor(message: bytes | Iterator[int], pad: bytes) bytes ¶
Returns the xor of message with a (repeated) pad.
The pad is repeated if it is shorter than m. This can be thought of as bytewise Vigenère.
>>> from toy_crypto.utils import xor
>>> message = b"Attack at dawn!"
>>> pad = bytes(10) + bytes.fromhex("00 14 04 05 00")
>>> modified_message = xor(message, pad)
>>> modified_message
b'Attack at dusk!'
Encodings for the RSA 129 challenge¶
When the RSA 129 challenge was first published in Scientific American in 1979 it used its own encoding scheme between text and integers. This class provides an encoder and decoder for that scheme.
- class toy_crypto.utils.Rsa129¶
Text encoder/decoder used in RSA-129 challenge.
Encoding scheme from Martin Gardner’s 1977 article.