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