miden_core_lib/handlers/
eddsa_ed25519.rs1use alloc::{vec, vec::Vec};
11use core::convert::TryInto;
12
13use miden_core::{
14 Felt,
15 events::EventName,
16 field::PrimeCharacteristicRing,
17 precompile::{PrecompileCommitment, PrecompileError, PrecompileRequest, PrecompileVerifier},
18 serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
19 utils::bytes_to_packed_u32_elements,
20};
21use miden_crypto::{
22 ZERO,
23 dsa::eddsa_25519_sha512::{PublicKey, Signature},
24 hash::poseidon2::Poseidon2,
25};
26use miden_processor::{
27 ProcessorState,
28 advice::AdviceMutation,
29 event::{EventError, EventHandler},
30};
31
32use crate::handlers::{MemoryReadError, read_memory_packed_u32};
33
34pub const EDDSA25519_VERIFY_EVENT_NAME: EventName =
39 EventName::new("miden::core::dsa::eddsa_ed25519::verify");
40
41const PUBLIC_KEY_LEN_BYTES: usize = 32;
42const K_DIGEST_LEN_BYTES: usize = 64;
43const SIGNATURE_LEN_BYTES: usize = 64;
44
45const PRECOMPILE_REQUEST_LEN: usize =
46 PUBLIC_KEY_LEN_BYTES + K_DIGEST_LEN_BYTES + SIGNATURE_LEN_BYTES;
47
48pub struct EddsaPrecompile;
50
51impl EventHandler for EddsaPrecompile {
52 fn on_event(&self, process: &ProcessorState) -> Result<Vec<AdviceMutation>, EventError> {
53 let pk_ptr = process.get_stack_item(1).as_canonical_u64();
55 let k_digest_ptr = process.get_stack_item(2).as_canonical_u64();
56 let sig_ptr = process.get_stack_item(3).as_canonical_u64();
57
58 let pk = {
59 let data_type = DataType::PublicKey;
60 let bytes = read_memory_packed_u32(process, pk_ptr, PUBLIC_KEY_LEN_BYTES)
61 .map_err(|source| EddsaError::ReadError { data_type, source })?;
62 PublicKey::read_from_bytes(&bytes)
63 .map_err(|source| EddsaError::DeserializeError { data_type, source })?
64 };
65
66 let k_digest = {
67 let data_type = DataType::KDigest;
68 let bytes = read_memory_packed_u32(process, k_digest_ptr, K_DIGEST_LEN_BYTES)
69 .map_err(|source| EddsaError::ReadError { data_type, source })?;
70 bytes.try_into().expect("k-digest length must be exactly 64 bytes")
71 };
72
73 let signature = {
74 let data_type = DataType::Signature;
75 let bytes = read_memory_packed_u32(process, sig_ptr, SIGNATURE_LEN_BYTES)
76 .map_err(|source| EddsaError::ReadError { data_type, source })?;
77 Signature::read_from_bytes(&bytes)
78 .map_err(|source| EddsaError::DeserializeError { data_type, source })?
79 };
80
81 let request = EddsaRequest::new(pk, k_digest, signature);
82 let result = request.result();
83
84 Ok(vec![
85 AdviceMutation::extend_stack([Felt::from_bool(result)]),
86 AdviceMutation::extend_precompile_requests([request.into()]),
87 ])
88 }
89}
90
91impl PrecompileVerifier for EddsaPrecompile {
92 fn verify(&self, calldata: &[u8]) -> Result<PrecompileCommitment, PrecompileError> {
93 let request = EddsaRequest::read_from_bytes(calldata)?;
94 Ok(request.as_precompile_commitment())
95 }
96}
97
98pub struct EddsaRequest {
103 pk: PublicKey,
104 k_digest: [u8; K_DIGEST_LEN_BYTES],
106 sig: Signature,
107}
108
109impl EddsaRequest {
110 pub fn new(pk: PublicKey, k_digest: [u8; K_DIGEST_LEN_BYTES], sig: Signature) -> Self {
111 Self { pk, k_digest, sig }
112 }
113
114 pub fn pk(&self) -> &PublicKey {
115 &self.pk
116 }
117
118 pub fn k_digest(&self) -> &[u8; K_DIGEST_LEN_BYTES] {
119 &self.k_digest
120 }
121
122 pub fn sig(&self) -> &Signature {
123 &self.sig
124 }
125
126 pub fn as_precompile_request(&self) -> PrecompileRequest {
127 let mut calldata = Vec::with_capacity(PRECOMPILE_REQUEST_LEN);
128 self.write_into(&mut calldata);
129 PrecompileRequest::new(EDDSA25519_VERIFY_EVENT_NAME.to_event_id(), calldata)
130 }
131
132 pub fn result(&self) -> bool {
133 self.pk.verify_with_unchecked_k(self.k_digest, &self.sig).is_ok()
134 }
135
136 pub fn as_precompile_commitment(&self) -> PrecompileCommitment {
137 let result = Felt::from_bool(self.result());
138 let tag = [EDDSA25519_VERIFY_EVENT_NAME.to_event_id().as_felt(), result, ZERO, ZERO].into();
139
140 let pk_comm = {
141 let felts = bytes_to_packed_u32_elements(&self.pk.to_bytes());
142 Poseidon2::hash_elements(&felts)
143 };
144 let k_digest_comm = {
145 let felts = bytes_to_packed_u32_elements(&self.k_digest);
146 Poseidon2::hash_elements(&felts)
147 };
148 let sig_comm = {
149 let felts = bytes_to_packed_u32_elements(&self.sig.to_bytes());
150 Poseidon2::hash_elements(&felts)
151 };
152
153 let commitment = Poseidon2::merge(&[Poseidon2::merge(&[pk_comm, k_digest_comm]), sig_comm]);
154
155 PrecompileCommitment::new(tag, commitment)
156 }
157}
158
159impl Serializable for EddsaRequest {
160 fn write_into<W: ByteWriter>(&self, target: &mut W) {
161 self.pk.write_into(target);
162 target.write_bytes(&self.k_digest);
163 self.sig.write_into(target);
164 }
165}
166
167impl Deserializable for EddsaRequest {
168 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
169 let pk = PublicKey::read_from(source)?;
170 let k_digest = source.read_array()?;
171 let sig = Signature::read_from(source)?;
172 Ok(Self { pk, k_digest, sig })
173 }
174}
175
176impl From<EddsaRequest> for PrecompileRequest {
177 fn from(request: EddsaRequest) -> Self {
178 request.as_precompile_request()
179 }
180}
181
182#[derive(Debug, Clone, Copy)]
186pub(crate) enum DataType {
187 PublicKey,
188 KDigest,
189 Signature,
190}
191
192impl core::fmt::Display for DataType {
193 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
194 match self {
195 DataType::PublicKey => write!(f, "public key"),
196 DataType::KDigest => write!(f, "k-digest"),
197 DataType::Signature => write!(f, "signature"),
198 }
199 }
200}
201
202#[derive(Debug, thiserror::Error)]
203pub(crate) enum EddsaError {
204 #[error("failed to read {data_type} from memory")]
205 ReadError {
206 data_type: DataType,
207 #[source]
208 source: MemoryReadError,
209 },
210
211 #[error("failed to deserialize {data_type}")]
212 DeserializeError {
213 data_type: DataType,
214 #[source]
215 source: DeserializationError,
216 },
217}