gmsm/ecdh/stealth_test.go
2024-11-27 17:58:05 +08:00

123 lines
3.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package ecdh
import (
"crypto/rand"
"testing"
"github.com/emmansun/gmsm/sm3"
)
// https://eips.ethereum.org/EIPS/eip-5564, but uses SM3 instead of Keccak256
// Generation - Generate stealth address from stealth meta-address
func generateStealthAddress(spendPub, viewPub *PublicKey) (ephemeralPub *PublicKey, stealth *PublicKey, err error) {
// generate ephemeral key pair
ephemeralPriv, err := P256().GenerateKey(rand.Reader)
if err != nil {
return nil, nil, err
}
ephemeralPub = ephemeralPriv.PublicKey()
// compute shared secret key
R, err := ephemeralPriv.SecretKey(viewPub)
if err != nil {
return nil, nil, err
}
// the secret key is hashed
sh := sm3.Sum(R[1:])
// multiply the hashed shared secret with the generator point
shPriv, err := P256().GenerateKeyFromScalar(sh[:])
if err != nil {
return nil, nil, err
}
shPublic := shPriv.PublicKey()
// compute the recipient's stealth public key
stealth, err = shPublic.Add(spendPub)
if err != nil {
return nil, nil, err
}
return ephemeralPub, stealth, nil
}
// Parsing - Locate ones own stealth address
func checkStealthAddress(viewPriv *PrivateKey, spendPub, ephemeralPub, stealth *PublicKey) (bool, error) {
// compute shared secret key
R, err := viewPriv.SecretKey(ephemeralPub)
if err != nil {
return false, err
}
// the secret key is hashed
sh := sm3.Sum(R[1:])
// multiply the hashed shared secret with the generator point
shPriv, err := P256().GenerateKeyFromScalar(sh[:])
if err != nil {
return false, err
}
shPublic := shPriv.PublicKey()
// compute the derived stealth address
goStealth, err := shPublic.Add(spendPub)
if err != nil {
return false, err
}
// compare the derived stealth address with the provided stealth address
return stealth.Equal(goStealth), nil
}
// Private key derivation - Generate the stealth address private key from the hashed shared secret and the spending private key.
func computeStealthKey(spendPriv, viewPriv *PrivateKey, ephemeralPub *PublicKey) (*PrivateKey, error) {
// compute shared secret key
R, err := viewPriv.SecretKey(ephemeralPub)
if err != nil {
return nil, err
}
// the secret key is hashed
sh := sm3.Sum(R[1:])
// multiply the hashed shared secret with the generator point
shPriv, err := P256().GenerateKeyFromScalar(sh[:])
if err != nil {
return nil, err
}
return spendPriv.Add(shPriv)
}
func testEIP5564StealthAddress(t *testing.T, spendPriv, viewPriv *PrivateKey) {
t.Helper()
ephemeralPub, expectedStealth, err := generateStealthAddress(spendPriv.PublicKey(), viewPriv.PublicKey())
if err != nil {
t.Fatalf("the recipient's stealth public key: failed to add public keys: %v", err)
}
passed, err := checkStealthAddress(viewPriv, spendPriv.PublicKey(), ephemeralPub, expectedStealth)
if err != nil {
t.Fatal(err)
}
if !passed {
t.Fatal("mismatched stealth address")
}
privStealth, err := computeStealthKey(spendPriv, viewPriv, ephemeralPub)
if err != nil {
t.Fatalf("failed to compute stealth key: %v", err)
}
if !privStealth.PublicKey().Equal(expectedStealth) {
t.Fatal("mismatched stealth key")
}
}
func TestEIP5564StealthAddress(t *testing.T) {
privSpend, err := P256().GenerateKey(rand.Reader)
if err != nil {
t.Fatalf("failed to generate private key: %v", err)
}
privView, err := P256().GenerateKey(rand.Reader)
if err != nil {
t.Fatalf("failed to generate private key: %v", err)
}
testEIP5564StealthAddress(t, privSpend, privView)
}