131 lines
4.1 KiB
Go
131 lines
4.1 KiB
Go
package secp256k1
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"math/big"
|
|
"testing"
|
|
)
|
|
|
|
func mustDecodeHex(t *testing.T, s string) []byte {
|
|
t.Helper()
|
|
b, err := hex.DecodeString(s)
|
|
if err != nil {
|
|
t.Fatalf("decode hex: %v", err)
|
|
}
|
|
return b
|
|
}
|
|
|
|
// TestBasePointOnCurve confirms the generator satisfies y^2 = x^3 + 7.
|
|
func TestBasePointOnCurve(t *testing.T) {
|
|
if !IsOnCurve(&Point{X: Gx, Y: Gy}) {
|
|
t.Fatalf("generator is not on the curve")
|
|
}
|
|
}
|
|
|
|
// TestPointDoublingMatchesScalarMult verifies group consistency: 2*G computed
|
|
// via point doubling equals k*G for k=2.
|
|
func TestPointDoublingMatchesScalarMult(t *testing.T) {
|
|
g := &Point{X: Gx, Y: Gy}
|
|
viaDouble := Add(g, g)
|
|
viaScalar := ScalarBaseMult(big.NewInt(2))
|
|
if viaDouble.X.Cmp(viaScalar.X) != 0 || viaDouble.Y.Cmp(viaScalar.Y) != 0 {
|
|
t.Fatalf("2G mismatch: double=%v scalar=%v", viaDouble, viaScalar)
|
|
}
|
|
if !IsOnCurve(viaScalar) {
|
|
t.Fatalf("2G not on curve")
|
|
}
|
|
}
|
|
|
|
// TestScalarMultDistributes checks (a+b)G == aG + bG.
|
|
func TestScalarMultDistributes(t *testing.T) {
|
|
a := big.NewInt(12345)
|
|
b := big.NewInt(67890)
|
|
sum := new(big.Int).Add(a, b)
|
|
left := ScalarBaseMult(sum)
|
|
right := Add(ScalarBaseMult(a), ScalarBaseMult(b))
|
|
if left.X.Cmp(right.X) != 0 || left.Y.Cmp(right.Y) != 0 {
|
|
t.Fatalf("(a+b)G != aG + bG")
|
|
}
|
|
}
|
|
|
|
// TestPublicKeyKnownValues locks the uncompressed public key for the t3 key.
|
|
func TestPublicKeyKnownValues(t *testing.T) {
|
|
priv := mustDecodeHex(t, "a96135266ba58bb5b3a450b8fe7a9d59ea3e6cb0cdb2300e8138d2d2d48e61a8")
|
|
point, err := PublicKey(priv)
|
|
if err != nil {
|
|
t.Fatalf("PublicKey: %v", err)
|
|
}
|
|
raw := make([]byte, 64)
|
|
point.X.FillBytes(raw[0:32])
|
|
point.Y.FillBytes(raw[32:64])
|
|
want := "076e3db946fcb53d575c4e742a9f8ff8c4b57ded53776b2a80d13022e1647adaa1641f3e2210f5f6a3bdd73d073ac029ba79d576093d8a92dd148e448a8e63cb"
|
|
if got := hex.EncodeToString(raw); got != want {
|
|
t.Fatalf("pubkey = %s, want %s", got, want)
|
|
}
|
|
if !IsOnCurve(point) {
|
|
t.Fatalf("derived public key not on curve")
|
|
}
|
|
}
|
|
|
|
// TestSignRecoverRoundTrip signs and recovers for several keys and hashes.
|
|
func TestSignRecoverRoundTrip(t *testing.T) {
|
|
privs := []string{
|
|
"a96135266ba58bb5b3a450b8fe7a9d59ea3e6cb0cdb2300e8138d2d2d48e61a8",
|
|
"3252a4cb9b3865c94dbb7d6f50107ca704c1c2b9e3d1eb81753e221c7db8fa25",
|
|
"993638df18a38ef2be9f8c915eb9063647d015edc8fb70e3bcb32469bee39c21",
|
|
}
|
|
hashes := []string{
|
|
"e93945efde601eed484553338e58218f4e81c51261dfda72db2d874f75378fe8",
|
|
"0000000000000000000000000000000000000000000000000000000000000001",
|
|
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
|
}
|
|
for _, p := range privs {
|
|
priv := mustDecodeHex(t, p)
|
|
wantPoint, _ := PublicKey(priv)
|
|
for _, h := range hashes {
|
|
hash := mustDecodeHex(t, h)
|
|
sig, err := Sign(priv, hash)
|
|
if err != nil {
|
|
t.Fatalf("Sign: %v", err)
|
|
}
|
|
// low-s enforcement
|
|
if sig.S.Cmp(halfN) > 0 {
|
|
t.Fatalf("signature s is not low-s")
|
|
}
|
|
recovered, err := RecoverPublicKey(hash, sig)
|
|
if err != nil {
|
|
t.Fatalf("RecoverPublicKey: %v", err)
|
|
}
|
|
if recovered.X.Cmp(wantPoint.X) != 0 || recovered.Y.Cmp(wantPoint.Y) != 0 {
|
|
t.Fatalf("recovered key differs for priv=%s hash=%s", p, h)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestSignIsDeterministic confirms RFC6979-style reproducibility.
|
|
func TestSignIsDeterministic(t *testing.T) {
|
|
priv := mustDecodeHex(t, "a96135266ba58bb5b3a450b8fe7a9d59ea3e6cb0cdb2300e8138d2d2d48e61a8")
|
|
hash := mustDecodeHex(t, "e93945efde601eed484553338e58218f4e81c51261dfda72db2d874f75378fe8")
|
|
a, err := Sign(priv, hash)
|
|
if err != nil {
|
|
t.Fatalf("Sign: %v", err)
|
|
}
|
|
b, err := Sign(priv, hash)
|
|
if err != nil {
|
|
t.Fatalf("Sign: %v", err)
|
|
}
|
|
if hex.EncodeToString(a.Bytes()) != hex.EncodeToString(b.Bytes()) {
|
|
t.Fatalf("signatures differ for identical inputs")
|
|
}
|
|
}
|
|
|
|
func TestPublicKeyRejectsInvalid(t *testing.T) {
|
|
if _, err := PublicKey(make([]byte, 31)); err == nil {
|
|
t.Fatalf("expected error for short key")
|
|
}
|
|
if _, err := PublicKey(make([]byte, 32)); err == nil {
|
|
t.Fatalf("expected error for zero key")
|
|
}
|
|
}
|