Files
dejo-node/internal/transactions/validation.go
2025-05-23 10:44:32 -03:00

63 lines
1.8 KiB
Go

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