如何在Python和JavaScript中以相同方式散列“json”嵌套字典?

zynd9foi  于 2023-03-13  发布在  Python
关注(0)|答案(4)|浏览(142)

在JavaScript和Python中,一致地散列一个仅限于JSON所能表示的对象/字典的最佳方法是什么?在许多不同的语言中呢?
当然,在许多不同的语言中都有一致实现的哈希函数,它们都接受字符串,但是要对一个对象进行哈希运算,首先必须将其转换为字符串表示。
我想要一个散列函数,它在任何语言中对于相同的字典总是返回相同的值,但是JSON规范不能保证序列化表示中键的顺序。
json.dumps()JSON.stringify()的行为是否相同?您将如何验证这一点?
如果没有,是否存在一种序列化格式,它包含多种语言的库(我实际上对Python和JavaScript很感兴趣,但也对所有语言都很好奇),不需要调用者进行任何额外的处理就能产生一致的结果?

ao218c7q

ao218c7q1#

我将把这个问题分成两个问题。
1.如何在JavaScript和Python中获得相同的序列化字符串?
1.应该使用哪个字节数组哈希函数?它必须是一个在JavaScript和Python中实现相同的成熟算法。
使用(1)获取两个字符串,然后使用UTF8编码,然后使用(2)获取哈希值。
因为(2)很简单,所以我只讨论(1)。
确保生成的两个JSON字符串相同的问题涉及多个方面。

  • 您可能希望使用未格式化的JSON(没有多余的空格、制表符或换行符)。
  • 空值必须被同等对待。2如果值为空,一些序列化器会默认丢弃字典键值对。
  • 字典中键值对的顺序必须一致。
  • JSON数字序列化应该是一致的,例如,不能将整数1序列化为一边的1和另一边的1.0(不过这可能不是什么大问题)。
  • 两者的字符串编码应该相同。JSON允许序列化为Unicode文本,只要求在JSON字符串中对"\进行反斜杠转义。然而,大多数序列化程序都做了很多不必要的事情,并将几乎所有的Unicode字符都简化为\uXXXX的等价形式,有关JSON字符串编码的详细信息,请参见json.org。消除所有歧义的一种方法是只在绝对必要时才逃避。

您需要确保JavaScript和Python之间的所有这些匹配。我使用过的大多数JSON序列化库都为上面提到的所有内容提供了配置钩子。不幸的是,我对JavaScript或Python库并不十分熟悉。

zz2j4svz

zz2j4svz2#

JSON是一种定义良好的表示对象状态的语言,函数的行为并不完全相同,但它们的行为是完全等同的。
例如:

json.dumps({'hello':'goodbye', 123: 456})

可能产生:

{"hello":"goodbye", "123": 456}

{"123": 456, "hello":"goodbye"}

如果传入indent参数,则会得到更多不同结果的可能性。
大多数语言如果没有内置的方式来处理JSON(例如Python和JS),那么他们会有一个第三方工具,这是完全足够的(见Newtonsoft JSON library for .NET)
我所知道的每种语言都会生成有效的JSON,这意味着它可以被提供JSON解析器的其他语言解析。

0md85ypi

0md85ypi3#

我想我可以尝试一个实际的例子。
在javascript中我做了:

import stringify from 'json-stable-stringify'
import sha256 from 'simple-sha256'

hash_str = sha256(stringify({'hello':'goodbye', '123': 456}))
// hash_str = 72804f4e0847a477ee69eae4fbf404b03a6c220bacf8d5df34c964985acd473f

json-stable-stringify保证json排序。sha256允许节点/浏览器兼容。
在python 3.8中,我做到了:

import hashlib
import json

hash_str = hashlib.sha256(json.dumps({'hello':'goodbye', '123': 456}, sort_keys=True, separators=(',', ':')).encode("utf-8")).hexdigest()
# hash_str = 72804f4e0847a477ee69eae4fbf404b03a6c220bacf8d5df34c964985acd473f

我还没有做广泛的测试,但是我已经尝试过json对象,它已经成功地匹配了。

mf98qq94

mf98qq944#

在python中,你可以用merkle-json来实现这一点,merkle-json可以为任何dict(python中)或json对象生成唯一的哈希值,它还支持列表和嵌套对象。
安装后:

pip install merkle-json

像这样使用它:

from merkle_json import MerkleJson

mj = MerkleJson()
obj = {
    'keyC': [3,4],
    'keyA': 2,
    'keyB': 4,
    'keyD': 1,
}
mj.hash(obj) # '7001bd2b415e6a624a23d7bc7c249b21'

相关问题