rings_node/extension/snark/
protocol.rs1#![warn(missing_docs)]
2use std::sync::Arc;
10
11use bytes::Bytes;
12use rings_core::dht::Did;
13use serde::Deserialize;
14use serde::Serialize;
15
16use super::SNARKBehaviour;
17use super::SNARKTaskManager;
18use super::TaskId;
19use super::NAMESPACE;
20use crate::error::Error;
21use crate::extension::ext::Ctx;
22use crate::extension::ext::Interpret;
23use crate::extension::ext::Protocol;
24use crate::extension::ext::Reject;
25use crate::extension::ext::Scope;
26use crate::extension::ext::Transition;
27use crate::extension::ext::Wire;
28use crate::extension::types::snark::SNARKProofTask;
29use crate::extension::types::snark::SNARKTask;
30use crate::extension::types::snark::SNARKTaskMessage;
31use crate::extension::types::snark::SNARKVerifyTask;
32
33#[derive(Serialize, Deserialize)]
35pub enum ComputeResult {
36 Proved {
38 task_id: TaskId,
40 reply_to: Did,
42 verify_task: SNARKVerifyTask,
44 },
45 Verified {
47 task_id: TaskId,
49 },
50}
51
52pub enum SnarkEvent {
54 Result(ComputeResult),
56 Task {
58 from: Did,
60 msg: SNARKTaskMessage,
62 },
63}
64
65pub enum SnarkEffect {
67 SendTask {
69 to: Did,
71 msg: SNARKTaskMessage,
73 },
74 Prove {
76 task_id: TaskId,
78 reply_to: Did,
80 task: Box<SNARKProofTask>,
82 },
83 Verify {
85 task_id: TaskId,
87 verify_task: SNARKVerifyTask,
89 },
90}
91
92#[derive(Clone)]
104pub struct SnarkProtocol;
105
106impl Protocol for SnarkProtocol {
107 type State = ();
108 type Event = SnarkEvent;
109 type Effect = SnarkEffect;
110
111 fn namespace(&self) -> &str {
112 NAMESPACE
113 }
114
115 fn init(&self) {}
116
117 fn decode(&self, wire: Wire<'_>) -> Result<SnarkEvent, Reject> {
118 if wire.from == wire.me {
119 let result = bincode::deserialize::<ComputeResult>(wire.payload)
120 .map_err(|e| Reject(format!("bad snark result: {e}")))?;
121 Ok(SnarkEvent::Result(result))
122 } else {
123 let msg = bincode::deserialize::<SNARKTaskMessage>(wire.payload)
124 .map_err(|e| Reject(format!("bad snark task: {e}")))?;
125 Ok(SnarkEvent::Task {
126 from: wire.from,
127 msg,
128 })
129 }
130 }
131
132 fn step(&self, _ctx: Ctx<'_, ()>, event: SnarkEvent) -> Transition<(), SnarkEffect> {
133 match event {
134 SnarkEvent::Result(ComputeResult::Proved {
135 task_id,
136 reply_to,
137 verify_task,
138 }) => Transition::with((), vec![SnarkEffect::SendTask {
139 to: reply_to,
140 msg: SNARKTaskMessage {
141 task_id,
142 task: SNARKTask::SNARKVerify(verify_task),
143 },
144 }]),
145 SnarkEvent::Result(ComputeResult::Verified { .. }) => Transition::pure(()),
146 SnarkEvent::Task { from, msg } => match msg.task {
147 SNARKTask::SNARKProof(task) => Transition::with((), vec![SnarkEffect::Prove {
148 task_id: msg.task_id,
149 reply_to: from,
150 task,
151 }]),
152 SNARKTask::SNARKVerify(verify_task) => {
153 Transition::with((), vec![SnarkEffect::Verify {
154 task_id: msg.task_id,
155 verify_task,
156 }])
157 }
158 },
159 }
160 }
161}
162
163pub struct SnarkShell {
165 manager: Arc<SNARKTaskManager>,
166}
167
168impl SnarkShell {
169 pub fn new(manager: Arc<SNARKTaskManager>) -> Self {
171 Self { manager }
172 }
173
174 fn reinject(&self, result: &ComputeResult) -> crate::error::Result<Vec<Bytes>> {
177 let payload = bincode::serialize(result).map_err(|_| Error::EncodeError)?;
178 Ok(vec![Bytes::from(payload)])
179 }
180}
181
182#[cfg_attr(feature = "browser", async_trait::async_trait(?Send))]
183#[cfg_attr(not(feature = "browser"), async_trait::async_trait)]
184impl Interpret for SnarkShell {
185 type Effect = SnarkEffect;
186
187 async fn run(&self, scope: &Scope, effect: SnarkEffect) -> crate::error::Result<Vec<Bytes>> {
188 match effect {
189 SnarkEffect::SendTask { to, msg } => {
190 let payload = bincode::serialize(&msg).map_err(|_| Error::EncodeError)?;
191 scope.send(to, Bytes::from(payload)).await?;
192 Ok(Vec::new())
193 }
194 SnarkEffect::Prove {
195 task_id,
196 reply_to,
197 task,
198 } => {
199 let verify_task = SNARKBehaviour::handle_snark_proof_task(task.as_ref())?;
200 self.reinject(&ComputeResult::Proved {
201 task_id,
202 reply_to,
203 verify_task,
204 })
205 }
206 SnarkEffect::Verify {
207 task_id,
208 verify_task,
209 } => {
210 let Some(task) = self.manager.task.get(&task_id) else {
211 return Err(Error::ExtensionError(format!(
212 "no pending SNARK proof task for {task_id}; cannot verify"
213 )));
214 };
215 let verified =
216 SNARKBehaviour::handle_snark_verify_task(&verify_task, task.value())?;
217 drop(task);
218 self.manager.verified.insert(task_id, verified);
219 self.reinject(&ComputeResult::Verified { task_id })
220 }
221 }
222 }
223}