Skip to content

Commit b06caa9

Browse files
committed
Refactor SignWithSigner to reduce cognitive complexity
Extract computeSigningDigest helper function to reduce cognitive complexity of SignWithSigner from 27 to under 15. The new helper handles: - Canonicalization of credential and proof config - Hash computation of both components - Curve-appropriate re-hashing of combined data This improves code maintainability per SonarCloud recommendations.
1 parent 593889a commit b06caa9

File tree

1 file changed

+37
-26
lines changed

1 file changed

+37
-26
lines changed

pkg/vc20/crypto/ecdsa/suite.go

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -147,29 +147,16 @@ func hashCombinedData(combined []byte, pubKey crypto.PublicKey) []byte {
147147
return hasher.Sum(nil)
148148
}
149149

150-
// SignWithSigner signs a credential using ecdsa-rdfc-2019 with a VCSigner.
151-
// This method supports both raw keys (via wrappers) and HSM-backed keys (via pki.RawSigner).
152-
func (s *Suite) SignWithSigner(ctx context.Context, cred *credential.RDFCredential, signer vccrypto.VCSigner, opts *SignOptions) (*credential.RDFCredential, error) {
153-
if cred == nil {
154-
return nil, fmt.Errorf("credential is nil")
155-
}
156-
if signer == nil {
157-
return nil, fmt.Errorf("signer is nil")
158-
}
159-
if opts == nil {
160-
return nil, fmt.Errorf("sign options are nil")
161-
}
162-
163-
// 1. Get canonical document hash (without proof)
150+
// computeSigningDigest computes the digest to be signed from credential and proof config.
151+
// Returns the combined hash of (proofHash || docHash) re-hashed to curve-appropriate size.
152+
func computeSigningDigest(cred *credential.RDFCredential, proofConfig map[string]any, pubKey crypto.PublicKey) ([]byte, error) {
153+
// Get canonical document (without proof)
164154
credWithoutProof, err := cred.CredentialWithoutProof()
165155
if err != nil {
166156
return nil, fmt.Errorf("failed to get credential without proof: %w", err)
167157
}
168158

169-
// 2. Create proof configuration using helper
170-
proofConfig := buildProofConfig(opts)
171-
172-
// 3. Canonicalize and hash proof configuration
159+
// Canonicalize proof configuration
173160
proofConfigBytes, err := json.Marshal(proofConfig)
174161
if err != nil {
175162
return nil, fmt.Errorf("failed to marshal proof config: %w", err)
@@ -183,7 +170,7 @@ func (s *Suite) SignWithSigner(ctx context.Context, cred *credential.RDFCredenti
183170
return nil, fmt.Errorf("failed to create RDF credential for proof config: %w", err)
184171
}
185172

186-
// 4. Combine hashes
173+
// Get canonical forms
187174
docCanonical, err := credWithoutProof.CanonicalForm()
188175
if err != nil {
189176
return nil, fmt.Errorf("failed to get canonical form of document: %w", err)
@@ -194,28 +181,49 @@ func (s *Suite) SignWithSigner(ctx context.Context, cred *credential.RDFCredenti
194181
return nil, fmt.Errorf("failed to get canonical form of proof config: %w", err)
195182
}
196183

184+
// Compute combined hash
197185
docHashBytes := sha256.Sum256([]byte(docCanonical))
198186
proofHashBytes := sha256.Sum256([]byte(proofCanonical))
199187
combined := append(proofHashBytes[:], docHashBytes[:]...)
200188

201-
// 5. Hash combined data to curve-appropriate size before signing.
202-
// This ensures both proofHash and docHash are cryptographically bound
203-
// in the signature (raw ECDSA would truncate to curve order size).
204-
digest := hashCombinedData(combined, signer.PublicKey())
189+
return hashCombinedData(combined, pubKey), nil
190+
}
191+
192+
// SignWithSigner signs a credential using ecdsa-rdfc-2019 with a VCSigner.
193+
// This method supports both raw keys (via wrappers) and HSM-backed keys (via pki.RawSigner).
194+
func (s *Suite) SignWithSigner(ctx context.Context, cred *credential.RDFCredential, signer vccrypto.VCSigner, opts *SignOptions) (*credential.RDFCredential, error) {
195+
if cred == nil {
196+
return nil, fmt.Errorf("credential is nil")
197+
}
198+
if signer == nil {
199+
return nil, fmt.Errorf("signer is nil")
200+
}
201+
if opts == nil {
202+
return nil, fmt.Errorf("sign options are nil")
203+
}
204+
205+
// Build proof configuration
206+
proofConfig := buildProofConfig(opts)
205207

206-
// 6. Sign using the VCSigner
208+
// Compute the digest to sign
209+
digest, err := computeSigningDigest(cred, proofConfig, signer.PublicKey())
210+
if err != nil {
211+
return nil, err
212+
}
213+
214+
// Sign using the VCSigner
207215
signature, err := signer.SignDigest(ctx, digest)
208216
if err != nil {
209217
return nil, fmt.Errorf("failed to sign: %w", err)
210218
}
211219

212-
// 7. Encode signature (multibase base58-btc)
220+
// Encode signature (multibase base58-btc)
213221
proofValue, err := multibase.Encode(multibase.Base58BTC, signature)
214222
if err != nil {
215223
return nil, fmt.Errorf("failed to encode signature: %w", err)
216224
}
217225

218-
// 7. Add proof to credential using helpers
226+
// Add proof to credential
219227
credMap, err := getCredentialAsMap(cred)
220228
if err != nil {
221229
return nil, err
@@ -230,6 +238,9 @@ func (s *Suite) SignWithSigner(ctx context.Context, cred *credential.RDFCredenti
230238
return nil, fmt.Errorf("failed to marshal new credential: %w", err)
231239
}
232240

241+
ldOpts := credential.NewJSONLDOptions("")
242+
ldOpts.Algorithm = ld.AlgorithmURDNA2015
243+
233244
return credential.NewRDFCredentialFromJSON(newCredBytes, ldOpts)
234245
}
235246

0 commit comments

Comments
 (0)