Just wrapped the first crypto milestone for the Sui Go SDK I'm building. I started by understanding how Sui treats signatures, then implemented the derivation logic and tests around those rules.
One important thing to know is that Sui never signs raw bytes. Every signature starts with a three-byte "intent" tag that answers:
- What kind of payload is this (transaction, personal message, checkpoint, etc.)?
- Which version of that payload are we using?
- Which application owns it (Sui, Narwhal, etc.)?
Only after that tag is in place do we hash and sign the combined bytes. It feels extra, but that's what prevents transaction replays elsewhere and keeps future format updates from breaking old signatures.
With the understanding of intent, I moved on to the core crypto implementation. I started with the easiest scheme: Ed25519, then Secp256k1 and Secp256r1. With this, you can now generate Sui keypairs and import private keys with the SDK for any of those schemes, and they stay consistent with the ones generated by the official Sui tools.
The SDK also adds support for 12- or 24-word recovery phrases (BIP39) and walks the same derivation paths the official tools use:
- Ed25519: m/44'/784'/{account}'/{change}'/{address}' (everything hardened)
- Secp256k1: m/54'/784'/{account}'/{change}/{address}
- Secp256r1: m/74'/784'/{account}'/{change}/{address}
Fun fact: that 784 isn't random; it maps to S-U-I on a phone keypad.
The SDK validates the path, updates the chain code at each hop, and emits a Bech32 secret key (suiprivkey1…) along with the Sui address.
Each curve needed its own touch to hit parity with Mysten's outputs:
- Ed25519 worked immediately once the hardened path was enforced; the base64 public keys matched the CLI exactly.
- Secp256k1 behaved once we mirrored Sui's mix of hardened account level and unhardened change/address steps.
- Secp256r1 needed a special treatment. Mysten's Rust code first runs BIP-32 math using Secp256k1 primitives, then converts the scalar into a P-256 keypair. Copying that flow made our base64 keys and addresses align perfectly with the Sui keytool output.
Finally, I added a test suite with keys and addresses pulled straight from Mysten's SDKs to confirm we're hitting parity.
There's still more to layer on: zkLogin, multisig, passkeys. But the core pieces are now in place and fully compatible with Sui's own tooling.