sui_derivable_account - [devnet]
Derivable account abstraction that verifies a message signed by Sui wallet.
- The message format is as follows:
 
Please confirm you explicitly initiated this request from 
Nonce: 
- The abstract public key is a BCS serialized 
SuiAbstractPublicKey. - The abstract signature is a BCS serialized 
SuiAbstractSignature. - This module has been tested for the following wallets:
 
use 0x1::aptos_hash;use 0x1::auth_data;use 0x1::bcs;use 0x1::bcs_stream;use 0x1::common_account_abstractions_utils;use 0x1::ed25519;use 0x1::option;use 0x1::string;use 0x1::string_utils;use 0x1::transaction_context;use 0x1::vector;Enum SuiAbstractSignature
enum SuiAbstractSignature has dropVariants
MessageV1
Fields
- 
signature: vector<u8> - The signature of the message in raw bytes
 
Constants
Invalid public key.
const EINVALID_PUBLIC_KEY: u64 = 6;Entry function payload is missing.
const EMISSING_ENTRY_FUNCTION_PAYLOAD: u64 = 1;Invalid signature.
const EINVALID_SIGNATURE: u64 = 5;Invalid signature type.
const EINVALID_SIGNATURE_TYPE: u64 = 2;Account address mismatch.
const EACCOUNT_ADDRESS_MISMATCH: u64 = 7;Invalid signature length.
const EINVALID_SIGNATURE_LENGTH: u64 = 4;Invalid signing scheme type.
const EINVALID_SIGNING_SCHEME_TYPE: u64 = 3;Structs
SuiAbstractPublicKey
Sui abstract public key defined with the
struct SuiAbstractPublicKey has dropIntentMessage
A wrapper struct that defines a message with its signing context (intent). https://github.com/MystenLabs/sui/blob/main/crates/shared-crypto/src/intent.rs#L168
struct IntentMessage has copy, drop, storeFields
- 
intent: sui_derivable_account::Intent - 
value: vector<u8> 
Intent
Metadata specifying the scope, version, and application domain of the message. https://github.com/MystenLabs/sui/blob/main/crates/shared-crypto/src/intent.rs#L86
struct Intent has copy, drop, storeFields
Functions
get_signing_scheme
Returns the signing scheme for the given value.
fun get_signing_scheme(value: u8): sui_derivable_account::SuiSigningSchemeImplementation
fun get_signing_scheme(value: u8): SuiSigningScheme {    if (value == 0) SuiSigningScheme::ED25519    else abort(EINVALID_SIGNING_SCHEME_TYPE)}deserialize_abstract_public_key
Deserializes the abstract public key which is supposed to be a bcs
serialized SuiAbstractPublicKey.
fun deserialize_abstract_public_key(abstract_public_key: &vector<u8>): sui_derivable_account::SuiAbstractPublicKeyImplementation
fun deserialize_abstract_public_key(abstract_public_key: &vector<u8>): SuiAbstractPublicKey {    let stream = bcs_stream::new(*abstract_public_key);    let sui_account_address = bcs_stream::deserialize_vector<u8>(&mut stream, |x| deserialize_u8(x));    let domain = bcs_stream::deserialize_vector<u8>(&mut stream, |x| deserialize_u8(x));    SuiAbstractPublicKey { sui_account_address, domain }}deserialize_abstract_signature
Returns a tuple of the signature.
fun deserialize_abstract_signature(abstract_signature: &vector<u8>): sui_derivable_account::SuiAbstractSignatureImplementation
fun deserialize_abstract_signature(abstract_signature: &vector<u8>): SuiAbstractSignature {    let stream = bcs_stream::new(*abstract_signature);    let signature_type = bcs_stream::deserialize_u8(&mut stream);    if (signature_type == 0x00) {        let signature = bcs_stream::deserialize_vector<u8>(&mut stream, |x| deserialize_u8(x));        SuiAbstractSignature::MessageV1 { signature }    } else {        abort(EINVALID_SIGNATURE_TYPE)    }}split_signature_bytes
Splits raw signature bytes containing scheme flag (1 byte), signature (64 bytes) and public key (32 bytes)
to a tuple of (signing_scheme, signature, public_key)
public fun split_signature_bytes(bytes: &vector<u8>): (u8, vector<u8>, vector<u8>)Implementation
public fun split_signature_bytes(bytes: &vector<u8>): (u8, vector<u8>, vector<u8>) {    // 1 + 64 + 32 = 97 bytes    assert!(bytes.length() == 97, EINVALID_SIGNATURE_LENGTH);
    let signing_scheme = bytes[0];    let abstract_signature_signature = vector::empty<u8>();    let abstract_signature_public_key = vector::empty<u8>();
    // Extract signature (64 bytes)    let i = 1;    while (i < 65) {        abstract_signature_signature.push_back(bytes[i]);        i += 1;    };
    // Extract public key (32 bytes)    while (i < 97) {        abstract_signature_public_key.push_back(bytes[i]);        i += 1;    };
    (signing_scheme, abstract_signature_signature, abstract_signature_public_key)}derive_account_address_from_public_key
Derives the account address from the public key and returns it is a hex string with “0x” prefix
fun derive_account_address_from_public_key(signing_scheme: u8, public_key_bytes: vector<u8>): vector<u8>Implementation
fun derive_account_address_from_public_key(signing_scheme: u8, public_key_bytes: vector<u8>): vector<u8> {    // Create a vector with signing scheme and public key bytes    let data_to_hash = vector[signing_scheme];    data_to_hash.append(public_key_bytes);
    // Compute blake2b hash    let sui_account_address = aptos_hash::blake2b_256(data_to_hash);
    // Convert the address bytes to a hex string with "0x" prefix    let sui_account_address_hex = b"0x";    let i = 0;    while (i < sui_account_address.length()) {        let byte = sui_account_address[i];        // Convert each byte to two hex characters        let hex_chars = vector[            if ((byte >> 4) < 10) ((byte >> 4) + 0x30) else ((byte >> 4) - 10 + 0x61),            if ((byte & 0xf) < 10) ((byte & 0xf) + 0x30) else ((byte & 0xf) - 10 + 0x61)        ];        sui_account_address_hex.append(hex_chars);        i += 1;    };
    // Return the account address as hex string    sui_account_address_hex}authenticate_auth_data
public fun authenticate_auth_data(aa_auth_data: auth_data::AbstractionAuthData, entry_function_name: &vector<u8>)Implementation
public fun authenticate_auth_data(    aa_auth_data: AbstractionAuthData,    entry_function_name: &vector<u8>) {    let abstract_signature = deserialize_abstract_signature(aa_auth_data.derivable_abstract_signature());    let (signing_scheme, abstract_signature_signature, abstract_signature_public_key) = split_signature_bytes(&abstract_signature.signature);
    // Check siging scheme is Ed25519 as we currently only support this scheme    assert!(get_signing_scheme(signing_scheme) == SuiSigningScheme::ED25519, EINVALID_SIGNING_SCHEME_TYPE);
    // Derive the account address from the public key    let sui_account_address = derive_account_address_from_public_key(signing_scheme, abstract_signature_public_key);
    let derivable_abstract_public_key = aa_auth_data.derivable_abstract_public_key();    let abstract_public_key = deserialize_abstract_public_key(derivable_abstract_public_key);
    // Check the account address matches the abstract public key    assert!(&sui_account_address == &abstract_public_key.sui_account_address, EACCOUNT_ADDRESS_MISMATCH);
    let public_key = new_validated_public_key_from_bytes(abstract_signature_public_key);    assert!(public_key.is_some(), EINVALID_PUBLIC_KEY);
    let digest_utf8 = string_utils::to_string(aa_auth_data.digest()).bytes();    // Build the raw message    let raw_message = construct_message(&b"Sui", &sui_account_address, &abstract_public_key.domain, entry_function_name, digest_utf8);
    // Prepend Intent to the message    let intent = Intent {        scope: PersonalMessage,        version: V0,        app_id: Sui,    };    let msg = IntentMessage {        intent,        value: raw_message,    };    // Serialize the whole struct    let bcs_bytes = bcs::to_bytes<IntentMessage>(&msg);
    // Hash full_message with blake2b256    let hash = aptos_hash::blake2b_256(bcs_bytes);
    let signature = new_signature_from_bytes(abstract_signature_signature);
    assert!(        ed25519::signature_verify_strict(            &signature,            &public_key_into_unvalidated(public_key.destroy_some()),            hash,        ),        EINVALID_SIGNATURE    );}authenticate
Authorization function for domain account abstraction.
public fun authenticate(account: signer, aa_auth_data: auth_data::AbstractionAuthData): signerImplementation
public fun authenticate(account: signer, aa_auth_data: AbstractionAuthData): signer {    daa_authenticate(account, aa_auth_data, |auth_data, entry_name| authenticate_auth_data(auth_data, entry_name))}Specification
derive_account_address_from_public_key
fun derive_account_address_from_public_key(signing_scheme: u8, public_key_bytes: vector<u8>): vector<u8>pragma verify = false;authenticate_auth_data
public fun authenticate_auth_data(aa_auth_data: auth_data::AbstractionAuthData, entry_function_name: &vector<u8>)pragma verify = false;authenticate
public fun authenticate(account: signer, aa_auth_data: auth_data::AbstractionAuthData): signerpragma verify = false;Enum SuiSigningScheme
Sui signing scheme as defined in https://github.com/MystenLabs/ts-sdks/blob/main/packages/typescript/src/cryptography/signature-scheme.ts#L19
enum SuiSigningScheme has dropVariants
ED25519
Fields
Enum IntentScope
https://github.com/MystenLabs/sui/blob/main/crates/shared-crypto/src/intent.rs#L60
enum IntentScope has copy, drop, storeVariants
TransactionData
Fields
TransactionEffects
Fields
CheckpointSummary
Fields
PersonalMessage
Fields
Enum IntentVersion
https://github.com/MystenLabs/sui/blob/main/crates/shared-crypto/src/intent.rs#L18
enum IntentVersion has copy, drop, storeVariants
V0
Fields
Enum AppId
https://github.com/MystenLabs/sui/blob/main/crates/shared-crypto/src/intent.rs#L35
enum AppId has copy, drop, store