Skip to main content

aztec_core/abi/
selectors.rs

1use ark_ff::{BigInteger, PrimeField};
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3use std::fmt;
4
5use super::types::{abi_type_signature, AbiParameter};
6use crate::hash::poseidon2_hash_bytes;
7use crate::types::Fr;
8use crate::Error;
9
10fn strip_0x(s: &str) -> &str {
11    s.strip_prefix("0x").unwrap_or(s)
12}
13
14fn decode_selector_hex(s: &str) -> Result<[u8; 4], Error> {
15    let raw = strip_0x(s);
16    if raw.len() > 8 {
17        return Err(Error::InvalidData(
18            "function selector must fit in 4 bytes".to_owned(),
19        ));
20    }
21    let padded = format!("{raw:0>8}");
22    let bytes = hex::decode(padded).map_err(|e| Error::InvalidData(e.to_string()))?;
23    let mut out = [0u8; 4];
24    out.copy_from_slice(&bytes);
25    Ok(out)
26}
27
28fn field_to_selector_bytes(field: Fr) -> [u8; 4] {
29    let raw = field.0.into_bigint().to_bytes_be();
30    let mut padded = [0u8; 32];
31    padded[32 - raw.len()..].copy_from_slice(&raw);
32    let mut out = [0u8; 4];
33    out.copy_from_slice(&padded[28..]);
34    out
35}
36
37fn selector_bytes_to_field(bytes: [u8; 4]) -> Fr {
38    Fr::from(u64::from(u32::from_be_bytes(bytes)))
39}
40
41fn selector_from_signature(signature: &str) -> [u8; 4] {
42    let hash = poseidon2_hash_bytes(signature.as_bytes());
43    field_to_selector_bytes(hash)
44}
45
46/// A 4-byte function selector used to identify contract functions.
47#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
48pub struct FunctionSelector(pub [u8; 4]);
49
50impl FunctionSelector {
51    /// Parse a function selector from a hex string (e.g. `"0xaabbccdd"`).
52    pub fn from_hex(value: &str) -> Result<Self, Error> {
53        Ok(Self(decode_selector_hex(value)?))
54    }
55
56    /// Convert a field element to a function selector using its low 32 bits.
57    pub fn from_field(field: Fr) -> Self {
58        Self(field_to_selector_bytes(field))
59    }
60
61    /// Compute a function selector from a Noir function signature string.
62    ///
63    /// Aztec computes selectors by Poseidon2-hashing the raw signature bytes and
64    /// taking the low 32 bits of the resulting field element.
65    ///
66    /// # Example
67    /// ```
68    /// # use aztec_core::abi::FunctionSelector;
69    /// let selector = FunctionSelector::from_signature("sponsor_unconditionally()");
70    /// ```
71    pub fn from_signature(signature: &str) -> Self {
72        Self(selector_from_signature(signature))
73    }
74
75    /// Derive a function selector from a function name and its ABI parameters.
76    ///
77    /// Constructs the canonical Noir signature (e.g., `transfer(Field,Field,u64)`)
78    /// and computes the Poseidon2-based selector from it.
79    pub fn from_name_and_parameters(name: &str, params: &[AbiParameter]) -> Self {
80        let param_sigs: Vec<String> = params.iter().map(|p| abi_type_signature(&p.typ)).collect();
81        let sig = format!("{}({})", name, param_sigs.join(","));
82        Self::from_signature(&sig)
83    }
84
85    /// The zero/empty function selector.
86    pub const fn empty() -> Self {
87        Self([0u8; 4])
88    }
89
90    /// Convert this selector to its field representation.
91    pub fn to_field(self) -> Fr {
92        selector_bytes_to_field(self.0)
93    }
94}
95
96impl fmt::Display for FunctionSelector {
97    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98        write!(f, "0x{}", hex::encode(self.0))
99    }
100}
101
102impl Serialize for FunctionSelector {
103    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
104    where
105        S: Serializer,
106    {
107        serializer.serialize_str(&self.to_string())
108    }
109}
110
111impl<'de> Deserialize<'de> for FunctionSelector {
112    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
113    where
114        D: Deserializer<'de>,
115    {
116        let s = String::deserialize(deserializer)?;
117        Self::from_hex(&s).map_err(serde::de::Error::custom)
118    }
119}
120
121/// A 4-byte authorization selector used to identify authwit request types.
122#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
123pub struct AuthorizationSelector(pub [u8; 4]);
124
125impl AuthorizationSelector {
126    /// Parse an authorization selector from a hex string.
127    pub fn from_hex(value: &str) -> Result<Self, Error> {
128        Ok(Self(decode_selector_hex(value)?))
129    }
130
131    /// Convert a field element to an authorization selector using its low 32 bits.
132    pub fn from_field(field: Fr) -> Self {
133        Self(field_to_selector_bytes(field))
134    }
135
136    /// Compute an authorization selector from an authorization signature.
137    pub fn from_signature(signature: &str) -> Self {
138        Self(selector_from_signature(signature))
139    }
140
141    /// Convert this selector to its field representation.
142    pub fn to_field(self) -> Fr {
143        selector_bytes_to_field(self.0)
144    }
145}
146
147impl fmt::Display for AuthorizationSelector {
148    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149        write!(f, "0x{}", hex::encode(self.0))
150    }
151}
152
153impl Serialize for AuthorizationSelector {
154    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
155    where
156        S: Serializer,
157    {
158        serializer.serialize_str(&self.to_string())
159    }
160}
161
162impl<'de> Deserialize<'de> for AuthorizationSelector {
163    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
164    where
165        D: Deserializer<'de>,
166    {
167        let s = String::deserialize(deserializer)?;
168        Self::from_hex(&s).map_err(serde::de::Error::custom)
169    }
170}
171
172/// A field-element event selector used to identify contract events.
173#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
174pub struct EventSelector(pub Fr);
175
176/// A 7-bit note selector identifying a note type within a contract.
177///
178/// Valid values are 0..127 (fits in 7 bits). Assigned at compile time,
179/// not derived from a hash like `FunctionSelector`.
180#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
181pub struct NoteSelector(pub u8);
182
183impl NoteSelector {
184    /// Maximum valid note selector value (2^7 - 1 = 127).
185    pub const MAX_VALUE: u8 = 127;
186
187    /// Create a new NoteSelector, returning an error if value >= 128.
188    pub fn new(value: u8) -> Result<Self, Error> {
189        if value > Self::MAX_VALUE {
190            return Err(Error::InvalidData(format!(
191                "note selector must fit in 7 bits (got {})",
192                value
193            )));
194        }
195        Ok(Self(value))
196    }
197
198    /// The empty/zero note selector.
199    pub fn empty() -> Self {
200        Self(0)
201    }
202
203    /// Convert from a field element.
204    pub fn from_field(field: Fr) -> Result<Self, Error> {
205        let val = field.to_usize();
206        if val > Self::MAX_VALUE as usize {
207            return Err(Error::InvalidData(format!(
208                "note selector must fit in 7 bits (got {})",
209                val
210            )));
211        }
212        Ok(Self(val as u8))
213    }
214
215    /// Convert to a field element.
216    pub fn to_field(self) -> Fr {
217        Fr::from(self.0 as u64)
218    }
219
220    /// Parse from a hex string (e.g. `"0x1a"` or `"1a"`).
221    pub fn from_hex(value: &str) -> Result<Self, Error> {
222        let raw = value.strip_prefix("0x").unwrap_or(value);
223        let val = u8::from_str_radix(raw, 16).map_err(|e| Error::InvalidData(e.to_string()))?;
224        Self::new(val)
225    }
226}
227
228impl fmt::Display for NoteSelector {
229    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230        write!(f, "0x{:02x}", self.0)
231    }
232}
233
234impl Serialize for NoteSelector {
235    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
236    where
237        S: Serializer,
238    {
239        serializer.serialize_u8(self.0)
240    }
241}
242
243impl<'de> Deserialize<'de> for NoteSelector {
244    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
245    where
246        D: Deserializer<'de>,
247    {
248        let val = u8::deserialize(deserializer)?;
249        Self::new(val).map_err(serde::de::Error::custom)
250    }
251}