Skip to main content

miden_standards/account/auth/
singlesig.rs

1use miden_protocol::Word;
2use miden_protocol::account::auth::{AuthScheme, PublicKey, PublicKeyCommitment};
3use miden_protocol::account::component::{
4    AccountComponentCode,
5    AccountComponentMetadata,
6    SchemaType,
7    StorageSchema,
8    StorageSlotSchema,
9};
10use miden_protocol::account::{
11    AccountComponent,
12    AccountComponentName,
13    StorageSlot,
14    StorageSlotName,
15};
16use miden_protocol::crypto::dsa::{ecdsa_k256_keccak, falcon512_poseidon2};
17use miden_protocol::utils::sync::LazyLock;
18
19use crate::account::account_component_code;
20
21account_component_code!(SINGLESIG_CODE, "auth/singlesig.masl");
22
23// CONSTANTS
24// ================================================================================================
25
26static PUBKEY_SLOT_NAME: LazyLock<StorageSlotName> = LazyLock::new(|| {
27    StorageSlotName::new("miden::standards::auth::singlesig::pub_key")
28        .expect("storage slot name should be valid")
29});
30
31static SCHEME_ID_SLOT_NAME: LazyLock<StorageSlotName> = LazyLock::new(|| {
32    StorageSlotName::new("miden::standards::auth::singlesig::scheme")
33        .expect("storage slot name should be valid")
34});
35
36/// An [`AccountComponent`] implementing the signature scheme for authentication
37/// of transactions.
38///
39/// This component exports `auth_tx`, which loads the public key and signature scheme id from
40/// storage and delegates transaction authentication to
41/// `miden::standards::auth::signature::authenticate_transaction`.
42///
43/// When linking against this component, the `miden::standards` library must be available to the
44/// assembler (which also implies availability of `miden::protocol`). This is the case when using
45/// [`CodeBuilder`][builder].
46///
47/// [builder]: crate::code_builder::CodeBuilder
48pub struct AuthSingleSig {
49    pub_key: PublicKeyCommitment,
50    auth_scheme: AuthScheme,
51}
52
53impl AuthSingleSig {
54    /// The name of the component.
55    pub const NAME: &'static str = "miden::standards::components::auth::singlesig";
56
57    /// Returns the canonical [`AccountComponentName`] of this component.
58    pub const fn name() -> AccountComponentName {
59        AccountComponentName::from_static_str(Self::NAME)
60    }
61
62    /// Returns the [`AccountComponentCode`] of this component.
63    pub fn code() -> &'static AccountComponentCode {
64        &SINGLESIG_CODE
65    }
66
67    /// Creates a new [`AuthSingleSig`] component with the given `public_key`.
68    pub fn new(pub_key: PublicKeyCommitment, auth_scheme: AuthScheme) -> Self {
69        Self { pub_key, auth_scheme }
70    }
71
72    /// Creates a new [`AuthSingleSig`] component using the Falcon512Poseidon2 signature scheme.
73    ///
74    /// The public key commitment is derived from the provided Falcon512 public key.
75    pub fn falcon512_poseidon2(pub_key: falcon512_poseidon2::PublicKey) -> Self {
76        Self {
77            pub_key: pub_key.into(),
78            auth_scheme: AuthScheme::Falcon512Poseidon2,
79        }
80    }
81
82    /// Creates a new [`AuthSingleSig`] component using the EcdsaK256Keccak signature scheme.
83    ///
84    /// The public key commitment is derived from the provided ECDSA K256 public key.
85    pub fn ecdsa_k256_keccak(pub_key: ecdsa_k256_keccak::PublicKey) -> Self {
86        Self {
87            pub_key: pub_key.into(),
88            auth_scheme: AuthScheme::EcdsaK256Keccak,
89        }
90    }
91
92    /// Creates a new [`AuthSingleSig`] component from a [`PublicKey`].
93    ///
94    /// The authentication scheme and public key commitment are derived from the provided key.
95    pub fn from_public_key(pub_key: PublicKey) -> Self {
96        Self {
97            auth_scheme: pub_key.auth_scheme(),
98            pub_key: pub_key.to_commitment(),
99        }
100    }
101
102    /// Returns the [`StorageSlotName`] where the public key is stored.
103    pub fn public_key_slot() -> &'static StorageSlotName {
104        &PUBKEY_SLOT_NAME
105    }
106
107    // Returns the [`StorageSlotName`] where the scheme ID is stored.
108    pub fn scheme_id_slot() -> &'static StorageSlotName {
109        &SCHEME_ID_SLOT_NAME
110    }
111
112    /// Returns the storage slot schema for the public key slot.
113    pub fn public_key_slot_schema() -> (StorageSlotName, StorageSlotSchema) {
114        (
115            Self::public_key_slot().clone(),
116            StorageSlotSchema::value("Public key commitment", SchemaType::pub_key()),
117        )
118    }
119    /// Returns the storage slot schema for the scheme ID slot.
120    pub fn auth_scheme_slot_schema() -> (StorageSlotName, StorageSlotSchema) {
121        (
122            Self::scheme_id_slot().clone(),
123            StorageSlotSchema::value("Scheme ID", SchemaType::auth_scheme()),
124        )
125    }
126
127    /// Returns the [`AccountComponentMetadata`] for this component.
128    pub fn component_metadata() -> AccountComponentMetadata {
129        let storage_schema = StorageSchema::new(vec![
130            Self::public_key_slot_schema(),
131            Self::auth_scheme_slot_schema(),
132        ])
133        .expect("storage schema should be valid");
134
135        AccountComponentMetadata::new(Self::NAME)
136            .with_description(
137                "Authentication component using ECDSA K256 Keccak or Falcon512 Poseidon2 signature scheme",
138            )
139            .with_storage_schema(storage_schema)
140    }
141}
142
143impl From<AuthSingleSig> for AccountComponent {
144    fn from(basic_signature: AuthSingleSig) -> Self {
145        let metadata = AuthSingleSig::component_metadata();
146
147        let storage_slots = vec![
148            StorageSlot::with_value(
149                AuthSingleSig::public_key_slot().clone(),
150                basic_signature.pub_key.into(),
151            ),
152            StorageSlot::with_value(
153                AuthSingleSig::scheme_id_slot().clone(),
154                Word::from([basic_signature.auth_scheme.as_u8(), 0, 0, 0]),
155            ),
156        ];
157
158        AccountComponent::new(AuthSingleSig::code().clone(), storage_slots, metadata).expect(
159            "singlesig component should satisfy the requirements of a valid account component",
160        )
161    }
162}