[英]TypeError: unsupported operand type(s) for <<: 'str' and 'int'
誰能給我一些關於我 10 歲兒子正在嘗試的 Python 項目的廣泛指導? 我很少尋找特定的編碼解決方案,但我希望這是一個提出問題的好地方。 我想看看我兒子是否正在着手對他的編碼項目進行實際操作,以及是否有一種相對簡單的方法可以讓他學習正確的步驟。 或者,這對於一個喜歡閱讀和嘗試各種編碼項目只是為了好玩的 10 歲孩子來說是不合時宜的? 如您所見,我不是編碼員,對此類項目知之甚少,因此將不勝感激!
我兒子喜歡密碼學,他告訴我他嘗試了下面的 Python 代碼。 他希望構建一個類似海綿的功能來加密按摩,使其無法被解密。 這受到他的書“Serious Cryptography”(J. Aumasson 着)中標題為“基於排列的哈希函數:海綿函數”的部分的啟發。 當他運行他編寫的代碼時,他收到錯誤消息“類型錯誤:<<:'str'和'int'不受支持的操作數類型”(請參閱他在代碼下方終端中的交互)。
非常感謝! 亞歷山大
這是他的代碼:
import math
import textwrap
plaintext = raw_input("The value to be hashed: ") # Get the user to input the data to be hashed
nonce = raw_input("The nonce to be used: ") # Get the user to input the nonce to be used
key = raw_input("The key to be used: ") # Get the user to input the key to be used
blocks = textwrap.wrap(plaintext, 16) # Split the string into 128-bit blocks
if len(blocks[len(blocks)-1]) < 16: # Check if the last block is less than 128 bits
while len(blocks[len(blocks)-1]) < 16: # Keep iterating the following code
blocks[len(blocks)-1] += "." # Add padding to the end of the block to make it 128-bit
sponge = nonce # Set the sponge's initial state to that of the nonce
for j in blocks: # Absorb all of the blocks
sponge = (sponge << 128) + j # Concatenate the current sponge value and the block
sponge = textwrap.wrap(sponge, 128) # Convert the sponge into 128-bit blocks
for z in sponge: # Keep iterating the following code
z = z^j # XOR the sponge block with the message block
sponge = join(sponge) # Convert the blocks back into a string
sponge = textwrap.wrap(sponge, len(key)*8) # Convert the sponge into blocks with the same length of the key
output = sponge # Create a new variable to save space
del nonce, blocks # Delete variables to save space
while len(output) > 1: # Keep iterating the following code
output[1] = output[1]^output[0] >> output[0] # XOR the second element with the first, then shift forward
del output[0] # Delete the first element, so it can repeat again
tag = ((output^plaintext) <<< sponge) + output # Generate an authentication tag. That's not overkill, is it?
print output # Oh yeah, just print it in hexadecimal, I dunno how to
當他在終端運行腳本時,這是交互:
例外:
Traceback (most recent call last):
File "DarkKnight-Sponge.py", line 13, in <module>
sponge = (sponge << 128) + j # Concatenate the current sponge value and the block
TypeError: unsupported operand type(s) for <<: 'str' and 'int'
恭喜你兒子! 這個項目對我來說看起來很現實。 我能想到的唯一雄心勃勃的事情是直接鑽研像<<
和^
這樣的按位運算符,而不是嘗試對字符序列實現相應的操作。 位運算符有時看起來像算術黑魔法,因為它們操縱數字的內部二進制表示,我們不像數字的十進制表示或文本那樣熟悉。
TypeError: unsupported operand type(s) for <<: 'str' and 'int'
這個錯誤非常簡單:它表示無法執行sponge << 128
操作,因為sponge
是一個str
,即(字符)字符串,即文本,而 128 是一個 int,即整數。
想象一下,如果您讓計算機計算"three" + 2
。 它會返回一個錯誤,因為+
需要兩個數字,但"three"
是一個字符串,而不是一個數字。 同樣,如果你讓計算機計算"327" + 173
,它會返回一個錯誤,因為"327"
是文本,而不是數字。
運算符<<
是左移運算符。 它將一個數字向左移動一定數量的位。 計算機以二進制表示形式存儲數字; 我們人類更習慣於十進制表示,所以讓我們用“左移數字”操作來做一個比喻。 “向左移動一個數字”意味着將它乘以 10 的冪。例如,138 向左移動兩次就是 13800。我們在右邊用零填充。 在二進制表示中,bitshift 的工作原理相同,但改為乘以 2 的冪。 二進制表示的 138 是1110110
; 將它向左移動兩次給出111011000
,這與將其乘以100
(即 4)相同。
如果sponge
和j
都是數字,並且j
小於 2^128,則該行:
sponge = (sponge << 128) + j # Concatenate the current sponge value and the block
將sponge
向左移動 128 位,然后將小於 128 位的數字添加到結果中。 實際上,這是將sponge
位與j
位連接起來。 回到我們的十進制類比:如果x
是一個數字,而y
是一個小於 100 的數字,那么數字x * 100 + y
是通過連接x
和y
的數字獲得的數字。 例如, 1374 * 100 + 56 = 137456
。
我沒有讀過啟發這段代碼的密碼學書籍,所以我只是從這里開始猜測。
我的理解是這本書期望plaintext
、 nonce
和key
是數字。 但是,在您兒子的代碼中,它們都是文本。 這兩種類型的對象之間的區別並非不可調和。 無論如何,在計算機的內存中,所有內容都存儲為位序列。 數字是位序列; 一個字符串是一個字符序列,每個字符本身就是一個短的位序列。
我看到三種可能性:(1)在執行操作之前將所有文本轉換為數字; (2) 調整操作,使它們可以應用於字符串而不是整數; (3) 將所有文本轉換為僅包含字符0
和1
字符串並調整操作,以便將它們應用於此類序列。 密碼算法在現實世界中的高效實現肯定都選擇了第二個選項。 第三個選項顯然是三個選項中效率較低的一個,但出於學習目的,這是一個可能的選項。
看看你的代碼,我注意到所有使用的操作都是關於序列的操作,而不是關於算術運算。 正如我提到的, (sponge << 128) + j
是兩個位序列的串聯。 稍后在代碼^
使用的按位異或運算期望兩個長度相同的位序列,並返回一個長度相同的序列,在兩個序列具有不同位的每個位置處為1
,在兩個序列具有不同位的每個位置處返回0
序列具有相同的位。 例如, 00010110 ^ 00110111 = 00100001
因為第三位和第八位不同,但所有其他位都相等。
要將文本轉換為數字(我稱之為選項 2),您可以用這些行替換代碼的前三行:
plaintext_string = raw_input("The value to be hashed: ") # Get the user to input the data to be hashed
nonce_string = raw_input("The nonce to be used: ") # Get the user to input the nonce to be used
key_string = raw_input("The key to be used: ") # Get the user to input the key to be used
def string_to_int(txt):
number = 0
for c in txt:
number = (number << 8) + ord(c)
return number
plaintext = string_to_int(plaintext_string)
nonce = string_to_int(plaintext_string)
key = string_to_int(key_string)
這是如何工作的:python 函數ord
每個 ascii 字符c
映射到一個 8 位數字。 8 位塊使用公式number = (number << 8) + ord(c)
,您可以從上面的討論中識別出來。
這不足以使您的代碼正常工作,因為之后直接使用的textwrap.wrap()
函數需要一個字符串,而不是一個 int。 一種可能性是用自定義函數text_to_intblocks()
替換textwrap.wrap()
函數:
def string_to_intblocks(txt, blocksize):
blocks = []
block_number = 0
for i,c in enumerate(txt):
block_number = (block_number << 8) + ord(c)
if i % blocksize == 0:
blocks.append(block_number)
block_number = 0
return blocks
然后將blocks = textwrap.wrap(plaintext, 16)
替換為blocks = string_to_intblocks(plaintext_string, 16)
。
這仍然不足以修復您兒子的代碼。 我確信以下六行中存在邏輯錯誤,盡管修復它需要比我目前對算法有更好的理解:
sponge = nonce # Set the sponge's initial state to that of the nonce
for j in blocks: # Absorb all of the blocks
sponge = (sponge << 128) + j # Concatenate the current sponge value and the block
sponge = textwrap.wrap(sponge, 128) # Convert the sponge into 128-bit blocks
for z in sponge: # Keep iterating the following code
z = z^j # XOR the sponge block with the message block
sponge = join(sponge)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.