Skip to content

Replace Math Random by Using Crypto Random#126

Merged
Laisky merged 4 commits intoLaisky:mainfrom
H0llyW00dzZ:crypto-random
Aug 21, 2025
Merged

Replace Math Random by Using Crypto Random#126
Laisky merged 4 commits intoLaisky:mainfrom
H0llyW00dzZ:crypto-random

Conversation

@H0llyW00dzZ
Copy link
Copy Markdown

@H0llyW00dzZ H0llyW00dzZ commented Aug 21, 2025

  • [+] refactor(random): replace math/rand with crypto/rand for secure random number generation
  • [+] feat(random): add GetRandomString and GetRandomNumberString functions for secure string generation
  • [+] fix(random): update GenerateKey function to use crypto/rand for random character selection

This PR Related #125

Summary by CodeRabbit

  • New Features

    • Added ability to generate custom-length alphanumeric and numeric-only random strings.
  • Refactor

    • All randomness now uses a cryptographically secure source for stronger, non-deterministic results.
    • Key generation updated to combine secure randomness with a UUID-derived segment.
    • Random-range selection updated to use secure randomness for more consistent distributions.
  • Tests

    • Added tests validating uniqueness and distribution of the secure random utilities.

- [+] refactor(random): replace math/rand with crypto/rand for secure random number generation
- [+] feat(random): add GetRandomString and GetRandomNumberString functions for secure string generation
- [+] fix(random): update GenerateKey function to use crypto/rand for random character selection
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Aug 21, 2025

Walkthrough

Replaced math/rand/time seeding with crypto/rand + math/big for all random utilities. GenerateKey now constructs a 48-char key (16 crypto-rand chars + 32 UUID-derived chars). Added GetRandomString and GetRandomNumberString. RandRange now uses crypto/rand. Added tests for uniqueness and distribution.

Changes

Cohort / File(s) Summary of changes
Secure RNG migration & helpers
common/random/main.go
Replaced math/rand/time seeding with crypto/rand + math/big. GenerateKey builds first 16 chars via crypto RNG and appends 32 chars derived from GetUUID() (UUID kept without hyphens; even indices uppercased). Added GetRandomString(length int) and GetRandomNumberString(length int). RandRange(min,max) now uses crypto RNG. Panic-on-error added for RNG failures.
Tests for crypto RNG utilities
common/random/crypto_rand_test.go
New tests in random_test: TestUniqueness (100000 iterations per generator across GetUUID, GenerateKey, GetRandomString(10/20), GetRandomNumberString(10/15) — allows up to 0.1% duplicates for GetRandomNumberString(10)), and TestRandRangeDistribution (100000 iterations validating RandRange(1,10) results and logging per-bucket distribution with 10% tolerance).

Sequence Diagram(s)

sequenceDiagram
  actor Caller
  participant Random as random package
  participant CRand as crypto/rand
  participant UUID as GetUUID

  Caller->>Random: GenerateKey()
  activate Random
  loop 16 times
    Random->>CRand: rand.Int(big.NewInt(len(keyChars)))
    CRand-->>Random: index
    Random->>Random: append keyChars[index]
  end
  Random->>UUID: GetUUID()
  UUID-->>Random: uuid (no hyphens)
  Random->>Random: take/transform 32 UUID chars (uppercase for even indices)
  Random-->>Caller: 48-char key
  deactivate Random
Loading
sequenceDiagram
  actor Caller
  participant Random as random package
  participant CRand as crypto/rand

  Caller->>Random: GetRandomString(n) / GetRandomNumberString(n)
  activate Random
  loop n times
    Random->>CRand: rand.Int(big.NewInt(len(charset)))
    CRand-->>Random: index
    Random->>Random: append charset[index]
  end
  Random-->>Caller: generated string
  deactivate Random

  Caller->>Random: RandRange(min, max)
  activate Random
  Random->>CRand: rand.Int(big.NewInt(max-min))
  CRand-->>Random: offset
  Random-->>Caller: min + offset
  deactivate Random
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Poem

I nibble bits beneath moonlight glow,
I trade the clock for seeds that flow.
Secure and steady, no loose thread—
Crypto carrots warm my bed. 🥕✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9a4e0f5 and 2d8a352.

📒 Files selected for processing (1)
  • common/random/main.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • common/random/main.go
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (3)
common/random/main.go (3)

11-12: Docstring LGTM; minor: prefer strings.ReplaceAll over Replace with -1.

Small readability nit: Replace strings.Replace(..., -1) with strings.ReplaceAll(...).

- code = strings.Replace(code, "-", "", -1)
+ code = strings.ReplaceAll(code, "-", "")

Also applies to: 15-15


31-31: Consider avoiding panics in a library package; return errors instead.

Panic on RNG failures will crash the process (e.g., during request handling). Exposing (string, error) or (int, error) returns, or providing MustXxx wrappers, would be more ergonomic and safer in many contexts.

If you want, I can draft a non-breaking Must-style API alongside error-returning variants.

Also applies to: 55-55, 71-71, 83-83


46-49: Go naming: consider dropping the “Get” prefix.

Idiomatic Go would name these RandomString and RandomNumberString. Not blocking, but worth considering if API stability permits.

Also applies to: 62-65

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between fb1a2a0 and f7cafda.

📒 Files selected for processing (1)
  • common/random/main.go (3 hunks)
🔇 Additional comments (1)
common/random/main.go (1)

22-24: Doc clarity looks good.

The description matches the actual construction (16 random chars + 32 UUID chars => 48 total).

Comment thread common/random/main.go
Comment thread common/random/main.go
Comment thread common/random/main.go
Comment thread common/random/main.go
Comment thread common/random/main.go
- [+] test(crypto_rand): add unit tests for random value generation and distribution
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
common/random/crypto_rand_test.go (1)

53-53: Consider adjusting the duplicate rate threshold.

The 0.1% (0.001) duplicate rate for GetRandomNumberString(10) seems overly strict. With 10 digits and 10 positions, there are 10^10 possible combinations, making duplicates extremely unlikely in 10,000 iterations. The birthday paradox suggests you'd need approximately √(10^10) ≈ 100,000 samples to see meaningful collision probability.

Consider either:

  1. Increasing the duplicate rate threshold to be more realistic
  2. Reducing iterations for this test case
  3. Or simply expect strict uniqueness like the 15-character version
-			allowDupsRate: 0.001, // Allow 0.1% duplicates due to limited numeric space
+			expectedUniq: true, // 10^10 possible combinations make duplicates extremely unlikely
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f7cafda and dc4e329.

📒 Files selected for processing (1)
  • common/random/crypto_rand_test.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
common/random/crypto_rand_test.go (1)
common/random/main.go (5)
  • GetUUID (13-17)
  • GenerateKey (25-44)
  • GetRandomString (49-60)
  • GetRandomNumberString (65-76)
  • RandRange (79-86)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run Tests
🔇 Additional comments (5)
common/random/crypto_rand_test.go (5)

1-7: LGTM! Clean test package structure.

The test package follows Go conventions with proper import organization and clear separation from the implementation package.


9-63: Comprehensive uniqueness testing with proper statistical considerations.

The table-driven test structure effectively covers all random generation functions with appropriate expectations for each. The distinction between strict uniqueness for UUID/GenerateKey and allowable duplicate rates for numeric strings shows good understanding of the mathematical constraints.


65-97: Excellent test execution with clear error reporting.

The test logic correctly tracks duplicates, calculates rates, and provides informative error messages and logging. The conditional checking based on expectedUniq and allowDupsRate handles both strict and probabilistic uniqueness requirements appropriately.


99-136: Well-designed distribution test with proper statistical validation.

The distribution test effectively validates that RandRange produces evenly distributed results within the expected range. The 10% tolerance is reasonable for statistical variation, and the logging provides valuable debugging information.


112-115: RandRange boundary behavior is correct and tests align with implementation
The RandRange function in common/random/main.go (lines 79–86) uses rand.Int(rand.Reader, big.NewInt(int64(max-min))), which returns a value in [0, max-min). Adding min yields a result in [min, max), exactly matching the test’s check in common/random/crypto_rand_test.go. No changes are needed.

- [+] test(crypto_rand): increase iterations from 10,000 to 100,000 for uniqueness tests
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
common/random/crypto_rand_test.go (5)

9-63: Cut test runtime: gate heavy iterations behind testing.Short and reuse a baseIter

Six generators × 100k iterations each triggers millions of crypto/rand draws and large maps, which can slow CI. Make iterations configurable and honor -short.

Apply this diff:

 func TestUniqueness(t *testing.T) {
-	// Table-driven test structure for uniqueness testing
+	// Table-driven test structure for uniqueness testing
+	baseIter := 100_000
+	if testing.Short() {
+		baseIter = 10_000
+	}
 	tests := []struct {
 		name          string
 		generator     func() string
 		iterations    int
 		expectedUniq  bool
 		allowDupsRate float64 // Allow this rate of duplicates (for functions with limited output space)
 	}{
 		{
 			name:         "GetUUID should always generate unique values",
 			generator:    random.GetUUID,
-			iterations:   100000,
+			iterations:   baseIter,
 			expectedUniq: true,
 		},
 		{
 			name:         "GenerateKey should always generate unique values",
 			generator:    random.GenerateKey,
-			iterations:   100000,
+			iterations:   baseIter,
 			expectedUniq: true,
 		},
 		{
 			name: "GetRandomString(10) should generate unique values",
 			generator: func() string {
 				return random.GetRandomString(10)
 			},
-			iterations:   100000,
+			iterations:   baseIter,
 			expectedUniq: true,
 		},
 		{
 			name: "GetRandomString(20) should generate unique values",
 			generator: func() string {
 				return random.GetRandomString(20)
 			},
-			iterations:   100000,
+			iterations:   baseIter,
 			expectedUniq: true,
 		},
 		{
 			name: "GetRandomNumberString(10) should generate mostly unique values",
 			generator: func() string {
 				return random.GetRandomNumberString(10)
 			},
-			iterations:    100000,
+			iterations:    baseIter,
 			expectedUniq:  false,
-			allowDupsRate: 0.001, // Allow 0.1% duplicates due to limited numeric space
+			allowDupsRate: 0.0001, // Allow 0.01% duplicates; generous vs. birthday bound (~0.0005%)
 		},
 		{
 			name: "GetRandomNumberString(15) should generate mostly unique values",
 			generator: func() string {
 				return random.GetRandomNumberString(15)
 			},
-			iterations:   100000,
+			iterations:   baseIter,
 			expectedUniq: true,
 		},
 	}

51-54: Tighten duplicate threshold for 10-digit numeric strings

For 100k samples over 10^10 possibilities, the expected duplicate count is ~0.5 (birthday bound), i.e., ~0.0005% rate. The current 0.1% threshold (≈100 duplicates) is so lax it would miss serious regressions. Suggest 0.01% (≈10 duplicates) to stay extremely safe while still non-flaky.

If you prefer not to touch base iterations, you can apply just this narrower change:

-			allowDupsRate: 0.001, // Allow 0.1% duplicates due to limited numeric space
+			allowDupsRate: 0.0001, // Allow 0.01% duplicates; still far above expectation

67-79: Minor memory win: use map[string]struct{} as a set

Avoids storing booleans and saves a word per entry in large maps.

-			// Use a map to track unique values
-			seen := make(map[string]bool, tt.iterations)
+			// Use a map as a set to track unique values
+			seen := make(map[string]struct{}, tt.iterations)
 			duplicates := 0

 			// Generate values and check for duplicates
 			for i := 0; i < tt.iterations; i++ {
 				val := tt.generator()
-				if seen[val] {
+				if _, ok := seen[val]; ok {
 					duplicates++
 				} else {
-					seen[val] = true
+					seen[val] = struct{}{}
 				}
 			}

99-136: Honor -short and keep the distribution test crisp

This test is solid and non-flaky with a wide 10% tolerance. Still, 100k iterations are heavy. Make it scale down for -short to speed CI.

 func TestRandRangeDistribution(t *testing.T) {
 	// For RandRange, we're more interested in distribution than uniqueness
 	min, max := 1, 10
-	iterations := 100000
+	iterations := 100_000
+	if testing.Short() {
+		iterations = 10_000
+	}

Optional: if you want the test to assert distribution more strictly without flakiness, reduce tolerance to 5% only when iterations >= 100k.


9-97: Add negative tests for RandRange(min,max) invalid inputs

RandRange uses crypto/rand.Int with modulus (max-min); when max <= min this panics via the error path. Add tests to document and lock this behavior.

Proposed additions:

func TestRandRangeInvalidInputs(t *testing.T) {
	t.Parallel()
	cases := [][2]int{
		{0, 0},
		{5, 5},
		{10, 3},
	}
	for _, c := range cases {
		min, max := c[0], c[1]
		func() {
			defer func() {
				if r := recover(); r == nil {
					t.Fatalf("expected panic for RandRange(%d,%d), got none", min, max)
				}
			}()
			_ = random.RandRange(min, max)
		}()
	}
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between dc4e329 and 9a4e0f5.

📒 Files selected for processing (1)
  • common/random/crypto_rand_test.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
common/random/crypto_rand_test.go (1)
common/random/main.go (5)
  • GetUUID (13-17)
  • GenerateKey (25-44)
  • GetRandomString (49-60)
  • GetRandomNumberString (65-76)
  • RandRange (79-86)
🔇 Additional comments (2)
common/random/crypto_rand_test.go (2)

1-7: External tests look good

Using package random_test and importing the module path exercises only the public API and prevents accidental reliance on internals. LGTM.


9-63: Fix invalid for … range loops in common/random/main.go

Two loops in common/random/main.go attempt to range over integer literals, which will not compile. Update them to standard index-based loops:

• In GenerateKey() (around line 27):

-	for i := range 16 {
+	for i := 0; i < 16; i++ {

• In the UUID-to-byte conversion (around line 36):

-	for i := range 32 {
+	for i := 0; i < 32; i++ {

Alternatively, if you meant to loop over the length of a slice (e.g. key or uuid), use for i := range key { … } or for i := range uuid { … }. These changes are required to resolve compile errors.

Likely an incorrect or invalid review comment.

- [+] docs(random.go): update comments to include references for uuid and crypto/rand packages
@Laisky Laisky merged commit 2d8a352 into Laisky:main Aug 21, 2025
2 of 3 checks passed
@H0llyW00dzZ H0llyW00dzZ deleted the crypto-random branch August 22, 2025 03:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants