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") } }