Skip to main content

miden_standards/account/auth/
singlesig.rs

1use miden_protocol::Word;
2use miden_protocol::account::auth::{AuthScheme, PublicKeyCommitment};
3use miden_protocol::account::component::{
4    AccountComponentMetadata,
5    SchemaType,
6    StorageSchema,
7    StorageSlotSchema,
8};
9use miden_protocol::account::{AccountComponent, AccountType, StorageSlot, StorageSlotName};
10use miden_protocol::utils::sync::LazyLock;
11
12use crate::account::components::singlesig_library;
13
14// CONSTANTS
15// ================================================================================================
16
17static PUBKEY_SLOT_NAME: LazyLock<StorageSlotName> = LazyLock::new(|| {
18    StorageSlotName::new("miden::standards::auth::singlesig::pub_key")
19        .expect("storage slot name should be valid")
20});
21
22static SCHEME_ID_SLOT_NAME: LazyLock<StorageSlotName> = LazyLock::new(|| {
23    StorageSlotName::new("miden::standards::auth::singlesig::scheme")
24        .expect("storage slot name should be valid")
25});
26
27/// An [`AccountComponent`] implementing the signature scheme for authentication
28/// of transactions.
29///
30/// This component exports `auth_tx`, which loads the public key and signature scheme id from
31/// storage and delegates transaction authentication to
32/// `miden::standards::auth::signature::authenticate_transaction`.
33///
34/// When linking against this component, the `miden::standards` library must be available to the
35/// assembler (which also implies availability of `miden::protocol`). This is the case when using
36/// [`CodeBuilder`][builder].
37///
38/// This component supports all account types.
39///
40/// [builder]: crate::code_builder::CodeBuilder
41pub struct AuthSingleSig {
42    pub_key: PublicKeyCommitment,
43    auth_scheme: AuthScheme,
44}
45
46impl AuthSingleSig {
47    /// The name of the component.
48    pub const NAME: &'static str = "miden::standards::components::auth::singlesig";
49
50    /// Creates a new [`AuthSingleSig`] component with the given `public_key`.
51    pub fn new(pub_key: PublicKeyCommitment, auth_scheme: AuthScheme) -> Self {
52        Self { pub_key, auth_scheme }
53    }
54
55    /// Returns the [`StorageSlotName`] where the public key is stored.
56    pub fn public_key_slot() -> &'static StorageSlotName {
57        &PUBKEY_SLOT_NAME
58    }
59
60    // Returns the [`StorageSlotName`] where the scheme ID is stored.
61    pub fn scheme_id_slot() -> &'static StorageSlotName {
62        &SCHEME_ID_SLOT_NAME
63    }
64
65    /// Returns the storage slot schema for the public key slot.
66    pub fn public_key_slot_schema() -> (StorageSlotName, StorageSlotSchema) {
67        (
68            Self::public_key_slot().clone(),
69            StorageSlotSchema::value("Public key commitment", SchemaType::pub_key()),
70        )
71    }
72    /// Returns the storage slot schema for the scheme ID slot.
73    pub fn auth_scheme_slot_schema() -> (StorageSlotName, StorageSlotSchema) {
74        (
75            Self::scheme_id_slot().clone(),
76            StorageSlotSchema::value("Scheme ID", SchemaType::auth_scheme()),
77        )
78    }
79
80    /// Returns the [`AccountComponentMetadata`] for this component.
81    pub fn component_metadata() -> AccountComponentMetadata {
82        let storage_schema = StorageSchema::new(vec![
83            Self::public_key_slot_schema(),
84            Self::auth_scheme_slot_schema(),
85        ])
86        .expect("storage schema should be valid");
87
88        AccountComponentMetadata::new(Self::NAME, AccountType::all())
89            .with_description(
90                "Authentication component using ECDSA K256 Keccak or Falcon512 Poseidon2 signature scheme",
91            )
92            .with_storage_schema(storage_schema)
93    }
94}
95
96impl From<AuthSingleSig> for AccountComponent {
97    fn from(basic_signature: AuthSingleSig) -> Self {
98        let metadata = AuthSingleSig::component_metadata();
99
100        let storage_slots = vec![
101            StorageSlot::with_value(
102                AuthSingleSig::public_key_slot().clone(),
103                basic_signature.pub_key.into(),
104            ),
105            StorageSlot::with_value(
106                AuthSingleSig::scheme_id_slot().clone(),
107                Word::from([basic_signature.auth_scheme.as_u8(), 0, 0, 0]),
108            ),
109        ];
110
111        AccountComponent::new(singlesig_library(), storage_slots, metadata).expect(
112            "singlesig component should satisfy the requirements of a valid account component",
113        )
114    }
115}