Skip to content

Comments

Add operator_key crate to bundle key serialization functionality#390

Merged
mergify[bot] merged 6 commits intosigp:unstablefrom
dknopik:ssv-keys
Jul 1, 2025
Merged

Add operator_key crate to bundle key serialization functionality#390
mergify[bot] merged 6 commits intosigp:unstablefrom
dknopik:ssv-keys

Conversation

@dknopik
Copy link
Member

@dknopik dknopik commented Jun 25, 2025

Issue Addressed

We have decided to switch to the same key format as used by SSV. The previous key format used by us (herein referred to as legacy) is to be supported in the next release version of Anchor, where we automatically convert to the new format on startup.

Proposed Changes

Add a new crate called operator_key. There, we support the following:

Module Name Format Reading Writing Notes
encrypted Encrypted private key This is basically the Crypto object of an Ethereum keystore with a pubKey tacked on to it optionally
legacy Legacy Anchor key Writing not supported as Anchor v0.2.0 will not write this kind of key anymore, just read it for conversion.
public Base64 public key A base64 encoded PKCS8 PEM key with PKCS1 header 🙃. This is the format found onchain.
unencrypted Unencrypted private key As can be specified in go-ssv's config. PKCS1 private key, base64 encoded. Correct header.

Existing functionality is adapted to use the new functions.

Additional Info

Not in the scope of this PR is actually using the new functionality to use new keys. A second PR will adjust the key split tool and client start up logic to convert to and use the new key format.

@dknopik dknopik added cryptography v0.2.0 Second testnet release labels Jun 25, 2025
@dknopik
Copy link
Member Author

dknopik commented Jun 25, 2025

will add some tests

@dknopik dknopik added the ready-for-review This PR is ready to be reviewed label Jun 27, 2025
@mergify
Copy link

mergify bot commented Jun 27, 2025

This pull request has merge conflicts. Could you please resolve them @dknopik? 🙏

@mergify mergify bot added waiting-on-author and removed ready-for-review This PR is ready to be reviewed labels Jun 27, 2025
@mergify mergify bot added ready-for-review This PR is ready to be reviewed and removed waiting-on-author labels Jun 27, 2025
@dknopik dknopik requested a review from Zacholme7 June 27, 2025 15:02
// Encode them to onchain format
let private_pem_encoded = Zeroizing::new(BASE64_STANDARD.encode(&private_pem));
let public_pem_encoded = BASE64_STANDARD.encode(&public_pem);
let public_pem_encoded = operator_key::public::to_base64(&private_key)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a mixup here? Setting public_pem_encoded to the encoding of private_key

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

operator_key::public::to_base64 takes a public or private key, as both have the needed information to encode the public key. This is why I wrote the full path here to make clear what kind of key we are encoding here.

I'll add some doc comments to the new functions to explain the exact behaviour, have been meaning to do that anyway but forgot.

@diegomrsantos diegomrsantos requested a review from Copilot July 1, 2025 11:49
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a new operator_key crate for unified handling of operator key formats and updates existing tools to use it.

  • Added operator_key crate supporting encrypted, legacy, public, and unencrypted key formats.
  • Updated keygen, keysplit, and client to replace ad-hoc parsing/serialization with operator_key APIs.
  • Removed deprecated parse_rsa utility and refactored ssv_types to depend on operator_key.

Reviewed Changes

Copilot reviewed 20 out of 21 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
anchor/common/operator_key/Cargo.toml Adds new crate; declares dependencies (incl. eth2_keystore)
anchor/common/operator_key/src/lib.rs Defines ConversionError and modules
anchor/keygen/src/lib.rs Switch to operator_key for public key encoding; expose SecurePassword
anchor/keysplit/src/cli.rs Replace parse_rsa with operator_key::public::from_base64
anchor/common/ssv_types/src/operator.rs Refactor to use operator_key::public::from_base64
anchor/client/src/lib.rs Use operator_key::legacy for on-disk key parsing
anchor/common/ssv_types/Cargo.toml Add operator_key dependency


#[derive(Zeroize, ZeroizeOnDrop, PartialEq, Debug)]
pub struct SecurePassword(String);
pub struct SecurePassword(pub String);
Copy link

Copilot AI Jul 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Exposing the inner String publicly bypasses the zeroizing safeguards and breaks encapsulation for a sensitive type. Consider keeping the field private and providing controlled accessors if needed.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reasonable point, but I'll revamp the password mechanism anyway to incorporate PW files with the next pr

///
/// [`Cipher::Aes128Ctr`] is used as cipher, and `scrypt` as constructed by [`default_kdf`] is
/// used as key derivation function.
pub fn encrypt(key: &Rsa<Private>, password: &str) -> Result<EncryptedKey, EncryptionError> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isnt hooked up yet, right? Hooking this up was the follow up you mentioned?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, I split it for an easier review.

Copy link
Member

@Zacholme7 Zacholme7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice im good with this

@mergify mergify bot merged commit 84db1e4 into sigp:unstable Jul 1, 2025
14 checks passed
@dknopik dknopik deleted the ssv-keys branch July 18, 2025 08:59
diegomrsantos pushed a commit to diegomrsantos/anchor that referenced this pull request Sep 17, 2025
…igp#390)

We have decided to switch to the same key format as used by SSV. The previous key format used by us (herein referred to as `legacy`) is to be supported in the next release version of Anchor, where we automatically convert to the new format on startup.


  Add a new crate called `operator_key`. There, we support the following:

| Module Name| Format | Reading | Writing | Notes |
|-|-|:-:|:-:|-|
| `encrypted` | Encrypted private key | :white_check_mark: | :white_check_mark: | This is basically the `Crypto` object of an Ethereum keystore with a `pubKey` tacked on to it optionally |
| `legacy` | Legacy Anchor key | :white_check_mark: | :x: | Writing not supported as Anchor `v0.2.0` will not write this kind of key anymore, just read it for conversion. |
| `public` | Base64 public key | :white_check_mark: | :white_check_mark: | A base64 encoded PKCS8 PEM key with PKCS1 header :upside_down_face:. This is the format found onchain. |
| `unencrypted` | Unencrypted private key | :white_check_mark: | :white_check_mark: | As can be specified in go-ssv's config. PKCS1 private key, base64 encoded. Correct header. |

Existing functionality is adapted to use the new functions.
jking-aus pushed a commit to jking-aus/anchor that referenced this pull request Oct 8, 2025
…igp#390)

We have decided to switch to the same key format as used by SSV. The previous key format used by us (herein referred to as `legacy`) is to be supported in the next release version of Anchor, where we automatically convert to the new format on startup.


  Add a new crate called `operator_key`. There, we support the following:

| Module Name| Format | Reading | Writing | Notes |
|-|-|:-:|:-:|-|
| `encrypted` | Encrypted private key | :white_check_mark: | :white_check_mark: | This is basically the `Crypto` object of an Ethereum keystore with a `pubKey` tacked on to it optionally |
| `legacy` | Legacy Anchor key | :white_check_mark: | :x: | Writing not supported as Anchor `v0.2.0` will not write this kind of key anymore, just read it for conversion. |
| `public` | Base64 public key | :white_check_mark: | :white_check_mark: | A base64 encoded PKCS8 PEM key with PKCS1 header :upside_down_face:. This is the format found onchain. |
| `unencrypted` | Unencrypted private key | :white_check_mark: | :white_check_mark: | As can be specified in go-ssv's config. PKCS1 private key, base64 encoded. Correct header. |

Existing functionality is adapted to use the new functions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cryptography ready-for-merge ready-for-review This PR is ready to be reviewed v0.2.0 Second testnet release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants