Skip to content

Conversation

@Vishalkulkarni45
Copy link
Collaborator

@Vishalkulkarni45 Vishalkulkarni45 commented Aug 15, 2025

DRAFT

Summary by CodeRabbit

  • New Features

    • Go SDK for verifying Self attestations with on‑chain checks and config-driven validations (age, OFAC, country exclusions), plus a BackendVerifier API.
    • Centralized 3‑letter country codes, endpoint hashing, and revealed-data unpack/format utilities.
    • Added contract ABIs and client bindings to support verification on mainnet/testnet.
    • In‑memory and pluggable config stores with action‑ID support.
  • Documentation

    • README with setup, API overview, and examples.
  • Tests

    • Verifier tests with a mock config store.
  • Chores

    • Go module and example apps added.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 15, 2025

Walkthrough

Adds a new Go SDK: country code constants, Poseidon-based hashing and endpoint formatting, packed-data utilities, contract ABIs and go-ethereum bindings, verifier implementations (public and internal), config stores (default and in-memory), examples, tests, and module metadata for verification workflows.

Changes

Cohort / File(s) Summary of changes
Common: constants & helpers
sdk/sdk-go/common/constants.go, sdk/sdk-go/common/customHash.go, sdk/sdk-go/common/utils.go
New Country3LetterCode type and many 3-letter country constants (one anomalous D = "D<<"); Poseidon hashing utilities, endpoint formatting, string→big.Int conversion, and UnpackReveal for packed reveal data.
Contract ABIs
sdk/sdk-go/contracts/abi/IdentityVerificationHubImpl.abi, sdk/sdk-go/contracts/abi/Registry.abi, sdk/sdk-go/contracts/abi/Verifier.abi
Added ABI JSON files defining view functions for IdentityVerificationHubImpl, Registry, and Verifier contracts.
Contract bindings (generated)
sdk/sdk-go/contracts/bindings/IdentityVerificationHubImpl.go, sdk/sdk-go/contracts/bindings/Registry.go, sdk/sdk-go/contracts/bindings/Verifier.go
Auto-generated go-ethereum contract bindings exposing constructors, caller/transactor/filterer types and typed methods for the ABIs.
Core SDK types & API
sdk/sdk-go/types.go, sdk/sdk-go/utils.go, sdk/sdk-go/verifier.go, sdk/sdk-go/sdk.go
Public types (AttestationId, proofs, VerificationConfig, results), data parsing/formatting utilities, BackendVerifier implementation and Verify flow, SDK Version constant.
Internal verifier & tests
sdk/sdk-go/internal/selfBackendVerifier.go, sdk/sdk-go/internal/selfBackendVerifier_test.go
Internal SelfBackendVerifier with on-/off-chain verification flow, config-mismatch error model, and unit tests + mock ConfigStore and fixtures.
Config stores
sdk/sdk-go/config.go, sdk/sdk-go/InMemoryConfigStore.go
ConfigStore interface; DefaultConfigStore (single-config) and InMemoryConfigStore with pluggable GetActionIdFunc implementation.
Examples
sdk/sdk-go/examples/basic/*, sdk/sdk-go/examples/custom-config/*
Two example projects demonstrating default and custom config stores and verifier initialization; example main.go files and example module manifests.
Module & docs
sdk/sdk-go/go.mod, sdk/sdk-go/README.md
New go.mod with dependencies and README documenting the Go SDK, APIs, and usage.

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant BackendVerifier
  participant Hub as IdentityVerificationHubImpl
  participant Registry
  participant Verifier as ZK_Verifier

  App->>BackendVerifier: Verify(attestationId, proof, pubSignals, userContextData)
  BackendVerifier->>BackendVerifier: Normalize signals, parse IDs, hash user context & scope
  BackendVerifier->>Hub: DiscloseVerifier(attestationId)
  Hub-->>BackendVerifier: verifierAddress
  BackendVerifier->>Hub: Registry(attestationId)
  Hub-->>BackendVerifier: registryAddress
  BackendVerifier->>Registry: checkIdentityCommitmentRoot(root)
  Registry-->>BackendVerifier: bool
  BackendVerifier->>Verifier: VerifyProof(a,b,c,pubSignals[21])
  Verifier-->>BackendVerifier: bool
  BackendVerifier->>BackendVerifier: Apply config checks (age, countries, OFAC, timestamp)
  BackendVerifier-->>App: VerificationResult or ConfigMismatchError
Loading
sequenceDiagram
  participant Util as common.HashEndpointWithScope
  Util->>Util: FormatEndpoint(endpoint)
  Util->>Util: Chunk domain (<=16, 31 chars)
  Util->>Util: StringToBigInt(each chunk)
  Util->>Util: FlexiblePoseidon(chunk BigInts)
  Util->>Util: StringToBigInt(scope)
  Util->>Util: poseidon.Hash(endpointHash, scopeBigInt)
  Util-->>Caller: hash string
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • remicolin
  • Nesopie

Poem

New codes whispered in three-letter strands,
Endpoints chopped to Poseidon's hands.
ABIs sing, bindings take their place,
Verifiers race the on-chain race.
Configs and tests in tidy rows—🎉 code grows.

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.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/go-core

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.

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
Contributor

@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: 20

🧹 Nitpick comments (17)
sdk/sdk-go/go.mod (1)

3-5: Use a valid go directive (omit patch) and keep the toolchain pin if intended.

The go directive should be major.minor only. The toolchain directive is fine if you want to enforce a minimum patch at build time.

Apply:

-go 1.23.0
+go 1.23

If you don’t intend to enforce a specific patch for downstream consumers, consider dropping Line [5] (toolchain) to reduce friction for users on newer/older 1.23.x:

-toolchain go1.23.12
sdk/sdk-go/common/customHash.go (2)

75-80: Fail fast on empty endpoint after formatting

If the endpoint is empty (or malformed) after normalization, FlexiblePoseidon will be called with 0 inputs and error. Make this explicit with a clearer error.

Apply this diff:

 func HashEndpointWithScope(endpoint, scope string) (string, error) {
 	formattedEndpoint := FormatEndpoint(endpoint)
 
+	if formattedEndpoint == "" {
+		return "", fmt.Errorf("endpoint cannot be empty or malformed")
+	}
+
 	// Split endpoint into 31-character chunks (different from ts)

77-81: Clarify comment about chunking

The “(different from ts)” note is confusing and risks future divergence. If this is intended to mirror TS behavior for 31 ASCII chars per chunk, make the comment explicit.

Apply this diff:

-	// Split endpoint into 31-character chunks (different from ts)
+	// Split endpoint into 31 ASCII-character chunks (31 bytes per chunk)
sdk/sdk-go/internal/utils/hash.go (1)

33-36: Zero-padding logic is unnecessary and currently pads with spaces, not zeros

RIPEMD-160 returns 20 bytes, so fmt.Sprintf("%x", ripemdHash) will always produce 40 hex chars; no padding needed. Also, "%040s" pads with spaces for string verbs.

Simplify by removing the padding block.

Apply this diff:

-	// Pad with leading zeros to ensure 40 hex chars
-	if len(hexString) < 40 {
-		hexString = fmt.Sprintf("%040s", hexString)
-	}
sdk/sdk-go/internal/utils/utils.go (1)

19-47: Straightforward unpacking logic; consider minor perf/readability tweaks

  • trimU0000 and 3-char chunking are clear and correct given UnpackReveal returns single-char strings.
  • Minor optional improvements:
    • Preallocate countries slice with capacity len(joined)/3.
    • Early-return if joined length < 3 to avoid looping.

Apply this diff:

 func UnpackForbiddenCountriesList(forbiddenCountriesListPacked []string) []string {
 	// Unpack the revealed data using the unpackReveal function
 	unpacked := common.UnpackReveal(forbiddenCountriesListPacked, "id")
 	trimmed := trimU0000(unpacked)
 
-	var countries []string
+	// Preallocate roughly to reduce reallocations
+	var countries []string
 
 	// Join all trimmed strings to work with characters
 	joined := strings.Join(trimmed, "")
 
+	if len(joined) < 3 {
+		return countries
+	}
+	countries = make([]string, 0, len(joined)/3)
+
 	// Extract 3-character country codes
 	for i := 0; i < len(joined); i += 3 {
 		if i+3 <= len(joined) {
 			countryCode := joined[i : i+3]
 			if len(countryCode) == 3 {
 				countries = append(countries, countryCode)
 			}
 		}
 	}
 
 	return countries
 }
sdk/sdk-go/common/utils.go (4)

13-14: Inconsistent comment case and missing parameter documentation

The comment uses lowercase "unpackReveal" while the function name is "UnpackReveal". Additionally, the comment should document the parameters and return value for better clarity.

-// unpackReveal unpacks revealed data from packed format
+// UnpackReveal unpacks revealed data from packed format.
+// It accepts revealedDataPacked as either a string or []string and idType to determine byte counts.
+// Returns a slice of single-character strings extracted from the packed data.

27-31: Consider using constants for byte counts

The hardcoded byte count arrays should be defined as constants or in a configuration to improve maintainability and avoid magic numbers.

Consider extracting these values to package-level constants:

const (
    PassportByteCounts = []int{31, 31, 31}
    IDByteCounts = []int{31, 31, 31, 31}
)

44-44: Use predefined constant for byte mask

The byte mask value could be defined as a package-level variable to avoid repeated allocation.

+var byteMask = big.NewInt(0xFF)

 func UnpackReveal(revealedDataPacked interface{}, idType string) []string {
     // ... existing code ...
-    byteMask := big.NewInt(255) // 0xFF
     // ... rest of function using byteMask ...

56-59: Consider filtering out null characters

The function converts byte values directly to runes without filtering null bytes (0x00), which might produce unexpected null characters in the output strings.

 // Convert bytes to characters
 var result []string
 for _, byteVal := range bytesArray {
-    result = append(result, string(rune(byteVal)))
+    if byteVal != 0 { // Skip null bytes
+        result = append(result, string(rune(byteVal)))
+    }
 }
sdk/sdk-go/internal/utils/id.go (1)

93-96: Optimize regex compilation

The regex is compiled on every function call. Consider compiling it once at package initialization for better performance.

+var cleanNameRegex = regexp.MustCompile(`([A-Z])<+([A-Z])`)

 func cleanName(nameRaw string) string {
-    // Replace pattern ([A-Z])<+([A-Z]) with '$1 $2'
-    re1 := regexp.MustCompile(`([A-Z])<+([A-Z])`)
-    name := re1.ReplaceAllString(nameRaw, "$1 $2")
+    name := cleanNameRegex.ReplaceAllString(nameRaw, "$1 $2")
sdk/sdk-go/internal/selfBackendVerifier_test.go (3)

17-20: MockConfigStore should be unexported for test isolation

The MockConfigStore type is exported but only used for testing. Consider making it unexported to prevent misuse.

-// MockConfigStore implements ConfigStore interface for testing
-type MockConfigStore struct {
+// mockConfigStore implements ConfigStore interface for testing
+type mockConfigStore struct {
     configs   map[string]types.VerificationConfig
     actionIds map[string]string
 }

Also update the method receivers accordingly.


46-89: Consider extracting test data to a separate file

The large test proof and public signals data could be moved to a separate test data file or constants file for better organization and reusability across tests.

Would you like me to help create a separate testdata.go file to organize these test constants?


99-108: Add validation for UUID format

The castToUUID function doesn't validate that the resulting string is a valid UUID format.

 func castToUUID(bigInt *big.Int) string {
     hexStr := bigInt.Text(16) // Convert to hex without 0x prefix
     // Pad to 32 characters (16 bytes = 32 hex chars)
     if len(hexStr) < 32 {
         hexStr = fmt.Sprintf("%032s", hexStr)
     }
+    if len(hexStr) > 32 {
+        hexStr = hexStr[len(hexStr)-32:] // Take last 32 chars
+    }
     // Format as UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
     return fmt.Sprintf("%s-%s-%s-%s-%s",
         hexStr[0:8], hexStr[8:12], hexStr[12:16], hexStr[16:20], hexStr[20:32])
 }
sdk/sdk-go/internal/utils/proof.go (1)

87-90: Potential integer overflow when converting to int

Converting byteVal.Int64() to int could potentially overflow on 32-bit systems where int is 32 bits.

 // Extract the least significant byte (equivalent to publicSignal & 0xffn)
 byteVal := new(big.Int)
 byteVal.And(publicSignal, big.NewInt(0xff))
-bytes = append(bytes, int(byteVal.Int64()))
+// Byte values are always 0-255, safe to convert
+bytes = append(bytes, int(byteVal.Uint64()))
sdk/sdk-go/internal/types/types.go (1)

38-51: Consider using pointers for optional fields in GenericDiscloseOutput

Since most fields in GenericDiscloseOutput represent optional disclosed information that may not always be present, consider using pointer types for these fields. This would provide a clearer API where nil explicitly indicates "not disclosed" versus an empty string which could be ambiguous.

 type GenericDiscloseOutput struct {
-	Nullifier                    string   `json:"nullifier"`
-	ForbiddenCountriesListPacked []string `json:"forbiddenCountriesListPacked"`
-	IssuingState                 string   `json:"issuingState"`
-	Name                         string   `json:"name"`
-	IdNumber                     string   `json:"idNumber"`
-	Nationality                  string   `json:"nationality"`
-	DateOfBirth                  string   `json:"dateOfBirth"`
-	Gender                       string   `json:"gender"`
-	ExpiryDate                   string   `json:"expiryDate"`
-	MinimumAge                   string   `json:"minimumAge"`
-	Ofac                         []bool   `json:"ofac"`
+	Nullifier                    string   `json:"nullifier"`
+	ForbiddenCountriesListPacked []string `json:"forbiddenCountriesListPacked"`
+	IssuingState                 *string  `json:"issuingState,omitempty"`
+	Name                         *string  `json:"name,omitempty"`
+	IdNumber                     *string  `json:"idNumber,omitempty"`
+	Nationality                  *string  `json:"nationality,omitempty"`
+	DateOfBirth                  *string  `json:"dateOfBirth,omitempty"`
+	Gender                       *string  `json:"gender,omitempty"`
+	ExpiryDate                   *string  `json:"expiryDate,omitempty"`
+	MinimumAge                   *string  `json:"minimumAge,omitempty"`
+	Ofac                         []bool   `json:"ofac"`
 }
sdk/sdk-go/common/constants.go (2)

3-3: Add a doc comment for the exported type to satisfy linters and improve clarity

Go tooling expects documentation for exported identifiers. This clarifies the expected format (ISO 3166-1 alpha-3) for downstream users.

- type Country3LetterCode string
+// Country3LetterCode represents an ISO 3166-1 alpha-3 country code (e.g., "USA", "DEU").
+type Country3LetterCode string

5-256: Consider adding validation helpers and/or code generation to avoid drift and runtime errors

Right now these are raw constants; any arbitrary string could still be accepted elsewhere as Country3LetterCode. Providing a small validation API and optionally generating the list from a canonical source reduces typos and keeps SDKs across languages in sync.

Options:

  • Minimal: provide a helper to check shape and membership.
  • Robust: generate constants + membership set via go:generate from ISO 3166 data to avoid manual drift and discrepancies between SDKs.

Example minimal addition (can live below this const block in the same file or a new helpers file):

// ValidCountry3 is a set for O(1) membership checks.
var ValidCountry3 = map[Country3LetterCode]struct{}{
	AFG: {}, ALA: {}, ALB: {}, DZA: {}, ASM: {}, AND: {}, AGO: {}, AIA: {}, ATA: {}, ATG: {},
	ARG: {}, ARM: {}, ABW: {}, AUS: {}, AUT: {}, AZE: {}, BHS: {}, BHR: {}, BGD: {}, BRB: {},
	// ... continue with the rest of the defined constants ...
	ZMB: {}, ZWE: {},
}

// IsValid reports whether c is one of the enumerated ISO alpha-3 codes.
func (c Country3LetterCode) IsValid() bool {
	_, ok = ValidCountry3[c]
	return ok
}

If you prefer generation, I can sketch a go:generate pipeline that pulls ISO data and emits both constants and the set to guarantee fidelity.

📜 Review details

Configuration used: .coderabbit.yaml
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 d33e329 and 7c4618f.

⛔ Files ignored due to path filters (1)
  • sdk/sdk-go/go.sum is excluded by !**/*.sum
📒 Files selected for processing (21)
  • sdk/sdk-go/common/constants.go (1 hunks)
  • sdk/sdk-go/common/customHash.go (1 hunks)
  • sdk/sdk-go/common/utils.go (1 hunks)
  • sdk/sdk-go/contracts/IdentityVerificationHubImpl.abi (1 hunks)
  • sdk/sdk-go/contracts/Registry.abi (1 hunks)
  • sdk/sdk-go/contracts/Verifier.abi (1 hunks)
  • sdk/sdk-go/contracts/abi/IdentityVerificationHubImpl.abi (1 hunks)
  • sdk/sdk-go/contracts/abi/Registry.abi (1 hunks)
  • sdk/sdk-go/contracts/abi/Verifier.abi (1 hunks)
  • sdk/sdk-go/contracts/bindings/IdentityVerificationHubImpl.go (1 hunks)
  • sdk/sdk-go/contracts/bindings/Registry.go (1 hunks)
  • sdk/sdk-go/contracts/bindings/Verifier.go (1 hunks)
  • sdk/sdk-go/go.mod (1 hunks)
  • sdk/sdk-go/internal/selfBackendVerifier.go (1 hunks)
  • sdk/sdk-go/internal/selfBackendVerifier_test.go (1 hunks)
  • sdk/sdk-go/internal/types/types.go (1 hunks)
  • sdk/sdk-go/internal/utils/constants.go (1 hunks)
  • sdk/sdk-go/internal/utils/hash.go (1 hunks)
  • sdk/sdk-go/internal/utils/id.go (1 hunks)
  • sdk/sdk-go/internal/utils/proof.go (1 hunks)
  • sdk/sdk-go/internal/utils/utils.go (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (7)
sdk/sdk-go/internal/utils/id.go (3)
sdk/sdk-go/internal/types/types.go (2)
  • AttestationId (9-9)
  • GenericDiscloseOutput (39-51)
sdk/sdk-go/internal/utils/proof.go (2)
  • PublicSignals (12-12)
  • GetRevealedDataBytes (55-97)
sdk/sdk-go/internal/utils/constants.go (10)
  • DiscloseIndices (26-53)
  • RevealedDataIndices (88-129)
  • IssuingState (56-56)
  • Name (57-57)
  • IdNumber (58-58)
  • Nationality (59-59)
  • DateOfBirth (60-60)
  • Gender (61-61)
  • ExpiryDate (62-62)
  • Ofac (64-64)
sdk/sdk-go/internal/utils/utils.go (1)
sdk/sdk-go/common/utils.go (1)
  • UnpackReveal (14-62)
sdk/sdk-go/internal/utils/proof.go (2)
sdk/sdk-go/internal/types/types.go (1)
  • AttestationId (9-9)
sdk/sdk-go/internal/utils/constants.go (3)
  • AttestationId1 (8-8)
  • AttestationId2 (9-9)
  • DiscloseIndices (26-53)
sdk/sdk-go/contracts/bindings/IdentityVerificationHubImpl.go (1)
sdk/sdk-go/contracts/bindings/Registry.go (1)
  • Registry (42-46)
sdk/sdk-go/internal/types/types.go (1)
sdk/sdk-go/internal/utils/constants.go (8)
  • Ofac (64-64)
  • IssuingState (56-56)
  • Name (57-57)
  • IdNumber (58-58)
  • Nationality (59-59)
  • DateOfBirth (60-60)
  • Gender (61-61)
  • ExpiryDate (62-62)
sdk/sdk-go/internal/selfBackendVerifier_test.go (4)
sdk/sdk-go/internal/utils/constants.go (1)
  • Ofac (64-64)
sdk/sdk-go/internal/selfBackendVerifier.go (2)
  • NewSelfBackendVerifier (91-134)
  • ConfigMismatchError (59-61)
sdk/sdk-go/internal/types/types.go (1)
  • UserIDTypeUUID (66-66)
sdk/sdk-go/internal/utils/hash.go (1)
  • CalculateUserIdentifierHash (20-39)
sdk/sdk-go/internal/utils/constants.go (1)
sdk/sdk-go/internal/types/types.go (1)
  • AttestationId (9-9)
🔇 Additional comments (17)
sdk/sdk-go/contracts/Verifier.abi (1)

1-36: Confirm pubSignals length (21) in ABI & bindings — verify circuit ordering matches

I ran the checks you suggested. The ABI and generated Go bindings consistently use 21 public signals, but you should confirm the circuit's public-output ordering matches the SDK unpacking.

Files to check (found by ripgrep):

  • sdk/sdk-go/contracts/Verifier.abi — "uint256[21]" (lines ~20,22)
  • sdk/sdk-go/contracts/abi/Verifier.abi — "uint256[21]" (lines ~20,22)
  • sdk/sdk-go/contracts/bindings/Verifier.go — VerifyProof signatures expect pubSignals [21]*big.Int (lines ~186, 203, 210)
  • sdk/sdk-go/internal/selfBackendVerifier.go — var publicSignalsArray [21]*big.Int (line ~332)

Note: abigen generates a compile-time fixed [21]*big.Int — if your circuit or unpacker uses a different count or ordering, update the ABI and re-run abigen (and adjust unpacking) to avoid runtime/compile errors.

sdk/sdk-go/go.mod (1)

13-35: Action: run go mod tidy inside sdk/sdk-go and confirm the heavy indirect deps weren't promoted

Automated check failed here — go.mod wasn't found (script didn't cd into sdk/sdk-go). Please run this locally and confirm:

# from repo root
cd sdk/sdk-go
go mod tidy -v
go mod graph | rg -nP 'github.com/gorilla/websocket|github.com/go-ole/go-ole|github.com/StackExchange/wmi|github.com/Microsoft/go-winio|github.com/consensys/gnark-crypto'

Checks to perform

  • Inspect sdk/sdk-go/go.mod (lines ~13-35): ensure the listed deps remain marked with // indirect (i.e., not promoted to direct requires).
  • If go mod tidy removed unused entries, that’s fine—no action needed.
  • If any heavy platform-specific or crypto libs were promoted to direct but are unused, drop the require (or revert) and run go mod tidy again.

If you paste the go mod graph output here I’ll re-check.

sdk/sdk-go/common/customHash.go (1)

12-27: LGTM: FlexiblePoseidon input validation and error wrapping are solid

  • Bounds [1..16] inputs are enforced.
  • Errors from poseidon.Hash are properly wrapped.
sdk/sdk-go/contracts/bindings/Verifier.go (2)

1-7: Do not hand-edit generated code; re-generate if ABI changes

Header is present and clear. If ABIs evolve, please re-run abigen to avoid drift.


183-199: Generated binding OK — pubSignals length = 21 matches ABI / circuits

Quick verdict: I checked the repo: the generated Go binding uses pubSignals [21]*big.Int and the ABI, Solidity verifiers, interfaces and tests consistently declare uint256[21] / uint[21]. No mismatch found.

Key evidence (paths):

  • sdk/sdk-go/contracts/bindings/Verifier.go — VerifyProof(... pubSignals [21]*big.Int)
  • sdk/sdk-go/contracts/Verifier.abi and sdk/core/src/abi/Verifier.json — ABI declares uint256[21]
  • contracts/contracts/verifiers/disclose/Verifier_vc_and_disclose.sol & Verifier_vc_and_disclose_id.sol — declare uint[21] calldata _pubSignals
  • contracts/contracts/interfaces/IVcAndDiscloseCircuitVerifier.sol and ISelfVerificationRoot.sol — interface types use uint[21]/uint256[21]
  • contracts/test/v2/disclose*.test.ts — tests construct/use pubSignals as uint256[21]

Small actionable note:

  • Higher-level code often uses dynamic slices (e.g. sdk/sdk-go/internal/selfBackendVerifier.go uses []*big.Int, TS uses BigNumberish[]). If you call the generated Go VerifyProof, validate length and convert the slice to a fixed [21]*big.Int (slices do not implicitly convert to fixed-size arrays).
sdk/sdk-go/contracts/IdentityVerificationHubImpl.abi (1)

1-40: ABI entries look correct for read-only accessors

  • Both functions are view and typed as expected: (bytes32) -> address.
  • Matches typical hub pattern (discloseVerifier, registry).
sdk/sdk-go/internal/utils/hash.go (1)

20-39: LGTM overall; hashing pipeline (SHA-256 -> RIPEMD-160) is deterministic and efficient

  • Write calls on hash.Hash don’t return errors; safe to ignore.
  • Output format 0x-prefixed hex is consistent.
sdk/sdk-go/internal/utils/utils.go (1)

4-4: Verify import path matches your module path

I couldn't confirm the module path because the repo check didn't find a usable go.mod (script output showed "go.mod: No such file or directory"), so I can't verify whether the import "self-sdk-go/common" is valid. Please confirm and fix if needed.

  • Location to check:

    • sdk/sdk-go/internal/utils/utils.go — import: "self-sdk-go/common" (around line 4)
  • Action required:

    • Confirm the module path in go.mod. If the module is e.g. github.com/owner/repo, the import should be "github.com/owner/repo/sdk/sdk-go/common". If the module is literally "self-sdk-go" then the current import is fine.
    • Update the import to match the module path (or add an appropriate go.mod/replace if this is a multi-module layout).
  • Commands to run locally to verify:

    • sed -n '1,5p' go.mod
    • find . -name 'go.mod' -print -exec sed -n '1,5p' {} ;
    • rg -n '"self-sdk-go/common"' -S || true
sdk/sdk-go/contracts/abi/IdentityVerificationHubImpl.abi (1)

1-40: LGTM! Well-structured ABI definition

The ABI correctly defines two view functions for querying the disclose verifier and registry addresses. The structure follows the standard Ethereum ABI format with appropriate type definitions and state mutability settings.

sdk/sdk-go/internal/utils/constants.go (2)

26-53: Confirm intention: PassportNoSmtRootIndex = 99 in AttestationId2

I searched the repo for usages and bounds checks. I only found the declaration in the constants map — no other references that justify 99 as a valid index. Absence of usages is inconclusive, so please confirm.

  • File to inspect: sdk/sdk-go/internal/utils/constants.go
    • AttestationId1 — PassportNoSmtRootIndex: 16 (line ~38)
    • AttestationId2 — PassportNoSmtRootIndex: 99 (line ~51)

Action requested (pick one):

  • If 99 is accidental, replace with the correct index and run tests.
  • If 99 is an intentional sentinel, replace it with a named constant (e.g., PassportNoSmtRootMissing) and document why it’s out of normal range; also ensure any code that consumes these indices checks bounds or handles the sentinel.

I couldn’t find any code that already does those checks — please verify and apply the appropriate fix or add a comment/constant to make the intent explicit.


88-129: Revealed data indices verified — differences are intentional and align with circuit packing

Checked the Go constants, unpacking logic, circuits and contract/TS extractors — the differing start/end offsets correspond to different revealedData layouts (passport vs ID) and are correct.

Evidence:

  • sdk/sdk-go/internal/utils/constants.go — RevealedDataIndices mapping (AttestationId1 vs AttestationId2).
  • sdk/sdk-go/internal/utils/proof.go — BytesCount and GetRevealedDataPublicSignalsLength (93 vs 94 bytes) and GetRevealedDataBytes unpack loop.
  • circuits/circuits/utils/passport/disclose/disclose.circom and disclose_id.circom — revealedData lengths and explicit indices for older_than and OFAC flags (PackBytes(93) vs PackBytes(94)).
  • contracts/contracts/libraries/SelfCircuitLibrary.sol — extraction helpers using Formatter.fieldElementsToBytes that rely on the same layout.
  • sdk/core/src/utils/constants.ts and sdk/core/src/utils/id.ts — TypeScript counterparts using identical slices.

Conclusion: no bug found in the index values — no code change required. (Optional: add a short comment in constants.go pointing to the circom source-of-truth and/or add a defensive bounds check before slicing to avoid panics if inputs change.)

sdk/sdk-go/contracts/bindings/Registry.go (2)

1-2: Good use of code generation for contract bindings

The auto-generated bindings ensure type safety and reduce manual errors when interacting with smart contracts. The warning about manual changes is appropriately placed.


186-197: Consistent error handling in CheckIdentityCommitmentRoot

The error handling correctly returns a zero value along with the error, following Go conventions. The ABI type conversion is properly handled.

sdk/sdk-go/internal/selfBackendVerifier.go (2)

544-591: Well-structured timestamp validation logic

The timestamp validation correctly handles the date component extraction from the circuit's YYMMDD format and appropriately checks for both future and past timestamps with a 1-day tolerance. The comments explaining the date indexing differences between JavaScript and Go are helpful.


253-306: Improve error handling for user context data extraction

The function continues processing even after detecting that userContextData is too short. This could lead to panic or unexpected behavior when trying to extract substrings.

 	if len(userContextData) < 128 {
 		issues = append(issues, ConfigIssue{
 			Type:    ConfigNotFound,
 			Message: "userContextData too short",
 		})
+		// Early return or skip further processing to avoid index out of bounds
+		if len(issues) > 0 {
+			return nil, NewConfigMismatchError(issues)
+		}
 	} else {

Likely an incorrect or invalid review comment.

sdk/sdk-go/contracts/bindings/IdentityVerificationHubImpl.go (2)

1-2: Auto-generated code properly marked

The file is correctly marked as auto-generated with appropriate warnings about manual changes.


183-198: Consistent error handling patterns in contract methods

Both DiscloseVerifier and Registry methods follow consistent error handling patterns, properly returning zero values on error and using ABI type conversion correctly.

Also applies to: 214-229

GMB Country3LetterCode = "GMB" // Gambia
GEO Country3LetterCode = "GEO" // Georgia
DEU Country3LetterCode = "DEU" // Germany
D Country3LetterCode = "D<<" // Germany (Bundesrepublik Deutschland passport format)
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Remove anomalous non-ISO code D = "D<<" to prevent misuse and confusion

This exported constant deviates from ISO 3166-1 alpha-3 (three uppercase letters), introduces ambiguous naming, and could leak into UI/templating paths where angle brackets become problematic. If MRZ-specific tokens are needed, model them with a separate type in a dedicated MRZ module rather than mixing them into ISO country codes.

Apply this diff to remove the invalid constant:

-	D   Country3LetterCode = "D<<" // Germany (Bundesrepublik Deutschland passport format)

To proactively catch similar issues project-wide, you can verify no usages exist:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Searching for anomalous MRZ token and symbol usage..."
# 1) Direct string usage
rg -nP -C2 '"D<<"' || true
# 2) Symbol usage if imported as common.D
rg -nP -C2 '\bcommon\.D\b' || true
# 3) Sanity check: find any Country3LetterCode const values not matching ^[A-Z]{3}$
python - << 'PY'
import re, sys, pathlib
p = pathlib.Path("sdk/sdk-go/common/constants.go")
src = p.read_text(encoding="utf-8")
bad = []
for i, line in enumerate(src.splitlines(), 1):
    m = re.match(r'^\s*([A-Z0-9_]+)\s+Country3LetterCode\s*=\s*"([^"]+)"', line)
    if m:
        name, val = m.group(1), m.group(2)
        if not re.fullmatch(r'[A-Z]{3}', name) or not re.fullmatch(r'[A-Z]{3}', val):
            bad.append((i, name, val))
if bad:
    print("Found non-ISO alpha-3 entries (line, name, value):")
    for b in bad:
        print(b)
    sys.exit(1)
else:
    print("OK: All constants conform to ^[A-Z]{3}$")
PY

Length of output: 702


Remove anomalous non‑ISO constant D = "D<<" from sdk/sdk-go/common/constants.go

This constant is not a valid ISO 3166‑1 alpha‑3 code (it's an MRZ token) and should not live in the exported Country3LetterCode set — it risks confusion and templating/escaping issues.

Findings

  • File: sdk/sdk-go/common/constants.go — line 90: D Country3LetterCode = "D<<" (only occurrence found).
  • Verification: ripgrep + sanity check flagged only that line; no other references to "D<<" or common.D were found.

Apply this removal diff:

-	D   Country3LetterCode = "D<<" // Germany (Bundesrepublik Deutschland passport format)

Recommended fixes (pick one)

  • Remove the line (safe: no usages found).
  • OR move MRZ tokens into a dedicated MRZ package (e.g., sdk/sdk-go/mrz) and model them with a distinct type (e.g., type MRZToken string) and clear names like MRZ_GER = "D<<".

Quick note: since no references were found, removing or relocating this constant is a low‑risk, high‑clarity fix.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
D Country3LetterCode = "D<<" // Germany (Bundesrepublik Deutschland passport format)
🤖 Prompt for AI Agents
In sdk/sdk-go/common/constants.go around line 90, the exported
Country3LetterCode set contains an anomalous non‑ISO constant `D  
Country3LetterCode = "D<<"` which is an MRZ token and should be removed; delete
that line from the file, run go fmt/golangci-lint or your repo’s
formatting/linting, run unit tests/compile to verify no references break, and if
you prefer to keep MRZ tokens later, create a separate package (e.g.,
sdk/sdk-go/mrz) with a distinct type (type MRZToken string) and clearly named
constants like MRZ_GER = "D<<" instead of adding them to Country3LetterCode.

Comment on lines +59 to +71
func FormatEndpoint(endpoint string) string {
if endpoint == "" {
return ""
}

// Remove protocol (http:// or https://)
re := regexp.MustCompile(`^https?://`)
formatted := re.ReplaceAllString(endpoint, "")

// Split by '/' and take only the first part (domain)
parts := strings.Split(formatted, "/")
return parts[0]
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use url.Parse for robust endpoint normalization (remove ports, handle case-insensitive schemes), and align behavior with comment

The current regex-based approach:

  • Misses uppercase schemes (e.g., HTTPS://).
  • Retains ports despite the comment saying “domain”.
  • Doesn’t trim spaces or handle odd inputs as reliably as url.Parse.

Refactor to use net/url and trim whitespace. This also removes the need for regexp here.

Apply this diff:

-import (
-	"fmt"
-	"math/big"
-	"regexp"
-	"strings"
-
-	"github.com/iden3/go-iden3-crypto/poseidon"
-)
+import (
+	"fmt"
+	"math/big"
+	"net/url"
+	"strings"
+
+	"github.com/iden3/go-iden3-crypto/poseidon"
+)
-// FormatEndpoint removes protocol and path from URL, keeping only the domain
+// FormatEndpoint removes protocol and path from URL, keeping only the domain (without port)
 func FormatEndpoint(endpoint string) string {
-	if endpoint == "" {
-		return ""
-	}
-
-	// Remove protocol (http:// or https://)
-	re := regexp.MustCompile(`^https?://`)
-	formatted := re.ReplaceAllString(endpoint, "")
-
-	// Split by '/' and take only the first part (domain)
-	parts := strings.Split(formatted, "/")
-	return parts[0]
+	s := strings.TrimSpace(endpoint)
+	if s == "" {
+		return ""
+	}
+	// Ensure a scheme for proper parsing when the input is a bare host
+	if !strings.Contains(s, "://") {
+		s = "https://" + s
+	}
+	u, err := url.Parse(s)
+	if err != nil {
+		return ""
+	}
+	// Hostname strips the port if present
+	return u.Hostname()
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func FormatEndpoint(endpoint string) string {
if endpoint == "" {
return ""
}
// Remove protocol (http:// or https://)
re := regexp.MustCompile(`^https?://`)
formatted := re.ReplaceAllString(endpoint, "")
// Split by '/' and take only the first part (domain)
parts := strings.Split(formatted, "/")
return parts[0]
}
import (
"fmt"
"math/big"
"net/url"
"strings"
"github.com/iden3/go-iden3-crypto/poseidon"
)
// FormatEndpoint removes protocol and path from URL, keeping only the domain (without port)
func FormatEndpoint(endpoint string) string {
s := strings.TrimSpace(endpoint)
if s == "" {
return ""
}
// Ensure a scheme for proper parsing when the input is a bare host
if !strings.Contains(s, "://") {
s = "https://" + s
}
u, err := url.Parse(s)
if err != nil {
return ""
}
// Hostname strips the port if present
return u.Hostname()
}
🤖 Prompt for AI Agents
In sdk/sdk-go/common/customHash.go around lines 59-71: the current regex-based
FormatEndpoint fails on uppercase schemes, leaves ports, and doesn't trim
spaces; replace it to trim whitespace, ensure a scheme exists (if missing,
prepend "http://"), parse with net/url.Parse, and return the hostname via
URL.Hostname() to drop ports; on parse error fall back to taking the trimmed
string before the first '/' and stripping any ":port" suffix; remove the regexp
usage and update imports accordingly.

Comment on lines +1 to +21
[
{
"inputs": [
{
"internalType": "uint256",
"name": "root",
"type": "uint256"
}
],
"name": "checkIdentityCommitmentRoot",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
}
]
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid duplicated ABI artifacts — keep a single canonical location.

This ABI also exists at sdk/sdk-go/contracts/Registry.abi. Maintaining two copies of the same ABI invites drift and brittle build pipelines. Pick one location (recommend sdk/sdk-go/contracts/abi) and delete the other. Ensure any codegen or import paths point to the canonical file.

🤖 Prompt for AI Agents
In sdk/sdk-go/contracts/abi/Registry.abi lines 1-21: this ABI is duplicated
elsewhere (sdk/sdk-go/contracts/Registry.abi); remove the duplicate file and
keep this canonical copy under sdk/sdk-go/contracts/abi, then update any codegen
configs, import paths, and build scripts to reference
sdk/sdk-go/contracts/abi/Registry.abi (or regenerate code) so all consumers
point to the single canonical location.

💡 Verification agent

🧩 Analysis chain

ABI shape looks good; verify call-site types and opts across bindings.

The signature is simple and view-only. Please confirm all Go call sites pass a *big.Int for root and set bind.CallOpts correctly (context, block number where needed).

Run this to spot-check call sites:


🏁 Script executed:

#!/bin/bash
# Find CheckIdentityCommitmentRoot usages and surrounding context to confirm *big.Int and CallOpts usage.
rg -nP --type=go -C3 '\bCheckIdentityCommitmentRoot\s*\('

Length of output: 2755


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "---- sdk/sdk-go/internal/selfBackendVerifier.go (first 400 lines) ----"
nl -ba sdk/sdk-go/internal/selfBackendVerifier.go | sed -n '1,400p'

Length of output: 331


CheckIdentityCommitmentRoot — ABI OK; pass explicit bind.CallOpts at call sites

Binding signature confirmed: the generated contract binding expects root *big.Int (OK). I found an application call that passes a nil CallOpts — prefer supplying explicit CallOpts (context and/or BlockNumber) or using the Session wrapper.

  • sdk/sdk-go/contracts/bindings/Registry.go
    • Generated signature: func (_Registry *RegistryCaller) CheckIdentityCommitmentRoot(opts *bind.CallOpts, root *big.Int) (bool, error) (binding is correct).
  • sdk/sdk-go/internal/selfBackendVerifier.go:232
    • Current: currentRoot, err := registryContract.CheckIdentityCommitmentRoot(nil, merkleRoot)
    • Suggestion: pass a non-nil CallOpts, e.g.
      • currentRoot, err := registryContract.CheckIdentityCommitmentRoot(&bind.CallOpts{Context: ctx}, merkleRoot)
      • or set a RegistrySession with _Registry.CallOpts populated and call the session wrapper (registrySession.CheckIdentityCommitmentRoot(merkleRoot)) for reuse.

If nil was intentional (accept default behavior), this is fine — otherwise make the change for deterministic block reads and cancellable context.

🤖 Prompt for AI Agents
In sdk/sdk-go/internal/selfBackendVerifier.go around line 232, the call to
registryContract.CheckIdentityCommitmentRoot passes a nil *bind.CallOpts which
makes the call uncontrolled and non-cancellable; replace the nil with an
explicit CallOpts containing the current context (e.g. &bind.CallOpts{Context:
ctx}) to ensure deterministic block reads and cancellation, or alternatively
create and use a RegistrySession with its CallOpts populated and call the
session wrapper for repeated calls.

Comment on lines +502 to +505
circuitMinAgeInt := 0
if circuitMinAge != "00" {
fmt.Sscanf(circuitMinAge, "%d", &circuitMinAgeInt)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Duplicate minimum age parsing logic

The same parsing logic for circuitMinAge appears both here and in the main Verify function (lines 382-385). This duplication could lead to maintenance issues.

Consider extracting this into a helper function:

func parseMinimumAge(minAge string) int {
    if minAge == "00" {
        return 0
    }
    var age int
    if _, err := fmt.Sscanf(minAge, "%d", &age); err != nil {
        return 0
    }
    return age
}
🤖 Prompt for AI Agents
In sdk/sdk-go/internal/selfBackendVerifier.go around lines 502 to 505, the
parsing of circuitMinAge duplicates logic present earlier (lines ~382-385);
extract that logic into a single helper function (e.g., parseMinimumAge(minAge
string) int) that returns 0 for "00" and returns the parsed int otherwise
(safely checking fmt.Sscanf's error and falling back to 0 on error), then
replace both duplicated blocks with calls to this helper so parsing behavior is
centralized and maintenance-safe.

forbiddenCountriesListPacked := publicSignals[fcStartIndex : fcStartIndex+3]

// Extract issuing state
issuingState := string(revealedDataPackedBytes[revealedDataIndices.IssuingStateStart : revealedDataIndices.IssuingStateEnd+1])
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Validate slice bounds before accessing revealedDataPackedBytes

Multiple slice operations throughout this function could panic if the indices exceed the slice bounds.

Add bounds checking before each slice operation:

+// Validate all indices are within bounds
+maxIndex := revealedDataIndices.OfacEnd
+if maxIndex >= len(revealedDataPackedBytes) {
+    return GenericDiscloseOutput{}, fmt.Errorf("revealed data indices out of bounds: max index %d, data length %d", maxIndex, len(revealedDataPackedBytes))
+}

 // Extract issuing state
 issuingState := string(revealedDataPackedBytes[revealedDataIndices.IssuingStateStart : revealedDataIndices.IssuingStateEnd+1])

Committable suggestion skipped: line range outside the PR's diff.

var bytes []int

for i := 0; i < length; i++ {
signalIndex := discloseIndices.RevealedDataPackedIndex + i
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add bounds check for signalIndex

The code should validate that signalIndex doesn't exceed the bounds of publicSignals before accessing it.

 for i := 0; i < length; i++ {
     signalIndex := discloseIndices.RevealedDataPackedIndex + i
+    
+    if signalIndex >= len(publicSignals) {
+        return nil, fmt.Errorf("signal index %d out of bounds, public signals length: %d", signalIndex, len(publicSignals))
+    }

     publicSignal := new(big.Int)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
signalIndex := discloseIndices.RevealedDataPackedIndex + i
for i := 0; i < length; i++ {
signalIndex := discloseIndices.RevealedDataPackedIndex + i
if signalIndex >= len(publicSignals) {
return nil, fmt.Errorf("signal index %d out of bounds, public signals length: %d", signalIndex, len(publicSignals))
}
publicSignal := new(big.Int)
🤖 Prompt for AI Agents
In sdk/sdk-go/internal/utils/proof.go around line 77, the computed signalIndex
:= discloseIndices.RevealedDataPackedIndex + i must be validated against the
publicSignals slice bounds before any access; add a check that signalIndex >= 0
&& signalIndex < len(publicSignals) and if it fails return a clear error (e.g.,
fmt.Errorf with the offending indices and lengths) or otherwise handle the
out-of-range case to avoid panics.

return nil, fmt.Errorf("no inputs provided")
}

if len(inputs) > 16 {
Copy link
Collaborator

Choose a reason for hiding this comment

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

shouldn't this be > 17?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

we decided not to change the circuits right? so kept it same like the circuit algo

Copy link
Collaborator

Choose a reason for hiding this comment

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

no if you look at the typescript code it considers the switch case of 16.

see:

export function flexiblePoseidon(inputs: bigint[]): bigint {

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

tru tru , will change it

)

const (
AttestationId1 types.AttestationId = 1
Copy link
Collaborator

Choose a reason for hiding this comment

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

can you make this passport and the other one IdCard?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I can, but it changes the mapping a lot. I think this way is faster than using a string-to-struct mapping ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

It's better for readability. I just meant renaming the constants to something like this:

const (
	Passport types.AttestationId = 1
...

return &ConfigMismatchError{Issues: issue}
}

type ConfigStore interface {
Copy link
Collaborator

Choose a reason for hiding this comment

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

move config store to a different file and and the DefaultConfigStore and InMemoryConfigStore implementations as well


// VcAndDiscloseProof represents the zero-knowledge proof structure
type VcAndDiscloseProof struct {
A [2]*big.Int `json:"a"`
Copy link
Collaborator

Choose a reason for hiding this comment

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

accept these in string

ctx context.Context,
attestationId types.AttestationId,
proof types.VcAndDiscloseProof,
pubSignals []*big.Int,
Copy link
Collaborator

Choose a reason for hiding this comment

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

accept this in string too. When you're making an API you'll get the inputs in string. Convert them to bigint internally

}

// castToUserIdentifier converts a big integer to user identifier string based on the specified type
func (s *SelfBackendVerifier) castToUserIdentifier(bigInt *big.Int, userIdType types.UserIDType) string {
Copy link
Collaborator

Choose a reason for hiding this comment

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

put this in utils.go

Copy link
Contributor

@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: 7

♻️ Duplicate comments (8)
sdk/sdk-go/internal/utils/proof.go (2)

31-39: Replace magic numbers with named constants

Use named constants for 93, 94, and 31 to explain intent and avoid drift across the codebase.

Example:

+const (
+	revealedDataBitsPassport = 93
+	revealedDataBitsEUCard   = 94
+	bitsPerByteChunk         = 31
+)
@@
-	case Passport:
-		return int(93 / 31), nil
-	case EUCard:
-		return int(math.Ceil(94.0 / 31.0)), nil
+	case Passport:
+		return revealedDataBitsPassport / bitsPerByteChunk, nil
+	case EUCard:
+		return int(math.Ceil(float64(revealedDataBitsEUCard) / float64(bitsPerByteChunk))), nil

76-83: Bounds check required to avoid panic on invalid/malformed publicSignals

Accessing publicSignals[signalIndex] without verifying bounds can panic. Validate signalIndex and that bytesCount has an entry for i.

Apply:

 for i := 0; i < length; i++ {
     signalIndex := discloseIndices.RevealedDataPackedIndex + i
+    if signalIndex < 0 || signalIndex >= len(publicSignals) {
+        return nil, fmt.Errorf("signal index %d out of bounds (publicSignals length: %d)", signalIndex, len(publicSignals))
+    }
+    if i >= len(bytesCount) {
+        return nil, fmt.Errorf("bytesCount missing entry for index %d (len: %d)", i, len(bytesCount))
+    }
 
     publicSignal := new(big.Int)
     publicSignal, success := publicSignal.SetString(publicSignals[signalIndex], 10)
     if !success {
         return nil, fmt.Errorf("failed to parse public signal at index %d: %s", signalIndex, publicSignals[signalIndex])
     }
sdk/sdk-go/internal/selfBackendVerifier_test.go (2)

217-231: Add assertions so the test fails on verification errors

Right now the test only logs results; it should fail if verification fails or result is nil.

Apply:

 	// Log detailed results for debugging
 	if err != nil {
 		t.Logf("Verification failed: %v", err)
 		// Check if it's a ConfigMismatchError or contract-related error
 		if configErr, ok := err.(*ConfigMismatchError); ok {
 			t.Logf("Config validation issues found:")
 			for i, issue := range configErr.Issues {
 				t.Logf("  Issue %d: %s - %s", i+1, issue.Type, issue.Message)
 			}
 		}
-	}
-	if result != nil {
-		t.Logf("Got verification result: %+v", result)
-	}
+		t.Fatalf("Expected successful verification, got error: %v", err)
+	}
+	if result == nil {
+		t.Fatal("Expected non-nil verification result")
+	}
+	t.Logf("Got verification result: %+v", result)

261-267: Fail the test on hash mismatch (don’t just log emojis)

Make the mismatch explicit using t.Errorf with expected vs actual.

Apply:

-		if calculatedHashBigInt.Cmp(circuitHashBigInt) == 0 {
-			t.Logf("✅ UserContextHash matches!")
-		} else {
-			t.Logf("❌ UserContextHash mismatch!")
-			t.Logf("Expected: %s", calculatedHashBigInt.String())
-			t.Logf("Got: %s", circuitHash)
-		}
+		if calculatedHashBigInt.Cmp(circuitHashBigInt) == 0 {
+			t.Logf("✅ UserContextHash matches!")
+		} else {
+			t.Errorf("❌ UserContextHash mismatch! Expected: %s, Got: %s",
+				calculatedHashBigInt.String(), circuitHash)
+		}
sdk/sdk-go/internal/selfBackendVerifier.go (4)

86-93: Consider accepting string inputs for API flexibility.

As noted by the previous reviewer, APIs typically receive string inputs that need to be converted to appropriate types internally.


45-53: Remove unreliable hex detection function.

The containsHexChars function is problematic as it can't reliably distinguish between hex and decimal strings. A string like "123abc" would be detected as hex, but "123456" (valid hex) would not be.

-// containsHexChars checks if a string contains hexadecimal characters (a-f)
-func containsHexChars(s string) bool {
-	for _, char := range s {
-		if (char >= 'a' && char <= 'f') || (char >= 'A' && char <= 'F') {
-			return true
-		}
-	}
-	return false
-}

477-480: Fix unsafe parsing without error checking.

The fmt.Sscanf usage without error checking could silently fail, leaving circuitMinAgeInt as 0.

-		circuitMinAgeInt := 0
-		if circuitMinAge != "00" {
-			fmt.Sscanf(circuitMinAge, "%d", &circuitMinAgeInt)
-		}
+		circuitMinAgeInt := 0
+		if circuitMinAge != "00" {
+			if parsed, err := strconv.Atoi(circuitMinAge); err == nil {
+				circuitMinAgeInt = parsed
+			}
+		}

156-163: Fix unreliable hex prefix logic.

The current approach using containsHexChars is unreliable. Use proper parsing instead.

-	// Process public signals, adding 0x prefix for hex values if needed
-	publicSignals := make([]string, len(pubSignals))
-	for i, signal := range pubSignals {
-		if len(signal) > 0 && containsHexChars(signal) {
-			publicSignals[i] = "0x" + signal
-		} else {
-			publicSignals[i] = signal
-		}
-	}
+	// Process public signals - convert to consistent format
+	publicSignals := make([]string, len(pubSignals))
+	for i, signal := range pubSignals {
+		// Try parsing as decimal first, then handle as needed
+		if bigInt, ok := new(big.Int).SetString(signal, 10); ok {
+			publicSignals[i] = bigInt.String()
+		} else {
+			publicSignals[i] = signal
+		}
+	}
🧹 Nitpick comments (9)
sdk/sdk-go/internal/utils/store/configStore.go (2)

9-13: Prefer ID acronym capitalization and align naming with Go conventions

  • Use “ID” for acronyms: GetActionID(ctx, userIdentifier, actionID string).
  • Consider dropping the “Get” prefix for a more Go-idiomatic API (e.g., ActionID or ResolveActionID), if feasible.

This improves readability and consistency across the SDK.


11-11: Clarify SetConfig’s boolean return value or simplify to error-only

The bool return isn’t self-explanatory. If it signals created vs updated, document it clearly (and name it created). Otherwise, consider returning just error to simplify the API.

sdk/sdk-go/internal/utils/store/DefaultConfigStore.go (1)

30-32: Parameter name mismatch increases confusion

Method signature is GetActionId(ctx, userIdentifier, actionId string) but the parameter name here is userDefinedData. Keep naming consistent with the interface’s semantics.

sdk/sdk-go/internal/utils/utils.go (1)

39-47: Safer country slicing using runes to avoid breaking on multibyte characters

If UnpackReveal ever returns non-ASCII, slicing strings by byte indices may split runes. Using runes is safer and negligible overhead here.

Proposed adjustment:

-	for i := 0; i < len(joined); i += 3 {
-		if i+3 <= len(joined) {
-			countryCode := joined[i : i+3]
-			if len(countryCode) == 3 {
-				countries = append(countries, countryCode)
-			}
-		}
-	}
+	runes := []rune(joined)
+	for i := 0; i+3 <= len(runes); i += 3 {
+		countries = append(countries, string(runes[i:i+3]))
+	}
sdk/sdk-go/internal/utils/proof.go (2)

3-8: Avoid dot-imports; they obscure provenance and hinder readability

Replace . "self-sdk-go/internal/types" with a standard import and qualify uses with types.AttestationId.

Apply:

-import (
-	"fmt"
-	"math"
-	"math/big"
-	. "self-sdk-go/internal/types"
-)
+import (
+	"fmt"
+	"math"
+	"math/big"
+	types "self-sdk-go/internal/types"
+)
@@
-type PublicSignals []string
+type PublicSignals []string
@@
-var BytesCount = map[AttestationId][]int{
+var BytesCount = map[types.AttestationId][]int{
@@
-func GetRevealedDataPublicSignalsLength(attestationId AttestationId) (int, error) {
+func GetRevealedDataPublicSignalsLength(attestationId types.AttestationId) (int, error) {
@@
-func GetRevealedDataBytes(attestationId AttestationId, publicSignals PublicSignals) ([]int, error) {
+func GetRevealedDataBytes(attestationId types.AttestationId, publicSignals PublicSignals) ([]int, error) {

85-93: Consider returning []byte instead of []int for extracted bytes

Bytes are semantically bytes. Returning []byte avoids conversions downstream and conveys intent more clearly. This is a soft suggestion; adjust only if it doesn’t ripple too widely.

sdk/sdk-go/internal/selfBackendVerifier_test.go (1)

91-101: Avoid duplicating CastToUUID; use the exported utility to keep behavior in sync

Prefer utils.CastToUUID to ensure formatting changes are centralized.

As a minimal change:

-// Helper function to convert big integer to UUID format (matching the main implementation)
-func castToUUID(bigInt *big.Int) string {
-	hexStr := bigInt.Text(16) // Convert to hex without 0x prefix
-	// Pad to 32 characters (16 bytes = 32 hex chars)
-	if len(hexStr) < 32 {
-		hexStr = fmt.Sprintf("%032s", hexStr)
-	}
-	// Format as UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
-	return fmt.Sprintf("%s-%s-%s-%s-%s",
-		hexStr[0:8], hexStr[8:12], hexStr[12:16], hexStr[16:20], hexStr[20:32])
-}
+// Prefer: utils.CastToUUID(bigInt)

If keeping the helper locally, fix zero-padding as suggested in utils.go.

sdk/sdk-go/internal/types/types.go (2)

7-8: Consider using a more descriptive type for AttestationId.

While int works functionally, consider using a more specific type like int64 or even a custom type with validation methods. This would provide better type safety and make the API more explicit about the expected range of values.

-type AttestationId int
+type AttestationId int64

61-66: Consider adding validation for UserIDType constants.

While the constants are well-defined, consider adding a validation method to ensure only valid UserIDType values are used throughout the system.

+func (u UserIDType) IsValid() bool {
+	return u == UserIDTypeHex || u == UserIDTypeUUID
+}
📜 Review details

Configuration used: .coderabbit.yaml
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 7c4618f and 30d8a92.

📒 Files selected for processing (10)
  • sdk/sdk-go/common/customHash.go (1 hunks)
  • sdk/sdk-go/internal/selfBackendVerifier.go (1 hunks)
  • sdk/sdk-go/internal/selfBackendVerifier_test.go (1 hunks)
  • sdk/sdk-go/internal/types/types.go (1 hunks)
  • sdk/sdk-go/internal/utils/constants.go (1 hunks)
  • sdk/sdk-go/internal/utils/proof.go (1 hunks)
  • sdk/sdk-go/internal/utils/store/DefaultConfigStore.go (1 hunks)
  • sdk/sdk-go/internal/utils/store/InMemoryConfigStore.go (1 hunks)
  • sdk/sdk-go/internal/utils/store/configStore.go (1 hunks)
  • sdk/sdk-go/internal/utils/utils.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • sdk/sdk-go/common/customHash.go
🧰 Additional context used
🧬 Code Graph Analysis (8)
sdk/sdk-go/internal/utils/store/DefaultConfigStore.go (1)
sdk/sdk-go/internal/utils/store/configStore.go (1)
  • ConfigStore (9-13)
sdk/sdk-go/internal/utils/utils.go (2)
sdk/sdk-go/common/utils.go (1)
  • UnpackReveal (14-62)
sdk/sdk-go/internal/types/types.go (3)
  • UserIDType (61-61)
  • UserIDTypeHex (64-64)
  • UserIDTypeUUID (65-65)
sdk/sdk-go/internal/utils/store/InMemoryConfigStore.go (1)
sdk/sdk-go/internal/utils/store/configStore.go (1)
  • ConfigStore (9-13)
sdk/sdk-go/internal/utils/proof.go (2)
sdk/sdk-go/internal/types/types.go (1)
  • AttestationId (8-8)
sdk/sdk-go/internal/utils/constants.go (3)
  • Passport (8-8)
  • EUCard (9-9)
  • DiscloseIndices (26-53)
sdk/sdk-go/internal/types/types.go (1)
sdk/sdk-go/internal/utils/constants.go (8)
  • Ofac (64-64)
  • IssuingState (56-56)
  • Name (57-57)
  • IdNumber (58-58)
  • Nationality (59-59)
  • DateOfBirth (60-60)
  • Gender (61-61)
  • ExpiryDate (62-62)
sdk/sdk-go/internal/utils/constants.go (1)
sdk/sdk-go/internal/types/types.go (1)
  • AttestationId (8-8)
sdk/sdk-go/internal/selfBackendVerifier_test.go (4)
sdk/sdk-go/internal/types/types.go (4)
  • VerificationConfig (18-22)
  • VcAndDiscloseProof (11-15)
  • AttestationId (8-8)
  • UserIDTypeUUID (65-65)
sdk/sdk-go/internal/utils/constants.go (1)
  • Ofac (64-64)
sdk/sdk-go/internal/selfBackendVerifier.go (2)
  • NewSelfBackendVerifier (86-129)
  • ConfigMismatchError (60-62)
sdk/sdk-go/internal/utils/hash.go (1)
  • CalculateUserIdentifierHash (20-39)
sdk/sdk-go/internal/selfBackendVerifier.go (9)
sdk/sdk-go/contracts/bindings/IdentityVerificationHubImpl.go (2)
  • IdentityVerificationHubImpl (42-46)
  • NewIdentityVerificationHubImpl (101-107)
sdk/sdk-go/internal/utils/store/configStore.go (1)
  • ConfigStore (9-13)
sdk/sdk-go/internal/types/types.go (7)
  • AttestationId (8-8)
  • UserIDType (61-61)
  • VcAndDiscloseProof (11-15)
  • VerificationConfig (18-22)
  • GenericDiscloseOutput (38-50)
  • IsValidDetails (25-29)
  • UserData (32-35)
sdk/sdk-go/internal/utils/constants.go (3)
  • DiscloseIndices (26-53)
  • Ofac (64-64)
  • DiscloseIndicesEntry (12-24)
sdk/sdk-go/internal/utils/hash.go (1)
  • CalculateUserIdentifierHash (20-39)
sdk/sdk-go/contracts/bindings/Registry.go (2)
  • Registry (42-46)
  • NewRegistry (101-107)
sdk/sdk-go/internal/utils/utils.go (1)
  • CastToUserIdentifier (53-62)
sdk/sdk-go/contracts/bindings/Verifier.go (1)
  • NewVerifier (101-107)
sdk/sdk-go/internal/utils/id.go (1)
  • FormatRevealedDataPacked (12-89)
🔇 Additional comments (7)
sdk/sdk-go/internal/utils/utils.go (1)

53-62: Default branch returns decimal string; confirm downstream expectations

CastToUserIdentifier returns decimal for unknown types. Ensure downstream hashing/formatting logic expects decimal here. If not, consider returning hex or erroring on unknown type to avoid mismatches.

sdk/sdk-go/internal/utils/store/InMemoryConfigStore.go (1)

1-46: LGTM! Well-structured in-memory configuration store implementation.

The implementation follows good Go practices with proper interface compliance checking, clear constructor pattern, and appropriate error handling. The delegation pattern for GetActionId allows for flexible action ID resolution logic injection.

sdk/sdk-go/internal/types/types.go (2)

10-15: Zero-knowledge proof structure looks solid.

The VcAndDiscloseProof struct correctly represents the standard zkSNARK proof format with proper JSON serialization tags.


17-22: Good use of pointer types for optional fields.

The VerificationConfig struct correctly uses pointer types for optional fields, allowing for proper omitempty behavior in JSON serialization.

sdk/sdk-go/internal/utils/constants.go (2)

7-10: Good naming convention for attestation constants.

The constant names Passport and EUCard are clear and follow the previous reviewer's suggestion for better readability.


26-53: Confirm DiscloseIndices mapping against the circuit specification

I searched the Go codebase for any docs or tests that validate these magic offsets and didn’t find any. Since all downstream logic (proof.go, id.go, selfBackendVerifier.go) depends on these hard-coded indices, any mismatch with the actual circuit layout will lead to incorrect data extraction or verification failures.

• constants.go (lines 26–53): Review each index against the source circuit definition.
• proof.go & id.go: These immediately panic or error if an unexpected attestation ID lookup occurs.
• selfBackendVerifier.go: Multiple slices (e.g. forbiddenCountriesListPacked, timestamp parts) are sliced by these indices.

Please add unit tests or reference the circuit spec to lock these mappings in place and prevent drift.

sdk/sdk-go/internal/selfBackendVerifier.go (1)

132-138: Good API design for verification method.

The Verify method has a clean signature that accepts the necessary parameters for attestation verification. The context parameter enables proper cancellation and timeouts.

Comment on lines +133 to +139
// Convert to address format (0x + 40 hex chars) - matching UserIDTypeHex
hexStr := userIdentifierBigInt.Text(16)
if len(hexStr) < 40 {
hexStr = fmt.Sprintf("%040s", hexStr)
}
return "0x" + hexStr
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Zero-padding for address extraction uses spaces; fix to prevent parse failures

fmt.Sprintf("%040s", ...) pads with spaces for %s; big.Int.SetString will fail on strings containing spaces. This likely zeroes userIdentifierBigInt, skewing the test.

Apply:

-	hexStr := userIdentifierBigInt.Text(16)
-	if len(hexStr) < 40 {
-		hexStr = fmt.Sprintf("%040s", hexStr)
-	}
+	hexStr := userIdentifierBigInt.Text(16)
+	if len(hexStr) < 40 {
+		hexStr = strings.Repeat("0", 40-len(hexStr)) + hexStr
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Convert to address format (0x + 40 hex chars) - matching UserIDTypeHex
hexStr := userIdentifierBigInt.Text(16)
if len(hexStr) < 40 {
hexStr = fmt.Sprintf("%040s", hexStr)
}
return "0x" + hexStr
}
// Convert to address format (0x + 40 hex chars) - matching UserIDTypeHex
hexStr := userIdentifierBigInt.Text(16)
if len(hexStr) < 40 {
hexStr = strings.Repeat("0", 40-len(hexStr)) + hexStr
}
return "0x" + hexStr
}
🤖 Prompt for AI Agents
In sdk/sdk-go/internal/selfBackendVerifier_test.go around lines 133–139 the code
uses fmt.Sprintf("%040s", hexStr) which pads with spaces (causing
big.Int.SetString to fail); replace that padding with zeros by prefixing with
strings.Repeat("0", 40-len(hexStr)) + hexStr (and add import "strings" if
missing), ensuring the hex string is left-padded with '0' characters to 40 chars
before returning "0x"+hexStr.

Comment on lines +325 to +333
a0, _ := new(big.Int).SetString(proof.A[0], 10)
a1, _ := new(big.Int).SetString(proof.A[1], 10)
b00, _ := new(big.Int).SetString(proof.B[0][0], 10)
b01, _ := new(big.Int).SetString(proof.B[0][1], 10)
b10, _ := new(big.Int).SetString(proof.B[1][0], 10)
b11, _ := new(big.Int).SetString(proof.B[1][1], 10)
c0, _ := new(big.Int).SetString(proof.C[0], 10)
c1, _ := new(big.Int).SetString(proof.C[1], 10)

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling for proof parsing.

The proof field parsing uses the blank identifier to ignore errors, which could lead to silent failures if the proof data is malformed.

-			// Convert string proof fields to *big.Int
-			a0, _ := new(big.Int).SetString(proof.A[0], 10)
-			a1, _ := new(big.Int).SetString(proof.A[1], 10)
-			b00, _ := new(big.Int).SetString(proof.B[0][0], 10)
-			b01, _ := new(big.Int).SetString(proof.B[0][1], 10)
-			b10, _ := new(big.Int).SetString(proof.B[1][0], 10)
-			b11, _ := new(big.Int).SetString(proof.B[1][1], 10)
-			c0, _ := new(big.Int).SetString(proof.C[0], 10)
-			c1, _ := new(big.Int).SetString(proof.C[1], 10)
+			// Convert string proof fields to *big.Int with error checking
+			a0, ok := new(big.Int).SetString(proof.A[0], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field A[0]: %s", proof.A[0])
+			}
+			a1, ok := new(big.Int).SetString(proof.A[1], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field A[1]: %s", proof.A[1])
+			}
+			// Similar error checking for other fields...

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In sdk/sdk-go/internal/selfBackendVerifier.go around lines 325 to 333 the code
ignores errors from new(big.Int).SetString when parsing proof fields which can
silently produce nil/zero values; update each SetString call to capture the
boolean result (or check returned *big.Int) and if parsing fails return a
descriptive error (or propagate it) indicating which proof field failed to parse
(A[0], A[1], B[0][0], etc.); ensure you do not use the blank identifier,
validate each parsed big.Int is non-nil and parsing succeeded before continuing,
and include the offending input value in the error message to aid debugging.

Comment on lines 88 to 129
var RevealedDataIndices = map[types.AttestationId]RevealedDataIndicesEntry{
Passport: {
IssuingStateStart: 2,
IssuingStateEnd: 4,
NameStart: 5,
NameEnd: 43,
IdNumberStart: 44,
IdNumberEnd: 52,
NationalityStart: 54,
NationalityEnd: 56,
DateOfBirthStart: 57,
DateOfBirthEnd: 62,
GenderStart: 64,
GenderEnd: 64,
ExpiryDateStart: 65,
ExpiryDateEnd: 70,
OlderThanStart: 88,
OlderThanEnd: 89,
OfacStart: 90,
OfacEnd: 92,
},
EUCard: {
IssuingStateStart: 2,
IssuingStateEnd: 4,
NameStart: 60,
NameEnd: 89,
IdNumberStart: 5,
IdNumberEnd: 13,
NationalityStart: 45,
NationalityEnd: 47,
DateOfBirthStart: 30,
DateOfBirthEnd: 35,
GenderStart: 37,
GenderEnd: 37,
ExpiryDateStart: 38,
ExpiryDateEnd: 43,
OlderThanStart: 90,
OlderThanEnd: 91,
OfacStart: 92,
OfacEnd: 93,
},
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Critical: Validate RevealedDataIndices ranges.

The start/end index pairs define byte ranges for extracting sensitive personal data. Incorrect ranges could lead to data corruption or security issues. These ranges should be thoroughly tested and documented.


🏁 Script executed:

#!/bin/bash
# Search for tests that validate the RevealedDataIndices ranges
echo "Looking for tests that validate data extraction ranges..."
rg -n "RevealedDataIndices|FormatRevealedDataPacked" --type=go -A 10 -B 5

Length of output: 7415


🏁 Script executed:

#!/bin/bash
echo "Searching tests referencing FormatRevealedDataPacked..."
rg -n 'FormatRevealedDataPacked' -g '*_test.go' -C3 || echo "No tests found for FormatRevealedDataPacked"
echo "Searching tests referencing GetRevealedDataBytes..."
rg -n 'GetRevealedDataBytes' -g '*_test.go' -C3 || echo "No tests found for GetRevealedDataBytes"

Length of output: 519


Critical: Add unit tests for RevealedDataIndices ranges

I searched the codebase and didn’t find any tests covering FormatRevealedDataPacked or GetRevealedDataBytes. Without targeted tests, off-by-one indexing bugs can sneak in and corrupt or expose sensitive PII. Please:

• Create a new Go test file (e.g. sdk/sdk-go/internal/utils/id_test.go).
• For each types.AttestationId (Passport, EUCard), build a synthetic publicSignals slice where each byte position is set to a known marker.
• Call FormatRevealedDataPacked(attestationID, publicSignals) and assert that each extracted field (IssuingState, Name, IdNumber, Nationality, DateOfBirth, Gender, ExpiryDate, OlderThan, Ofac) matches the expected substrings.
• Document the expected start/end index values above the RevealedDataIndices map (or in a UTILITIES.md) so future maintainers can cross-check easily.

Adding these targeted tests will catch any mis-indexed ranges early and keep our PII extraction rock-solid.

🤖 Prompt for AI Agents
In sdk/sdk-go/internal/utils/constants.go around lines 88 to 129, there are
RevealedDataIndices definitions for Passport and EUCard but no unit tests
validating those byte ranges; add a new test file (e.g.,
sdk/sdk-go/internal/utils/id_test.go) that for each types.AttestationId
(Passport, EUCard) constructs a synthetic publicSignals byte slice where each
position contains a unique, known marker (e.g., incremental byte values or
repeated letter tokens), calls FormatRevealedDataPacked(attestationID,
publicSignals) and asserts each extracted field (IssuingState, Name, IdNumber,
Nationality, DateOfBirth, Gender, ExpiryDate, OlderThan, Ofac) equals the
expected substring derived from the marked positions; include table-style
comments in the test (or add UTILITIES.md) listing the expected start/end
indices for both attestation types so future changes to RevealedDataIndices will
be validated by the tests.

Comment on lines 21 to 23
func (store *DefaultConfigStore) GetConfig(ctx context.Context, id string) (types.VerificationConfig, error) {
return store.config, nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

GetConfig ignores the id parameter; always returns the same config

This breaks multi-config scenarios and will cause incorrect behavior when different IDs are expected to return different configs.

Apply this refactor to support per-ID configs and a default config, with concurrency safety:

@@
-import (
-	"context"
-	"self-sdk-go/internal/types"
-)
+import (
+	"context"
+	"fmt"
+	"sync"
+	"self-sdk-go/internal/types"
+)
@@
-type DefaultConfigStore struct {
-	config types.VerificationConfig
-}
+type DefaultConfigStore struct {
+	mu            sync.RWMutex
+	defaultConfig types.VerificationConfig
+	configs       map[string]types.VerificationConfig
+	actionIds     map[string]string
+}
@@
-func NewDefaultConfigStore(config types.VerificationConfig) *DefaultConfigStore {
-	return &DefaultConfigStore{
-		config: config,
-	}
-}
+func NewDefaultConfigStore(config types.VerificationConfig) *DefaultConfigStore {
+	return &DefaultConfigStore{
+		defaultConfig: config,
+		configs:       make(map[string]types.VerificationConfig),
+		actionIds:     make(map[string]string),
+	}
+}
@@
-func (store *DefaultConfigStore) GetConfig(ctx context.Context, id string) (types.VerificationConfig, error) {
-	return store.config, nil
-}
+func (store *DefaultConfigStore) GetConfig(ctx context.Context, id string) (types.VerificationConfig, error) {
+	store.mu.RLock()
+	defer store.mu.RUnlock()
+	if id == "" {
+		return store.defaultConfig, nil
+	}
+	cfg, ok := store.configs[id]
+	if !ok {
+		return types.VerificationConfig{}, fmt.Errorf("config not found for id: %q", id)
+	}
+	return cfg, nil
+}
@@
-func (store *DefaultConfigStore) SetConfig(ctx context.Context, id string, config types.VerificationConfig) (bool, error) {
-	store.config = config
-	return true, nil
-}
+func (store *DefaultConfigStore) SetConfig(ctx context.Context, id string, config types.VerificationConfig) (bool, error) {
+	store.mu.Lock()
+	defer store.mu.Unlock()
+	if id == "" {
+		store.defaultConfig = config
+		return true, nil
+	}
+	_, exists := store.configs[id]
+	store.configs[id] = config
+	return !exists, nil // true if created, false if updated
+}
@@
-func (store *DefaultConfigStore) GetActionId(ctx context.Context, userIdentifier string, userDefinedData string) (string, error) {
-	return "random-id", nil
-}
+func (store *DefaultConfigStore) GetActionId(ctx context.Context, userIdentifier string, actionId string) (string, error) {
+	store.mu.RLock()
+	defer store.mu.RUnlock()
+	key := userIdentifier + actionId
+	if cfgID, ok := store.actionIds[key]; ok {
+		return cfgID, nil
+	}
+	return "", fmt.Errorf("action mapping not found for key: %q", key)
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (store *DefaultConfigStore) GetConfig(ctx context.Context, id string) (types.VerificationConfig, error) {
return store.config, nil
}
package store
import (
"context"
"fmt"
"sync"
"self-sdk-go/internal/types"
)
type DefaultConfigStore struct {
mu sync.RWMutex
defaultConfig types.VerificationConfig
configs map[string]types.VerificationConfig
actionIds map[string]string
}
func NewDefaultConfigStore(config types.VerificationConfig) *DefaultConfigStore {
return &DefaultConfigStore{
defaultConfig: config,
configs: make(map[string]types.VerificationConfig),
actionIds: make(map[string]string),
}
}
func (store *DefaultConfigStore) GetConfig(ctx context.Context, id string) (types.VerificationConfig, error) {
store.mu.RLock()
defer store.mu.RUnlock()
if id == "" {
return store.defaultConfig, nil
}
cfg, ok := store.configs[id]
if !ok {
return types.VerificationConfig{}, fmt.Errorf("config not found for id: %q", id)
}
return cfg, nil
}
func (store *DefaultConfigStore) SetConfig(ctx context.Context, id string, config types.VerificationConfig) (bool, error) {
store.mu.Lock()
defer store.mu.Unlock()
if id == "" {
store.defaultConfig = config
return true, nil
}
_, exists := store.configs[id]
store.configs[id] = config
return !exists, nil // true if created, false if updated
}
func (store *DefaultConfigStore) GetActionId(ctx context.Context, userIdentifier string, actionId string) (string, error) {
store.mu.RLock()
defer store.mu.RUnlock()
key := userIdentifier + actionId
if cfgID, ok := store.actionIds[key]; ok {
return cfgID, nil
}
return "", fmt.Errorf("action mapping not found for key: %q", key)
}
🤖 Prompt for AI Agents
In sdk/sdk-go/internal/utils/store/DefaultConfigStore.go around lines 21-23,
GetConfig currently ignores the id and always returns the same config; change
the store to hold a default config plus a map of per-ID configs and a
sync.RWMutex for concurrency safety. Modify the DefaultConfigStore struct to
include configs map[string]types.VerificationConfig, defaultConfig
types.VerificationConfig, and mu sync.RWMutex; initialize the map in the
constructor. Update GetConfig to mu.RLock(), check if a config exists for the
given id and return it if present, otherwise return the defaultConfig (or an
error if no default is set); remember to mu.RUnlock() before returning. Ensure
any setters that mutate configs use mu.Lock()/Unlock() when writing to the map.

Comment on lines 68 to 71
if len(hexStr) < 40 {
hexStr = fmt.Sprintf("%040s", hexStr)
}
return "0x" + hexStr
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Zero-padding with fmt on strings is incorrect; produces spaces, not zeros

Using fmt.Sprintf("%040s", hexStr) pads with spaces for %s. This will yield invalid addresses like "0x abc…".

Apply zero-padding explicitly:

-	if len(hexStr) < 40 {
-		hexStr = fmt.Sprintf("%040s", hexStr)
-	}
+	if len(hexStr) < 40 {
+		hexStr = strings.Repeat("0", 40-len(hexStr)) + hexStr
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if len(hexStr) < 40 {
hexStr = fmt.Sprintf("%040s", hexStr)
}
return "0x" + hexStr
if len(hexStr) < 40 {
hexStr = strings.Repeat("0", 40-len(hexStr)) + hexStr
}
return "0x" + hexStr
🤖 Prompt for AI Agents
In sdk/sdk-go/internal/utils/utils.go around lines 68 to 71, the current
zero-padding uses fmt.Sprintf with a %s specifier which pads with spaces;
replace that with explicit zero-padding by prepending the required number of '0'
characters (e.g., use strings.Repeat to create 40-len(hexStr) zeros and
concatenate them to hexStr when len(hexStr) < 40) and add the strings import if
missing, then return "0x"+hexStr as before.

Comment on lines 78 to 80
if len(hexStr) < 32 {
hexStr = fmt.Sprintf("%032s", hexStr)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Same zero-padding bug in UUID formatting

Space-padding yields malformed UUID strings for short hex payloads.

Fix similarly:

-	if len(hexStr) < 32 {
-		hexStr = fmt.Sprintf("%032s", hexStr)
-	}
+	if len(hexStr) < 32 {
+		hexStr = strings.Repeat("0", 32-len(hexStr)) + hexStr
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if len(hexStr) < 32 {
hexStr = fmt.Sprintf("%032s", hexStr)
}
if len(hexStr) < 32 {
hexStr = strings.Repeat("0", 32-len(hexStr)) + hexStr
}
🤖 Prompt for AI Agents
In sdk/sdk-go/internal/utils/utils.go around lines 78 to 80, the code uses
fmt.Sprintf("%032s", hexStr) which pads with spaces and produces malformed UUIDs
for short hex strings; change the padding to zero-padding by left-prepending the
required number of '0' characters (e.g., calculate n := 32-len(hexStr); if n>0
then hexStr = strings.Repeat("0", n) + hexStr) and add the strings import if
missing so the UUID hex string is correctly zero-padded to 32 chars.

Copy link
Contributor

@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: 26

♻️ Duplicate comments (10)
sdk/sdk-go/internal/selfBackendVerifier_test.go (5)

92-96: Fix zero-padding to use zeros instead of spaces

The fmt.Sprintf("%032s", hexStr) pads with spaces when using %s format, which will cause parsing issues. Use explicit zero-padding instead.

 func castToUUID(bigInt *big.Int) string {
 	hexStr := bigInt.Text(16) // Convert to hex without 0x prefix
 	// Pad to 32 characters (16 bytes = 32 hex chars)
 	if len(hexStr) < 32 {
-		hexStr = fmt.Sprintf("%032s", hexStr)
+		hexStr = strings.Repeat("0", 32-len(hexStr)) + hexStr
 	}

133-136: Critical: Zero-padding with spaces will break hex parsing

The same padding issue exists here - using %040s pads with spaces, not zeros. This will cause big.Int.SetString to fail when parsing the hex string.

 	// Convert to address format (0x + 40 hex chars) - matching UserIDTypeHex
 	hexStr := userIdentifierBigInt.Text(16)
 	if len(hexStr) < 40 {
-		hexStr = fmt.Sprintf("%040s", hexStr)
+		hexStr = strings.Repeat("0", 40-len(hexStr)) + hexStr
 	}

217-226: Test should fail on verification errors

The test logs errors but doesn't fail when verification fails. Tests should have clear pass/fail criteria.

 if err != nil {
     t.Logf("Verification failed: %v", err)
     // Check if it's a ConfigMismatchError or contract-related error
     if configErr, ok := err.(*self.ConfigMismatchError); ok {
         t.Logf("Config validation issues found:")
         for i, issue := range configErr.Issues {
             t.Logf("  Issue %d: %s - %s", i+1, issue.Type, issue.Message)
         }
     }
+    t.Fatalf("Expected successful verification, got error: %v", err)
 }

227-229: Add assertions for verification result

The test should validate the result fields rather than just logging them.

 if result != nil {
     t.Logf("Got verification result: %+v", result)
+    // Add assertions for expected result fields
+    if result.DiscloseOutput.Nullifier == "" {
+        t.Error("Expected non-empty nullifier")
+    }
+    if result.UserData.UserIdentifier == "" {
+        t.Error("Expected non-empty user identifier")
+    }
+} else {
+    t.Fatal("Expected non-nil verification result")
 }

260-266: Test should fail on hash mismatch

The hash comparison logs a mismatch but doesn't fail the test. This should be a test failure.

 if calculatedHashBigInt.Cmp(circuitHashBigInt) == 0 {
     t.Logf("✅ UserContextHash matches!")
 } else {
-    t.Logf("❌ UserContextHash mismatch!")
-    t.Logf("Expected: %s", calculatedHashBigInt.String())
-    t.Logf("Got: %s", circuitHash)
+    t.Errorf("❌ UserContextHash mismatch! Expected: %s, Got: %s",
+        calculatedHashBigInt.String(), circuitHash)
 }
sdk/sdk-go/verifier.go (1)

135-143: Remove unreliable containsHexChars function

This function checks for hex characters to determine formatting, but this approach is unreliable. A decimal number could contain 'a-f' characters when represented as a string, and the presence of these characters isn't a robust way to distinguish between hex and decimal strings.

-// containsHexChars checks if a string contains hexadecimal characters (a-f)
-func containsHexChars(s string) bool {
-	for _, char := range s {
-		if (char >= 'a' && char <= 'f') || (char >= 'A' && char <= 'F') {
-			return true
-		}
-	}
-	return false
-}

And update the signal processing logic to handle formats more reliably:

 	// Process public signals, adding 0x prefix for hex values if needed
 	publicSignals := make([]string, len(pubSignals))
 	for i, signal := range pubSignals {
-		if len(signal) > 0 && containsHexChars(signal) {
-			publicSignals[i] = "0x" + signal
-		} else {
-			publicSignals[i] = signal
-		}
+		// Signals should already be in the correct format
+		// If they need 0x prefix, they should come with it
+		publicSignals[i] = signal
 	}
sdk/sdk-go/internal/selfBackendVerifier.go (4)

20-28: Remove unreliable containsHexChars function

This function is duplicated from the main verifier and has the same reliability issues.

-// containsHexChars checks if a string contains hexadecimal characters (a-f)
-func containsHexChars(s string) bool {
-	for _, char := range s {
-		if (char >= 'a' && char <= 'f') || (char >= 'A' && char <= 'F') {
-			return true
-		}
-	}
-	return false
-}

279-287: Add error handling for proof field parsing

Similar to the main verifier, the proof parsing ignores errors which could lead to silent failures.


431-434: Check return value from fmt.Sscanf

The parsing of circuitMinAge doesn't check for errors, which could silently fail.

 		circuitMinAgeInt := 0
 		if circuitMinAge != "00" {
-			fmt.Sscanf(circuitMinAge, "%d", &circuitMinAgeInt)
+			n, err := fmt.Sscanf(circuitMinAge, "%d", &circuitMinAgeInt)
+			if err != nil || n != 1 {
+				*issues = append(*issues, self.ConfigIssue{
+					Type:    self.InvalidMinimumAge,
+					Message: fmt.Sprintf("Failed to parse minimum age from circuit: %s", circuitMinAge),
+				})
+				return forbiddenCountriesList, genericDiscloseOutput, nil
+			}
 		}

483-495: Add validation for timestamp component ranges

The timestamp parsing needs the same range validation as the main verifier.

🧹 Nitpick comments (8)
sdk/sdk-go/examples/basic/go.mod (1)

7-32: Trim indirect requirements from example module to reduce churn

Examples don’t need to pin a large set of transitive deps. Let the main SDK’s go.mod drive versions; go mod tidy will add required entries automatically. Keeping this list in the example increases maintenance burden and supply-chain surface.

Minimal diff to drop the indirect block:

 require github.com/self/sdk v0.0.0

-require (
-	github.com/Microsoft/go-winio v0.6.2 // indirect
-	github.com/StackExchange/wmi v1.2.1 // indirect
-	github.com/bits-and-blooms/bitset v1.20.0 // indirect
-	github.com/consensys/gnark-crypto v0.18.0 // indirect
-	github.com/crate-crypto/go-eth-kzg v1.3.0 // indirect
-	github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect
-	github.com/deckarep/golang-set/v2 v2.6.0 // indirect
-	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
-	github.com/ethereum/c-kzg-4844/v2 v2.1.0 // indirect
-	github.com/ethereum/go-ethereum v1.16.2 // indirect
-	github.com/ethereum/go-verkle v0.2.2 // indirect
-	github.com/fsnotify/fsnotify v1.6.0 // indirect
-	github.com/go-ole/go-ole v1.3.0 // indirect
-	github.com/google/uuid v1.3.0 // indirect
-	github.com/gorilla/websocket v1.4.2 // indirect
-	github.com/holiman/uint256 v1.3.2 // indirect
-	github.com/iden3/go-iden3-crypto v0.0.17 // indirect
-	github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
-	github.com/supranational/blst v0.3.14 // indirect
-	github.com/tklauser/go-sysconf v0.3.12 // indirect
-	github.com/tklauser/numcpus v0.6.1 // indirect
-	golang.org/x/crypto v0.36.0 // indirect
-	golang.org/x/sync v0.12.0 // indirect
-	golang.org/x/sys v0.31.0 // indirect
-)

Optional: add a toolchain pin for reproducible builds:

+toolchain go1.23.0
sdk/sdk-go/sdk.go (1)

87-92: Clarify the “mockPassport” flag semantics

The docs say “Set mockPassport to true in NewBackendVerifier to use testnet contracts.” The flag name suggests it only affects passport, while it actually toggles network selection (mainnet vs. testnet) for the verifier. Consider renaming the parameter to something like useTestnet (or clarifying the comment to say it toggles network selection).

sdk/sdk-go/types.go (2)

37-50: Use Go initialism casing for exported fields (ID, OFAC)

Go style prefers common initialisms in all-caps. Renaming fields improves readability and aligns with conventions while preserving JSON compatibility via tags.

Apply this diff:

 type GenericDiscloseOutput struct {
 	Nullifier                    string   `json:"nullifier"`
 	ForbiddenCountriesListPacked []string `json:"forbiddenCountriesListPacked"`
 	IssuingState                 string   `json:"issuingState"`
 	Name                         string   `json:"name"`
-	IdNumber                     string   `json:"idNumber"`
+	IDNumber                     string   `json:"idNumber"`
 	Nationality                  string   `json:"nationality"`
 	DateOfBirth                  string   `json:"dateOfBirth"`
 	Gender                       string   `json:"gender"`
 	ExpiryDate                   string   `json:"expiryDate"`
 	MinimumAge                   string   `json:"minimumAge"`
-	Ofac                         []bool   `json:"ofac"`
+	OFAC                         []bool   `json:"ofac"`
 }

7-9: Centralize AttestationId constants alongside the type

If constants like Passport and EUCard live in a different file/package, consider moving (or aliasing) them here for a cohesive public API surface. This avoids scattered definitions and accidental value drift.

sdk/sdk-go/examples/custom-config/go.mod (1)

7-32: Trim indirect requirements from this example as well

Same rationale as the basic example: keep the example go.mod minimal to reduce maintenance. Let go mod tidy manage transitive deps.

 require github.com/self/sdk v0.0.0

-require (
-	... many indirect deps ...
-)

Optional toolchain pin:

+toolchain go1.23.0
sdk/sdk-go/examples/basic/main.go (2)

16-20: Optional: simplify pointer literals in examples

The &[]T{v}[0] pattern is valid but noisy. For readability, consider a small helper:

// At file scope
func ptr[T any](v T) *T { return &v }

// Usage:
MinimumAge: ptr(18),
Ofac:       ptr(false),

No functional change; just improves clarity for readers.


49-51: Avoid hardcoding allowed attestation names in output

Derive the printed list from allowedIds to avoid drift if supported types change.

Example:

fmt.Print("  - Allowed attestations: ")
names := make([]string, 0, len(allowedIds))
if allowedIds[self.Passport] { names = append(names, "Passport") }
if allowedIds[self.EUCard]   { names = append(names, "EU Card") }
fmt.Println(strings.Join(names, ", "))
sdk/sdk-go/README.md (1)

279-279: Consider a more professional commit message example

While enthusiasm is good, consider using a more conventional commit message format in documentation examples.

-3. Commit your changes (`git commit -m 'Add some amazing feature'`)
+3. Commit your changes (`git commit -m 'feat: add [feature description]'`)
📜 Review details

Configuration used: .coderabbit.yaml
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 30d8a92 and e0c5b1b.

⛔ Files ignored due to path filters (2)
  • sdk/sdk-go/examples/basic/go.sum is excluded by !**/*.sum
  • sdk/sdk-go/examples/custom-config/go.sum is excluded by !**/*.sum
📒 Files selected for processing (14)
  • sdk/sdk-go/InMemoryConfigStore.go (1 hunks)
  • sdk/sdk-go/README.md (1 hunks)
  • sdk/sdk-go/config.go (1 hunks)
  • sdk/sdk-go/examples/basic/go.mod (1 hunks)
  • sdk/sdk-go/examples/basic/main.go (1 hunks)
  • sdk/sdk-go/examples/custom-config/go.mod (1 hunks)
  • sdk/sdk-go/examples/custom-config/main.go (1 hunks)
  • sdk/sdk-go/go.mod (1 hunks)
  • sdk/sdk-go/internal/selfBackendVerifier.go (1 hunks)
  • sdk/sdk-go/internal/selfBackendVerifier_test.go (1 hunks)
  • sdk/sdk-go/sdk.go (1 hunks)
  • sdk/sdk-go/types.go (1 hunks)
  • sdk/sdk-go/utils.go (1 hunks)
  • sdk/sdk-go/verifier.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • sdk/sdk-go/go.mod
🧰 Additional context used
🧬 Code Graph Analysis (9)
sdk/sdk-go/examples/custom-config/main.go (4)
sdk/sdk-go/types.go (3)
  • VerificationConfig (18-22)
  • AttestationId (8-8)
  • UserIDTypeUUID (66-66)
sdk/sdk-go/utils.go (3)
  • Ofac (76-76)
  • Passport (17-17)
  • EUCard (18-18)
sdk/sdk-go/common/constants.go (2)
  • RUS (190-190)
  • IRN (112-112)
sdk/sdk-go/verifier.go (1)
  • NewBackendVerifier (90-133)
sdk/sdk-go/examples/basic/main.go (5)
sdk/sdk-go/types.go (3)
  • VerificationConfig (18-22)
  • AttestationId (8-8)
  • UserIDTypeHex (65-65)
sdk/sdk-go/common/constants.go (1)
  • USA (242-242)
sdk/sdk-go/utils.go (3)
  • Ofac (76-76)
  • Passport (17-17)
  • EUCard (18-18)
sdk/sdk-go/config.go (1)
  • NewDefaultConfigStore (23-27)
sdk/sdk-go/verifier.go (1)
  • NewBackendVerifier (90-133)
sdk/sdk-go/types.go (1)
sdk/sdk-go/utils.go (8)
  • Ofac (76-76)
  • IssuingState (68-68)
  • Name (69-69)
  • IdNumber (70-70)
  • Nationality (71-71)
  • DateOfBirth (72-72)
  • Gender (73-73)
  • ExpiryDate (74-74)
sdk/sdk-go/config.go (1)
sdk/sdk-go/types.go (1)
  • VerificationConfig (18-22)
sdk/sdk-go/verifier.go (7)
sdk/sdk-go/contracts/bindings/IdentityVerificationHubImpl.go (2)
  • IdentityVerificationHubImpl (42-46)
  • NewIdentityVerificationHubImpl (101-107)
sdk/sdk-go/config.go (1)
  • ConfigStore (8-15)
sdk/sdk-go/types.go (8)
  • AttestationId (8-8)
  • UserIDType (62-62)
  • VcAndDiscloseProof (11-15)
  • VerificationResult (53-59)
  • VerificationConfig (18-22)
  • GenericDiscloseOutput (38-50)
  • IsValidDetails (25-29)
  • UserData (32-35)
sdk/sdk-go/common/customHash.go (1)
  • HashEndpointWithScope (74-122)
sdk/sdk-go/utils.go (7)
  • DiscloseIndices (37-64)
  • CalculateUserIdentifierHash (242-261)
  • CastToUserIdentifier (199-208)
  • UnpackForbiddenCountriesList (175-196)
  • FormatRevealedDataPacked (346-423)
  • Ofac (76-76)
  • DiscloseIndicesEntry (22-34)
sdk/sdk-go/contracts/bindings/Registry.go (2)
  • Registry (42-46)
  • NewRegistry (101-107)
sdk/sdk-go/contracts/bindings/Verifier.go (1)
  • NewVerifier (101-107)
sdk/sdk-go/internal/selfBackendVerifier_test.go (4)
sdk/sdk-go/types.go (4)
  • VerificationConfig (18-22)
  • VcAndDiscloseProof (11-15)
  • AttestationId (8-8)
  • UserIDTypeUUID (66-66)
sdk/sdk-go/utils.go (2)
  • Ofac (76-76)
  • CalculateUserIdentifierHash (242-261)
sdk/sdk-go/internal/selfBackendVerifier.go (1)
  • NewSelfBackendVerifier (40-83)
sdk/sdk-go/verifier.go (1)
  • ConfigMismatchError (50-52)
sdk/sdk-go/InMemoryConfigStore.go (2)
sdk/sdk-go/types.go (1)
  • VerificationConfig (18-22)
sdk/sdk-go/config.go (1)
  • ConfigStore (8-15)
sdk/sdk-go/utils.go (2)
sdk/sdk-go/types.go (5)
  • AttestationId (8-8)
  • UserIDType (62-62)
  • UserIDTypeHex (65-65)
  • UserIDTypeUUID (66-66)
  • GenericDiscloseOutput (38-50)
sdk/sdk-go/common/utils.go (1)
  • UnpackReveal (14-62)
sdk/sdk-go/internal/selfBackendVerifier.go (8)
sdk/sdk-go/contracts/bindings/IdentityVerificationHubImpl.go (2)
  • IdentityVerificationHubImpl (42-46)
  • NewIdentityVerificationHubImpl (101-107)
sdk/sdk-go/config.go (1)
  • ConfigStore (8-15)
sdk/sdk-go/types.go (8)
  • AttestationId (8-8)
  • UserIDType (62-62)
  • VcAndDiscloseProof (11-15)
  • VerificationResult (53-59)
  • VerificationConfig (18-22)
  • GenericDiscloseOutput (38-50)
  • IsValidDetails (25-29)
  • UserData (32-35)
sdk/sdk-go/verifier.go (4)
  • CELO_MAINNET_RPC_URL (20-20)
  • IDENTITY_VERIFICATION_HUB_ADDRESS (23-23)
  • CELO_TESTNET_RPC_URL (21-21)
  • IDENTITY_VERIFICATION_HUB_ADDRESS_STAGING (24-24)
sdk/sdk-go/common/customHash.go (1)
  • HashEndpointWithScope (74-122)
sdk/sdk-go/utils.go (6)
  • DiscloseIndices (37-64)
  • CalculateUserIdentifierHash (242-261)
  • UnpackForbiddenCountriesList (175-196)
  • FormatRevealedDataPacked (346-423)
  • Ofac (76-76)
  • DiscloseIndicesEntry (22-34)
sdk/sdk-go/contracts/bindings/Registry.go (2)
  • Registry (42-46)
  • NewRegistry (101-107)
sdk/sdk-go/contracts/bindings/Verifier.go (1)
  • NewVerifier (101-107)
🪛 LanguageTool
sdk/sdk-go/README.md

[grammar] ~139-~139: There might be a mistake here.
Context: ...port: Traditional passport verification - self.EUCard`: European ID card verification ## Netw...

(QB_NEW_EN)


[style] ~279-~279: Consider using a more formal and expressive alternative to ‘amazing’.
Context: ...azing-feature) 3. Commit your changes (git commit -m 'Add some amazing feature') 4. Push to the branch (git ...

(AWESOME)

🔇 Additional comments (8)
sdk/sdk-go/examples/basic/go.mod (1)

34-34: Replace directive is correct

Confirmed that ../.. (from sdk/sdk-go/examples/basic) resolves to sdk/sdk-go, where go.mod declares module github.com/self/sdk. No changes required.

sdk/sdk-go/sdk.go (1)

94-95: Version constant looks good

Public version exposure is useful for telemetry and debugging.

sdk/sdk-go/types.go (1)

48-49: Validate type of MinimumAge in disclose output

MinimumAge here is a string, while the config uses *int. If this field is numeric in the circuit/public signals, consider representing it as an int to avoid downstream parsing. If it must remain a string (e.g., packed/hex), add a brief comment documenting the encoding.

sdk/sdk-go/examples/custom-config/go.mod (1)

34-34: Verify replace target path maps to the actual module root

As with the basic example, ensure ../.. points to the module that declares module github.com/self/sdk. If the module root is higher, use ../../...

You can run the same verification script shared for the basic example.

sdk/sdk-go/examples/custom-config/main.go (1)

109-109: Fix emoji rendering issue

Another malformed emoji character that needs correction.

-	fmt.Println(" Verifier with custom config store initialized!")
+	fmt.Println("✅ Verifier with custom config store initialized!")

Likely an incorrect or invalid review comment.

sdk/sdk-go/utils.go (3)

15-19: Good organization of attestation constants!

Using typed constants for attestation IDs improves code readability and type safety.


326-329: Add error handling for SetString failure

The function ignores the boolean return value from SetString, which could lead to using zero values if parsing fails.

 		publicSignal := new(big.Int)
 		publicSignal, success := publicSignal.SetString(publicSignals[signalIndex], 10)
 		if !success {
 			return nil, fmt.Errorf("failed to parse public signal at index %d: %s", signalIndex, publicSignals[signalIndex])
 		}

Wait, the code already handles this correctly. The success variable is checked and an error is returned if parsing fails.


279-285: Consider using float64 for ceiling calculation

The integer division on line 280 will always truncate, making the ceiling operation ineffective. For EUCard with 94 bytes, 93/31 equals 3, not 4 as intended.

 	case Passport:
-		return int(93 / 31), nil
+		return 3, nil // 93 bytes / 31 bytes per signal = 3 signals
 	case EUCard:
-		return int(math.Ceil(94.0 / 31.0)), nil
+		return 4, nil // 94 bytes / 31 bytes per signal = 4 signals (ceiling of 94/31)

Likely an incorrect or invalid review comment.

// SetConfig stores a verification configuration with the given ID
SetConfig(ctx context.Context, id string, config VerificationConfig) (bool, error)
// GetActionId retrieves the action ID for a given user identifier and user-defined data
GetActionId(ctx context.Context, userIdentifier string, actionId string) (string, error)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Parameter name inconsistency in interface vs implementation

The ConfigStore interface declares GetActionId with parameter actionId string, but the DefaultConfigStore implementation uses userDefinedData string. While Go allows this (parameters are positional), it's confusing and should be consistent for clarity.

 // GetActionId retrieves the action ID for a given user identifier and user-defined data
-GetActionId(ctx context.Context, userIdentifier string, actionId string) (string, error)
+GetActionId(ctx context.Context, userIdentifier string, userDefinedData string) (string, error)

Also applies to: 41-41

🤖 Prompt for AI Agents
In sdk/sdk-go/config.go around lines 14 and 41, the parameter name for
GetActionId is inconsistent between the ConfigStore interface (actionId string)
and the DefaultConfigStore implementation (userDefinedData string); update the
signatures so both declaration and implementation use the same parameter name
(choose one clear name—e.g., userDefinedData or actionId) and update any related
references to that parameter within the file to match.

Comment on lines +18 to +38
type DefaultConfigStore struct {
config VerificationConfig
}

// NewDefaultConfigStore creates a new DefaultConfigStore with the given configuration
func NewDefaultConfigStore(config VerificationConfig) *DefaultConfigStore {
return &DefaultConfigStore{
config: config,
}
}

// GetConfig returns the stored configuration
func (store *DefaultConfigStore) GetConfig(ctx context.Context, id string) (VerificationConfig, error) {
return store.config, nil
}

// SetConfig updates the stored configuration
func (store *DefaultConfigStore) SetConfig(ctx context.Context, id string, config VerificationConfig) (bool, error) {
store.config = config
return true, nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

DefaultConfigStore is not thread-safe

The DefaultConfigStore struct stores a mutable config field that can be accessed and modified concurrently through GetConfig and SetConfig methods without any synchronization mechanism. This could lead to race conditions in concurrent environments.

Consider adding a mutex for thread safety:

+import (
+    "context"
+    "sync"
+)

 // DefaultConfigStore provides a simple in-memory implementation of ConfigStore
 type DefaultConfigStore struct {
     config VerificationConfig
+    mu     sync.RWMutex
 }

 // GetConfig returns the stored configuration
 func (store *DefaultConfigStore) GetConfig(ctx context.Context, id string) (VerificationConfig, error) {
+    store.mu.RLock()
+    defer store.mu.RUnlock()
     return store.config, nil
 }

 // SetConfig updates the stored configuration
 func (store *DefaultConfigStore) SetConfig(ctx context.Context, id string, config VerificationConfig) (bool, error) {
+    store.mu.Lock()
+    defer store.mu.Unlock()
     store.config = config
     return true, nil
 }

Would you like me to open an issue to track adding thread safety to all config store implementations?

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In sdk/sdk-go/config.go around lines 18 to 38, DefaultConfigStore is not
thread-safe because its mutable config field is accessed concurrently; fix by
adding a sync.RWMutex to the struct, use RLock/RUnlock in GetConfig and
Lock/Unlock in SetConfig, ensure the sync package is imported, and keep the rest
of the API unchanged so concurrent reads are allowed while writes are exclusive.

}

// SetConfig updates the stored configuration
func (store *DefaultConfigStore) SetConfig(ctx context.Context, id string, config VerificationConfig) (bool, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix indentation issue

There's an incorrect indentation at the beginning of this line.

-	func (store *DefaultConfigStore) SetConfig(ctx context.Context, id string, config VerificationConfig) (bool, error) {
+func (store *DefaultConfigStore) SetConfig(ctx context.Context, id string, config VerificationConfig) (bool, error) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (store *DefaultConfigStore) SetConfig(ctx context.Context, id string, config VerificationConfig) (bool, error) {
func (store *DefaultConfigStore) SetConfig(ctx context.Context, id string, config VerificationConfig) (bool, error) {
🤖 Prompt for AI Agents
In sdk/sdk-go/config.go around line 35, the function declaration line "func
(store *DefaultConfigStore) SetConfig(ctx context.Context, id string, config
VerificationConfig) (bool, error) {" has incorrect leading indentation; remove
the extra leading spaces/tabs so the declaration aligns with file's top-level
function definitions (no indentation), ensuring consistent formatting with
surrounding code and gofmt style.


// GetActionId returns a default action ID
func (store *DefaultConfigStore) GetActionId(ctx context.Context, userIdentifier string, userDefinedData string) (string, error) {
return "random-id", nil
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

GetActionId returns a hardcoded value

The GetActionId method always returns "random-id" regardless of the input parameters. This appears to be a placeholder implementation that should either be properly implemented or documented as a stub.

Consider implementing actual logic or documenting this as a stub:

 // GetActionId returns a default action ID
+// TODO: Implement proper action ID generation logic based on user identifier and data
 func (store *DefaultConfigStore) GetActionId(ctx context.Context, userIdentifier string, userDefinedData string) (string, error) {
-    return "random-id", nil
+    // This is a placeholder implementation. In production, generate a proper action ID
+    // based on your business logic (e.g., hashing userIdentifier + userDefinedData)
+    return "default-action-id", nil
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return "random-id", nil
// GetActionId returns a default action ID
// TODO: Implement proper action ID generation logic based on user identifier and data
func (store *DefaultConfigStore) GetActionId(ctx context.Context, userIdentifier string, userDefinedData string) (string, error) {
// This is a placeholder implementation. In production, generate a proper action ID
// based on your business logic (e.g., hashing userIdentifier + userDefinedData)
return "default-action-id", nil
}
🤖 Prompt for AI Agents
In sdk/sdk-go/config.go around line 42, GetActionId currently returns the
hardcoded string "random-id"; replace this placeholder with a proper
implementation (e.g., derive and return an ID based on input parameters or
configuration, such as hashing relevant fields or generating a UUID) or clearly
mark the function as a stub by returning an error and documenting it. Ensure the
new implementation uses deterministic logic if callers expect stable IDs or a
generated UUID if uniqueness is required, and update the function
signature/return values and any callers/tests accordingly to handle the real ID
or error case.

@@ -0,0 +1,34 @@
module basic-example

go 1.23.0
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix go directive: patch version not allowed in go.mod

Go’s go directive must be major.minor only. Use go 1.23 instead of go 1.23.0.

Apply this diff:

-go 1.23.0
+go 1.23
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
go 1.23.0
go 1.23
🤖 Prompt for AI Agents
In sdk/sdk-go/examples/basic/go.mod around line 3, the go directive uses a patch
version ("go 1.23.0") which is invalid; update the directive to the major.minor
form ("go 1.23") by replacing "go 1.23.0" with "go 1.23".

Comment on lines +210 to +218
// CastToAddress converts big integer to hex address format (0x + 40 hex chars)
func CastToAddress(bigInt *big.Int) string {
hexStr := bigInt.Text(16) // Convert to hex without 0x prefix
// Pad to 40 characters (20 bytes = 40 hex chars)
if len(hexStr) < 40 {
hexStr = fmt.Sprintf("%040s", hexStr)
}
return "0x" + hexStr
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect padding in CastToAddress function

The fmt.Sprintf("%040s", hexStr) pads with spaces instead of zeros, which will produce invalid hex addresses.

 func CastToAddress(bigInt *big.Int) string {
 	hexStr := bigInt.Text(16) // Convert to hex without 0x prefix
 	// Pad to 40 characters (20 bytes = 40 hex chars)
 	if len(hexStr) < 40 {
-		hexStr = fmt.Sprintf("%040s", hexStr)
+		hexStr = strings.Repeat("0", 40-len(hexStr)) + hexStr
 	}
 	return "0x" + hexStr
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// CastToAddress converts big integer to hex address format (0x + 40 hex chars)
func CastToAddress(bigInt *big.Int) string {
hexStr := bigInt.Text(16) // Convert to hex without 0x prefix
// Pad to 40 characters (20 bytes = 40 hex chars)
if len(hexStr) < 40 {
hexStr = fmt.Sprintf("%040s", hexStr)
}
return "0x" + hexStr
}
// CastToAddress converts big integer to hex address format (0x + 40 hex chars)
func CastToAddress(bigInt *big.Int) string {
hexStr := bigInt.Text(16) // Convert to hex without 0x prefix
// Pad to 40 characters (20 bytes = 40 hex chars)
if len(hexStr) < 40 {
hexStr = strings.Repeat("0", 40-len(hexStr)) + hexStr
}
return "0x" + hexStr
}
🤖 Prompt for AI Agents
In sdk/sdk-go/utils.go around lines 210 to 218, the padding uses
fmt.Sprintf("%040s", hexStr) which pads with spaces; change it to pad with zeros
(e.g., use fmt.Sprintf("%0*s", 40, hexStr) or prepend strings.Repeat("0",
40-len(hexStr)) + hexStr) so the hex string is zero-left-padded to 40 characters
before returning "0x"+hexStr.

Comment on lines +253 to +258
hexString := fmt.Sprintf("%x", ripemdHash)

// Pad with leading zeros to ensure 40 hex chars
if len(hexString) < 40 {
hexString = fmt.Sprintf("%040s", hexString)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect padding in CalculateUserIdentifierHash function

Similar to the CastToAddress function, this uses space padding instead of zero padding for hex strings.

 	hexString := fmt.Sprintf("%x", ripemdHash)
 
 	// Pad with leading zeros to ensure 40 hex chars
 	if len(hexString) < 40 {
-		hexString = fmt.Sprintf("%040s", hexString)
+		hexString = strings.Repeat("0", 40-len(hexString)) + hexString
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
hexString := fmt.Sprintf("%x", ripemdHash)
// Pad with leading zeros to ensure 40 hex chars
if len(hexString) < 40 {
hexString = fmt.Sprintf("%040s", hexString)
}
hexString := fmt.Sprintf("%x", ripemdHash)
// Pad with leading zeros to ensure 40 hex chars
if len(hexString) < 40 {
hexString = strings.Repeat("0", 40-len(hexString)) + hexString
}
🤖 Prompt for AI Agents
In sdk/sdk-go/utils.go around lines 253 to 258, the code pads the hex string
using fmt.Sprintf("%040s", hexString) which inserts spaces not zeros; replace
the padding with zero-left hex formatting, e.g. produce the hex with zero
padding directly using fmt.Sprintf("%040x", ripemdHash) (or, if keeping the
initial hexString, set hexString = fmt.Sprintf("%040x", ripemdHash) when length
< 40) so hex digits are zero-padded correctly.

Comment on lines +350 to +358
a0, _ := new(big.Int).SetString(proof.A[0], 10)
a1, _ := new(big.Int).SetString(proof.A[1], 10)
b00, _ := new(big.Int).SetString(proof.B[0][0], 10)
b01, _ := new(big.Int).SetString(proof.B[0][1], 10)
b10, _ := new(big.Int).SetString(proof.B[1][0], 10)
b11, _ := new(big.Int).SetString(proof.B[1][1], 10)
c0, _ := new(big.Int).SetString(proof.C[0], 10)
c1, _ := new(big.Int).SetString(proof.C[1], 10)

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for proof field parsing

The proof field parsing ignores errors using the blank identifier, which could lead to silent failures with malformed proof data.

 			// Convert string proof fields to *big.Int
-			a0, _ := new(big.Int).SetString(proof.A[0], 10)
-			a1, _ := new(big.Int).SetString(proof.A[1], 10)
-			b00, _ := new(big.Int).SetString(proof.B[0][0], 10)
-			b01, _ := new(big.Int).SetString(proof.B[0][1], 10)
-			b10, _ := new(big.Int).SetString(proof.B[1][0], 10)
-			b11, _ := new(big.Int).SetString(proof.B[1][1], 10)
-			c0, _ := new(big.Int).SetString(proof.C[0], 10)
-			c1, _ := new(big.Int).SetString(proof.C[1], 10)
+			a0, ok := new(big.Int).SetString(proof.A[0], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field A[0]: %s", proof.A[0])
+			}
+			a1, ok := new(big.Int).SetString(proof.A[1], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field A[1]: %s", proof.A[1])
+			}
+			b00, ok := new(big.Int).SetString(proof.B[0][0], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field B[0][0]: %s", proof.B[0][0])
+			}
+			b01, ok := new(big.Int).SetString(proof.B[0][1], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field B[0][1]: %s", proof.B[0][1])
+			}
+			b10, ok := new(big.Int).SetString(proof.B[1][0], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field B[1][0]: %s", proof.B[1][0])
+			}
+			b11, ok := new(big.Int).SetString(proof.B[1][1], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field B[1][1]: %s", proof.B[1][1])
+			}
+			c0, ok := new(big.Int).SetString(proof.C[0], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field C[0]: %s", proof.C[0])
+			}
+			c1, ok := new(big.Int).SetString(proof.C[1], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field C[1]: %s", proof.C[1])
+			}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
a0, _ := new(big.Int).SetString(proof.A[0], 10)
a1, _ := new(big.Int).SetString(proof.A[1], 10)
b00, _ := new(big.Int).SetString(proof.B[0][0], 10)
b01, _ := new(big.Int).SetString(proof.B[0][1], 10)
b10, _ := new(big.Int).SetString(proof.B[1][0], 10)
b11, _ := new(big.Int).SetString(proof.B[1][1], 10)
c0, _ := new(big.Int).SetString(proof.C[0], 10)
c1, _ := new(big.Int).SetString(proof.C[1], 10)
// Convert string proof fields to *big.Int
a0, ok := new(big.Int).SetString(proof.A[0], 10)
if !ok {
return nil, fmt.Errorf("invalid proof field A[0]: %s", proof.A[0])
}
a1, ok := new(big.Int).SetString(proof.A[1], 10)
if !ok {
return nil, fmt.Errorf("invalid proof field A[1]: %s", proof.A[1])
}
b00, ok := new(big.Int).SetString(proof.B[0][0], 10)
if !ok {
return nil, fmt.Errorf("invalid proof field B[0][0]: %s", proof.B[0][0])
}
b01, ok := new(big.Int).SetString(proof.B[0][1], 10)
if !ok {
return nil, fmt.Errorf("invalid proof field B[0][1]: %s", proof.B[0][1])
}
b10, ok := new(big.Int).SetString(proof.B[1][0], 10)
if !ok {
return nil, fmt.Errorf("invalid proof field B[1][0]: %s", proof.B[1][0])
}
b11, ok := new(big.Int).SetString(proof.B[1][1], 10)
if !ok {
return nil, fmt.Errorf("invalid proof field B[1][1]: %s", proof.B[1][1])
}
c0, ok := new(big.Int).SetString(proof.C[0], 10)
if !ok {
return nil, fmt.Errorf("invalid proof field C[0]: %s", proof.C[0])
}
c1, ok := new(big.Int).SetString(proof.C[1], 10)
if !ok {
return nil, fmt.Errorf("invalid proof field C[1]: %s", proof.C[1])
}
🤖 Prompt for AI Agents
In sdk/sdk-go/verifier.go around lines 350 to 358, the big.Int parsing uses
new(big.Int).SetString(..., 10) while discarding the boolean result, which can
silently accept malformed proof fields; update each call to capture the (bigInt,
ok) result, check ok and return or propagate a descriptive error identifying the
failing field (including its name and value) so malformed proof data fails fast;
perform this validation for a0, a1, b00, b01, b10, b11, c0 and c1 and avoid
continuing when any SetString returns false.

Comment on lines +503 to +505
if circuitMinAge != "00" {
fmt.Sscanf(circuitMinAge, "%d", &circuitMinAgeInt)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Check return value from fmt.Sscanf

The use of fmt.Sscanf without checking the return value could silently fail, leaving circuitMinAgeInt as 0.

 		circuitMinAgeInt := 0
 		if circuitMinAge != "00" {
-			fmt.Sscanf(circuitMinAge, "%d", &circuitMinAgeInt)
+			n, err := fmt.Sscanf(circuitMinAge, "%d", &circuitMinAgeInt)
+			if err != nil || n != 1 {
+				// Handle parsing error - treat as invalid
+				*issues = append(*issues, ConfigIssue{
+					Type:    InvalidMinimumAge,
+					Message: fmt.Sprintf("Failed to parse minimum age from circuit: %s", circuitMinAge),
+				})
+				return forbiddenCountriesList, genericDiscloseOutput, nil
+			}
 		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if circuitMinAge != "00" {
fmt.Sscanf(circuitMinAge, "%d", &circuitMinAgeInt)
}
circuitMinAgeInt := 0
if circuitMinAge != "00" {
n, err := fmt.Sscanf(circuitMinAge, "%d", &circuitMinAgeInt)
if err != nil || n != 1 {
// Handle parsing error - treat as invalid
*issues = append(*issues, ConfigIssue{
Type: InvalidMinimumAge,
Message: fmt.Sprintf("Failed to parse minimum age from circuit: %s", circuitMinAge),
})
return forbiddenCountriesList, genericDiscloseOutput, nil
}
}
🤖 Prompt for AI Agents
In sdk/sdk-go/verifier.go around lines 503 to 505, the call to
fmt.Sscanf(circuitMinAge, "%d", &circuitMinAgeInt) is used without checking its
return values which can silently fail and leave circuitMinAgeInt as 0; update
the code to check fmt.Sscanf's returned count and error (or use strconv.Atoi to
parse the string), and if parsing does not return a single value or returns an
error, handle it explicitly by returning/logging an error or applying a defined
default value so failures are not silent.

Comment on lines +554 to +567
yy1, _ := strconv.Atoi(publicSignals[currentDateIndex])
yy2, _ := strconv.Atoi(publicSignals[currentDateIndex+1])
year := 2000 + yy1*10 + yy2

// Build month: MM digits
mm1, _ := strconv.Atoi(publicSignals[currentDateIndex+2])
mm2, _ := strconv.Atoi(publicSignals[currentDateIndex+3])
month := mm1*10 + mm2

// Build day: DD digits
dd1, _ := strconv.Atoi(publicSignals[currentDateIndex+4])
dd2, _ := strconv.Atoi(publicSignals[currentDateIndex+5])
day := dd1*10 + dd2

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add validation for timestamp component ranges

The timestamp parsing doesn't validate that the parsed components are within valid ranges (e.g., month 1-12, day 1-31).

 	// Build month: MM digits
 	mm1, _ := strconv.Atoi(publicSignals[currentDateIndex+2])
 	mm2, _ := strconv.Atoi(publicSignals[currentDateIndex+3])
 	month := mm1*10 + mm2
+	if month < 1 || month > 12 {
+		*issues = append(*issues, ConfigIssue{
+			Type:    InvalidTimestamp,
+			Message: fmt.Sprintf("Invalid month in timestamp: %d", month),
+		})
+		return
+	}
 
 	// Build day: DD digits
 	dd1, _ := strconv.Atoi(publicSignals[currentDateIndex+4])
 	dd2, _ := strconv.Atoi(publicSignals[currentDateIndex+5])
 	day := dd1*10 + dd2
+	if day < 1 || day > 31 {
+		*issues = append(*issues, ConfigIssue{
+			Type:    InvalidTimestamp,
+			Message: fmt.Sprintf("Invalid day in timestamp: %d", day),
+		})
+		return
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
yy1, _ := strconv.Atoi(publicSignals[currentDateIndex])
yy2, _ := strconv.Atoi(publicSignals[currentDateIndex+1])
year := 2000 + yy1*10 + yy2
// Build month: MM digits
mm1, _ := strconv.Atoi(publicSignals[currentDateIndex+2])
mm2, _ := strconv.Atoi(publicSignals[currentDateIndex+3])
month := mm1*10 + mm2
// Build day: DD digits
dd1, _ := strconv.Atoi(publicSignals[currentDateIndex+4])
dd2, _ := strconv.Atoi(publicSignals[currentDateIndex+5])
day := dd1*10 + dd2
yy1, _ := strconv.Atoi(publicSignals[currentDateIndex])
yy2, _ := strconv.Atoi(publicSignals[currentDateIndex+1])
year := 2000 + yy1*10 + yy2
// Build month: MM digits
mm1, _ := strconv.Atoi(publicSignals[currentDateIndex+2])
mm2, _ := strconv.Atoi(publicSignals[currentDateIndex+3])
month := mm1*10 + mm2
if month < 1 || month > 12 {
*issues = append(*issues, ConfigIssue{
Type: InvalidTimestamp,
Message: fmt.Sprintf("Invalid month in timestamp: %d", month),
})
return
}
// Build day: DD digits
dd1, _ := strconv.Atoi(publicSignals[currentDateIndex+4])
dd2, _ := strconv.Atoi(publicSignals[currentDateIndex+5])
day := dd1*10 + dd2
if day < 1 || day > 31 {
*issues = append(*issues, ConfigIssue{
Type: InvalidTimestamp,
Message: fmt.Sprintf("Invalid day in timestamp: %d", day),
})
return
}
🤖 Prompt for AI Agents
In sdk/sdk-go/verifier.go around lines 554 to 567, the code parses YYMMDD digits
from publicSignals but does not validate conversion errors nor that
month/day/year fall into valid ranges; update the parsing to check Atoi errors
for each component and verify ranges (yy >= 0, yy <= 99; month between 1 and 12;
day between 1 and the max day for that month/year), construct the full year as
2000+YY and validate the full date (e.g., by attempting to create a time.Date
and ensuring the resulting year/month/day match) and return a clear error if any
component or the assembled date is invalid.

Copy link
Contributor

@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: 2

♻️ Duplicate comments (17)
sdk/sdk-go/utils.go (2)

210-218: Fix incorrect padding in CastToAddress function

The fmt.Sprintf("%040s", hexStr) pads with spaces instead of zeros, which will produce invalid hex addresses.

 func CastToAddress(bigInt *big.Int) string {
 	hexStr := bigInt.Text(16) // Convert to hex without 0x prefix
 	// Pad to 40 characters (20 bytes = 40 hex chars)
 	if len(hexStr) < 40 {
-		hexStr = fmt.Sprintf("%040s", hexStr)
+		hexStr = strings.Repeat("0", 40-len(hexStr)) + hexStr
 	}
 	return "0x" + hexStr
 }

253-258: Fix incorrect padding in CalculateUserIdentifierHash function

Similar to the other padding issues, this uses space padding instead of zero padding for hex strings.

 	hexString := fmt.Sprintf("%x", ripemdHash)
 
 	// Pad with leading zeros to ensure 40 hex chars
 	if len(hexString) < 40 {
-		hexString = fmt.Sprintf("%040s", hexString)
+		hexString = strings.Repeat("0", 40-len(hexString)) + hexString
 	}
sdk/sdk-go/internal/selfBackendVerifier.go (5)

483-495: Add validation for timestamp component parsing

The timestamp parsing doesn't validate that the individual components are within valid ranges (e.g., month 1-12, day 1-31).

	// Build year: "20" + YY digits
	yy1, _ := strconv.Atoi(publicSignals[currentDateIndex])
	yy2, _ := strconv.Atoi(publicSignals[currentDateIndex+1])
	year := 2000 + yy1*10 + yy2

	// Build month: MM digits
	mm1, _ := strconv.Atoi(publicSignals[currentDateIndex+2])
	mm2, _ := strconv.Atoi(publicSignals[currentDateIndex+3])
	month := mm1*10 + mm2
+	if month < 1 || month > 12 {
+		*issues = append(*issues, ConfigIssue{
+			Type:    InvalidTimestamp,
+			Message: fmt.Sprintf("Invalid month in timestamp: %d", month),
+		})
+		return
+	}

	// Build day: DD digits
	dd1, _ := strconv.Atoi(publicSignals[currentDateIndex+4])
	dd2, _ := strconv.Atoi(publicSignals[currentDateIndex+5])
	day := dd1*10 + dd2
+	if day < 1 || day > 31 {
+		*issues = append(*issues, ConfigIssue{
+			Type:    InvalidTimestamp,
+			Message: fmt.Sprintf("Invalid day in timestamp: %d", day),
+		})
+		return
+	}

1-528: Consider consolidating duplicate code with main verifier

This file appears to duplicate significant functionality from sdk/sdk-go/verifier.go. The duplication includes the verification logic, helper functions, and error handling. This could lead to maintenance issues where fixes need to be applied in multiple places.

Consider refactoring to share common code between the two verifiers. You could:

  1. Create a base verifier struct with shared logic
  2. Have both BackendVerifier and SelfBackendVerifier embed or compose this base
  3. Move shared helper functions to a common utilities package

20-28: Remove unnecessary containsHexChars function

The containsHexChars function is checking for hex characters to determine formatting, but this approach is unreliable. A decimal number like "123456" could be valid hex, and checking for 'a-f' characters isn't a robust way to distinguish between hex and decimal strings.

-// containsHexChars checks if a string contains hexadecimal characters (a-f)
-func containsHexChars(s string) bool {
-	for _, char := range s {
-		if (char >= 'a' && char <= 'f') || (char >= 'A' && char <= 'F') {
-			return true
-		}
-	}
-	return false
-}

And update the usage in lines 112-117 to handle the format more reliably:

 	publicSignals := make([]string, len(pubSignals))
 	for i, signal := range pubSignals {
-		if len(signal) > 0 && containsHexChars(signal) {
-			publicSignals[i] = "0x" + signal
-		} else {
-			publicSignals[i] = signal
-		}
+		// Convert to decimal string format
+		publicSignals[i] = signal
 	}

431-434: Potential parsing error in minimum age validation

The use of fmt.Sscanf without checking the return value could silently fail, leaving circuitMinAgeInt as 0. This could lead to incorrect validation results.

 		circuitMinAgeInt := 0
 		if circuitMinAge != "00" {
-			fmt.Sscanf(circuitMinAge, "%d", &circuitMinAgeInt)
+			_, err := fmt.Sscanf(circuitMinAge, "%d", &circuitMinAgeInt)
+			if err != nil {
+				// Handle parsing error appropriately
+				circuitMinAgeInt = 0
+			}
 		}

279-287: Improve error handling for proof parsing

The proof field parsing uses the blank identifier to ignore errors, which could lead to silent failures if the proof data is malformed.

-			// Convert string proof fields to *big.Int
-			a0, _ := new(big.Int).SetString(proof.A[0], 10)
-			a1, _ := new(big.Int).SetString(proof.A[1], 10)
-			b00, _ := new(big.Int).SetString(proof.B[0][0], 10)
-			b01, _ := new(big.Int).SetString(proof.B[0][1], 10)
-			b10, _ := new(big.Int).SetString(proof.B[1][0], 10)
-			b11, _ := new(big.Int).SetString(proof.B[1][1], 10)
-			c0, _ := new(big.Int).SetString(proof.C[0], 10)
-			c1, _ := new(big.Int).SetString(proof.C[1], 10)
+			// Convert string proof fields to *big.Int with error checking
+			a0, ok := new(big.Int).SetString(proof.A[0], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field A[0]: %s", proof.A[0])
+			}
+			a1, ok := new(big.Int).SetString(proof.A[1], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field A[1]: %s", proof.A[1])
+			}
+			// Similar error checking for other fields...
sdk/sdk-go/README.md (3)

8-9: Fix the Go module import path

The import path should match the actual module path defined in your go.mod file. Based on the repository structure, it should be github.com/selfxyz/self/sdk/sdk-go rather than github.com/selfxyz/self/sdk/sdk-go@main.

The current import is already correct in the file. No change needed.


175-176: Fix import path for common package

The import path for the common package is incorrect and won't resolve properly.

-import "github.com/self/sdk/common"
+import "github.com/selfxyz/self/sdk/sdk-go/common"

294-294: Update Discord link to point to Self Protocol's community

The Discord link currently points to Worldcoin's community. This should be updated to point to the Self Protocol's official Discord server.

-- Join our [Discord community](https://discord.gg/worldcoin)
+- Join our [Discord community](https://discord.gg/self-protocol)
sdk/sdk-go/examples/custom-config/main.go (4)

67-67: Fix emoji rendering in console output

The emoji at the beginning of the line appears to be malformed or using an incorrect Unicode sequence.

-	fmt.Println(" Custom Configuration Store Example")
+	fmt.Println("🔧 Custom Configuration Store Example")

112-112: Fix emoji display issue

The configuration section header has a rendering issue with the emoji.

-	fmt.Println("\n Configuration Examples:")
+	fmt.Println("\n📋 Configuration Examples:")

125-125: Fix emoji in Action ID header

Emoji rendering issue in the Action ID Examples header.

-	fmt.Println("\n Action ID Examples:")
+	fmt.Println("\n🔑 Action ID Examples:")

135-135: Fix emoji in ready message

The final status message has an emoji rendering issue.

-	fmt.Println("\n Ready for verification with custom configuration logic!")
+	fmt.Println("\n🚀 Ready for verification with custom configuration logic!")
sdk/sdk-go/verifier.go (3)

554-567: Add validation for timestamp component ranges

The timestamp parsing doesn't validate that the parsed components are within valid ranges (e.g., month 1-12, day 1-31).

 	// Build month: MM digits
 	mm1, _ := strconv.Atoi(publicSignals[currentDateIndex+2])
 	mm2, _ := strconv.Atoi(publicSignals[currentDateIndex+3])
 	month := mm1*10 + mm2
+	if month < 1 || month > 12 {
+		*issues = append(*issues, ConfigIssue{
+			Type:    InvalidTimestamp,
+			Message: fmt.Sprintf("Invalid month in timestamp: %d", month),
+		})
+		return
+	}
 
 	// Build day: DD digits
 	dd1, _ := strconv.Atoi(publicSignals[currentDateIndex+4])
 	dd2, _ := strconv.Atoi(publicSignals[currentDateIndex+5])
 	day := dd1*10 + dd2
+	if day < 1 || day > 31 {
+		*issues = append(*issues, ConfigIssue{
+			Type:    InvalidTimestamp,
+			Message: fmt.Sprintf("Invalid day in timestamp: %d", day),
+		})
+		return
+	}

350-358: Add error handling for proof field parsing

The proof field parsing ignores errors using the blank identifier, which could lead to silent failures with malformed proof data.

 			// Convert string proof fields to *big.Int
-			a0, _ := new(big.Int).SetString(proof.A[0], 10)
-			a1, _ := new(big.Int).SetString(proof.A[1], 10)
-			b00, _ := new(big.Int).SetString(proof.B[0][0], 10)
-			b01, _ := new(big.Int).SetString(proof.B[0][1], 10)
-			b10, _ := new(big.Int).SetString(proof.B[1][0], 10)
-			b11, _ := new(big.Int).SetString(proof.B[1][1], 10)
-			c0, _ := new(big.Int).SetString(proof.C[0], 10)
-			c1, _ := new(big.Int).SetString(proof.C[1], 10)
+			a0, ok := new(big.Int).SetString(proof.A[0], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field A[0]: %s", proof.A[0])
+			}
+			a1, ok := new(big.Int).SetString(proof.A[1], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field A[1]: %s", proof.A[1])
+			}
+			b00, ok := new(big.Int).SetString(proof.B[0][0], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field B[0][0]: %s", proof.B[0][0])
+			}
+			b01, ok := new(big.Int).SetString(proof.B[0][1], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field B[0][1]: %s", proof.B[0][1])
+			}
+			b10, ok := new(big.Int).SetString(proof.B[1][0], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field B[1][0]: %s", proof.B[1][0])
+			}
+			b11, ok := new(big.Int).SetString(proof.B[1][1], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field B[1][1]: %s", proof.B[1][1])
+			}
+			c0, ok := new(big.Int).SetString(proof.C[0], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field C[0]: %s", proof.C[0])
+			}
+			c1, ok := new(big.Int).SetString(proof.C[1], 10)
+			if !ok {
+				return nil, fmt.Errorf("invalid proof field C[1]: %s", proof.C[1])
+			}

502-505: Check return value from fmt.Sscanf

The use of fmt.Sscanf without checking the return value could silently fail, leaving circuitMinAgeInt as 0.

 		circuitMinAgeInt := 0
 		if circuitMinAge != "00" {
-			fmt.Sscanf(circuitMinAge, "%d", &circuitMinAgeInt)
+			n, err := fmt.Sscanf(circuitMinAge, "%d", &circuitMinAgeInt)
+			if err != nil || n != 1 {
+				// Handle parsing error - treat as invalid
+				*issues = append(*issues, ConfigIssue{
+					Type:    InvalidMinimumAge,
+					Message: fmt.Sprintf("Failed to parse minimum age from circuit: %s", circuitMinAge),
+				})
+				return forbiddenCountriesList, genericDiscloseOutput, nil
+			}
 		}
📜 Review details

Configuration used: .coderabbit.yaml
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 e0c5b1b and 42f081a.

📒 Files selected for processing (11)
  • sdk/sdk-go/README.md (1 hunks)
  • sdk/sdk-go/examples/basic/go.mod (1 hunks)
  • sdk/sdk-go/examples/basic/main.go (1 hunks)
  • sdk/sdk-go/examples/custom-config/go.mod (1 hunks)
  • sdk/sdk-go/examples/custom-config/main.go (1 hunks)
  • sdk/sdk-go/go.mod (1 hunks)
  • sdk/sdk-go/internal/selfBackendVerifier.go (1 hunks)
  • sdk/sdk-go/internal/selfBackendVerifier_test.go (1 hunks)
  • sdk/sdk-go/types.go (1 hunks)
  • sdk/sdk-go/utils.go (1 hunks)
  • sdk/sdk-go/verifier.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • sdk/sdk-go/examples/basic/main.go
  • sdk/sdk-go/examples/custom-config/go.mod
  • sdk/sdk-go/types.go
  • sdk/sdk-go/internal/selfBackendVerifier_test.go
  • sdk/sdk-go/examples/basic/go.mod
  • sdk/sdk-go/go.mod
🧰 Additional context used
🧬 Code Graph Analysis (2)
sdk/sdk-go/examples/custom-config/main.go (4)
sdk/sdk-go/types.go (2)
  • VerificationConfig (18-22)
  • AttestationId (8-8)
sdk/sdk-go/utils.go (3)
  • Ofac (76-76)
  • Passport (17-17)
  • EUCard (18-18)
sdk/sdk-go/common/constants.go (2)
  • RUS (190-190)
  • IRN (112-112)
sdk/sdk-go/verifier.go (1)
  • NewBackendVerifier (90-133)
sdk/sdk-go/verifier.go (7)
sdk/sdk-go/contracts/bindings/IdentityVerificationHubImpl.go (2)
  • IdentityVerificationHubImpl (42-46)
  • NewIdentityVerificationHubImpl (101-107)
sdk/sdk-go/config.go (1)
  • ConfigStore (8-15)
sdk/sdk-go/types.go (8)
  • AttestationId (8-8)
  • UserIDType (62-62)
  • VcAndDiscloseProof (11-15)
  • VerificationResult (53-59)
  • VerificationConfig (18-22)
  • GenericDiscloseOutput (38-50)
  • IsValidDetails (25-29)
  • UserData (32-35)
sdk/sdk-go/common/customHash.go (1)
  • HashEndpointWithScope (74-122)
sdk/sdk-go/utils.go (5)
  • DiscloseIndices (37-64)
  • CalculateUserIdentifierHash (242-261)
  • FormatRevealedDataPacked (346-423)
  • Ofac (76-76)
  • DiscloseIndicesEntry (22-34)
sdk/sdk-go/contracts/bindings/Registry.go (2)
  • Registry (42-46)
  • NewRegistry (101-107)
sdk/sdk-go/contracts/bindings/Verifier.go (1)
  • NewVerifier (101-107)
🪛 LanguageTool
sdk/sdk-go/README.md

[grammar] ~140-~140: There might be a mistake here.
Context: ...port: Traditional passport verification - self.EUCard`: European ID card verification ## Netw...

(QB_NEW_EN)


[style] ~280-~280: Consider using a more formal and expressive alternative to ‘amazing’.
Context: ...azing-feature) 3. Commit your changes (git commit -m 'Add some amazing feature') 4. Push to the branch (git ...

(AWESOME)

🔇 Additional comments (2)
sdk/sdk-go/README.md (1)

23-24: Import path is already correct

The import statement correctly uses the full module path.

sdk/sdk-go/examples/custom-config/main.go (1)

9-11: Import paths are correct

The import paths correctly reference the module structure.

Comment on lines +220 to +230
// CastToUUID converts big integer to UUID format
func CastToUUID(bigInt *big.Int) string {
hexStr := bigInt.Text(16) // Convert to hex without 0x prefix
// Pad to 32 characters
if len(hexStr) < 32 {
hexStr = fmt.Sprintf("%032s", hexStr)
}
// Format as UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
return fmt.Sprintf("%s-%s-%s-%s-%s",
hexStr[0:8], hexStr[8:12], hexStr[12:16], hexStr[16:20], hexStr[20:32])
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect padding in CastToUUID function

Similar to CastToAddress, this function uses space padding instead of zero padding, which will result in malformed UUIDs.

 func CastToUUID(bigInt *big.Int) string {
 	hexStr := bigInt.Text(16) // Convert to hex without 0x prefix
 	// Pad to 32 characters
 	if len(hexStr) < 32 {
-		hexStr = fmt.Sprintf("%032s", hexStr)
+		hexStr = strings.Repeat("0", 32-len(hexStr)) + hexStr
 	}
 	// Format as UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
 	return fmt.Sprintf("%s-%s-%s-%s-%s",
 		hexStr[0:8], hexStr[8:12], hexStr[12:16], hexStr[16:20], hexStr[20:32])
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// CastToUUID converts big integer to UUID format
func CastToUUID(bigInt *big.Int) string {
hexStr := bigInt.Text(16) // Convert to hex without 0x prefix
// Pad to 32 characters
if len(hexStr) < 32 {
hexStr = fmt.Sprintf("%032s", hexStr)
}
// Format as UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
return fmt.Sprintf("%s-%s-%s-%s-%s",
hexStr[0:8], hexStr[8:12], hexStr[12:16], hexStr[16:20], hexStr[20:32])
}
// CastToUUID converts big integer to UUID format
func CastToUUID(bigInt *big.Int) string {
hexStr := bigInt.Text(16) // Convert to hex without 0x prefix
// Pad to 32 characters
if len(hexStr) < 32 {
hexStr = strings.Repeat("0", 32-len(hexStr)) + hexStr
}
// Format as UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
return fmt.Sprintf("%s-%s-%s-%s-%s",
hexStr[0:8], hexStr[8:12], hexStr[12:16], hexStr[16:20], hexStr[20:32])
}
🤖 Prompt for AI Agents
In sdk/sdk-go/utils.go around lines 220 to 230, CastToUUID currently pads the
hex string using fmt.Sprintf("%032s") which pads with spaces and produces
malformed UUIDs; replace that padding with zero-padding by prepending the
required number of '0' characters (e.g. if len(hexStr) < 32 then hexStr =
strings.Repeat("0", 32-len(hexStr)) + hexStr), update imports to include
"strings" if missing, and keep the existing UUID slicing/formatting logic
unchanged.

Comment on lines +135 to +143
// containsHexChars checks if a string contains hexadecimal characters (a-f)
func containsHexChars(s string) bool {
for _, char := range s {
if (char >= 'a' && char <= 'f') || (char >= 'A' && char <= 'F') {
return true
}
}
return false
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove unnecessary containsHexChars function

The containsHexChars function is unreliable for determining hex vs decimal format. The approach of checking for 'a-f' characters won't work correctly for all cases.

-// containsHexChars checks if a string contains hexadecimal characters (a-f)
-func containsHexChars(s string) bool {
-	for _, char := range s {
-		if (char >= 'a' && char <= 'f') || (char >= 'A' && char <= 'F') {
-			return true
-		}
-	}
-	return false
-}

And update the usage in lines 182-188:

 	publicSignals := make([]string, len(pubSignals))
 	for i, signal := range pubSignals {
-		if len(signal) > 0 && containsHexChars(signal) {
-			publicSignals[i] = "0x" + signal
-		} else {
-			publicSignals[i] = signal
-		}
+		// Keep signals as-is - they should already be properly formatted
+		publicSignals[i] = signal
 	}
🤖 Prompt for AI Agents
In sdk/sdk-go/verifier.go around lines 135-143 (and update usage at lines
182-188): remove the unreliable containsHexChars function entirely and change
the code that depended on it to parse numeric strings using the standard library
detection instead of character inspection; specifically, replace logic that
checks containsHexChars with strconv.ParseUint (or strconv.ParseInt) using base
0 so Go will auto-detect "0x" hex prefixes and decimal values, handle parse
errors explicitly, and use the parsed numeric result rather than inferring
format from character ranges.

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.

3 participants