Ed25519(ref10)中的點加法和加倍?
我剛剛將 CodesInChaos 的 Ed25519(ref10) 的 C# 埠遷移到 Java,一切正常。(即我在密鑰生成、簽名和驗證方面得到相同的結果。)
現在,我想直接在 Ed25519 上進行 Diffie-Hellman 密鑰交換。因此,我正在研究點加法、加倍和乘法的函式。
經過幾次測試,似乎加倍了一個點
分貝(P)
提供與向自身添加相同點不同的結果
添加(P,P)。
即使我使用不同的點進行加法,結果仍然不同。例如:dbl(dbl(P)) 也不同於 add(add(dbl(P),P),P)。
這是正常的嗎?(我不熟悉 ECC,並且我曾期望這些函式會返回相同的值。)
更新
由於 CodesInChaos,我的程式碼中有一個錯誤現在已得到糾正。
這是我的 C# 測試程式碼:
using System; using Chaos.NaCl.Internal.Ed25519Ref10; namespace Chaos.NaCl { public static class RunTest { static void Main () { testAddition (); } public static void testAddition () { Console.WriteLine ("============================= testAddition "); byte[] l_Seed = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; byte[] l_PK = new byte[32]; byte[] l_SK = new byte[64]; Ed25519Operations.crypto_sign_keypair (l_PK, 0, l_SK, 0, l_Seed, 0); byte[] l_A = add (l_PK, l_PK); byte[] l_B = dbl (l_PK); Console.WriteLine (CryptoBytes.ToHexStringUpper (l_A)); Console.WriteLine (CryptoBytes.ToHexStringUpper (l_B)); // Output Java and C#: // 382CE0B6971265E859F317BBCD18F6ADF4517102055DEFA3ED7C4EBFD2C0D655 // 382CE0B6971265E859F317BBCD18F6ADF4517102055DEFA3ED7C4EBFD2C0D655 // which is OK // LETS DO IT AGAIN: byte[] l_C = add (l_B, l_B); byte[] l_D = dbl (l_B); Console.WriteLine (CryptoBytes.ToHexStringUpper (l_C)); Console.WriteLine (CryptoBytes.ToHexStringUpper (l_D)); // Output Java port: // 40838B988FB4A3809EBEAA600604EAB4A39A75BD86509A73C40B5A2820BEB94E // 90A0F26E495C4A73BCE8BE36B361FF84F8CA8E19E15B9F623AC538E5F9646B63 // which is wrong ? // Output C# (Mono): // 0000000000000000000000000000000000000000000000000000000000000040 // 0000000000000000000000000000000000000000000000000000000000000040 // which is also wrong ?? :) } static byte[] dbl (byte[] p_Element) { byte[] l_Result = new byte[32]; GroupElementP3 l_P3; GroupOperations.ge_frombytes_negate_vartime(out l_P3, p_Element, 0); GroupElementP1P1 l_P1P1; GroupOperations.ge_p3_dbl(out l_P1P1,ref l_P3); GroupElementP3 l_P3again; GroupOperations.ge_p1p1_to_p3(out l_P3again,ref l_P1P1); GroupOperations.ge_p3_tobytes(l_Result,0,ref l_P3again); // EVIL MISTAKE: ScalarOperations.sc_clamp(l_Result, 0); return l_Result; } static byte[] add (byte[] p_ElementA, byte[]p_ElementB) { byte[] l_Result = new byte[32]; GroupElementP3 l_A; GroupOperations.ge_frombytes_negate_vartime(out l_A, p_ElementA, 0); GroupElementP3 l_B; GroupOperations.ge_frombytes_negate_vartime(out l_B, p_ElementB, 0); GroupElementCached l_Cached; GroupOperations.ge_p3_to_cached(out l_Cached,ref l_A); GroupElementP1P1 l_P1P1; GroupOperations.ge_add(out l_P1P1, ref l_B, ref l_Cached); GroupElementP3 l_P3again; GroupOperations.ge_p1p1_to_p3(out l_P3again, ref l_P1P1); GroupOperations.ge_p3_tobytes(l_Result, 0, ref l_P3again); // EVIL MISTAKE: ScalarOperations.sc_clamp (l_Result, 0); return l_Result; } } }
愛德華茲曲線具有統一的加法,因此向自身添加一個點會返回正確的結果。這與 Weierstrass 曲線不同,後者向自身添加一個點會產生錯誤的結果,您必須使用加倍。所以你期望加法和加倍應該返回相同的點是正確的。
ECC 的高性能實現使用某種形式的擴展或投影座標,您可以在其中為分母添加附加欄位。 $ (x,y) $ 可以表示為 $ (X, Y,Z) $ 和 $ x=X/Z $ 和 $ y=Y/Z $ . Ref10 使用了這些表示中的幾種不同,但想法保持不變。
所以你不能簡單地通過比較所有的來比較分數 $ X,Y,Z $ 因為同一點有多個表示。類似於如何 $ \frac{1}{3} $ 和 $ \frac{2}{6} $ 儘管看起來不同,但數字相同。加倍和加法返回相同的點,但表示不同。
比較分數
- 最簡單的方法是
ge_tobytes
. 這將轉換為仿射座標,但需要昂貴的場反轉。- 或者,如果您想比較 $ \frac{X_1}{Z_1} $ 和 $ \frac{X_2}{Z_2} $ 你檢查一下 $ X_1 Z_2 = X_2 Z_1 $ .
這是從 $ \frac{X_1}{Z_1} = \frac{X_1 Z_2}{Z_1 Z_2} $ 和 $ \frac{X_2}{Z_2} = \frac{X_2 Z_1}{Z_1 Z_2} $ 由於分母相同,因此您只需要比較提名者即可。
對 $ Y/Z $ 或者 $ Y/T $ 適合您正在使用的點表示的部分。