Align Go SDK Cascade Signatures with JS (Keplr) ADR-36 Format#233
Align Go SDK Cascade Signatures with JS (Keplr) ADR-36 Format#233
Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR aligns the Go SDK's Cascade signature generation with the JavaScript SDK (Keplr) by implementing ADR-36 signing. Previously, Go signed raw bytes while JS signed ADR-36 documents, causing signature mismatches even when using the same account and file.
Key Changes:
- Implemented ADR-36 signing support via new
SignADR36StringandCreateSignaturesWithKeyringADR36functions - Updated signature generation to sign layout base64 and index JSON using ADR-36 (matching Keplr behavior)
- Enhanced verification functions (
VerifyLayout,VerifyIndex) to support both legacy raw signatures and new ADR-36 signatures for backward compatibility
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| sdk/action/client.go | Migrated to ADR-36 signature generation; deprecated old raw signing function; removed unused imports; changed initial counter to hardcoded value |
| pkg/cascadekit/signatures.go | Added ADR-36 signing functions (SignADR36String, CreateSignaturesWithKeyringADR36); updated SignIndexB64 to sign JSON string instead of base64; moved CreateSignaturesWithKeyring from deleted file; improved documentation |
| pkg/cascadekit/verify.go | Enhanced VerifyLayout and VerifyIndex to support both legacy and ADR-36 signature schemes; improved documentation formatting |
| pkg/cascadekit/keyring_signatures.go | Removed file; functionality moved to signatures.go |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| //rnd, _ := crand.Int(crand.Reader, big.NewInt(100)) | ||
| ic := uint32(6) |
There was a problem hiding this comment.
The initial counter ic is now hardcoded to 6 instead of being randomly selected from [1, 100]. This change reduces the randomness of generated RQIDs and could lead to predictable signature patterns. While the commented-out line suggests this might be temporary for testing/debugging purposes, it should either be removed or the random generation should be restored for production use.
If this is intentional for JS compatibility, please add a comment explaining why this specific value is required.
| //rnd, _ := crand.Int(crand.Reader, big.NewInt(100)) | |
| ic := uint32(6) | |
| rnd, err := crand.Int(crand.Reader, big.NewInt(100)) | |
| if err != nil { | |
| return actiontypes.CascadeMetadata{}, "", "", fmt.Errorf("failed to generate random initial counter: %w", err) | |
| } | |
| ic := uint32(rnd.Int64() + 1) |
PR: Align Go SDK Cascade Signatures with JS (Keplr) ADR-36 Format
Summary
This PR updates the Go Cascade SDK to generate signatures and metadata identical to the JS SDK (Keplr). Previously, Cascade actions created via Go (
sn-api-server) produced signatures that did not match those produced by the JS SDK, even when using the same account and the same file. This caused mismatches when testing across Go and browser clients, and made it difficult to verify signatures in a unified way.Problem
The signature mismatch came from two root causes:
1. Go signed raw bytes while JS (Keplr) signed ADR-36 documents
Go used:
JS used:
which internally constructs:
{ "chain_id": "", "account_number": "0", "sequence": "0", "fee": {"gas":"0","amount":[]}, "msgs":[{"type":"sign/MsgSignData","value":{"signer": "<bech32>", "data": base64(messageBytes) }}], "memo":"" }This means:
[]byte(message)2. JS signs different message strings
Go previously signed:
layoutB64bytes (not ADR-36),indexB64,dataHashB64.So even if both sides used the same key, the signed payloads differed → signatures diverged.
What This PR Changes
✅ 1. Added full ADR-36 signing support in Go (
SignADR36String)Go now constructs ADR-36 canonical sign bytes identical to Keplr:
✅ 2. Reimplemented layout + index signature generation to match JS
Replaced raw signing with ADR-36 Keplr-compatible signing:
layoutB64using ADR-36This is now identical to JS’s
indexWithSignature.✅ 3.
GenerateStartCascadeSignatureFromFilenow matcheskeplr.signArbitrary(dataHash)Go now produces the same auth/start-cascade signature as JS for the same file and key.
✅ 4. Kept backward compatibility
Supernode validation (
VerifyIndex,VerifyLayout) already tries:So:
Result
After these changes:
Go and JS produce identical values for:
data_hashsignatures(indexSignatureFormat)authSignature(StartCascade signature)Cross-client Cascade actions work consistently.
Supernodes can process both legacy Go and modern JS signatures.