Skip to content

jwks - [mainnet]

JWK functions and structs.

Note: An important design constraint for this module is that the JWK consensus Rust code is unable to spawn a VM and make a Move function call. Instead, the JWK consensus Rust code will have to directly write some of the resources in this file. As a result, the structs in this file are declared so as to have a simple layout which is easily accessible in Rust.

use 0x1::bcs;
use 0x1::chain_status;
use 0x1::comparator;
use 0x1::config_buffer;
use 0x1::copyable_any;
use 0x1::error;
use 0x1::event;
use 0x1::features;
use 0x1::option;
use 0x1::reconfiguration;
use 0x1::signer;
use 0x1::string;
use 0x1::system_addresses;
use 0x1::vector;

Constants

const DELETE_COMMAND_INDICATOR: vector<u8> = [84, 72, 73, 83, 95, 73, 83, 95, 65, 95, 68, 69, 76, 69, 84, 69, 95, 67, 79, 77, 77, 65, 78, 68];
const EFEDERATED_JWKS_TOO_LARGE: u64 = 8;
const EINSTALL_FEDERATED_JWKS_AT_APTOS_FRAMEWORK: u64 = 7;
const EINVALID_FEDERATED_JWK_SET: u64 = 9;
const EISSUER_NOT_FOUND: u64 = 5;
const EJWK_ID_NOT_FOUND: u64 = 6;
const ENATIVE_INCORRECT_VERSION: u64 = 259;
const ENATIVE_MISSING_RESOURCE_OBSERVED_JWKS: u64 = 258;
const ENATIVE_MISSING_RESOURCE_VALIDATOR_SET: u64 = 257;
const ENATIVE_MULTISIG_VERIFICATION_FAILED: u64 = 260;
const ENATIVE_NOT_ENOUGH_VOTING_POWER: u64 = 261;
const EUNEXPECTED_EPOCH: u64 = 1;
const EUNEXPECTED_VERSION: u64 = 2;
const EUNKNOWN_JWK_VARIANT: u64 = 4;
const EUNKNOWN_PATCH_VARIANT: u64 = 3;

We limit the size of a PatchedJWKs resource installed by a dapp owner for federated keyless accounts. Note: If too large, validators waste work reading it for invalid TXN signatures.

const MAX_FEDERATED_JWKS_SIZE_BYTES: u64 = 2048;

Structs

OIDCProvider

An OIDC provider.

struct OIDCProvider has copy, drop, store
Fields
name: vector<u8>
The utf-8 encoded issuer string. E.g., b"https://www.facebook.com".
config_url: vector<u8>
The ut8-8 encoded OpenID configuration URL of the provider. E.g., b"https://www.facebook.com/.well-known/openid-configuration/".

UnsupportedJWK

An JWK variant that represents the JWKs which were observed but not yet supported by Aptos. Observing UnsupportedJWKs means the providers adopted a new key type/format, and the system should be updated.

struct UnsupportedJWK has copy, drop, store
Fields
id: vector<u8>
payload: vector<u8>

RSA_JWK

A JWK variant where kty is RSA.

struct RSA_JWK has copy, drop, store
Fields
kid: string::String
kty: string::String
alg: string::String
e: string::String
n: string::String

JWK

A JSON web key.

struct JWK has copy, drop, store
Fields
variant: copyable_any::Any
A JWK variant packed as an Any. Currently the variant type is one of the following. - RSA_JWK - UnsupportedJWK

ProviderJWKs

A provider and its JWKs.

struct ProviderJWKs has copy, drop, store
Fields
issuer: vector<u8>
The utf-8 encoding of the issuer string (e.g., "https://www.facebook.com").
version: u64
A version number is needed by JWK consensus to dedup the updates. e.g, when on chain version = 5, multiple nodes can propose an update with version = 6. Bumped every time the JWKs for the current issuer is updated. The Rust authenticator only uses the latest version.
jwks: vector<jwks::JWK>
Vector of JWK's sorted by their unique ID (from get_jwk_id) in dictionary order.

AllProvidersJWKs

Multiple ProviderJWKs objects, indexed by issuer and key ID.

struct AllProvidersJWKs has copy, drop, store
Fields
entries: vector<jwks::ProviderJWKs>
Vector of ProviderJWKs sorted by ProviderJWKs::issuer in dictionary order.

ObservedJWKsUpdated

When ObservedJWKs is updated, this event is sent to resync the JWK consensus state in all validators.

#[event]
struct ObservedJWKsUpdated has drop, store
Fields
epoch: u64
jwks: jwks::AllProvidersJWKs

Patch

A small edit or patch that is applied to a AllProvidersJWKs to obtain PatchedJWKs.

struct Patch has copy, drop, store
Fields
variant: copyable_any::Any
A Patch variant packed as an Any. Currently the variant type is one of the following. - PatchRemoveAll - PatchRemoveIssuer - PatchRemoveJWK - PatchUpsertJWK

PatchRemoveAll

A Patch variant to remove all JWKs.

struct PatchRemoveAll has copy, drop, store
Fields
dummy_field: bool

PatchRemoveIssuer

A Patch variant to remove an issuer and all its JWKs.

struct PatchRemoveIssuer has copy, drop, store
Fields
issuer: vector<u8>

PatchRemoveJWK

A Patch variant to remove a specific JWK of an issuer.

struct PatchRemoveJWK has copy, drop, store
Fields
issuer: vector<u8>
jwk_id: vector<u8>

PatchUpsertJWK

A Patch variant to upsert a JWK for an issuer.

struct PatchUpsertJWK has copy, drop, store
Fields
issuer: vector<u8>
jwk: jwks::JWK

Resources

SupportedOIDCProviders

A list of OIDC providers whose JWKs should be watched by validators. Maintained by governance proposals.

struct SupportedOIDCProviders has copy, drop, store, key
Fields
providers: vector<jwks::OIDCProvider>

ObservedJWKs

The AllProvidersJWKs that validators observed and agreed on.

struct ObservedJWKs has copy, drop, store, key
Fields
jwks: jwks::AllProvidersJWKs

Patches

A sequence of Patch objects that are applied one by one to the ObservedJWKs.

Maintained by governance proposals.

struct Patches has key
Fields
patches: vector<jwks::Patch>

PatchedJWKs

The result of applying the Patches to the ObservedJWKs. This is what applications should consume.

struct PatchedJWKs has drop, key
Fields
jwks: jwks::AllProvidersJWKs

FederatedJWKs

JWKs for federated keyless accounts are stored in this resource.

struct FederatedJWKs has drop, key
Fields
jwks: jwks::AllProvidersJWKs

Functions

patch_federated_jwks

Called by a federated keyless dapp owner to install the JWKs for the federated OIDC provider (e.g., Auth0, AWS Cognito, etc). For type-safety, we explicitly use a struct FederatedJWKs { jwks: AllProviderJWKs } instead of reusing PatchedJWKs { jwks: AllProviderJWKs }, which is a JWK-consensus-specific struct.

public fun patch_federated_jwks(jwk_owner: &signer, patches: vector<jwks::Patch>)
Implementation
public fun patch_federated_jwks(jwk_owner: &signer, patches: vector<Patch>) acquires FederatedJWKs {
// Prevents accidental calls in 0x1::jwks that install federated JWKs at the Aptos framework address.
assert!(!system_addresses::is_aptos_framework_address(signer::address_of(jwk_owner)),
error::invalid_argument(EINSTALL_FEDERATED_JWKS_AT_APTOS_FRAMEWORK)
);
let jwk_addr = signer::address_of(jwk_owner);
if (!exists<FederatedJWKs>(jwk_addr)) {
move_to(jwk_owner, FederatedJWKs { jwks: AllProvidersJWKs { entries: vector[] } });
};
let fed_jwks = borrow_global_mut<FederatedJWKs>(jwk_addr);
vector::for_each_ref(&patches, |obj|{
let patch: &Patch = obj;
apply_patch(&mut fed_jwks.jwks, *patch);
});
// TODO: Can we check the size more efficiently instead of serializing it via BCS?
let num_bytes = vector::length(&bcs::to_bytes(fed_jwks));
assert!(num_bytes < MAX_FEDERATED_JWKS_SIZE_BYTES, error::invalid_argument(EFEDERATED_JWKS_TOO_LARGE));
}

update_federated_jwk_set

This can be called to install or update a set of JWKs for a federated OIDC provider. This function should be invoked to intially install a set of JWKs or to update a set of JWKs when a keypair is rotated.

The iss parameter is the value of the iss claim on the JWTs that are to be verified by the JWK set. kid_vec, alg_vec, e_vec, n_vec are String vectors of the JWK attributes kid, alg, e and n respectively. See https://datatracker.ietf.org/doc/html/rfc7517#section-4 for more details about the JWK attributes aforementioned.

For the example JWK set snapshot below containing 2 keys for Google found at https://www.googleapis.com/oauth2/v3/certs -

{
"keys": [
{
"alg": "RS256",
"use": "sig",
"kty": "RSA",
"n": "wNHgGSG5B5xOEQNFPW2p_6ZxZbfPoAU5VceBUuNwQWLop0ohW0vpoZLU1tAsq_S9s5iwy27rJw4EZAOGBR9oTRq1Y6Li5pDVJfmzyRNtmWCWndR-bPqhs_dkJU7MbGwcvfLsN9FSHESFrS9sfGtUX-lZfLoGux23TKdYV9EE-H-NDASxrVFUk2GWc3rL6UEMWrMnOqV9-tghybDU3fcRdNTDuXUr9qDYmhmNegYjYu4REGjqeSyIG1tuQxYpOBH-tohtcfGY-oRTS09kgsSS9Q5BRM4qqCkGP28WhlSf4ui0-norS0gKMMI1P_ZAGEsLn9p2TlYMpewvIuhjJs1thw",
"kid": "d7b939771a7800c413f90051012d975981916d71",
"e": "AQAB"
},
{
"kty": "RSA",
"kid": "b2620d5e7f132b52afe8875cdf3776c064249d04",
"alg": "RS256",
"n": "pi22xDdK2fz5gclIbDIGghLDYiRO56eW2GUcboeVlhbAuhuT5mlEYIevkxdPOg5n6qICePZiQSxkwcYMIZyLkZhSJ2d2M6Szx2gDtnAmee6o_tWdroKu0DjqwG8pZU693oLaIjLku3IK20lTs6-2TeH-pUYMjEqiFMhn-hb7wnvH_FuPTjgz9i0rEdw_Hf3Wk6CMypaUHi31y6twrMWq1jEbdQNl50EwH-RQmQ9bs3Wm9V9t-2-_Jzg3AT0Ny4zEDU7WXgN2DevM8_FVje4IgztNy29XUkeUctHsr-431_Iu23JIy6U4Kxn36X3RlVUKEkOMpkDD3kd81JPW4Ger_w",
"e": "AQAB",
"use": "sig"
}
]
}

We can call update_federated_jwk_set for Google’s iss - “https://accounts.google.com” and for each vector argument kid_vec, alg_vec, e_vec, n_vec, we set in index 0 the corresponding attribute in the first JWK and we set in index 1 the corresponding attribute in the second JWK as shown below.

use std::string::utf8;
aptos_framework::jwks::update_federated_jwk_set(
jwk_owner,
b"https://accounts.google.com",
vector[utf8(b"d7b939771a7800c413f90051012d975981916d71"), utf8(b"b2620d5e7f132b52afe8875cdf3776c064249d04")],
vector[utf8(b"RS256"), utf8(b"RS256")],
vector[utf8(b"AQAB"), utf8(b"AQAB")],
vector[
utf8(b"wNHgGSG5B5xOEQNFPW2p_6ZxZbfPoAU5VceBUuNwQWLop0ohW0vpoZLU1tAsq_S9s5iwy27rJw4EZAOGBR9oTRq1Y6Li5pDVJfmzyRNtmWCWndR-bPqhs_dkJU7MbGwcvfLsN9FSHESFrS9sfGtUX-lZfLoGux23TKdYV9EE-H-NDASxrVFUk2GWc3rL6UEMWrMnOqV9-tghybDU3fcRdNTDuXUr9qDYmhmNegYjYu4REGjqeSyIG1tuQxYpOBH-tohtcfGY-oRTS09kgsSS9Q5BRM4qqCkGP28WhlSf4ui0-norS0gKMMI1P_ZAGEsLn9p2TlYMpewvIuhjJs1thw"),
utf8(b"pi22xDdK2fz5gclIbDIGghLDYiRO56eW2GUcboeVlhbAuhuT5mlEYIevkxdPOg5n6qICePZiQSxkwcYMIZyLkZhSJ2d2M6Szx2gDtnAmee6o_tWdroKu0DjqwG8pZU693oLaIjLku3IK20lTs6-2TeH-pUYMjEqiFMhn-hb7wnvH_FuPTjgz9i0rEdw_Hf3Wk6CMypaUHi31y6twrMWq1jEbdQNl50EwH-RQmQ9bs3Wm9V9t-2-_Jzg3AT0Ny4zEDU7WXgN2DevM8_FVje4IgztNy29XUkeUctHsr-431_Iu23JIy6U4Kxn36X3RlVUKEkOMpkDD3kd81JPW4Ger_w")
]
)

See AIP-96 for more details about federated keyless - https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-96.md

NOTE: Currently only RSA keys are supported.

public entry fun update_federated_jwk_set(jwk_owner: &signer, iss: vector<u8>, kid_vec: vector<string::String>, alg_vec: vector<string::String>, e_vec: vector<string::String>, n_vec: vector<string::String>)
Implementation
public entry fun update_federated_jwk_set(jwk_owner: &signer, iss: vector<u8>, kid_vec: vector<String>, alg_vec: vector<String>, e_vec: vector<String>, n_vec: vector<String>) acquires FederatedJWKs {
assert!(!vector::is_empty(&kid_vec), error::invalid_argument(EINVALID_FEDERATED_JWK_SET));
let num_jwk = vector::length<String>(&kid_vec);
assert!(vector::length(&alg_vec) == num_jwk , error::invalid_argument(EINVALID_FEDERATED_JWK_SET));
assert!(vector::length(&e_vec) == num_jwk, error::invalid_argument(EINVALID_FEDERATED_JWK_SET));
assert!(vector::length(&n_vec) == num_jwk, error::invalid_argument(EINVALID_FEDERATED_JWK_SET));
let remove_all_patch = new_patch_remove_all();
let patches = vector[remove_all_patch];
while (!vector::is_empty(&kid_vec)) {
let kid = vector::pop_back(&mut kid_vec);
let alg = vector::pop_back(&mut alg_vec);
let e = vector::pop_back(&mut e_vec);
let n = vector::pop_back(&mut n_vec);
let jwk = new_rsa_jwk(kid, alg, e, n);
let patch = new_patch_upsert_jwk(iss, jwk);
vector::push_back(&mut patches, patch)
};
patch_federated_jwks(jwk_owner, patches);
}

get_patched_jwk

Get a JWK by issuer and key ID from the PatchedJWKs. Abort if such a JWK does not exist. More convenient to call from Rust, since it does not wrap the JWK in an Option.

public fun get_patched_jwk(issuer: vector<u8>, jwk_id: vector<u8>): jwks::JWK
Implementation
public fun get_patched_jwk(issuer: vector<u8>, jwk_id: vector<u8>): JWK acquires PatchedJWKs {
option::extract(&mut try_get_patched_jwk(issuer, jwk_id))
}

try_get_patched_jwk

Get a JWK by issuer and key ID from the PatchedJWKs, if it exists. More convenient to call from Move, since it does not abort.

public fun try_get_patched_jwk(issuer: vector<u8>, jwk_id: vector<u8>): option::Option<jwks::JWK>
Implementation
public fun try_get_patched_jwk(issuer: vector<u8>, jwk_id: vector<u8>): Option<JWK> acquires PatchedJWKs {
let jwks = &borrow_global<PatchedJWKs>(@aptos_framework).jwks;
try_get_jwk_by_issuer(jwks, issuer, jwk_id)
}

upsert_oidc_provider

Deprecated by upsert_oidc_provider_for_next_epoch().

TODO: update all the tests that reference this function, then disable this function.

public fun upsert_oidc_provider(fx: &signer, name: vector<u8>, config_url: vector<u8>): option::Option<vector<u8>>
Implementation
public fun upsert_oidc_provider(fx: &signer, name: vector<u8>, config_url: vector<u8>): Option<vector<u8>> acquires SupportedOIDCProviders {
system_addresses::assert_aptos_framework(fx);
chain_status::assert_genesis();
let provider_set = borrow_global_mut<SupportedOIDCProviders>(@aptos_framework);
let old_config_url= remove_oidc_provider_internal(provider_set, name);
vector::push_back(&mut provider_set.providers, OIDCProvider { name, config_url });
old_config_url
}

upsert_oidc_provider_for_next_epoch

Used in on-chain governances to update the supported OIDC providers, effective starting next epoch. Example usage:

aptos_framework::jwks::upsert_oidc_provider_for_next_epoch(
&framework_signer,
b"https://accounts.google.com",
b"https://accounts.google.com/.well-known/openid-configuration"
);
aptos_framework::aptos_governance::reconfigure(&framework_signer);
public fun upsert_oidc_provider_for_next_epoch(fx: &signer, name: vector<u8>, config_url: vector<u8>): option::Option<vector<u8>>
Implementation
public fun upsert_oidc_provider_for_next_epoch(fx: &signer, name: vector<u8>, config_url: vector<u8>): Option<vector<u8>> acquires SupportedOIDCProviders {
system_addresses::assert_aptos_framework(fx);
let provider_set = if (config_buffer::does_exist<SupportedOIDCProviders>()) {
config_buffer::extract_v2<SupportedOIDCProviders>()
} else {
*borrow_global<SupportedOIDCProviders>(@aptos_framework)
};
let old_config_url = remove_oidc_provider_internal(&mut provider_set, name);
vector::push_back(&mut provider_set.providers, OIDCProvider { name, config_url });
config_buffer::upsert(provider_set);
old_config_url
}

remove_oidc_provider

Deprecated by remove_oidc_provider_for_next_epoch().

TODO: update all the tests that reference this function, then disable this function.

public fun remove_oidc_provider(fx: &signer, name: vector<u8>): option::Option<vector<u8>>
Implementation
public fun remove_oidc_provider(fx: &signer, name: vector<u8>): Option<vector<u8>> acquires SupportedOIDCProviders {
system_addresses::assert_aptos_framework(fx);
chain_status::assert_genesis();
let provider_set = borrow_global_mut<SupportedOIDCProviders>(@aptos_framework);
remove_oidc_provider_internal(provider_set, name)
}

remove_oidc_provider_for_next_epoch

Used in on-chain governances to update the supported OIDC providers, effective starting next epoch. Example usage:

aptos_framework::jwks::remove_oidc_provider_for_next_epoch(
&framework_signer,
b"https://accounts.google.com",
);
aptos_framework::aptos_governance::reconfigure(&framework_signer);
public fun remove_oidc_provider_for_next_epoch(fx: &signer, name: vector<u8>): option::Option<vector<u8>>
Implementation
public fun remove_oidc_provider_for_next_epoch(fx: &signer, name: vector<u8>): Option<vector<u8>> acquires SupportedOIDCProviders {
system_addresses::assert_aptos_framework(fx);
let provider_set = if (config_buffer::does_exist<SupportedOIDCProviders>()) {
config_buffer::extract_v2<SupportedOIDCProviders>()
} else {
*borrow_global<SupportedOIDCProviders>(@aptos_framework)
};
let ret = remove_oidc_provider_internal(&mut provider_set, name);
config_buffer::upsert(provider_set);
ret
}

on_new_epoch

Only used in reconfigurations to apply the pending SupportedOIDCProviders, if there is any.

public(friend) fun on_new_epoch(framework: &signer)
Implementation
public(friend) fun on_new_epoch(framework: &signer) acquires SupportedOIDCProviders {
system_addresses::assert_aptos_framework(framework);
if (config_buffer::does_exist<SupportedOIDCProviders>()) {
let new_config = config_buffer::extract_v2<SupportedOIDCProviders>();
if (exists<SupportedOIDCProviders>(@aptos_framework)) {
*borrow_global_mut<SupportedOIDCProviders>(@aptos_framework) = new_config;
} else {
move_to(framework, new_config);
}
}
}

set_patches

Set the Patches. Only called in governance proposals.

public fun set_patches(fx: &signer, patches: vector<jwks::Patch>)
Implementation
public fun set_patches(fx: &signer, patches: vector<Patch>) acquires Patches, PatchedJWKs, ObservedJWKs {
system_addresses::assert_aptos_framework(fx);
borrow_global_mut<Patches>(@aptos_framework).patches = patches;
regenerate_patched_jwks();
}

new_patch_remove_all

Create a Patch that removes all entries.

public fun new_patch_remove_all(): jwks::Patch
Implementation
public fun new_patch_remove_all(): Patch {
Patch {
variant: copyable_any::pack(PatchRemoveAll {}),
}
}

new_patch_remove_issuer

Create a Patch that removes the entry of a given issuer, if exists.

public fun new_patch_remove_issuer(issuer: vector<u8>): jwks::Patch
Implementation
public fun new_patch_remove_issuer(issuer: vector<u8>): Patch {
Patch {
variant: copyable_any::pack(PatchRemoveIssuer { issuer }),
}
}

new_patch_remove_jwk

Create a Patch that removes the entry of a given issuer, if exists.

public fun new_patch_remove_jwk(issuer: vector<u8>, jwk_id: vector<u8>): jwks::Patch
Implementation
public fun new_patch_remove_jwk(issuer: vector<u8>, jwk_id: vector<u8>): Patch {
Patch {
variant: copyable_any::pack(PatchRemoveJWK { issuer, jwk_id })
}
}

new_patch_upsert_jwk

Create a Patch that upserts a JWK into an issuer’s JWK set.

public fun new_patch_upsert_jwk(issuer: vector<u8>, jwk: jwks::JWK): jwks::Patch
Implementation
public fun new_patch_upsert_jwk(issuer: vector<u8>, jwk: JWK): Patch {
Patch {
variant: copyable_any::pack(PatchUpsertJWK { issuer, jwk })
}
}

new_rsa_jwk

Create a JWK of variant RSA_JWK.

public fun new_rsa_jwk(kid: string::String, alg: string::String, e: string::String, n: string::String): jwks::JWK
Implementation
public fun new_rsa_jwk(kid: String, alg: String, e: String, n: String): JWK {
JWK {
variant: copyable_any::pack(RSA_JWK {
kid,
kty: utf8(b"RSA"),
e,
n,
alg,
}),
}
}

new_unsupported_jwk

Create a JWK of variant UnsupportedJWK.

public fun new_unsupported_jwk(id: vector<u8>, payload: vector<u8>): jwks::JWK
Implementation
public fun new_unsupported_jwk(id: vector<u8>, payload: vector<u8>): JWK {
JWK {
variant: copyable_any::pack(UnsupportedJWK { id, payload })
}
}

initialize

Initialize some JWK resources. Should only be invoked by genesis.

public fun initialize(fx: &signer)
Implementation
public fun initialize(fx: &signer) {
system_addresses::assert_aptos_framework(fx);
move_to(fx, SupportedOIDCProviders { providers: vector[] });
move_to(fx, ObservedJWKs { jwks: AllProvidersJWKs { entries: vector[] } });
move_to(fx, Patches { patches: vector[] });
move_to(fx, PatchedJWKs { jwks: AllProvidersJWKs { entries: vector[] } });
}

remove_oidc_provider_internal

Helper function that removes an OIDC provider from the SupportedOIDCProviders. Returns the old config URL of the provider, if any, as an Option.

fun remove_oidc_provider_internal(provider_set: &mut jwks::SupportedOIDCProviders, name: vector<u8>): option::Option<vector<u8>>
Implementation
fun remove_oidc_provider_internal(provider_set: &mut SupportedOIDCProviders, name: vector<u8>): Option<vector<u8>> {
let (name_exists, idx) = vector::find(&provider_set.providers, |obj| {
let provider: &OIDCProvider = obj;
provider.name == name
});
if (name_exists) {
let old_provider = vector::swap_remove(&mut provider_set.providers, idx);
option::some(old_provider.config_url)
} else {
option::none()
}
}

upsert_into_observed_jwks

Only used by validators to publish their observed JWK update.

NOTE: It is assumed verification has been done to ensure each update is quorum-certified, and its version equals to the on-chain version + 1.

public fun upsert_into_observed_jwks(fx: &signer, provider_jwks_vec: vector<jwks::ProviderJWKs>)
Implementation
public fun upsert_into_observed_jwks(fx: &signer, provider_jwks_vec: vector<ProviderJWKs>) acquires ObservedJWKs, PatchedJWKs, Patches {
system_addresses::assert_aptos_framework(fx);
let observed_jwks = borrow_global_mut<ObservedJWKs>(@aptos_framework);
if (features::is_jwk_consensus_per_key_mode_enabled()) {
vector::for_each(provider_jwks_vec, |proposed_provider_jwks|{
let maybe_cur_issuer_jwks = remove_issuer(&mut observed_jwks.jwks, proposed_provider_jwks.issuer);
let cur_issuer_jwks = if (option::is_some(&maybe_cur_issuer_jwks)) {
option::extract(&mut maybe_cur_issuer_jwks)
} else {
ProviderJWKs {
issuer: proposed_provider_jwks.issuer,
version: 0,
jwks: vector[],
}
};
assert!(cur_issuer_jwks.version + 1 == proposed_provider_jwks.version, error::invalid_argument(EUNEXPECTED_VERSION));
vector::for_each(proposed_provider_jwks.jwks, |jwk|{
let variant_type_name = *string::bytes(copyable_any::type_name(&jwk.variant));
let is_delete = if (variant_type_name == b"0x1::jwks::UnsupportedJWK") {
let repr = copyable_any::unpack<UnsupportedJWK>(jwk.variant);
&repr.payload == &DELETE_COMMAND_INDICATOR
} else {
false
};
if (is_delete) {
remove_jwk(&mut cur_issuer_jwks, get_jwk_id(&jwk));
} else {
upsert_jwk(&mut cur_issuer_jwks, jwk);
}
});
cur_issuer_jwks.version = cur_issuer_jwks.version + 1;
upsert_provider_jwks(&mut observed_jwks.jwks, cur_issuer_jwks);
});
} else {
vector::for_each(provider_jwks_vec, |provider_jwks| {
upsert_provider_jwks(&mut observed_jwks.jwks, provider_jwks);
});
};
let epoch = reconfiguration::current_epoch();
emit(ObservedJWKsUpdated { epoch, jwks: observed_jwks.jwks });
regenerate_patched_jwks();
}

remove_issuer_from_observed_jwks

Only used by governance to delete an issuer from ObservedJWKs, if it exists.

Return the potentially existing ProviderJWKs of the given issuer.

public fun remove_issuer_from_observed_jwks(fx: &signer, issuer: vector<u8>): option::Option<jwks::ProviderJWKs>
Implementation
public fun remove_issuer_from_observed_jwks(fx: &signer, issuer: vector<u8>): Option<ProviderJWKs> acquires ObservedJWKs, PatchedJWKs, Patches {
system_addresses::assert_aptos_framework(fx);
let observed_jwks = borrow_global_mut<ObservedJWKs>(@aptos_framework);
let old_value = remove_issuer(&mut observed_jwks.jwks, issuer);
let epoch = reconfiguration::current_epoch();
emit(ObservedJWKsUpdated { epoch, jwks: observed_jwks.jwks });
regenerate_patched_jwks();
old_value
}

regenerate_patched_jwks

Regenerate PatchedJWKs from ObservedJWKs and Patches and save the result.

fun regenerate_patched_jwks()
Implementation
fun regenerate_patched_jwks() acquires PatchedJWKs, Patches, ObservedJWKs {
let jwks = borrow_global<ObservedJWKs>(@aptos_framework).jwks;
let patches = borrow_global<Patches>(@aptos_framework);
vector::for_each_ref(&patches.patches, |obj|{
let patch: &Patch = obj;
apply_patch(&mut jwks, *patch);
});
*borrow_global_mut<PatchedJWKs>(@aptos_framework) = PatchedJWKs { jwks };
}

try_get_jwk_by_issuer

Get a JWK by issuer and key ID from an AllProvidersJWKs, if it exists.

fun try_get_jwk_by_issuer(jwks: &jwks::AllProvidersJWKs, issuer: vector<u8>, jwk_id: vector<u8>): option::Option<jwks::JWK>
Implementation
fun try_get_jwk_by_issuer(jwks: &AllProvidersJWKs, issuer: vector<u8>, jwk_id: vector<u8>): Option<JWK> {
let (issuer_found, index) = vector::find(&jwks.entries, |obj| {
let provider_jwks: &ProviderJWKs = obj;
issuer == provider_jwks.issuer
});
if (issuer_found) {
try_get_jwk_by_id(vector::borrow(&jwks.entries, index), jwk_id)
} else {
option::none()
}
}

try_get_jwk_by_id

Get a JWK by key ID from a ProviderJWKs, if it exists.

fun try_get_jwk_by_id(provider_jwks: &jwks::ProviderJWKs, jwk_id: vector<u8>): option::Option<jwks::JWK>
Implementation
fun try_get_jwk_by_id(provider_jwks: &ProviderJWKs, jwk_id: vector<u8>): Option<JWK> {
let (jwk_id_found, index) = vector::find(&provider_jwks.jwks, |obj|{
let jwk: &JWK = obj;
jwk_id == get_jwk_id(jwk)
});
if (jwk_id_found) {
option::some(*vector::borrow(&provider_jwks.jwks, index))
} else {
option::none()
}
}

get_jwk_id

Get the ID of a JWK.

fun get_jwk_id(jwk: &jwks::JWK): vector<u8>
Implementation
fun get_jwk_id(jwk: &JWK): vector<u8> {
let variant_type_name = *string::bytes(copyable_any::type_name(&jwk.variant));
if (variant_type_name == b"0x1::jwks::RSA_JWK") {
let rsa = copyable_any::unpack<RSA_JWK>(jwk.variant);
*string::bytes(&rsa.kid)
} else if (variant_type_name == b"0x1::jwks::UnsupportedJWK") {
let unsupported = copyable_any::unpack<UnsupportedJWK>(jwk.variant);
unsupported.id
} else {
abort(error::invalid_argument(EUNKNOWN_JWK_VARIANT))
}
}

upsert_provider_jwks

Upsert a ProviderJWKs into an AllProvidersJWKs. If this upsert replaced an existing entry, return it. Maintains the sorted-by-issuer invariant in AllProvidersJWKs.

fun upsert_provider_jwks(jwks: &mut jwks::AllProvidersJWKs, provider_jwks: jwks::ProviderJWKs): option::Option<jwks::ProviderJWKs>
Implementation
fun upsert_provider_jwks(jwks: &mut AllProvidersJWKs, provider_jwks: ProviderJWKs): Option<ProviderJWKs> {
// NOTE: Using a linear-time search here because we do not expect too many providers.
let found = false;
let index = 0;
let num_entries = vector::length(&jwks.entries);
while (index < num_entries) {
let cur_entry = vector::borrow(&jwks.entries, index);
let comparison = compare_u8_vector(provider_jwks.issuer, cur_entry.issuer);
if (is_greater_than(&comparison)) {
index = index + 1;
} else {
found = is_equal(&comparison);
break
}
};
// Now if `found == true`, `index` points to the JWK we want to update/remove; otherwise, `index` points to
// where we want to insert.
let ret = if (found) {
let entry = vector::borrow_mut(&mut jwks.entries, index);
let old_entry = option::some(*entry);
*entry = provider_jwks;
old_entry
} else {
vector::insert(&mut jwks.entries, index, provider_jwks);
option::none()
};
ret
}

remove_issuer

Remove the entry of an issuer from a AllProvidersJWKs and return the entry, if exists. Maintains the sorted-by-issuer invariant in AllProvidersJWKs.

fun remove_issuer(jwks: &mut jwks::AllProvidersJWKs, issuer: vector<u8>): option::Option<jwks::ProviderJWKs>
Implementation
fun remove_issuer(jwks: &mut AllProvidersJWKs, issuer: vector<u8>): Option<ProviderJWKs> {
let (found, index) = vector::find(&jwks.entries, |obj| {
let provider_jwk_set: &ProviderJWKs = obj;
provider_jwk_set.issuer == issuer
});
let ret = if (found) {
option::some(vector::remove(&mut jwks.entries, index))
} else {
option::none()
};
ret
}

upsert_jwk

Upsert a JWK into a ProviderJWKs. If this upsert replaced an existing entry, return it.

fun upsert_jwk(set: &mut jwks::ProviderJWKs, jwk: jwks::JWK): option::Option<jwks::JWK>
Implementation
fun upsert_jwk(set: &mut ProviderJWKs, jwk: JWK): Option<JWK> {
let found = false;
let index = 0;
let num_entries = vector::length(&set.jwks);
while (index < num_entries) {
let cur_entry = vector::borrow(&set.jwks, index);
let comparison = compare_u8_vector(get_jwk_id(&jwk), get_jwk_id(cur_entry));
if (is_greater_than(&comparison)) {
index = index + 1;
} else {
found = is_equal(&comparison);
break
}
};
// Now if `found == true`, `index` points to the JWK we want to update/remove; otherwise, `index` points to
// where we want to insert.
let ret = if (found) {
let entry = vector::borrow_mut(&mut set.jwks, index);
let old_entry = option::some(*entry);
*entry = jwk;
old_entry
} else {
vector::insert(&mut set.jwks, index, jwk);
option::none()
};
ret
}

remove_jwk

Remove the entry of a key ID from a ProviderJWKs and return the entry, if exists.

fun remove_jwk(jwks: &mut jwks::ProviderJWKs, jwk_id: vector<u8>): option::Option<jwks::JWK>
Implementation
fun remove_jwk(jwks: &mut ProviderJWKs, jwk_id: vector<u8>): Option<JWK> {
let (found, index) = vector::find(&jwks.jwks, |obj| {
let jwk: &JWK = obj;
jwk_id == get_jwk_id(jwk)
});
let ret = if (found) {
option::some(vector::remove(&mut jwks.jwks, index))
} else {
option::none()
};
ret
}

apply_patch

Modify an AllProvidersJWKs object with a Patch. Maintains the sorted-by-issuer invariant in AllProvidersJWKs.

fun apply_patch(jwks: &mut jwks::AllProvidersJWKs, patch: jwks::Patch)
Implementation
fun apply_patch(jwks: &mut AllProvidersJWKs, patch: Patch) {
let variant_type_name = *string::bytes(copyable_any::type_name(&patch.variant));
if (variant_type_name == b"0x1::jwks::PatchRemoveAll") {
jwks.entries = vector[];
} else if (variant_type_name == b"0x1::jwks::PatchRemoveIssuer") {
let cmd = copyable_any::unpack<PatchRemoveIssuer>(patch.variant);
remove_issuer(jwks, cmd.issuer);
} else if (variant_type_name == b"0x1::jwks::PatchRemoveJWK") {
let cmd = copyable_any::unpack<PatchRemoveJWK>(patch.variant);
// TODO: This is inefficient: we remove the issuer, modify its JWKs & and reinsert the updated issuer. Why
// not just update it in place?
let existing_jwk_set = remove_issuer(jwks, cmd.issuer);
if (option::is_some(&existing_jwk_set)) {
let jwk_set = option::extract(&mut existing_jwk_set);
remove_jwk(&mut jwk_set, cmd.jwk_id);
upsert_provider_jwks(jwks, jwk_set);
};
} else if (variant_type_name == b"0x1::jwks::PatchUpsertJWK") {
let cmd = copyable_any::unpack<PatchUpsertJWK>(patch.variant);
// TODO: This is inefficient: we remove the issuer, modify its JWKs & and reinsert the updated issuer. Why
// not just update it in place?
let existing_jwk_set = remove_issuer(jwks, cmd.issuer);
let jwk_set = if (option::is_some(&existing_jwk_set)) {
option::extract(&mut existing_jwk_set)
} else {
ProviderJWKs {
version: 0,
issuer: cmd.issuer,
jwks: vector[],
}
};
upsert_jwk(&mut jwk_set, cmd.jwk);
upsert_provider_jwks(jwks, jwk_set);
} else {
abort(std::error::invalid_argument(EUNKNOWN_PATCH_VARIANT))
}
}

Specification

on_new_epoch

public(friend) fun on_new_epoch(framework: &signer)
requires @aptos_framework == std::signer::address_of(framework);
include config_buffer::OnNewEpochRequirement<SupportedOIDCProviders>;
aborts_if false;