Skip to content

feat(backend): add ETH/SOL public-key-to-address encoders#13166

Draft
AntonioVentilii wants to merge 2 commits into
mainfrom
feat/onramper-address-encoders
Draft

feat(backend): add ETH/SOL public-key-to-address encoders#13166
AntonioVentilii wants to merge 2 commits into
mainfrom
feat/onramper-address-encoders

Conversation

@AntonioVentilii

Copy link
Copy Markdown
Collaborator

Motivation

Prep for closing the OnRamper signing oracle (spec: docs/ai/spec-driven-development/specs/2026-06-22-fix-onramper-signing-oracle.md, draft PR #13164). To sign only the caller's own wallet addresses, the backend must derive them from the caller principal — which needs a way to turn a threshold public key into an Ethereum and a Solana address. The backend already does this for Bitcoin (btc_principal_to_p2wpkh_address) but had no ETH/SOL equivalent.

This is the first, additive PR in a 2-PR stack. It adds the pure pubkey→address encoders (no inter-canister calls), fully unit-tested in isolation. The follow-up PR wires the management-canister public-key reads and the endpoint rewrite, where integration tests prove end-to-end derivation parity against the signer.

Changes

  • Add tiny-keccak (Keccak-256 — Ethereum's hash, distinct from NIST SHA-3) and bs58 as backend dependencies. Both were already in the lockfile; tiny-keccak is the crate used elsewhere in the dfinity Ethereum stack.
  • src/backend/src/signer/service.rs:
    • eth_address_from_ecdsa_pubkey — EIP-55-checksummed Ethereum address from a SEC1 secp256k1 public key (keccak256 of the 64-byte uncompressed key, last 20 bytes, checksummed).
    • sol_address_from_ed25519_pubkey — Solana address (base58 of the 32-byte Ed25519 public key).
    • Helpers keccak256 and to_eip55_checksum.
  • Both entry points are #[cfg_attr(not(test), expect(dead_code, ...))] until the stacked follow-up PR wires them into sign_onramper_widget_url.

Tests

New unit tests in signer::service::tests (all passing):

  • ETH address matches the canonical known-answer vector for secp256k1 private key 1 (0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf), proving both keccak derivation and EIP-55 checksum; compressed/uncompressed pubkey inputs agree; invalid pubkey rejected.
  • SOL address of the all-zero pubkey is the known System-Program base58 string; base58 round-trips back to the pubkey; wrong-length pubkey rejected.

Local gates: cargo fmt, ./scripts/lint.rust.sh (wasm + native), targeted cargo test all pass.

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.

1 participant