Is it safe to use the latest index of principal vector to generate different EVM addresses?

Hello everyone,

I’m trying to work around an example provided in the NoKeyWallet for creating a similar wallet.

I have a question about using the latest index of a principal vector to generate Ethereum addresses. I noticed that the latest index always returns 02, so I was thinking of using this to generate a maximum of 254 EVM addresses per principal and access them using the same principle.

fn get_principal(index: u8) -> Result<Principal, String> {
    let principal = ic_cdk::caller();

    let mut principal_with_index = principal.as_slice().to_vec();
    let latest_index = principal_with_index.len() - 1;

    principal_with_index[latest_index] = get_current_index(principal) + index;

        format!("Failed to convert principal {}", e)

My question is: is this safe to do? Are there any potential security risks or issues I should know of? I would appreciate any feedback or insights on this matter.

Many thanks for considering my request.

Why not just use the principal itself? Or the numbers 1-254 happened to the principal bytes? What are you trying to accomplish?

To generate additional EVM addresses for a user, you can use the principal’s bytes and increment the last byte by a value between 2 and 256.
I’m trying to make a no-key wallet and the user should be able to generate more addresses and pay cycles with the main principle.

I don’t see any obvious problem.

As can be seen in the spec:

  1. Self-authenticating ids.
    These have the form H(public_key) · 0x02 (29 bytes).

The Principal of a caller is a self-authenticating id which always ends in 0x02.

In ic_evm::create_address(), the principal_id argument will be used as the derivation_path in ecdsa_public_key which can be arbitrary bytes.

1 Like

Yes, It seems to be the best possible way to generate the additional keys with no additional state needing to be stored.
The self-authenticating id specification provided by the DFINITY team is helpful in clarifying the use of the 0x02 byte in the principal ID. We appreciate the ongoing effort of the DFINITY team in providing such valuable resources to the community. Keep up the awesome work!

I am not sure I fully understand the question. Is the idea that you would derive public keys based on the caller id using the ecdsa_public_key API? If that’s the case, note that you can specify arbitrary derivation paths to derive new subkeys. So you could concatenate any string to the ID of the caller, e.g. something like:

let mut derivation_path = Vec::new();
derivation_path.push(vec![index as u8]); // You can use any byte string of any length here.
1 Like

I’m using the ic_evm_sign library and it takes ic_evm_sign::create_address(principal).await Principal as a parameter, how can I convert this to the principal?