sxs_dcrd_test.go raw
1 //go:build !js
2
3 package p256k1
4
5 import (
6 "encoding/hex"
7 "testing"
8
9 dcrd "git.smesh.lol/orly/pkg/nostr/crypto/ec/secp256k1"
10 )
11
12 // TestSxSDcrd compares p256k1 pubkey generation against the vendored Decred
13 // secp256k1 library for a range of known secret keys.
14 // This validates the native (64-bit) code path.
15 func TestSxSDcrd(t *testing.T) {
16 secrets := []string{
17 "0000000000000000000000000000000000000000000000000000000000000001",
18 "0000000000000000000000000000000000000000000000000000000000000002",
19 "0000000000000000000000000000000000000000000000000000000000000003",
20 "0000000000000000000000000000000000000000000000000000000000000007",
21 "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35",
22 "deadbeefcafebabe1234567890abcdef0123456789abcdef0123456789abcdef",
23 "7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0",
24 // Near-order edge cases
25 "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413e",
26 "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
27 // GLV lambda
28 "5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72",
29 }
30
31 for _, secHex := range secrets {
32 secBytes, _ := hex.DecodeString(secHex)
33
34 // --- Decred ---
35 dcrdKey := dcrd.SecKeyFromBytes(secBytes)
36 dcrdPub := dcrdKey.PubKey()
37 dcrdSer := dcrdPub.SerializeCompressed()
38 dcrdX := hex.EncodeToString(dcrdSer[1:33])
39
40 // --- p256k1 ---
41 var pubkey PublicKey
42 if err := ECPubkeyCreate(&pubkey, secBytes); err != nil {
43 t.Errorf("[%s] p256k1 ECPubkeyCreate failed: %v", secHex[:8], err)
44 continue
45 }
46 var p256Ser [33]byte
47 ECPubkeySerialize(p256Ser[:], &pubkey, ECCompressed)
48 p256X := hex.EncodeToString(p256Ser[1:33])
49
50 if dcrdX != p256X {
51 t.Errorf("[%s] X mismatch:\n dcrd: %s\n p256k1: %s", secHex[:8], dcrdX, p256X)
52 }
53 if dcrdSer[0] != p256Ser[0] {
54 t.Errorf("[%s] parity mismatch: dcrd=0x%02x p256k1=0x%02x", secHex[:8], dcrdSer[0], p256Ser[0])
55 }
56
57 // Cross-validate: parse p256k1 pubkey with Decred
58 _, err := dcrd.ParsePubKey(p256Ser[:])
59 if err != nil {
60 t.Errorf("[%s] Decred rejects p256k1 pubkey: %v", secHex[:8], err)
61 }
62
63 // Cross-validate: parse Decred pubkey with p256k1
64 var p256FromDcrd PublicKey
65 if err := ECPubkeyParse(&p256FromDcrd, dcrdSer[:]); err != nil {
66 t.Errorf("[%s] p256k1 rejects Decred pubkey: %v", secHex[:8], err)
67 }
68
69 t.Logf("[%s] OK x=%s parity=0x%02x", secHex[:8], dcrdX, dcrdSer[0])
70 }
71 }
72
73 // TestSxSDcrdECDH compares ECDH shared secret computation between both libs.
74 func TestSxSDcrdECDH(t *testing.T) {
75 // Alice and Bob each have a secret key
76 aliceSec, _ := hex.DecodeString("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35")
77 bobSec, _ := hex.DecodeString("deadbeefcafebabe1234567890abcdef0123456789abcdef0123456789abcdef")
78
79 // --- Decred ECDH ---
80 dcrdAlice := dcrd.SecKeyFromBytes(aliceSec)
81 dcrdBob := dcrd.SecKeyFromBytes(bobSec)
82
83 dcrdShared1 := dcrd.GenerateSharedSecret(dcrdAlice, dcrdBob.PubKey())
84 dcrdShared2 := dcrd.GenerateSharedSecret(dcrdBob, dcrdAlice.PubKey())
85
86 if hex.EncodeToString(dcrdShared1) != hex.EncodeToString(dcrdShared2) {
87 t.Fatal("Decred ECDH not symmetric")
88 }
89
90 // --- p256k1 ECDH ---
91 // Compute Bob's pubkey with p256k1
92 var bobPub PublicKey
93 ECPubkeyCreate(&bobPub, bobSec)
94 var bobSer [33]byte
95 ECPubkeySerialize(bobSer[:], &bobPub, ECCompressed)
96
97 // Compute Alice's pubkey with p256k1
98 var alicePub PublicKey
99 ECPubkeyCreate(&alicePub, aliceSec)
100 var aliceSer [33]byte
101 ECPubkeySerialize(aliceSer[:], &alicePub, ECCompressed)
102
103 // Use p256k1's EcmultConst for ECDH: alice_sec * bob_pub
104 var aliceScalar Scalar
105 aliceScalar.setB32(aliceSec)
106 var bobPoint GroupElementAffine
107 pubkeyLoad(&bobPoint, &bobPub)
108
109 var sharedJac GroupElementJacobian
110 EcmultConst(&sharedJac, &bobPoint, &aliceScalar)
111 var sharedAff GroupElementAffine
112 sharedAff.setGEJ(&sharedJac)
113 sharedAff.x.normalize()
114 var p256SharedX [32]byte
115 sharedAff.x.getB32(p256SharedX[:])
116
117 // Decred ECDH returns just the X coordinate
118 // Compare
119 dcrdSharedX := hex.EncodeToString(dcrdShared1)
120 p256SharedXHex := hex.EncodeToString(p256SharedX[:])
121
122 t.Logf("Decred ECDH shared X: %s", dcrdSharedX)
123 t.Logf("p256k1 ECDH shared X: %s", p256SharedXHex)
124
125 if dcrdSharedX != p256SharedXHex {
126 t.Errorf("ECDH X mismatch")
127 }
128 }
129