1use super::{
2 ExecutableTransaction,
3 Interpreter,
4 Memory,
5 MemoryInstance,
6 internal::{
7 clear_err,
8 inc_pc,
9 set_err,
10 },
11 memory::OwnershipRegisters,
12};
13use crate::{
14 constraints::reg_key::*,
15 error::SimpleResult,
16};
17
18use alloc::vec::Vec;
19use bn::{
20 AffineG1,
21 AffineG2,
22 Fq,
23 Fq2,
24 Fr,
25 G1,
26 G2,
27 Group,
28 Gt,
29};
30use fuel_asm::RegId;
31use fuel_crypto::{
32 Hasher,
33 Message,
34 PublicKey,
35 Signature,
36};
37use fuel_types::{
38 Bytes32,
39 Bytes64,
40 Word,
41};
42
43#[cfg(test)]
44mod tests;
45
46impl<M, S, Tx, Ecal, V> Interpreter<M, S, Tx, Ecal, V>
47where
48 M: Memory,
49 Tx: ExecutableTransaction,
50{
51 pub(crate) fn secp256k1_recover(
52 &mut self,
53 a: Word,
54 b: Word,
55 c: Word,
56 ) -> SimpleResult<()> {
57 let owner = self.ownership_registers();
58 let (SystemRegisters { err, pc, .. }, _) = split_registers(&mut self.registers);
59 secp256k1_recover(self.memory.as_mut(), owner, err, pc, a, b, c)
60 }
61
62 pub(crate) fn secp256r1_recover(
63 &mut self,
64 a: Word,
65 b: Word,
66 c: Word,
67 ) -> SimpleResult<()> {
68 let owner = self.ownership_registers();
69 let (SystemRegisters { err, pc, .. }, _) = split_registers(&mut self.registers);
70 secp256r1_recover(self.memory.as_mut(), owner, err, pc, a, b, c)
71 }
72
73 pub(crate) fn ed25519_verify(
74 &mut self,
75 a: Word,
76 b: Word,
77 c: Word,
78 len: Word,
79 ) -> SimpleResult<()> {
80 let (SystemRegisters { err, pc, .. }, _) = split_registers(&mut self.registers);
81 ed25519_verify(self.memory.as_mut(), err, pc, a, b, c, len)
82 }
83
84 pub(crate) fn keccak256(&mut self, a: Word, b: Word, c: Word) -> SimpleResult<()> {
85 let owner = self.ownership_registers();
86 keccak256(
87 self.memory.as_mut(),
88 owner,
89 self.registers.pc_mut(),
90 a,
91 b,
92 c,
93 )
94 }
95
96 pub(crate) fn sha256(&mut self, a: Word, b: Word, c: Word) -> SimpleResult<()> {
97 let owner = self.ownership_registers();
98 sha256(
99 self.memory.as_mut(),
100 owner,
101 self.registers.pc_mut(),
102 a,
103 b,
104 c,
105 )
106 }
107
108 pub(crate) fn ec_operation(
109 &mut self,
110 a: Word,
111 b: Word,
112 c: Word,
113 d: Word,
114 ) -> SimpleResult<()> {
115 let owner = self.ownership_registers();
116 ec_operation(
117 self.memory.as_mut(),
118 owner,
119 self.registers.pc_mut(),
120 a,
121 b,
122 c,
123 d,
124 )
125 }
126
127 pub(crate) fn ec_pairing(
128 &mut self,
129 ra: RegId,
130 b: Word,
131 c: Word,
132 d: Word,
133 ) -> SimpleResult<()> {
134 let (SystemRegisters { pc, .. }, mut w) = split_registers(&mut self.registers);
135 let dest = &mut w[ra.try_into()?];
136 ec_pairing(self.memory.as_mut(), pc, dest, b, c, d)
137 }
138}
139
140pub(crate) fn secp256k1_recover(
141 memory: &mut MemoryInstance,
142 owner: OwnershipRegisters,
143 err: RegMut<ERR>,
144 pc: RegMut<PC>,
145 a: Word,
146 b: Word,
147 c: Word,
148) -> SimpleResult<()> {
149 let sig = Bytes64::from(memory.read_bytes(b)?);
150 let msg = Bytes32::from(memory.read_bytes(c)?);
151
152 let signature = Signature::from_bytes_ref(&sig);
153 let message = Message::from_bytes_ref(&msg);
154
155 match signature.recover(message) {
156 Ok(pub_key) => {
157 memory.write_bytes(owner, a, *pub_key)?;
158 clear_err(err);
159 }
160 Err(_) => {
161 memory.write_bytes(owner, a, [0; PublicKey::LEN])?;
162 set_err(err);
163 }
164 }
165
166 inc_pc(pc);
167 Ok(())
168}
169
170pub(crate) fn secp256r1_recover(
171 memory: &mut MemoryInstance,
172 owner: OwnershipRegisters,
173 err: RegMut<ERR>,
174 pc: RegMut<PC>,
175 a: Word,
176 b: Word,
177 c: Word,
178) -> SimpleResult<()> {
179 let sig = Bytes64::from(memory.read_bytes(b)?);
180 let msg = Bytes32::from(memory.read_bytes(c)?);
181 let message = Message::from_bytes_ref(&msg);
182
183 match fuel_crypto::secp256r1::recover(&sig, message) {
184 Ok(pub_key) => {
185 memory.write_bytes(owner, a, *pub_key)?;
186 clear_err(err);
187 }
188 Err(_) => {
189 memory.write_bytes(owner, a, [0; PublicKey::LEN])?;
190 set_err(err);
191 }
192 }
193
194 inc_pc(pc);
195 Ok(())
196}
197
198pub(crate) fn ed25519_verify(
199 memory: &mut MemoryInstance,
200 err: RegMut<ERR>,
201 pc: RegMut<PC>,
202 a: Word,
203 b: Word,
204 c: Word,
205 len: Word,
206) -> SimpleResult<()> {
207 let pub_key = Bytes32::from(memory.read_bytes(a)?);
208 let sig = Bytes64::from(memory.read_bytes(b)?);
209 let msg = memory.read(c, len)?;
210
211 if fuel_crypto::ed25519::verify(&pub_key, &sig, msg).is_ok() {
212 clear_err(err);
213 } else {
214 set_err(err);
215 }
216
217 inc_pc(pc);
218 Ok(())
219}
220
221pub(crate) fn keccak256(
222 memory: &mut MemoryInstance,
223 owner: OwnershipRegisters,
224 pc: RegMut<PC>,
225 a: Word,
226 b: Word,
227 c: Word,
228) -> SimpleResult<()> {
229 use sha3::{
230 Digest,
231 Keccak256,
232 };
233 let mut h = Keccak256::new();
234 h.update(memory.read(b, c)?);
235
236 memory.write_bytes(owner, a, *h.finalize().as_ref())?;
237
238 inc_pc(pc);
239 Ok(())
240}
241
242pub(crate) fn sha256(
243 memory: &mut MemoryInstance,
244 owner: OwnershipRegisters,
245 pc: RegMut<PC>,
246 a: Word,
247 b: Word,
248 c: Word,
249) -> SimpleResult<()> {
250 memory.write_bytes(owner, a, *Hasher::hash(memory.read(b, c)?))?;
251 inc_pc(pc);
252 Ok(())
253}
254
255fn read_g1_point_alt_bn_128(
256 memory: &MemoryInstance,
257 point_ptr: Word,
258) -> SimpleResult<G1> {
259 let arg_bytes: [u8; 2 * 32] = memory.read_bytes(point_ptr)?;
261
262 let px = Fq::from_slice(&arg_bytes[..32])
263 .map_err(|_| fuel_tx::PanicReason::InvalidEllipticCurvePoint)?;
264 let py = Fq::from_slice(&arg_bytes[32..64])
265 .map_err(|_| fuel_tx::PanicReason::InvalidEllipticCurvePoint)?;
266
267 Ok(if px == Fq::zero() && py == Fq::zero() {
268 G1::zero()
269 } else {
270 AffineG1::new(px, py)
271 .map(Into::into)
272 .map_err(|_| fuel_tx::PanicReason::InvalidEllipticCurvePoint)?
273 })
274}
275
276fn read_g2_point_alt_bn_128(
277 memory: &MemoryInstance,
278 point_ptr: Word,
279) -> SimpleResult<G2> {
280 let arg_bytes: [u8; 4 * 32] = memory.read_bytes(point_ptr)?;
282
283 let ay = Fq::from_slice(&arg_bytes[..32])
284 .map_err(|_| fuel_tx::PanicReason::InvalidEllipticCurvePoint)?;
285 let ax = Fq::from_slice(&arg_bytes[32..64])
286 .map_err(|_| fuel_tx::PanicReason::InvalidEllipticCurvePoint)?;
287 let by = Fq::from_slice(&arg_bytes[64..96])
288 .map_err(|_| fuel_tx::PanicReason::InvalidEllipticCurvePoint)?;
289 let bx = Fq::from_slice(&arg_bytes[96..128])
290 .map_err(|_| fuel_tx::PanicReason::InvalidEllipticCurvePoint)?;
291
292 let a = Fq2::new(ax, ay);
293 let b = Fq2::new(bx, by);
294 Ok(if a.is_zero() && b.is_zero() {
295 G2::zero()
296 } else {
297 G2::from(
298 AffineG2::new(a, b)
299 .map_err(|_| fuel_tx::PanicReason::InvalidEllipticCurvePoint)?,
300 )
301 })
302}
303
304pub(crate) fn ec_operation(
305 memory: &mut MemoryInstance,
306 owner: OwnershipRegisters,
307 pc: RegMut<PC>,
308 dst: Word,
309 curve_id: Word,
310 operation_type: Word,
311 points_ptr: Word,
312) -> SimpleResult<()> {
313 match curve_id {
314 0 => {
315 match operation_type {
316 0 => {
318 let point1 = read_g1_point_alt_bn_128(memory, points_ptr)?;
319 let point2 = read_g1_point_alt_bn_128(
320 memory,
321 points_ptr
322 .checked_add(64)
323 .ok_or(fuel_tx::PanicReason::MemoryOverflow)?,
324 )?;
325 let mut output = [0u8; 64];
326 #[allow(clippy::arithmetic_side_effects)]
330 if let Some(sum) = AffineG1::from_jacobian(point1 + point2) {
331 sum.x().to_big_endian(&mut output[..32]).unwrap();
332 sum.y().to_big_endian(&mut output[32..]).unwrap();
333 }
334 memory.write_bytes(owner, dst, output)?;
335 }
336 1 => {
338 let point = read_g1_point_alt_bn_128(memory, points_ptr)?;
339 let scalar = Fr::from_slice(
340 memory.read(
341 points_ptr
342 .checked_add(64)
343 .ok_or(fuel_tx::PanicReason::MemoryOverflow)?,
344 32u64,
345 )?,
346 )
347 .map_err(|_| fuel_tx::PanicReason::InvalidEllipticCurvePoint)?;
348 let mut output = [0u8; 64];
349 #[allow(clippy::arithmetic_side_effects)]
353 if let Some(product) = AffineG1::from_jacobian(point * scalar) {
354 product.x().to_big_endian(&mut output[..32]).unwrap();
355 product.y().to_big_endian(&mut output[32..]).unwrap();
356 }
357 memory.write_bytes(owner, dst, output)?;
358 }
359 _ => return Err(fuel_tx::PanicReason::UnsupportedOperationType.into()),
360 }
361 }
362 _ => return Err(fuel_tx::PanicReason::UnsupportedCurveId.into()),
363 }
364 inc_pc(pc);
365 Ok(())
366}
367
368pub(crate) fn ec_pairing(
369 memory: &mut MemoryInstance,
370 pc: RegMut<PC>,
371 success: &mut u64,
372 identifier: Word,
373 number_elements: Word,
374 elements_ptr: Word,
375) -> SimpleResult<()> {
376 match identifier {
377 0 => {
379 let element_size = 128 + 64;
382 let mut elements = Vec::with_capacity(
383 usize::try_from(number_elements)
384 .map_err(|_| fuel_tx::PanicReason::MemoryOverflow)?,
385 );
386 for idx in 0..number_elements {
387 let start_offset = elements_ptr
388 .checked_add(
389 idx.checked_mul(element_size)
390 .ok_or(fuel_tx::PanicReason::MemoryOverflow)?,
391 )
392 .ok_or(fuel_tx::PanicReason::MemoryOverflow)?;
393 let a = read_g1_point_alt_bn_128(memory, start_offset)?;
394 let b = read_g2_point_alt_bn_128(
395 memory,
396 start_offset
397 .checked_add(64)
398 .ok_or(fuel_tx::PanicReason::MemoryOverflow)?,
399 )?;
400 elements.push((a, b));
401 }
402 *success = (bn::pairing_batch(&elements) == Gt::one()) as u64;
403 }
404 _ => return Err(fuel_tx::PanicReason::UnsupportedOperationType.into()),
405 }
406 inc_pc(pc);
407 Ok(())
408}