mirror of
https://github.com/luxfi/kms.git
synced 2026-10-30 16:23:36 +00:00
It asserted on lastSign.Message. SignRequest carries Payload and never had a Message, so the package has not compiled since the plane was added — the whole of pkg/sdksign, not one case. It went unseen because a dependency of this package could not be fetched at all, so the failure everyone saw was the fetch. With that cleared, go build ./... and go test ./... both pass: 15 packages, no failures.
169 lines
4.9 KiB
Go
169 lines
4.9 KiB
Go
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package sdksign
|
|
|
|
import (
|
|
"context"
|
|
"crypto/ed25519"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/luxfi/kms/pkg/keys"
|
|
"github.com/luxfi/kms/pkg/mpc"
|
|
"github.com/luxfi/kms/pkg/store"
|
|
badger "github.com/luxfi/zapdb"
|
|
)
|
|
|
|
// fakeMPC records Sign delegations and returns a canned signature. It
|
|
// implements keys.MPCBackend (Signer + Encryptor). It does NOT fake
|
|
// threshold math — it only proves the manager delegated the right
|
|
// (walletID, keyType, message).
|
|
type fakeMPC struct {
|
|
lastSign mpc.SignRequest
|
|
signN int
|
|
}
|
|
|
|
func (f *fakeMPC) Keygen(context.Context, string, mpc.KeygenRequest) (*mpc.KeygenResult, error) {
|
|
return &mpc.KeygenResult{}, nil
|
|
}
|
|
func (f *fakeMPC) Sign(_ context.Context, req mpc.SignRequest) (*mpc.SignResult, error) {
|
|
f.lastSign = req
|
|
f.signN++
|
|
return &mpc.SignResult{Signature: "canned-sig", R: "0xr", S: "0xs"}, nil
|
|
}
|
|
func (f *fakeMPC) Reshare(context.Context, string, mpc.ReshareRequest) error { return nil }
|
|
func (f *fakeMPC) GetWallet(context.Context, string) (*mpc.Wallet, error) {
|
|
return &mpc.Wallet{}, nil
|
|
}
|
|
func (f *fakeMPC) Status(context.Context) (*mpc.ClusterStatus, error) {
|
|
return &mpc.ClusterStatus{Ready: true}, nil
|
|
}
|
|
|
|
func newManager(t *testing.T) (*keys.Manager, *store.Store, *fakeMPC) {
|
|
t.Helper()
|
|
db, err := badger.Open(badger.DefaultOptions("").WithInMemory(true))
|
|
if err != nil {
|
|
t.Fatalf("zapdb: %v", err)
|
|
}
|
|
t.Cleanup(func() { db.Close() })
|
|
st, err := store.New(db)
|
|
if err != nil {
|
|
t.Fatalf("store.New: %v", err)
|
|
}
|
|
f := &fakeMPC{}
|
|
return keys.NewManager(f, st, "vault-1"), st, f
|
|
}
|
|
|
|
// TestSign_DelegatesToMPC proves Backend.Sign routes to the right MPC
|
|
// wallet for each scheme and propagates the signature. No key material
|
|
// is held locally.
|
|
func TestSign_DelegatesToMPC(t *testing.T) {
|
|
mgr, st, f := newManager(t)
|
|
if err := st.Put(&keys.ValidatorKeySet{
|
|
ValidatorID: "val-1",
|
|
BLSWalletID: "w-bls",
|
|
CoronaWalletID: "w-corona",
|
|
}); err != nil {
|
|
t.Fatalf("seed: %v", err)
|
|
}
|
|
b := New(mgr)
|
|
|
|
msg := []byte("header")
|
|
res, err := b.Sign(context.Background(), "val-1", "bls", msg)
|
|
if err != nil {
|
|
t.Fatalf("bls sign: %v", err)
|
|
}
|
|
if f.lastSign.WalletID != "w-bls" || string(f.lastSign.Payload) != "header" {
|
|
t.Fatalf("bls delegated wrong: %+v", f.lastSign)
|
|
}
|
|
if res.Signature != "canned-sig" || res.R != "0xr" {
|
|
t.Fatalf("bls result not propagated: %+v", res)
|
|
}
|
|
|
|
if _, err := b.Sign(context.Background(), "val-1", "corona", msg); err != nil {
|
|
t.Fatalf("corona sign: %v", err)
|
|
}
|
|
if f.lastSign.WalletID != "w-corona" {
|
|
t.Fatalf("corona delegated to wrong wallet: %+v", f.lastSign)
|
|
}
|
|
if f.signN != 2 {
|
|
t.Fatalf("sign calls=%d want 2", f.signN)
|
|
}
|
|
}
|
|
|
|
func TestSign_UnsupportedScheme(t *testing.T) {
|
|
mgr, st, _ := newManager(t)
|
|
_ = st.Put(&keys.ValidatorKeySet{ValidatorID: "val-1", BLSWalletID: "w"})
|
|
b := New(mgr)
|
|
if _, err := b.Sign(context.Background(), "val-1", "rsa", []byte("m")); err == nil {
|
|
t.Fatalf("expected error for unsupported scheme")
|
|
}
|
|
}
|
|
|
|
// TestVerify_Corona_Ed25519 exercises the REAL ed25519 verify path with a
|
|
// real keypair — a valid signature verifies, a tampered one does not.
|
|
func TestVerify_Corona_Ed25519(t *testing.T) {
|
|
pub, priv, err := ed25519.GenerateKey(rand.Reader)
|
|
if err != nil {
|
|
t.Fatalf("gen: %v", err)
|
|
}
|
|
mgr, st, _ := newManager(t)
|
|
if err := st.Put(&keys.ValidatorKeySet{
|
|
ValidatorID: "val-1",
|
|
CoronaPublicKey: hex.EncodeToString(pub),
|
|
}); err != nil {
|
|
t.Fatalf("seed: %v", err)
|
|
}
|
|
b := New(mgr)
|
|
|
|
msg := []byte("consensus-round-42")
|
|
sig := ed25519.Sign(priv, msg)
|
|
|
|
ok, err := b.Verify(context.Background(), "val-1", "corona", msg, sig)
|
|
if err != nil {
|
|
t.Fatalf("verify: %v", err)
|
|
}
|
|
if !ok {
|
|
t.Fatalf("valid signature must verify")
|
|
}
|
|
|
|
// Tamper the signature → must NOT verify (and no error).
|
|
bad := append([]byte(nil), sig...)
|
|
bad[0] ^= 0xFF
|
|
ok, err = b.Verify(context.Background(), "val-1", "corona", msg, bad)
|
|
if err != nil {
|
|
t.Fatalf("verify(bad): %v", err)
|
|
}
|
|
if ok {
|
|
t.Fatalf("tampered signature must NOT verify")
|
|
}
|
|
|
|
// Tamper the message → must NOT verify.
|
|
ok, _ = b.Verify(context.Background(), "val-1", "corona", []byte("other"), sig)
|
|
if ok {
|
|
t.Fatalf("signature over a different message must NOT verify")
|
|
}
|
|
}
|
|
|
|
// TestVerify_BLS_Delegated pins the documented capability boundary.
|
|
func TestVerify_BLS_Delegated(t *testing.T) {
|
|
mgr, st, _ := newManager(t)
|
|
_ = st.Put(&keys.ValidatorKeySet{ValidatorID: "val-1", BLSPublicKey: "abcd"})
|
|
b := New(mgr)
|
|
_, err := b.Verify(context.Background(), "val-1", "bls", []byte("m"), []byte("s"))
|
|
if !errors.Is(err, ErrVerifyBLSDelegated) {
|
|
t.Fatalf("bls verify err=%v want ErrVerifyBLSDelegated", err)
|
|
}
|
|
}
|
|
|
|
func TestVerify_UnknownValidator(t *testing.T) {
|
|
mgr, _, _ := newManager(t)
|
|
b := New(mgr)
|
|
if _, err := b.Verify(context.Background(), "nope", "corona", []byte("m"), []byte("s")); err == nil {
|
|
t.Fatalf("expected error for unknown validator")
|
|
}
|
|
}
|