package transactions import ( "crypto/ecdsa" "crypto/rand" "crypto/sha256" "encoding/hex" "errors" "fmt" "math/big" ) // IsValid realiza validações na transação: assinatura, saldo e nonce. func (tx *Transaction) IsValid(pubKey *ecdsa.PublicKey, balance float64, currentNonce uint64) error { if tx.IsZero() { return errors.New("transação malformada: campos obrigatórios ausentes") } if tx.Value+float64(tx.Gas) > balance { return fmt.Errorf("saldo insuficiente: necessário %.2f, disponível %.2f", tx.Value+float64(tx.Gas), balance) } if tx.Nonce != currentNonce { return fmt.Errorf("nonce inválido: esperado %d, recebido %d", currentNonce, tx.Nonce) } r, s, err := parseSignature(tx.Signature) if err != nil { return fmt.Errorf("erro ao parsear assinatura: %v", err) } hash := sha256.Sum256([]byte(fmt.Sprintf("%s:%s:%f:%d:%d", tx.From, tx.To, tx.Value, tx.Nonce, tx.Gas))) if !ecdsa.Verify(pubKey, hash[:], r, s) { return errors.New("assinatura inválida") } return nil } // parseSignature converte a assinatura hex (formato r||s) em *big.Int. func parseSignature(sig string) (*big.Int, *big.Int, error) { bytes, err := hex.DecodeString(sig) if err != nil { return nil, nil, err } if len(bytes) != 64 { return nil, nil, errors.New("assinatura deve ter 64 bytes (r||s)") } r := new(big.Int).SetBytes(bytes[:32]) s := new(big.Int).SetBytes(bytes[32:]) return r, s, nil } // GenerateSignature é uma função auxiliar (para testes): assina tx com chave privada. func (tx *Transaction) GenerateSignature(priv *ecdsa.PrivateKey) string { hash := sha256.Sum256([]byte(fmt.Sprintf("%s:%s:%f:%d:%d", tx.From, tx.To, tx.Value, tx.Nonce, tx.Gas))) r, s, _ := ecdsa.Sign(rand.Reader, priv, hash[:]) return fmt.Sprintf("%064x%064x", r, s) }