1#[cfg(target_os = "zkvm")]
16use core::arch::asm;
17use core::{cmp::min, ffi::CStr, ptr::null_mut, slice, str::Utf8Error};
18
19use crate::WORD_SIZE;
20
21pub mod ecall {
22 pub const HALT: u32 = 0;
23 pub const INPUT: u32 = 1;
24 pub const SOFTWARE: u32 = 2;
25 pub const SHA: u32 = 3;
26 pub const BIGINT: u32 = 4;
27 pub const USER: u32 = 5;
28 pub const BIGINT2: u32 = 6;
29 pub const POSEIDON2: u32 = 7;
30}
31
32pub mod halt {
33 pub const TERMINATE: u32 = 0;
34 pub const PAUSE: u32 = 1;
35 pub const SPLIT: u32 = 2;
36}
37
38pub mod reg_abi {
39 pub const REG_ZERO: usize = 0; pub const REG_RA: usize = 1; pub const REG_SP: usize = 2; pub const REG_GP: usize = 3; pub const REG_TP: usize = 4; pub const REG_T0: usize = 5; pub const REG_T1: usize = 6; pub const REG_T2: usize = 7; pub const REG_S0: usize = 8; pub const REG_FP: usize = 8; pub const REG_S1: usize = 9; pub const REG_A0: usize = 10; pub const REG_A1: usize = 11; pub const REG_A2: usize = 12; pub const REG_A3: usize = 13; pub const REG_A4: usize = 14; pub const REG_A5: usize = 15; pub const REG_A6: usize = 16; pub const REG_A7: usize = 17; pub const REG_S2: usize = 18; pub const REG_S3: usize = 19; pub const REG_S4: usize = 20; pub const REG_S5: usize = 21; pub const REG_S6: usize = 22; pub const REG_S7: usize = 23; pub const REG_S8: usize = 24; pub const REG_S9: usize = 25; pub const REG_S10: usize = 26; pub const REG_S11: usize = 27; pub const REG_T3: usize = 28; pub const REG_T4: usize = 29; pub const REG_T5: usize = 30; pub const REG_T6: usize = 31; pub const REG_MAX: usize = 32; }
74
75pub mod keccak_mode {
76 pub const KECCAK_PERMUTE: u32 = 0;
77 pub const KECCAK_PROVE: u32 = 1;
78}
79
80pub const DIGEST_WORDS: usize = 8;
81pub const DIGEST_BYTES: usize = WORD_SIZE * DIGEST_WORDS;
82
83pub const KECCACK_STATE_BYTES: usize = 200;
84pub const KECCACK_STATE_WORDS: usize = 200 / WORD_SIZE;
85pub const KECCACK_STATE_DWORDS: usize = 200 / 8;
86
87pub const IO_CHUNK_WORDS: usize = 4;
89
90pub const MAX_BUF_BYTES: usize = 4 * 1024;
93pub const MAX_BUF_WORDS: usize = MAX_BUF_BYTES / WORD_SIZE;
94pub const MAX_SHA_COMPRESS_BLOCKS: usize = 1000;
95
96pub mod bigint {
97 pub const OP_MULTIPLY: u32 = 0;
98
99 pub const WIDTH_BITS: usize = 256;
101
102 pub const WIDTH_BYTES: usize = WIDTH_BITS / 8;
104
105 pub const WIDTH_WORDS: usize = WIDTH_BYTES / crate::WORD_SIZE;
107}
108
109#[derive(Clone, Copy, Debug)]
111#[repr(transparent)]
112pub struct SyscallName(*const u8);
113
114#[macro_export]
122macro_rules! declare_syscall {
123 (
124 $(#[$meta:meta])*
125 $vis:vis $name:ident
126 ) => {
127 $(#[$meta])*
129 $vis const $name: $crate::syscall::SyscallName = match ::core::ffi::CStr::from_bytes_until_nul(
130 concat!(module_path!(), "::", stringify!($name), "\0").as_bytes(),
131 ) {
132 Ok(c_str) => match $crate::syscall::SyscallName::from_c_str(c_str) {
133 Ok(name) => name,
134 Err(_) => unreachable!(),
135 },
136 Err(_) => unreachable!(),
137 };
138 };
139}
140
141pub mod nr {
142 declare_syscall!(pub SYS_ARGC);
143 declare_syscall!(pub SYS_ARGV);
144 declare_syscall!(pub SYS_CYCLE_COUNT);
145 declare_syscall!(pub SYS_EXIT);
146 declare_syscall!(pub SYS_FORK);
147 declare_syscall!(pub SYS_GETENV);
148 declare_syscall!(pub SYS_KECCAK);
149 declare_syscall!(pub SYS_LOG);
150 declare_syscall!(pub SYS_PANIC);
151 declare_syscall!(pub SYS_PIPE);
152 declare_syscall!(pub SYS_PROVE_KECCAK);
153 declare_syscall!(pub SYS_PROVE_ZKR);
154 declare_syscall!(pub SYS_RANDOM);
155 declare_syscall!(pub SYS_READ);
156 declare_syscall!(pub SYS_VERIFY_INTEGRITY);
157 declare_syscall!(pub SYS_VERIFY_INTEGRITY2);
158 declare_syscall!(pub SYS_WRITE);
159}
160
161impl SyscallName {
162 #[inline]
164 pub const fn from_c_str(c_str: &'static CStr) -> Result<Self, Utf8Error> {
165 match c_str.to_str() {
166 Ok(_) => Ok(unsafe { Self::from_bytes_with_nul(c_str.as_ptr().cast()) }),
167 Err(error) => Err(error),
168 }
169 }
170
171 pub const unsafe fn from_bytes_with_nul(ptr: *const u8) -> Self {
177 Self(ptr)
178 }
179
180 pub fn as_ptr(&self) -> *const u8 {
181 self.0
182 }
183
184 pub fn as_str(&self) -> &str {
185 core::str::from_utf8(unsafe { core::ffi::CStr::from_ptr(self.as_ptr().cast()).to_bytes() })
186 .unwrap()
187 }
188}
189
190impl AsRef<str> for SyscallName {
191 fn as_ref(&self) -> &str {
192 self.as_str()
193 }
194}
195
196#[repr(C)]
198pub struct Return(pub u32, pub u32);
199
200macro_rules! impl_syscall {
201 ($func_name:ident
202 $(, $a0:ident
205 $(, $a1:ident
206 $(, $a2: ident
207 $(, $a3: ident
208 $(, $a4: ident
209 )?
210 )?
211 )?
212 )?
213 )?) => {
214 #[cfg_attr(feature = "export-syscalls", no_mangle)]
220 pub unsafe extern "C" fn $func_name(syscall: SyscallName,
221 from_host: *mut u32,
222 from_host_words: usize
223 $(,$a0: u32
224 $(,$a1: u32
225 $(,$a2: u32
226 $(,$a3: u32
227 $(,$a4: u32
228 )?
229 )?
230 )?
231 )?
232 )?
233 ) -> Return {
234 #[cfg(target_os = "zkvm")] {
235 let a0: u32;
236 let a1: u32;
237 ::core::arch::asm!(
238 "ecall",
239 in("t0") $crate::syscall::ecall::SOFTWARE,
240 inlateout("a0") from_host => a0,
241 inlateout("a1") from_host_words => a1,
242 in("a2") syscall.as_ptr()
243 $(,in("a3") $a0
244 $(,in("a4") $a1
245 $(,in("a5") $a2
246 $(,in("a6") $a3
247 $(,in("a7") $a4
248 )?
249 )?
250 )?
251 )?
252 )?);
253 Return(a0, a1)
254 }
255 #[cfg(not(target_os = "zkvm"))]
256 unimplemented!()
257 }
258 }
259}
260
261impl_syscall!(syscall_0);
262impl_syscall!(syscall_1, a3);
263impl_syscall!(syscall_2, a3, a4);
264impl_syscall!(syscall_3, a3, a4, a5);
265impl_syscall!(syscall_4, a3, a4, a5, a6);
266impl_syscall!(syscall_5, a3, a4, a5, a6, a7);
267
268fn ecall_1(t0: u32, a0: u32, a1: u32) {
269 #[cfg(target_os = "zkvm")]
270 unsafe {
271 asm!(
272 "ecall",
273 in("t0") t0,
274 in("a0") a0,
275 in("a1") a1,
276 )
277 };
278 #[cfg(not(target_os = "zkvm"))]
279 {
280 core::hint::black_box((t0, a0, a1));
281 unimplemented!()
282 }
283}
284
285fn ecall_3(t0: u32, a0: u32, a1: u32, a2: u32, a3: u32) {
286 #[cfg(target_os = "zkvm")]
287 unsafe {
288 asm!(
289 "ecall",
290 in("t0") t0,
291 in("a0") a0,
292 in("a1") a1,
293 in("a2") a2,
294 in("a3") a3,
295 )
296 };
297 #[cfg(not(target_os = "zkvm"))]
298 {
299 core::hint::black_box((t0, a0, a1, a2, a3));
300 unimplemented!()
301 }
302}
303
304fn ecall_4(t0: u32, a0: u32, a1: u32, a2: u32, a3: u32, a4: u32) {
305 #[cfg(target_os = "zkvm")]
306 unsafe {
307 asm!(
308 "ecall",
309 in("t0") t0,
310 in("a0") a0,
311 in("a1") a1,
312 in("a2") a2,
313 in("a3") a3,
314 in("a4") a4,
315 )
316 };
317 #[cfg(not(target_os = "zkvm"))]
318 {
319 core::hint::black_box((t0, a0, a1, a2, a3, a4));
320 unimplemented!()
321 }
322}
323
324#[inline(never)]
332#[cfg_attr(feature = "export-syscalls", no_mangle)]
333pub extern "C" fn sys_halt(user_exit: u8, out_state: *const [u32; DIGEST_WORDS]) -> ! {
334 ecall_1(
335 ecall::HALT,
336 halt::TERMINATE | ((user_exit as u32) << 8),
337 out_state as u32,
338 );
339 unreachable!();
340}
341
342#[inline(never)]
350#[cfg_attr(feature = "export-syscalls", no_mangle)]
351pub unsafe extern "C" fn sys_pause(user_exit: u8, out_state: *const [u32; DIGEST_WORDS]) {
352 ecall_1(
353 ecall::HALT,
354 halt::PAUSE | ((user_exit as u32) << 8),
355 out_state as u32,
356 );
357}
358
359#[cfg_attr(feature = "export-syscalls", no_mangle)]
360pub extern "C" fn sys_input(index: u32) -> u32 {
361 let t0 = ecall::INPUT;
362 let index = index & 0x07;
363 #[cfg(target_os = "zkvm")]
364 unsafe {
365 let a0: u32;
366 asm!(
367 "ecall",
368 in("t0") t0,
369 inlateout("a0") index => a0,
370 );
371 a0
372 }
373 #[cfg(not(target_os = "zkvm"))]
374 {
375 core::hint::black_box((t0, index));
376 unimplemented!()
377 }
378}
379
380#[cfg_attr(feature = "export-syscalls", no_mangle)]
385#[cfg_attr(not(feature = "export-syscalls"), inline(always))]
386pub unsafe extern "C" fn sys_sha_compress(
387 out_state: *mut [u32; DIGEST_WORDS],
388 in_state: *const [u32; DIGEST_WORDS],
389 block1_ptr: *const [u32; DIGEST_WORDS],
390 block2_ptr: *const [u32; DIGEST_WORDS],
391) {
392 ecall_4(
393 ecall::SHA,
394 out_state as u32,
395 in_state as u32,
396 block1_ptr as u32,
397 block2_ptr as u32,
398 1,
399 );
400}
401
402#[cfg_attr(feature = "export-syscalls", no_mangle)]
406#[cfg_attr(not(feature = "export-syscalls"), inline(always))]
407pub unsafe extern "C" fn sys_sha_buffer(
408 out_state: *mut [u32; DIGEST_WORDS],
409 in_state: *const [u32; DIGEST_WORDS],
410 buf: *const u8,
411 count: u32,
412) {
413 let mut ptr = buf;
414 let mut count_remain = count;
415 let mut in_state = in_state;
416 while count_remain > 0 {
417 let count = min(count_remain, MAX_SHA_COMPRESS_BLOCKS as u32);
418 ecall_4(
419 ecall::SHA,
420 out_state as u32,
421 in_state as u32,
422 ptr as u32,
423 ptr.add(DIGEST_BYTES) as u32,
424 count,
425 );
426 count_remain -= count;
427 ptr = ptr.add(2 * DIGEST_BYTES * count as usize);
428 in_state = out_state;
429 }
430}
431
432#[cfg_attr(feature = "export-syscalls", no_mangle)]
437#[cfg_attr(not(feature = "export-syscalls"), inline(always))]
438pub unsafe extern "C" fn sys_poseidon2(
439 state_addr: *mut [u32; DIGEST_WORDS],
440 in_buf_addr: *const u8,
441 out_buf_addr: *mut [u32; DIGEST_WORDS],
442 bits_count: u32,
443) {
444 debug_assert!(state_addr as usize % WORD_SIZE == 0);
445 debug_assert!(in_buf_addr as usize % WORD_SIZE == 0);
446 debug_assert!(out_buf_addr as usize % WORD_SIZE == 0);
447
448 ecall_3(
449 ecall::POSEIDON2,
450 state_addr as u32 / WORD_SIZE as u32,
451 in_buf_addr as u32 / WORD_SIZE as u32,
452 out_buf_addr as u32 / WORD_SIZE as u32,
453 bits_count,
454 );
455}
456
457#[cfg_attr(feature = "export-syscalls", no_mangle)]
461#[cfg_attr(not(feature = "export-syscalls"), inline(always))]
462pub unsafe extern "C" fn sys_bigint(
463 result: *mut [u32; bigint::WIDTH_WORDS],
464 op: u32,
465 x: *const [u32; bigint::WIDTH_WORDS],
466 y: *const [u32; bigint::WIDTH_WORDS],
467 modulus: *const [u32; bigint::WIDTH_WORDS],
468) {
469 ecall_4(
470 ecall::BIGINT,
471 result as u32,
472 op,
473 x as u32,
474 y as u32,
475 modulus as u32,
476 );
477}
478
479#[cfg_attr(feature = "export-syscalls", no_mangle)]
483pub unsafe extern "C" fn sys_rand(recv_buf: *mut u32, words: usize) {
484 syscall_0(nr::SYS_RANDOM, recv_buf, words);
485}
486
487#[cfg_attr(feature = "export-syscalls", no_mangle)]
491pub unsafe extern "C" fn sys_panic(msg_ptr: *const u8, len: usize) -> ! {
492 syscall_2(nr::SYS_PANIC, null_mut(), 0, msg_ptr as u32, len as u32);
493
494 #[cfg(target_os = "zkvm")]
496 asm!("sw x0, 1(x0)");
497 unreachable!()
498}
499
500#[cfg_attr(feature = "export-syscalls", no_mangle)]
504pub unsafe extern "C" fn sys_log(msg_ptr: *const u8, len: usize) {
505 syscall_2(nr::SYS_LOG, null_mut(), 0, msg_ptr as u32, len as u32);
506}
507
508#[cfg_attr(feature = "export-syscalls", no_mangle)]
509pub extern "C" fn sys_cycle_count() -> u64 {
510 let Return(hi, lo) = unsafe { syscall_0(nr::SYS_CYCLE_COUNT, null_mut(), 0) };
511 ((hi as u64) << 32) + lo as u64
512}
513
514#[cfg_attr(feature = "export-syscalls", no_mangle)]
527pub unsafe extern "C" fn sys_read(fd: u32, recv_ptr: *mut u8, nread: usize) -> usize {
528 unsafe fn fill_from_word(mut ptr: *mut u8, mut word: u32, nfill: usize) -> *mut u8 {
543 debug_assert!(nfill < 4, "nfill={nfill}");
544 for _ in 0..nfill {
545 *ptr = (word & 0xFF) as u8;
546 word >>= 8;
547 ptr = ptr.add(1);
548 }
549 ptr
550 }
551
552 let ptr_offset = (recv_ptr as usize) & (WORD_SIZE - 1);
555 let (main_ptr, main_requested, nread_first) = if ptr_offset == 0 {
556 (recv_ptr, nread, 0)
557 } else {
558 let unaligned_at_start = min(nread, WORD_SIZE - ptr_offset);
559 let Return(nread_first, firstword) =
561 syscall_2(nr::SYS_READ, null_mut(), 0, fd, unaligned_at_start as u32);
562 debug_assert_eq!(nread_first as usize, unaligned_at_start);
563
564 let main_ptr = fill_from_word(recv_ptr, firstword, unaligned_at_start);
566 if nread == unaligned_at_start {
567 return nread;
569 }
570 (main_ptr, nread - unaligned_at_start, nread_first as usize)
571 };
572
573 let main_words = main_requested / WORD_SIZE;
575 let (nread_main, lastword) =
576 sys_read_internal(fd, main_ptr as *mut u32, main_words, main_requested);
577 debug_assert!(nread_main <= main_requested);
578 let read_words = nread_main / WORD_SIZE;
579
580 let unaligned_at_end = main_requested % WORD_SIZE;
582
583 fill_from_word(
585 main_ptr.add(main_words * WORD_SIZE),
586 lastword,
587 unaligned_at_end,
588 );
589
590 nread_first + nread_main
591}
592
593#[cfg_attr(feature = "export-syscalls", no_mangle)]
612pub unsafe extern "C" fn sys_read_words(fd: u32, recv_ptr: *mut u32, nwords: usize) -> usize {
613 sys_read_internal(fd, recv_ptr, nwords, nwords * WORD_SIZE).0
614}
615
616fn sys_read_internal(fd: u32, recv_ptr: *mut u32, nwords: usize, nbytes: usize) -> (usize, u32) {
617 let mut nwords_remain = nwords;
618 let mut nbytes_remain = nbytes;
619 let mut nread_total_bytes = 0;
620 let mut recv_ptr = recv_ptr;
621 let mut final_word = 0;
622 while nbytes_remain > 0 {
623 debug_assert!(
624 final_word == 0,
625 "host returned non-zero final word on a fully aligned read"
626 );
627 let chunk_len = min(nbytes_remain, MAX_BUF_BYTES) as u32;
628 let Return(nread_bytes, last_word) = unsafe {
629 syscall_2(
630 nr::SYS_READ,
631 recv_ptr,
632 min(nwords_remain, MAX_BUF_WORDS),
633 fd,
634 chunk_len,
635 )
636 };
637 let nread_bytes = nread_bytes as usize;
638 let nread_words = nread_bytes / WORD_SIZE;
639 recv_ptr = unsafe { recv_ptr.add(nread_words) };
640 final_word = last_word;
641 nwords_remain -= nread_words;
642 nread_total_bytes += nread_bytes;
643 nbytes_remain -= nread_bytes;
644 if nread_bytes < chunk_len as usize {
645 break;
647 }
648 }
649 (nread_total_bytes, final_word)
650}
651
652#[cfg_attr(feature = "export-syscalls", no_mangle)]
656pub unsafe extern "C" fn sys_write(fd: u32, write_ptr: *const u8, nbytes: usize) {
657 let mut nbytes_remain = nbytes;
658 let mut write_ptr = write_ptr;
659 while nbytes_remain > 0 {
660 let nbytes = min(nbytes_remain, MAX_BUF_BYTES);
661 syscall_3(
662 nr::SYS_WRITE,
663 null_mut(),
664 0,
665 fd,
666 write_ptr as u32,
667 nbytes as u32,
668 );
669 write_ptr = write_ptr.add(nbytes);
670 nbytes_remain -= nbytes;
671 }
672}
673
674const ALLOWED_ENV_VARNAMES: &[&[u8]] = &[
678 b"RUST_BACKTRACE",
679 b"RUST_LIB_BACKTRACE",
680 b"RISC0_KECCAK_PO2",
681];
682
683#[cfg_attr(feature = "export-syscalls", no_mangle)]
701pub unsafe extern "C" fn sys_getenv(
702 out_words: *mut u32,
703 out_nwords: usize,
704 varname: *const u8,
705 varname_len: usize,
706) -> usize {
707 if cfg!(not(feature = "sys-getenv")) {
708 let mut allowed = false;
709 for allowed_varname in ALLOWED_ENV_VARNAMES {
710 let varname_buf = unsafe { slice::from_raw_parts(varname, varname_len) };
711 if *allowed_varname == varname_buf {
712 allowed = true;
713 break;
714 }
715 }
716 if !allowed {
717 const MSG_1: &[u8] = "sys_getenv not enabled for var".as_bytes();
718 unsafe { sys_log(MSG_1.as_ptr(), MSG_1.len()) };
719 unsafe { sys_log(varname, varname_len) };
720 const MSG_2: &[u8] = "sys_getenv is disabled; can be enabled with the sys-getenv feature flag on risc0-zkvm-platform".as_bytes();
721 unsafe { sys_panic(MSG_2.as_ptr(), MSG_2.len()) };
722 }
723 }
724 let Return(a0, _) = syscall_2(
725 nr::SYS_GETENV,
726 out_words,
727 out_nwords,
728 varname as u32,
729 varname_len as u32,
730 );
731 if a0 == u32::MAX {
732 usize::MAX
733 } else {
734 a0 as usize
735 }
736}
737
738#[cfg_attr(feature = "export-syscalls", no_mangle)]
743pub extern "C" fn sys_argc() -> usize {
744 if cfg!(not(feature = "sys-args")) {
745 const MSG: &[u8] = "sys_argc is disabled; can be enabled with the sys-args feature flag on risc0-zkvm-platform".as_bytes();
746 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
747 }
748 let Return(a0, _) = unsafe { syscall_0(nr::SYS_ARGC, null_mut(), 0) };
749 a0 as usize
750}
751
752#[cfg_attr(feature = "export-syscalls", no_mangle)]
770pub unsafe extern "C" fn sys_argv(
771 out_words: *mut u32,
772 out_nwords: usize,
773 arg_index: usize,
774) -> usize {
775 if cfg!(not(feature = "sys-args")) {
776 const MSG: &[u8] = "sys_argv is disabled; can be enabled with the sys-args feature flag on risc0-zkvm-platform".as_bytes();
777 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
778 }
779 let Return(a0, _) = syscall_1(nr::SYS_ARGV, out_words, out_nwords, arg_index as u32);
780 a0 as usize
781}
782
783#[cfg_attr(feature = "export-syscalls", no_mangle)]
784#[deprecated]
785pub extern "C" fn sys_alloc_words(nwords: usize) -> *mut u32 {
786 unsafe { sys_alloc_aligned(WORD_SIZE * nwords, WORD_SIZE) as *mut u32 }
787}
788
789#[cfg(all(feature = "export-syscalls", not(target_os = "zkvm")))]
793#[no_mangle]
794pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 {
795 unimplemented!("sys_alloc_aligned called outside of target_os = zkvm");
796}
797
798#[cfg(all(
802 feature = "export-syscalls",
803 feature = "heap-embedded-alloc",
804 target_os = "zkvm"
805))]
806#[no_mangle]
807pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 {
808 use core::alloc::GlobalAlloc;
809 crate::heap::embedded::HEAP.alloc(core::alloc::Layout::from_size_align(bytes, align).unwrap())
810}
811
812#[cfg(all(
816 feature = "export-syscalls",
817 not(feature = "heap-embedded-alloc"),
818 target_os = "zkvm"
819))]
820#[no_mangle]
821pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 {
822 crate::heap::bump::alloc_aligned(bytes, align)
823}
824
825#[cfg(feature = "export-syscalls")]
837#[no_mangle]
838pub unsafe extern "C" fn sys_verify_integrity(
839 claim_digest: *const [u32; DIGEST_WORDS],
840 control_root: *const [u32; DIGEST_WORDS],
841) {
842 let mut to_host = [0u32; DIGEST_WORDS * 2];
843 to_host[..DIGEST_WORDS].copy_from_slice(claim_digest.as_ref().unwrap_unchecked());
844 to_host[DIGEST_WORDS..].copy_from_slice(control_root.as_ref().unwrap_unchecked());
845
846 let Return(a0, _) = unsafe {
847 syscall_2(
849 nr::SYS_VERIFY_INTEGRITY,
850 null_mut(),
851 0,
852 to_host.as_ptr() as u32,
853 (DIGEST_BYTES * 2) as u32,
854 )
855 };
856
857 if a0 != 0 {
861 const MSG: &[u8] = "sys_verify_integrity returned error result".as_bytes();
862 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
863 }
864}
865
866#[cfg(feature = "export-syscalls")]
873#[no_mangle]
874pub unsafe extern "C" fn sys_verify_integrity2(
875 claim_digest: *const [u32; DIGEST_WORDS],
876 control_root: *const [u32; DIGEST_WORDS],
877) {
878 let mut to_host = [0u32; DIGEST_WORDS * 2];
879 to_host[..DIGEST_WORDS].copy_from_slice(claim_digest.as_ref().unwrap_unchecked());
880 to_host[DIGEST_WORDS..].copy_from_slice(control_root.as_ref().unwrap_unchecked());
881
882 let Return(a0, _) = unsafe {
883 syscall_2(
885 nr::SYS_VERIFY_INTEGRITY2,
886 null_mut(),
887 0,
888 to_host.as_ptr() as u32,
889 (DIGEST_BYTES * 2) as u32,
890 )
891 };
892
893 if a0 != 0 {
897 const MSG: &[u8] = "sys_verify_integrity2 returned error result".as_bytes();
898 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
899 }
900}
901#[cfg(not(feature = "export-syscalls"))]
903extern "C" {
904 pub fn sys_alloc_aligned(nwords: usize, align: usize) -> *mut u8;
905}
906
907#[cfg(feature = "export-syscalls")]
920#[no_mangle]
921pub extern "C" fn sys_fork() -> i32 {
922 let Return(a0, _) = unsafe { syscall_0(nr::SYS_FORK, null_mut(), 0) };
923 a0 as i32
924}
925
926#[cfg(feature = "export-syscalls")]
943#[no_mangle]
944pub unsafe extern "C" fn sys_pipe(pipefd: *mut u32) -> i32 {
945 let Return(a0, _) = syscall_0(nr::SYS_PIPE, pipefd, 2);
946 a0 as i32
947}
948
949#[cfg(feature = "export-syscalls")]
953#[no_mangle]
954pub extern "C" fn sys_exit(status: i32) -> ! {
955 let Return(a0, _) = unsafe { syscall_0(nr::SYS_EXIT, null_mut(), 0) };
956 #[allow(clippy::empty_loop)]
957 loop {
958 }
961}
962
963#[cfg_attr(feature = "export-syscalls", no_mangle)]
967pub unsafe extern "C" fn sys_keccak(
968 in_state: *const [u64; KECCACK_STATE_DWORDS],
969 out_state: *mut [u64; KECCACK_STATE_DWORDS],
970) -> i32 {
971 let Return(a0, _) = syscall_3(
972 nr::SYS_KECCAK,
973 out_state as *mut u32,
974 KECCACK_STATE_WORDS,
975 keccak_mode::KECCAK_PERMUTE,
976 in_state as u32,
977 0,
978 );
979 a0 as i32
980}
981
982#[cfg_attr(feature = "export-syscalls", no_mangle)]
996pub unsafe extern "C" fn sys_prove_keccak(
997 claim_digest: *const [u32; DIGEST_WORDS],
998 control_root: *const [u32; DIGEST_WORDS],
999) {
1000 let Return(a0, _) = unsafe {
1001 syscall_3(
1002 nr::SYS_KECCAK,
1003 null_mut(),
1004 0,
1005 keccak_mode::KECCAK_PROVE,
1006 claim_digest as u32,
1007 control_root as u32,
1008 )
1009 };
1010
1011 if a0 != 0 {
1015 const MSG: &[u8] = "sys_prove_keccak returned error result".as_bytes();
1016 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
1017 }
1018}
1019
1020#[repr(C)]
1021pub struct BigIntBlobHeader {
1022 pub nondet_program_size: u32,
1023 pub verify_program_size: u32,
1024 pub consts_size: u32,
1025 pub temp_size: u32,
1026}
1027
1028macro_rules! impl_sys_bigint2 {
1029 ($func_name:ident, $a1:ident
1030 $(, $a2: ident
1031 $(, $a3: ident
1032 $(, $a4: ident
1033 $(, $a5: ident
1034 $(, $a6: ident)?
1035 )?
1036 )?
1037 )?
1038 )?
1039 ) => {
1040 #[cfg_attr(feature = "export-syscalls", no_mangle)]
1046 pub unsafe extern "C" fn $func_name(blob_ptr: *const u8, a1: *const u32
1047 $(, $a2: *const u32
1048 $(, $a3: *const u32
1049 $(, $a4: *const u32
1050 $(, $a5: *const u32
1051 $(, $a6: *const u32)?
1052 )?
1053 )?
1054 )?
1055 )?
1056 ) {
1057 #[cfg(target_os = "zkvm")]
1058 {
1059 let header = blob_ptr as *const $crate::syscall::BigIntBlobHeader;
1060 let nondet_program_ptr = (header.add(1)) as *const u32;
1061 let verify_program_ptr = nondet_program_ptr.add((*header).nondet_program_size as usize);
1062 let consts_ptr = verify_program_ptr.add((*header).verify_program_size as usize);
1063 let temp_space = ((*header).temp_size as usize) << 2;
1064
1065 ::core::arch::asm!(
1066 "sub sp, sp, {temp_space}",
1067 "ecall",
1068 "add sp, sp, {temp_space}",
1069 temp_space = in(reg) temp_space,
1070 in("t0") ecall::BIGINT2,
1071 in("t1") nondet_program_ptr,
1072 in("t2") verify_program_ptr,
1073 in("t3") consts_ptr,
1074 in("a0") blob_ptr,
1075 in("a1") a1,
1076 $(in("a2") $a2,
1077 $(in("a3") $a3,
1078 $(in("a4") $a4,
1079 $(in("a5") $a5,
1080 $(in("a6") $a6)?
1081 )?
1082 )?
1083 )?
1084 )?
1085 );
1086 }
1087
1088 #[cfg(not(target_os = "zkvm"))]
1089 unimplemented!()
1090 }
1091 }
1092}
1093
1094impl_sys_bigint2!(sys_bigint2_1, a1);
1095impl_sys_bigint2!(sys_bigint2_2, a1, a2);
1096impl_sys_bigint2!(sys_bigint2_3, a1, a2, a3);
1097impl_sys_bigint2!(sys_bigint2_4, a1, a2, a3, a4);
1098impl_sys_bigint2!(sys_bigint2_5, a1, a2, a3, a4, a5);
1099impl_sys_bigint2!(sys_bigint2_6, a1, a2, a3, a4, a5, a6);