【问题标题】:TypeError: unsupported operand type(s) for <<: 'str' and 'int'TypeError: <<: 'str' 和 'int' 的操作数类型不受支持
【发布时间】:2020-09-02 10:34:55
【问题描述】:

对于我 10 岁的儿子正在尝试的 Python 项目,谁能给我一些广泛的指导?我正在寻找特定的编码解决方案,但我希望这是一个提出问题的好地方。我想看看我的儿子是否对他的编码项目感兴趣,以及是否有一种相对简单的方法让他学习正确的步骤。或者,对于一个喜欢阅读和尝试各种编码项目只是为了好玩的 10 岁孩子来说,这只是一个不合群的东西吗?如您所见,我不是编码员,对此类项目知之甚少,因此我们将不胜感激!

我儿子喜欢密码学,他告诉我他尝试了下面的 Python 代码。他希望构建一个类似海绵的函数来加密按摩,使其无法被解密。这是受他的书“Serious Cryptography”(J. Aumasson 着)中的一个章节启发的,该章节的标题是“Permutation-based Hash Functions: Sponge Functions”。当他运行他编写的代码时,他收到错误消息“TypeError: unsupported operand type(s) for

非常感谢!亚历山大

这是他的代码:

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

当他在终端运行脚本时,这是交互:

  • 要散列的值:abcioagdsbvasizfuvbosuif
  • 要使用的随机数:iugzaliuglieas
  • 要使用的密钥:asljdgadskj

例外:

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'

【问题讨论】:

  • sponge 是一个字符串,您不能将&lt;&lt; 与它一起使用
  • 如果您能在书中写出描述该算法的段落,那将非常有帮助。我确信从 for j in blocks:sponge = join(sponge) 的六行代码中存在逻辑错误,但如果不知道这六行代码的用途,要修复它并不容易

标签: python


【解决方案1】:

祝贺你的儿子!这个项目对我来说看起来很现实。我能想到的唯一雄心勃勃的事情是直接钻研像&lt;&lt;^ 这样的按位运算符,而不是尝试对字符序列实现相应的操作。位运算符有时看起来像算术黑魔法,因为它们操纵数字的内部二进制表示,我们不像数字的十进制表示或文本那样熟悉。

了解错误信息

TypeError: unsupported operand type(s) for <<: 'str' and 'int'

这个错误非常简单:它表示操作sponge &lt;&lt; 128 无法执行,因为spongestr,即(字符)字符串,即文本,而128 是int,即, 一个整数。

想象一下,如果你让计算机计算"three" + 2。它会返回一个错误,因为+ 需要两个数字,但"three" 是一个字符串,而不是一个数字。同样,如果你让计算机计算"327" + 173,它会返回错误,因为"327" 是文本,而不是数字。

了解发生错误的行

运算符&lt;&lt;leftwise bitshift 运算符。它将一个数字向左移动一定数量的位。计算机以二进制表示形式存储数字;我们人类更习惯于十进制表示,所以让我们用“左移数字”操作做一个类比。 “向左移动一个数字”意味着将它乘以 10 的幂。例如,向左移动两次的 138 将是 13800。我们在右侧填充了零。在二进制表示中,bitshift 的工作原理相同,但乘以 2 的幂。 138 的二进制表示是1110110;将其向左移动两次得到111011000,这与将其乘以100(即4)相同。

如果spongej 都是数字,并且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就是xy的数字串联得到的数字。例如,1374 * 100 + 56 = 137456

解决问题

我还没有阅读启发这段代码的密码学书籍,所以我只是从这里开始猜测。

我的理解是本书期望plaintextnoncekey 是数字。但是,在您儿子的代码中,它们都是文本。这两种对象之间的区别并非不可调和。在计算机的内存中,无论如何,一切都存储为位序列。数字是位序列;字符串是一个字符序列,每个字符本身就是一个短的位序列。

我看到三种可能性:(1)在执行操作之前将所有文本转换为数字; (2) 调整操作,以便它们可以应用于字符串而不是整数; (3) 将所有文本转换为仅包含字符01 的字符串,并调整操作以便它们可以应用于此类序列。加密算法的现实世界高效实现肯定都选择了第二个选项。第三个选项显然是三个选项中效率较低的选项,但出于学习目的,这是一个可能的选项。

查看您的代码,我注意到所有使用的操作都是关于序列操作,而不是算术运算。正如我所提到的,(sponge &lt;&lt; 128) + j 是两个位序列的串联。 bitwise xor 操作(稍后在代码^ 中使用)需要两个相同长度的位序列,并在两个序列所在的每个位置返回一个相同长度的序列1在两个序列具有相同位的每个位置都有不同的位和0。例如,00010110 ^ 00110111 = 00100001,因为第三和第八位是不同的,但所有其他位都是相等的。

将文本转换为 int

要将文本转换为数字(我称之为选项 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)

这是如何工作的:每个 ascii 字符 c 都被 python 函数 ord 映射到一个 8 位数字。 8 位块使用公式number = (number &lt;&lt; 8) + ord(c) 连接,您可以从上面的讨论中识别出来。

这不足以使您的代码正常工作,因为之后直接使用的 textwrap.wrap() 函数需要一个字符串,而不是一个 int。一种可能性是将textwrap.wrap() 函数替换为自定义函数text_to_intblocks()

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)

【讨论】:

    猜你喜欢
    • 2016-04-15
    • 2012-11-29
    • 2012-12-31
    • 1970-01-01
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多