Hash

是否有針對複雜資料結構設計的雜湊樹方案?

  • February 14, 2022

我有一個帶有私有數據的 JSON 對象。它具有以下(複雜!)結構:

{
   name: "JB",
   age: 35,
   children: 
       [ {
          name: "Alice", 
          age: "5",
          favColor: "pink"
         },
         {
          name: "Bob", 
          age: "8",
          favColor: "blue"
         },
         {
          name: "Charlie", 
          age: "9",
          favColor: "green"
         },
      ]
}

我想創建一個雜湊樹(或類似的),允許其他人驗證我發送給他們的數據片段 - 例如通過在公共區塊鏈上聲明根。資料結構是任意的——它可以是任何東西。

例如,我希望能夠只分享我的年齡,並讓接收者能夠計算散列並檢查它是否正確。稍後,我可能想向其他使用者透露我的第一個孩子名叫“Alice”,她最喜歡的顏色是“粉紅色”。

我的理解是默克爾樹是二元的——每個節點只有兩個葉子——在我見過的 npm 庫中似乎就是這種情況。是否有一種固定的模式或方法可以始終如一地將上述複雜結構“扁平化”為默克爾樹?

或者,是否有另一種類型的雜湊樹結構天生就可以為數據提供這種複雜性?

例如:

      Root ( = hash of name + age + children)
    /  |  \
   /   |   \
name  age  children  (= hash of all children in array)
          /      | \
         /       |  \
        /        |   \
     [0]        [1]  [n]
    / | \        
   /  |  \      
name age favC 

似乎無論樹是如何構造的,重要的是原始數據的結構以某種方式被保留並且可以由驗證器仔細檢查。

  • 例如,阻止我提供孩子的年齡而不是我自己的年齡。
  • 在二叉默克爾樹的情況下:考慮到葉索引可能代表完全不同的數據,具體取決於它們擁有的孩子的數量。

解決這個問題的最佳方法是什麼?我正在使用 Node.JS 和整潔的Merkle Tools 包,但我不確定 merkle 樹是否適合這項工作。

表達這個問題的另一種方式是問:是否存在允許我們一致地將任意 Json 對像一致地呈現為類似雜湊樹的結構的雜湊模式?並且通過共享數據+其他雜湊來促進驗證。我應該將雜湊表與樹結合起來嗎?或者俱有某些節點的雜湊列表是樹?

如果我遺漏了任何重要的內容,或者您​​有任何澄清問題,我會盡力改進問題。根據 SO 主站點的建議,我已將問題重定向到此處。

非常感謝。

樹散列的一般技術(獨立於部分顯示內容的問題)是將節點的散列定義為其葉子散列的串聯散列,並帶有一個後綴(或前綴),使散列的輸入葉子和節點不同。顯然,這從加密雜湊繼承了它在隨機 Oracle 模型中的抗碰撞、抗原像和安全性的屬性。證明留給讀者作為練習。

魔鬼在細節中,尤其是在

  • 定義必須具有相同雜湊值的事物的規範形式;
  • 定義離開的順序是否重要;
  • 如果節點的類型或/和命名超出了葉子的範圍(在這種情況下,必須對類型/名稱副檔名進行散列);
  • 確保用於此類擴展的雜湊輸入格式不會導致衝突(可能是故意的)。

我不知道JSON沒有現成的雜湊標準,也就是ECMA-404。我在此半認真地建議選擇一個加密雜湊,例如 SHA-512,並將 SHA-512-JSON-V1 定義為:

  • JSON數組的散列是其值的散列串聯的散列,按照它們在數組中出現的順序排列;最後一個八位字節 41 h (ASCII A)。
  • JSON對象的散列是偶數個散列的串聯散列,其中第一個散列是對象成員名稱的散列,第二個散列是對應的散列,其中對的兩個雜湊值按字典順序排列;最後一個八位字節 4F h (ASCII O)。
  • 任何其他 JSON(即包含名稱、數字、特殊值、、、以及任何其他未由ECMA-404定義的字元串)的雜湊值是其UTF8字元表示的串聯的雜湊值(不包括開頭和結尾隨之而來的字元串,並將三個特殊值轉換為小寫);和最後一個八位字節true``false``null``"
  • 53 h (ASCII S) 用於字元串,包括名稱
  • 4E h (ASCII N) 表示數字
  • 56 h (ASCII V) 用於其他

對象注意事項:

JSON 語法 (..) 對名稱/值對的排序沒有任何意義

  • 案件很重要,包括姓名。否則,除非我們將大小寫規範化限制為 ASCII 字母,否則使用 unicode 將是一場噩夢。
  • 在不改變散列方案的情況下,可以允許或不允許在對象的葉子中多次出現相同名稱(如ECMA-404中)。
  • 更新每條評論:提案根據兩個散列的連接(一個用於名稱,另一個用於值)對散列對(每個名稱:對*像中的值對一個)進行排序。*這確保了雜湊結果是相同的,而不管節點的順序如何。如果我們僅按名稱的雜湊值或按名稱進行排序,則無法保證對像中多次出現相同名稱(這是可能的,請參見上面的項目符號)。此外,根據散列直接排序允許用任何與順序無關的散列代替排序,從而對大型對象進行相當大的優化;請參閱此答案的最後一部分。

編碼注意事項:

  • UTF8 的優勢在於它是緊湊的、字節序中性的,並且為每個 unicode 點分配一個表示為八位字節字元串(包括如果它沒有 UTF-16 表示)。
  • 例如,JSON 的雜湊"4\u00e9\u144E\uD834\uDD1E"(四個字元的字元串 “4éᑎ𝄞” ,最後一個字元由最後兩個十六進制轉義序列表示)是 11 個八位字節的雜湊

  34 h C3 h A9 h E1 h 91 h 8E h F0 h 9D h 84 h 9E h 53 h

第一個字元分別為 1(分別為 2、3、4 和 1)八位字節(分別為第二個字元、第三個字元、第四個字元和後綴八位字節)。

  • 該問題使用 JSON 放寬,其中不需要引用用作欄位名稱的字元串。因此有意指定在object中,age: 35, false:0, True:true, 1e0:42,{}:{},[0]:{}(如果被解析器接受)雜湊與"age":35, "false":0, "True":true, "1e0":42, "{}":{}, "[0]":{}即使某些貶義名稱可能是valuenumberobjectarray類型相同。
  • 指定true以小寫形式散列的特殊值未指定是否True有效及其類型,但指定如果它是同化為 JSON 的特殊true,則它必須像後者一樣散列。
  • 更一般地,為解析鬆弛/擴展留下了自由:例如,可以在問題中允許在數組或對象之前]}末尾添加額外的“,”,或者可以允許null在“,”之後省略’。雜湊將遵循解析器使用的任何約定。

編號編碼注意事項:

  • 照原樣,相等的數字(在某種意義上由 JSON 未指定)仍然可以具有不同的雜湊值。例如,零可以是(在無限的可能性中)

  0   -0   0.0   0e0   0E0   0e+0   0e-0   0e00314

  • 如果我們想解決這個問題,就需要做出選擇,而且並不容易。對於 C 編譯器,0.0 和 0 是不一樣的。對於實驗物理學家來說,1.2e4 和 1.20e4 是一樣的。

注意:它使用後綴而不是前綴,因為這樣可以很好地對齊objectarray的數據,特別是對於內部數據塊大小是輸出大小兩倍的雜湊算法,例如 SHA-512。


效率:SHA-512-JSON-V1 允許計算任何長度的 JSON 的雜湊值 $ n $ 及時 $ \mathcal O(n\log n) $ . 這 $ \log n $ 術語只是由於對大對象的雜湊進行排序。我們可以擺脫這個術語,並且通常會大大減少使用的記憶體,使用這個答案第二部分中的技術,它概述瞭如何使用線上算法使用超出輸入的常量記憶體來製作與順序無關的雜湊。我們將其留作將來擴展!


更新:現在正在努力規範化 JSON,我認為解決了一些問題。請參閱RFC 8785

引用自:https://crypto.stackexchange.com/questions/54953