1use crate::constants::DID_SOL_PREFIX;
2use crate::{id, DID_ACCOUNT_SEED};
3use anchor_lang::prelude::{Error, ErrorCode};
4use solana_program::keccak;
5use solana_program::pubkey::Pubkey;
6use solana_program::secp256k1_recover::{
7 secp256k1_recover, Secp256k1Pubkey, Secp256k1RecoverError,
8};
9
10pub fn convert_secp256k1pub_key_to_address(pubkey: &Secp256k1Pubkey) -> [u8; 20] {
11 let mut address = [0u8; 20];
12 address.copy_from_slice(&keccak::hash(pubkey.to_bytes().as_ref()).to_bytes()[12..]);
13 address
14}
15
16pub fn is_did_sol_prefix(did: &str) -> bool {
17 did.starts_with(DID_SOL_PREFIX)
18}
19
20pub fn check_other_controllers(controllers: &[String]) -> bool {
21 controllers.iter().all(|did| !is_did_sol_prefix(did))
22}
23
24pub fn eth_verify_message(
26 message: &[u8],
27 nonce: u64,
28 signature: [u8; 64],
29 recovery_id: u8,
30) -> Result<Secp256k1Pubkey, Secp256k1RecoverError> {
31 let message_with_nonce = [message, nonce.to_le_bytes().as_ref()].concat();
32 let sign_message_input = [
35 "\x19Ethereum Signed Message:\n".as_bytes(),
36 message_with_nonce.len().to_string().as_bytes(),
37 message_with_nonce.as_ref(),
38 ]
39 .concat();
40
41 let hash = keccak::hash(sign_message_input.as_ref());
42 let secp256k1_pubkey = secp256k1_recover(hash.as_ref(), recovery_id, signature.as_ref());
53 secp256k1_pubkey
61}
62
63pub fn derive_did_account(key: &[u8]) -> (Pubkey, u8) {
64 Pubkey::find_program_address(&[DID_ACCOUNT_SEED.as_bytes(), key], &id())
65}
66
67pub fn derive_did_account_with_bump(key: &[u8], bump_seed: u8) -> Result<Pubkey, Error> {
68 Pubkey::create_program_address(&[DID_ACCOUNT_SEED.as_bytes(), key, &[bump_seed]], &id())
69 .map_err(|_| Error::from(ErrorCode::ConstraintSeeds))
70}