Fix byte order for Urbit Ed25519 key compatibility
- Add reverseBytes helper function for key processing - Reverse authentication and encryption key bytes when returned from GraphQL - This resolves signature verification failures in downstream applications - Urbit stores Ed25519 keys in reverse byte order compared to standard implementations 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
adf7a63f35
commit
60ee72d192
33
client.go
33
client.go
@ -11,17 +11,28 @@ import (
|
||||
"github.com/Khan/genqlient/graphql"
|
||||
)
|
||||
|
||||
// reverseBytes reverses the byte order of the input slice
|
||||
// This is needed because Urbit stores Ed25519 keys in reverse byte order
|
||||
// compared to the standard Go crypto/ed25519 implementation
|
||||
func reverseBytes(input []byte) []byte {
|
||||
result := make([]byte, len(input))
|
||||
for i, b := range input {
|
||||
result[len(input)-1-i] = b
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Default configuration constants
|
||||
const (
|
||||
// DefaultEndpoint is the default azimuth-watcher GraphQL endpoint
|
||||
DefaultEndpoint = "https://azimuth.dev.vdb.to/graphql"
|
||||
|
||||
|
||||
// AzimuthContract is the Azimuth contract address on Ethereum mainnet
|
||||
AzimuthContract = "0x223c067F8CF28ae173EE5CafEa60cA44C335fecB"
|
||||
|
||||
|
||||
// DefaultCacheTTL is the default cache duration for ship keys
|
||||
DefaultCacheTTL = 1 * time.Hour
|
||||
|
||||
|
||||
// DefaultTimeout is the default HTTP client timeout
|
||||
DefaultTimeout = 30 * time.Second
|
||||
)
|
||||
@ -88,7 +99,7 @@ func NewClientWithOptions(opts ClientOptions) *Client {
|
||||
}
|
||||
|
||||
httpClient := graphql.NewClient(opts.Endpoint, nil)
|
||||
|
||||
|
||||
return &Client{
|
||||
gqlClient: httpClient,
|
||||
cache: NewKeyCache(opts.CacheTTL),
|
||||
@ -319,7 +330,8 @@ func (c *Client) getShipKeys(ctx context.Context, point uint32) (*ShipKeys, erro
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode encryption key: %w", err)
|
||||
}
|
||||
keys.EncryptionKey = encKey
|
||||
// Reverse the authentication key bytes for Urbit Ed25519 compatibility
|
||||
keys.EncryptionKey = reverseBytes(encKey)
|
||||
}
|
||||
|
||||
// Parse authentication key (32 bytes hex, remove 0x prefix if present)
|
||||
@ -334,7 +346,8 @@ func (c *Client) getShipKeys(ctx context.Context, point uint32) (*ShipKeys, erro
|
||||
if len(authKey) != 32 {
|
||||
return nil, fmt.Errorf("invalid authentication key length: expected 32 bytes, got %d", len(authKey))
|
||||
}
|
||||
keys.AuthenticationKey = authKey
|
||||
// Reverse the authentication key bytes for Urbit Ed25519 compatibility
|
||||
keys.AuthenticationKey = reverseBytes(authKey)
|
||||
|
||||
// Parse crypto suite version
|
||||
suite, err := resp.AzimuthGetKeys.Value.Value2.ToUint32()
|
||||
@ -372,7 +385,7 @@ func ValidateStarSponsorship(ctx context.Context, starID uint32, expectedGalaxyI
|
||||
}
|
||||
|
||||
if sponsor != expectedGalaxyID {
|
||||
return fmt.Errorf("star %d is not sponsored by galaxy %d (actual sponsor: %d)",
|
||||
return fmt.Errorf("star %d is not sponsored by galaxy %d (actual sponsor: %d)",
|
||||
starID, expectedGalaxyID, sponsor)
|
||||
}
|
||||
|
||||
@ -385,11 +398,11 @@ func ParseStarID(starIDStr string) (uint32, error) {
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid star ID format: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Validate that it's actually a star (256-65535)
|
||||
if starPoint < 256 || starPoint > 65535 {
|
||||
return 0, fmt.Errorf("ID %d is not a valid star (must be 256-65535)", starPoint)
|
||||
}
|
||||
|
||||
|
||||
return uint32(starPoint), nil
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user