From 859bd989be2c70b7252dfaea388c4d0815eafa41 Mon Sep 17 00:00:00 2001 From: Savely Krendelhoff Date: Fri, 22 Aug 2025 18:57:48 +0700 Subject: [PATCH] Add pow config --- internal/pow/challenge/config.go | 147 +++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 internal/pow/challenge/config.go diff --git a/internal/pow/challenge/config.go b/internal/pow/challenge/config.go new file mode 100644 index 0000000..c1d8951 --- /dev/null +++ b/internal/pow/challenge/config.go @@ -0,0 +1,147 @@ +package challenge + +import ( + "crypto/rand" + "fmt" + "time" +) + +// Config holds configuration for the PoW system +type Config struct { + DefaultDifficulty int // Default difficulty in bits (e.g., 4) + MaxDifficulty int // Maximum allowed difficulty (e.g., 10) + MinDifficulty int // Minimum allowed difficulty (e.g., 3) + ChallengeTTL time.Duration // Time-to-live for challenges (e.g., 5 minutes) + HMACSecret []byte // Secret key for HMAC signing + Resource string // Resource identifier (e.g., "quotes") + RandomBytes int // Number of random bytes in challenge (e.g., 6) + LoadAdjustmentBits int // Extra difficulty bits when server under load + FailurePenaltyBits int // Extra difficulty bits per failure group + MaxFailurePenaltyBits int // Maximum failure penalty bits +} + +// configOption represents a functional option for Config +type configOption func(*Config) + +// WithDefaultDifficulty sets the default difficulty +func WithDefaultDifficulty(difficulty int) configOption { + return func(c *Config) { + c.DefaultDifficulty = difficulty + } +} + +// WithMaxDifficulty sets the maximum difficulty +func WithMaxDifficulty(difficulty int) configOption { + return func(c *Config) { + c.MaxDifficulty = difficulty + } +} + +// WithMinDifficulty sets the minimum difficulty +func WithMinDifficulty(difficulty int) configOption { + return func(c *Config) { + c.MinDifficulty = difficulty + } +} + +// WithChallengeTTL sets the challenge time-to-live +func WithChallengeTTL(ttl time.Duration) configOption { + return func(c *Config) { + c.ChallengeTTL = ttl + } +} + +// WithHMACSecret sets the HMAC secret +func WithHMACSecret(secret []byte) configOption { + return func(c *Config) { + c.HMACSecret = secret + } +} + +// WithResource sets the resource identifier +func WithResource(resource string) configOption { + return func(c *Config) { + c.Resource = resource + } +} + +// WithRandomBytes sets the number of random bytes +func WithRandomBytes(bytes int) configOption { + return func(c *Config) { + c.RandomBytes = bytes + } +} + +// WithLoadAdjustmentBits sets the load adjustment bits +func WithLoadAdjustmentBits(bits int) configOption { + return func(c *Config) { + c.LoadAdjustmentBits = bits + } +} + +// WithFailurePenaltyBits sets the failure penalty bits +func WithFailurePenaltyBits(bits int) configOption { + return func(c *Config) { + c.FailurePenaltyBits = bits + } +} + +// WithMaxFailurePenaltyBits sets the maximum failure penalty bits +func WithMaxFailurePenaltyBits(bits int) configOption { + return func(c *Config) { + c.MaxFailurePenaltyBits = bits + } +} + +// NewConfig creates and validates a new PoW configuration with defaults +func NewConfig(opts ...configOption) (*Config, error) { + // Generate default HMAC secret + secret := make([]byte, 32) + rand.Read(secret) + + // Create config with defaults + config := &Config{ + DefaultDifficulty: 4, + MaxDifficulty: 10, + MinDifficulty: 3, + ChallengeTTL: 5 * time.Minute, + HMACSecret: secret, + Resource: "quotes", + RandomBytes: 6, + LoadAdjustmentBits: 1, + FailurePenaltyBits: 2, + MaxFailurePenaltyBits: 6, + } + + // Apply options + for _, opt := range opts { + opt(config) + } + + // Validate configuration + if config.RandomBytes <= 0 || config.RandomBytes > 32 { + return nil, fmt.Errorf("%w: random bytes must be between 1-32, got %d", ErrInvalidConfig, config.RandomBytes) + } + + if config.MinDifficulty < 1 { + return nil, fmt.Errorf("%w: minimum difficulty must be >= 1, got %d", ErrInvalidConfig, config.MinDifficulty) + } + + if config.MaxDifficulty < config.MinDifficulty { + return nil, fmt.Errorf("%w: maximum difficulty (%d) must be >= minimum difficulty (%d)", ErrInvalidConfig, config.MaxDifficulty, config.MinDifficulty) + } + + if config.DefaultDifficulty < config.MinDifficulty || config.DefaultDifficulty > config.MaxDifficulty { + return nil, fmt.Errorf("%w: default difficulty (%d) must be between min (%d) and max (%d)", ErrInvalidConfig, config.DefaultDifficulty, config.MinDifficulty, config.MaxDifficulty) + } + + if len(config.HMACSecret) == 0 { + return nil, fmt.Errorf("%w: HMAC secret cannot be empty", ErrInvalidConfig) + } + + if config.ChallengeTTL <= 0 { + return nil, fmt.Errorf("%w: challenge TTL must be positive, got %v", ErrInvalidConfig, config.ChallengeTTL) + } + + return config, nil +}