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    /// Convert this selector to its field representation.
86    pub fn to_field(self) -> Fr {
87        selector_bytes_to_field(self.0)
88    }
89}
90
91impl fmt::Display for FunctionSelector {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        write!(f, "0x{}", hex::encode(self.0))
94    }
95}
96
97impl Serialize for FunctionSelector {
98    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
99    where
100        S: Serializer,
101    {
102        serializer.serialize_str(&self.to_string())
103    }
104}
105
106impl<'de> Deserialize<'de> for FunctionSelector {
107    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
108    where
109        D: Deserializer<'de>,
110    {
111        let s = String::deserialize(deserializer)?;
112        Self::from_hex(&s).map_err(serde::de::Error::custom)
113    }
114}
115
116/// A 4-byte authorization selector used to identify authwit request types.
117#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
118pub struct AuthorizationSelector(pub [u8; 4]);
119
120impl AuthorizationSelector {
121    /// Parse an authorization selector from a hex string.
122    pub fn from_hex(value: &str) -> Result<Self, Error> {
123        Ok(Self(decode_selector_hex(value)?))
124    }
125
126    /// Convert a field element to an authorization selector using its low 32 bits.
127    pub fn from_field(field: Fr) -> Self {
128        Self(field_to_selector_bytes(field))
129    }
130
131    /// Compute an authorization selector from an authorization signature.
132    pub fn from_signature(signature: &str) -> Self {
133        Self(selector_from_signature(signature))
134    }
135
136    /// Convert this selector to its field representation.
137    pub fn to_field(self) -> Fr {
138        selector_bytes_to_field(self.0)
139    }
140}
141
142impl fmt::Display for AuthorizationSelector {
143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144        write!(f, "0x{}", hex::encode(self.0))
145    }
146}
147
148impl Serialize for AuthorizationSelector {
149    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
150    where
151        S: Serializer,
152    {
153        serializer.serialize_str(&self.to_string())
154    }
155}
156
157impl<'de> Deserialize<'de> for AuthorizationSelector {
158    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
159    where
160        D: Deserializer<'de>,
161    {
162        let s = String::deserialize(deserializer)?;
163        Self::from_hex(&s).map_err(serde::de::Error::custom)
164    }
165}
166
167/// A field-element event selector used to identify contract events.
168#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
169pub struct EventSelector(pub Fr);
170
171/// A 7-bit note selector identifying a note type within a contract.
172///
173/// Valid values are 0..127 (fits in 7 bits). Assigned at compile time,
174/// not derived from a hash like `FunctionSelector`.
175#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
176pub struct NoteSelector(pub u8);
177
178impl NoteSelector {
179    /// Maximum valid note selector value (2^7 - 1 = 127).
180    pub const MAX_VALUE: u8 = 127;
181
182    /// Create a new NoteSelector, returning an error if value >= 128.
183    pub fn new(value: u8) -> Result<Self, Error> {
184        if value > Self::MAX_VALUE {
185            return Err(Error::InvalidData(format!(
186                "note selector must fit in 7 bits (got {})",
187                value
188            )));
189        }
190        Ok(Self(value))
191    }
192
193    /// The empty/zero note selector.
194    pub fn empty() -> Self {
195        Self(0)
196    }
197
198    /// Convert from a field element.
199    pub fn from_field(field: Fr) -> Result<Self, Error> {
200        let val = field.to_usize();
201        if val > Self::MAX_VALUE as usize {
202            return Err(Error::InvalidData(format!(
203                "note selector must fit in 7 bits (got {})",
204                val
205            )));
206        }
207        Ok(Self(val as u8))
208    }
209
210    /// Convert to a field element.
211    pub fn to_field(self) -> Fr {
212        Fr::from(self.0 as u64)
213    }
214
215    /// Parse from a hex string (e.g. `"0x1a"` or `"1a"`).
216    pub fn from_hex(value: &str) -> Result<Self, Error> {
217        let raw = value.strip_prefix("0x").unwrap_or(value);
218        let val = u8::from_str_radix(raw, 16).map_err(|e| Error::InvalidData(e.to_string()))?;
219        Self::new(val)
220    }
221}
222
223impl fmt::Display for NoteSelector {
224    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225        write!(f, "0x{:02x}", self.0)
226    }
227}
228
229impl Serialize for NoteSelector {
230    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
231    where
232        S: Serializer,
233    {
234        serializer.serialize_u8(self.0)
235    }
236}
237
238impl<'de> Deserialize<'de> for NoteSelector {
239    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
240    where
241        D: Deserializer<'de>,
242    {
243        let val = u8::deserialize(deserializer)?;
244        Self::new(val).map_err(serde::de::Error::custom)
245    }
246}