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}
30
31pub mod halt {
32 pub const TERMINATE: u32 = 0;
33 pub const PAUSE: u32 = 1;
34 pub const SPLIT: u32 = 2;
35}
36
37pub mod reg_abi {
38 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; }
73
74pub mod keccak_mode {
75 pub const KECCAK_PERMUTE: u32 = 0;
76 pub const KECCAK_PROVE: u32 = 1;
77}
78
79pub const DIGEST_WORDS: usize = 8;
80pub const DIGEST_BYTES: usize = WORD_SIZE * DIGEST_WORDS;
81
82pub const KECCACK_STATE_BYTES: usize = 200;
83pub const KECCACK_STATE_WORDS: usize = 200 / WORD_SIZE;
84pub const KECCACK_STATE_DWORDS: usize = 200 / 8;
85
86pub const IO_CHUNK_WORDS: usize = 4;
88
89pub const MAX_BUF_BYTES: usize = 4 * 1024;
92pub const MAX_BUF_WORDS: usize = MAX_BUF_BYTES / WORD_SIZE;
93pub const MAX_SHA_COMPRESS_BLOCKS: usize = 1000;
94
95pub mod bigint {
96 pub const OP_MULTIPLY: u32 = 0;
97
98 pub const WIDTH_BITS: usize = 256;
100
101 pub const WIDTH_BYTES: usize = WIDTH_BITS / 8;
103
104 pub const WIDTH_WORDS: usize = WIDTH_BYTES / crate::WORD_SIZE;
106}
107
108#[derive(Clone, Copy, Debug)]
110#[repr(transparent)]
111pub struct SyscallName(*const u8);
112
113#[macro_export]
121macro_rules! declare_syscall {
122 (
123 $(#[$meta:meta])*
124 $vis:vis $name:ident
125 ) => {
126 $(#[$meta])*
128 $vis const $name: $crate::syscall::SyscallName = match ::core::ffi::CStr::from_bytes_until_nul(
129 concat!(module_path!(), "::", stringify!($name), "\0").as_bytes(),
130 ) {
131 Ok(c_str) => match $crate::syscall::SyscallName::from_c_str(c_str) {
132 Ok(name) => name,
133 Err(_) => unreachable!(),
134 },
135 Err(_) => unreachable!(),
136 };
137 };
138}
139
140pub mod nr {
141 declare_syscall!(pub SYS_ARGC);
142 declare_syscall!(pub SYS_ARGV);
143 declare_syscall!(pub SYS_CYCLE_COUNT);
144 declare_syscall!(pub SYS_EXIT);
145 declare_syscall!(pub SYS_FORK);
146 declare_syscall!(pub SYS_GETENV);
147 declare_syscall!(pub SYS_KECCAK);
148 declare_syscall!(pub SYS_LOG);
149 declare_syscall!(pub SYS_PANIC);
150 declare_syscall!(pub SYS_PIPE);
151 declare_syscall!(pub SYS_PROVE_KECCAK);
152 declare_syscall!(pub SYS_PROVE_ZKR);
153 declare_syscall!(pub SYS_RANDOM);
154 declare_syscall!(pub SYS_READ);
155 declare_syscall!(pub SYS_VERIFY_INTEGRITY);
156 declare_syscall!(pub SYS_VERIFY_INTEGRITY2);
157 declare_syscall!(pub SYS_WRITE);
158}
159
160impl SyscallName {
161 #[inline]
163 pub const fn from_c_str(c_str: &'static CStr) -> Result<Self, Utf8Error> {
164 match c_str.to_str() {
165 Ok(_) => Ok(unsafe { Self::from_bytes_with_nul(c_str.as_ptr().cast()) }),
166 Err(error) => Err(error),
167 }
168 }
169
170 pub const unsafe fn from_bytes_with_nul(ptr: *const u8) -> Self {
176 Self(ptr)
177 }
178
179 pub fn as_ptr(&self) -> *const u8 {
180 self.0
181 }
182
183 pub fn as_str(&self) -> &str {
184 core::str::from_utf8(unsafe { core::ffi::CStr::from_ptr(self.as_ptr().cast()).to_bytes() })
185 .unwrap()
186 }
187}
188
189impl AsRef<str> for SyscallName {
190 fn as_ref(&self) -> &str {
191 self.as_str()
192 }
193}
194
195#[repr(C)]
197pub struct Return(pub u32, pub u32);
198
199macro_rules! impl_syscall {
200 ($func_name:ident
201 $(, $a0:ident
204 $(, $a1:ident
205 $(, $a2: ident
206 $(, $a3: ident
207 $(, $a4: ident
208 )?
209 )?
210 )?
211 )?
212 )?) => {
213 #[cfg_attr(feature = "export-syscalls", no_mangle)]
219 pub unsafe extern "C" fn $func_name(syscall: SyscallName,
220 from_host: *mut u32,
221 from_host_words: usize
222 $(,$a0: u32
223 $(,$a1: u32
224 $(,$a2: u32
225 $(,$a3: u32
226 $(,$a4: u32
227 )?
228 )?
229 )?
230 )?
231 )?
232 ) -> Return {
233 #[cfg(target_os = "zkvm")] {
234 let a0: u32;
235 let a1: u32;
236 ::core::arch::asm!(
237 "ecall",
238 in("t0") $crate::syscall::ecall::SOFTWARE,
239 inlateout("a0") from_host => a0,
240 inlateout("a1") from_host_words => a1,
241 in("a2") syscall.as_ptr()
242 $(,in("a3") $a0
243 $(,in("a4") $a1
244 $(,in("a5") $a2
245 $(,in("a6") $a3
246 $(,in("a7") $a4
247 )?
248 )?
249 )?
250 )?
251 )?);
252 Return(a0, a1)
253 }
254 #[cfg(not(target_os = "zkvm"))]
255 unimplemented!()
256 }
257 }
258}
259
260impl_syscall!(syscall_0);
261impl_syscall!(syscall_1, a3);
262impl_syscall!(syscall_2, a3, a4);
263impl_syscall!(syscall_3, a3, a4, a5);
264impl_syscall!(syscall_4, a3, a4, a5, a6);
265impl_syscall!(syscall_5, a3, a4, a5, a6, a7);
266
267fn ecall_1(t0: u32, a0: u32, a1: u32) {
268 #[cfg(target_os = "zkvm")]
269 unsafe {
270 asm!(
271 "ecall",
272 in("t0") t0,
273 in("a0") a0,
274 in("a1") a1,
275 )
276 };
277 #[cfg(not(target_os = "zkvm"))]
278 {
279 core::hint::black_box((t0, a0, a1));
280 unimplemented!()
281 }
282}
283
284fn ecall_4(t0: u32, a0: u32, a1: u32, a2: u32, a3: u32, a4: u32) {
285 #[cfg(target_os = "zkvm")]
286 unsafe {
287 asm!(
288 "ecall",
289 in("t0") t0,
290 in("a0") a0,
291 in("a1") a1,
292 in("a2") a2,
293 in("a3") a3,
294 in("a4") a4,
295 )
296 };
297 #[cfg(not(target_os = "zkvm"))]
298 {
299 core::hint::black_box((t0, a0, a1, a2, a3, a4));
300 unimplemented!()
301 }
302}
303
304#[inline(never)]
312#[cfg_attr(feature = "export-syscalls", no_mangle)]
313pub extern "C" fn sys_halt(user_exit: u8, out_state: *const [u32; DIGEST_WORDS]) -> ! {
314 ecall_1(
315 ecall::HALT,
316 halt::TERMINATE | ((user_exit as u32) << 8),
317 out_state as u32,
318 );
319 unreachable!();
320}
321
322#[inline(never)]
330#[cfg_attr(feature = "export-syscalls", no_mangle)]
331pub unsafe extern "C" fn sys_pause(user_exit: u8, out_state: *const [u32; DIGEST_WORDS]) {
332 ecall_1(
333 ecall::HALT,
334 halt::PAUSE | ((user_exit as u32) << 8),
335 out_state as u32,
336 );
337}
338
339#[cfg_attr(feature = "export-syscalls", no_mangle)]
340pub extern "C" fn sys_input(index: u32) -> u32 {
341 let t0 = ecall::INPUT;
342 let index = index & 0x07;
343 #[cfg(target_os = "zkvm")]
344 unsafe {
345 let a0: u32;
346 asm!(
347 "ecall",
348 in("t0") t0,
349 inlateout("a0") index => a0,
350 );
351 a0
352 }
353 #[cfg(not(target_os = "zkvm"))]
354 {
355 core::hint::black_box((t0, index));
356 unimplemented!()
357 }
358}
359
360#[inline(always)]
365#[cfg_attr(feature = "export-syscalls", no_mangle)]
366pub unsafe extern "C" fn sys_sha_compress(
367 out_state: *mut [u32; DIGEST_WORDS],
368 in_state: *const [u32; DIGEST_WORDS],
369 block1_ptr: *const [u32; DIGEST_WORDS],
370 block2_ptr: *const [u32; DIGEST_WORDS],
371) {
372 ecall_4(
373 ecall::SHA,
374 out_state as u32,
375 in_state as u32,
376 block1_ptr as u32,
377 block2_ptr as u32,
378 1,
379 );
380}
381
382#[inline(always)]
386#[cfg_attr(feature = "export-syscalls", no_mangle)]
387pub unsafe extern "C" fn sys_sha_buffer(
388 out_state: *mut [u32; DIGEST_WORDS],
389 in_state: *const [u32; DIGEST_WORDS],
390 buf: *const u8,
391 count: u32,
392) {
393 let mut ptr = buf;
394 let mut count_remain = count;
395 let mut in_state = in_state;
396 while count_remain > 0 {
397 let count = min(count_remain, MAX_SHA_COMPRESS_BLOCKS as u32);
398 ecall_4(
399 ecall::SHA,
400 out_state as u32,
401 in_state as u32,
402 ptr as u32,
403 ptr.add(DIGEST_BYTES) as u32,
404 count,
405 );
406 count_remain -= count;
407 ptr = ptr.add(2 * DIGEST_BYTES * count as usize);
408 in_state = out_state;
409 }
410}
411
412#[inline(always)]
416#[cfg_attr(feature = "export-syscalls", no_mangle)]
417pub unsafe extern "C" fn sys_bigint(
418 result: *mut [u32; bigint::WIDTH_WORDS],
419 op: u32,
420 x: *const [u32; bigint::WIDTH_WORDS],
421 y: *const [u32; bigint::WIDTH_WORDS],
422 modulus: *const [u32; bigint::WIDTH_WORDS],
423) {
424 ecall_4(
425 ecall::BIGINT,
426 result as u32,
427 op,
428 x as u32,
429 y as u32,
430 modulus as u32,
431 );
432}
433
434#[cfg_attr(feature = "export-syscalls", no_mangle)]
438pub unsafe extern "C" fn sys_rand(recv_buf: *mut u32, words: usize) {
439 syscall_0(nr::SYS_RANDOM, recv_buf, words);
440}
441
442#[cfg_attr(feature = "export-syscalls", no_mangle)]
446pub unsafe extern "C" fn sys_panic(msg_ptr: *const u8, len: usize) -> ! {
447 syscall_2(nr::SYS_PANIC, null_mut(), 0, msg_ptr as u32, len as u32);
448
449 #[cfg(target_os = "zkvm")]
451 asm!("sw x0, 1(x0)");
452 unreachable!()
453}
454
455#[cfg_attr(feature = "export-syscalls", no_mangle)]
459pub unsafe extern "C" fn sys_log(msg_ptr: *const u8, len: usize) {
460 syscall_2(nr::SYS_LOG, null_mut(), 0, msg_ptr as u32, len as u32);
461}
462
463#[cfg_attr(feature = "export-syscalls", no_mangle)]
464pub extern "C" fn sys_cycle_count() -> u64 {
465 let Return(hi, lo) = unsafe { syscall_0(nr::SYS_CYCLE_COUNT, null_mut(), 0) };
466 ((hi as u64) << 32) + lo as u64
467}
468
469#[cfg_attr(feature = "export-syscalls", no_mangle)]
482pub unsafe extern "C" fn sys_read(fd: u32, recv_ptr: *mut u8, nread: usize) -> usize {
483 unsafe fn fill_from_word(mut ptr: *mut u8, mut word: u32, nfill: usize) -> *mut u8 {
498 debug_assert!(nfill < 4, "nfill={nfill}");
499 for _ in 0..nfill {
500 *ptr = (word & 0xFF) as u8;
501 word >>= 8;
502 ptr = ptr.add(1);
503 }
504 ptr
505 }
506
507 let ptr_offset = (recv_ptr as usize) & (WORD_SIZE - 1);
510 let (main_ptr, main_requested, nread_first) = if ptr_offset == 0 {
511 (recv_ptr, nread, 0)
512 } else {
513 let unaligned_at_start = min(nread, WORD_SIZE - ptr_offset);
514 let Return(nread_first, firstword) =
516 syscall_2(nr::SYS_READ, null_mut(), 0, fd, unaligned_at_start as u32);
517 debug_assert_eq!(nread_first as usize, unaligned_at_start);
518
519 let main_ptr = fill_from_word(recv_ptr, firstword, unaligned_at_start);
521 if nread == unaligned_at_start {
522 return nread;
524 }
525 (main_ptr, nread - unaligned_at_start, nread_first as usize)
526 };
527
528 let main_words = main_requested / WORD_SIZE;
530 let (nread_main, lastword) =
531 sys_read_internal(fd, main_ptr as *mut u32, main_words, main_requested);
532 debug_assert!(nread_main <= main_requested);
533 let read_words = nread_main / WORD_SIZE;
534
535 let unaligned_at_end = main_requested % WORD_SIZE;
537
538 fill_from_word(
540 main_ptr.add(main_words * WORD_SIZE),
541 lastword,
542 unaligned_at_end,
543 );
544
545 nread_first + nread_main
546}
547
548#[cfg_attr(feature = "export-syscalls", no_mangle)]
567pub unsafe extern "C" fn sys_read_words(fd: u32, recv_ptr: *mut u32, nwords: usize) -> usize {
568 sys_read_internal(fd, recv_ptr, nwords, nwords * WORD_SIZE).0
569}
570
571fn sys_read_internal(fd: u32, recv_ptr: *mut u32, nwords: usize, nbytes: usize) -> (usize, u32) {
572 let mut nwords_remain = nwords;
573 let mut nbytes_remain = nbytes;
574 let mut nread_total_bytes = 0;
575 let mut recv_ptr = recv_ptr;
576 let mut final_word = 0;
577 while nbytes_remain > 0 {
578 debug_assert!(
579 final_word == 0,
580 "host returned non-zero final word on a fully aligned read"
581 );
582 let chunk_len = min(nbytes_remain, MAX_BUF_BYTES) as u32;
583 let Return(nread_bytes, last_word) = unsafe {
584 syscall_2(
585 nr::SYS_READ,
586 recv_ptr,
587 min(nwords_remain, MAX_BUF_WORDS),
588 fd,
589 chunk_len,
590 )
591 };
592 let nread_bytes = nread_bytes as usize;
593 let nread_words = nread_bytes / WORD_SIZE;
594 recv_ptr = unsafe { recv_ptr.add(nread_words) };
595 final_word = last_word;
596 nwords_remain -= nread_words;
597 nread_total_bytes += nread_bytes;
598 nbytes_remain -= nread_bytes;
599 if nread_bytes < chunk_len as usize {
600 break;
602 }
603 }
604 (nread_total_bytes, final_word)
605}
606
607#[cfg_attr(feature = "export-syscalls", no_mangle)]
611pub unsafe extern "C" fn sys_write(fd: u32, write_ptr: *const u8, nbytes: usize) {
612 let mut nbytes_remain = nbytes;
613 let mut write_ptr = write_ptr;
614 while nbytes_remain > 0 {
615 let nbytes = min(nbytes_remain, MAX_BUF_BYTES);
616 syscall_3(
617 nr::SYS_WRITE,
618 null_mut(),
619 0,
620 fd,
621 write_ptr as u32,
622 nbytes as u32,
623 );
624 write_ptr = write_ptr.add(nbytes);
625 nbytes_remain -= nbytes;
626 }
627}
628
629const ALLOWED_ENV_VARNAMES: &[&[u8]] = &[
633 b"RUST_BACKTRACE",
634 b"RUST_LIB_BACKTRACE",
635 b"RISC0_KECCAK_PO2",
636];
637
638#[cfg_attr(feature = "export-syscalls", no_mangle)]
656pub unsafe extern "C" fn sys_getenv(
657 out_words: *mut u32,
658 out_nwords: usize,
659 varname: *const u8,
660 varname_len: usize,
661) -> usize {
662 if cfg!(not(feature = "sys-getenv")) {
663 let mut allowed = false;
664 for allowed_varname in ALLOWED_ENV_VARNAMES {
665 let varname_buf = unsafe { slice::from_raw_parts(varname, varname_len) };
666 if *allowed_varname == varname_buf {
667 allowed = true;
668 break;
669 }
670 }
671 if !allowed {
672 const MSG_1: &[u8] = "sys_getenv not enabled for var".as_bytes();
673 unsafe { sys_log(MSG_1.as_ptr(), MSG_1.len()) };
674 unsafe { sys_log(varname, varname_len) };
675 const MSG_2: &[u8] = "sys_getenv is disabled; can be enabled with the sys-getenv feature flag on risc0-zkvm-platform".as_bytes();
676 unsafe { sys_panic(MSG_2.as_ptr(), MSG_2.len()) };
677 }
678 }
679 let Return(a0, _) = syscall_2(
680 nr::SYS_GETENV,
681 out_words,
682 out_nwords,
683 varname as u32,
684 varname_len as u32,
685 );
686 if a0 == u32::MAX {
687 usize::MAX
688 } else {
689 a0 as usize
690 }
691}
692
693#[cfg_attr(feature = "export-syscalls", no_mangle)]
698pub extern "C" fn sys_argc() -> usize {
699 if cfg!(not(feature = "sys-args")) {
700 const MSG: &[u8] = "sys_argc is disabled; can be enabled with the sys-args feature flag on risc0-zkvm-platform".as_bytes();
701 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
702 }
703 let Return(a0, _) = unsafe { syscall_0(nr::SYS_ARGC, null_mut(), 0) };
704 a0 as usize
705}
706
707#[cfg_attr(feature = "export-syscalls", no_mangle)]
725pub unsafe extern "C" fn sys_argv(
726 out_words: *mut u32,
727 out_nwords: usize,
728 arg_index: usize,
729) -> usize {
730 if cfg!(not(feature = "sys-args")) {
731 const MSG: &[u8] = "sys_argv is disabled; can be enabled with the sys-args feature flag on risc0-zkvm-platform".as_bytes();
732 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
733 }
734 let Return(a0, _) = syscall_1(nr::SYS_ARGV, out_words, out_nwords, arg_index as u32);
735 a0 as usize
736}
737
738#[cfg_attr(feature = "export-syscalls", no_mangle)]
739#[deprecated]
740pub extern "C" fn sys_alloc_words(nwords: usize) -> *mut u32 {
741 unsafe { sys_alloc_aligned(WORD_SIZE * nwords, WORD_SIZE) as *mut u32 }
742}
743
744#[cfg(all(feature = "export-syscalls", not(target_os = "zkvm")))]
748#[no_mangle]
749pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 {
750 unimplemented!("sys_alloc_aligned called outside of target_os = zkvm");
751}
752
753#[cfg(all(
757 feature = "export-syscalls",
758 feature = "heap-embedded-alloc",
759 target_os = "zkvm"
760))]
761#[no_mangle]
762pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 {
763 use core::alloc::GlobalAlloc;
764 crate::heap::embedded::HEAP.alloc(core::alloc::Layout::from_size_align(bytes, align).unwrap())
765}
766
767#[cfg(all(
771 feature = "export-syscalls",
772 not(feature = "heap-embedded-alloc"),
773 target_os = "zkvm"
774))]
775#[no_mangle]
776pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 {
777 crate::heap::bump::alloc_aligned(bytes, align)
778}
779
780#[cfg(feature = "export-syscalls")]
792#[no_mangle]
793pub unsafe extern "C" fn sys_verify_integrity(
794 claim_digest: *const [u32; DIGEST_WORDS],
795 control_root: *const [u32; DIGEST_WORDS],
796) {
797 let mut to_host = [0u32; DIGEST_WORDS * 2];
798 to_host[..DIGEST_WORDS].copy_from_slice(claim_digest.as_ref().unwrap_unchecked());
799 to_host[DIGEST_WORDS..].copy_from_slice(control_root.as_ref().unwrap_unchecked());
800
801 let Return(a0, _) = unsafe {
802 syscall_2(
804 nr::SYS_VERIFY_INTEGRITY,
805 null_mut(),
806 0,
807 to_host.as_ptr() as u32,
808 (DIGEST_BYTES * 2) as u32,
809 )
810 };
811
812 if a0 != 0 {
816 const MSG: &[u8] = "sys_verify_integrity returned error result".as_bytes();
817 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
818 }
819}
820
821#[cfg(feature = "export-syscalls")]
828#[no_mangle]
829pub unsafe extern "C" fn sys_verify_integrity2(
830 claim_digest: *const [u32; DIGEST_WORDS],
831 control_root: *const [u32; DIGEST_WORDS],
832) {
833 let mut to_host = [0u32; DIGEST_WORDS * 2];
834 to_host[..DIGEST_WORDS].copy_from_slice(claim_digest.as_ref().unwrap_unchecked());
835 to_host[DIGEST_WORDS..].copy_from_slice(control_root.as_ref().unwrap_unchecked());
836
837 let Return(a0, _) = unsafe {
838 syscall_2(
840 nr::SYS_VERIFY_INTEGRITY2,
841 null_mut(),
842 0,
843 to_host.as_ptr() as u32,
844 (DIGEST_BYTES * 2) as u32,
845 )
846 };
847
848 if a0 != 0 {
852 const MSG: &[u8] = "sys_verify_integrity2 returned error result".as_bytes();
853 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
854 }
855}
856#[cfg(not(feature = "export-syscalls"))]
858extern "C" {
859 pub fn sys_alloc_aligned(nwords: usize, align: usize) -> *mut u8;
860}
861
862#[cfg(feature = "export-syscalls")]
875#[no_mangle]
876pub extern "C" fn sys_fork() -> i32 {
877 let Return(a0, _) = unsafe { syscall_0(nr::SYS_FORK, null_mut(), 0) };
878 a0 as i32
879}
880
881#[cfg(feature = "export-syscalls")]
898#[no_mangle]
899pub unsafe extern "C" fn sys_pipe(pipefd: *mut u32) -> i32 {
900 let Return(a0, _) = syscall_0(nr::SYS_PIPE, pipefd, 2);
901 a0 as i32
902}
903
904#[cfg(feature = "export-syscalls")]
908#[no_mangle]
909pub extern "C" fn sys_exit(status: i32) -> ! {
910 let Return(a0, _) = unsafe { syscall_0(nr::SYS_EXIT, null_mut(), 0) };
911 #[allow(clippy::empty_loop)]
912 loop {
913 }
916}
917
918#[cfg_attr(all(feature = "export-syscalls", feature = "unstable"), no_mangle)]
933#[stability::unstable]
934pub unsafe extern "C" fn sys_prove_zkr(
935 claim_digest: *const [u32; DIGEST_WORDS],
936 control_id: *const [u32; DIGEST_WORDS],
937 control_root: *const [u32; DIGEST_WORDS],
938 input: *const u32,
939 input_len: usize,
940) {
941 let Return(a0, _) = unsafe {
942 syscall_5(
943 nr::SYS_PROVE_ZKR,
944 null_mut(),
945 0,
946 claim_digest as u32,
947 control_id as u32,
948 control_root as u32,
949 input as u32,
950 input_len as u32,
951 )
952 };
953
954 if a0 != 0 {
958 const MSG: &[u8] = "sys_prove_zkr returned error result".as_bytes();
959 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
960 }
961}
962
963#[cfg_attr(all(feature = "export-syscalls", feature = "unstable"), no_mangle)]
967#[stability::unstable]
968pub unsafe extern "C" fn sys_keccak(
969 in_state: *const [u64; KECCACK_STATE_DWORDS],
970 out_state: *mut [u64; KECCACK_STATE_DWORDS],
971) -> i32 {
972 let Return(a0, _) = syscall_3(
973 nr::SYS_KECCAK,
974 out_state as *mut u32,
975 KECCACK_STATE_WORDS,
976 keccak_mode::KECCAK_PERMUTE,
977 in_state as u32,
978 0,
979 );
980 a0 as i32
981}
982
983#[cfg_attr(all(feature = "export-syscalls", feature = "unstable"), no_mangle)]
997#[stability::unstable]
998pub unsafe extern "C" fn sys_prove_keccak(
999 claim_digest: *const [u32; DIGEST_WORDS],
1000 control_root: *const [u32; DIGEST_WORDS],
1001) {
1002 let Return(a0, _) = unsafe {
1003 syscall_3(
1004 nr::SYS_KECCAK,
1005 null_mut(),
1006 0,
1007 keccak_mode::KECCAK_PROVE,
1008 claim_digest as u32,
1009 control_root as u32,
1010 )
1011 };
1012
1013 if a0 != 0 {
1017 const MSG: &[u8] = "sys_prove_keccak returned error result".as_bytes();
1018 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
1019 }
1020}
1021
1022#[repr(C)]
1023pub struct BigIntBlobHeader {
1024 pub nondet_program_size: u32,
1025 pub verify_program_size: u32,
1026 pub consts_size: u32,
1027 pub temp_size: u32,
1028}
1029
1030macro_rules! impl_sys_bigint2 {
1031 ($func_name:ident, $a1:ident
1032 $(, $a2: ident
1033 $(, $a3: ident
1034 $(, $a4: ident
1035 $(, $a5: ident
1036 $(, $a6: ident)?
1037 )?
1038 )?
1039 )?
1040 )?
1041 ) => {
1042 #[cfg_attr(all(feature = "export-syscalls", feature = "unstable"), no_mangle)]
1048 #[stability::unstable]
1049 pub unsafe extern "C" fn $func_name(blob_ptr: *const u8, a1: *const u32
1050 $(, $a2: *const u32
1051 $(, $a3: *const u32
1052 $(, $a4: *const u32
1053 $(, $a5: *const u32
1054 $(, $a6: *const u32)?
1055 )?
1056 )?
1057 )?
1058 )?
1059 ) {
1060 #[cfg(target_os = "zkvm")]
1061 {
1062 let header = blob_ptr as *const $crate::syscall::BigIntBlobHeader;
1063 let nondet_program_ptr = (header.add(1)) as *const u32;
1064 let verify_program_ptr = nondet_program_ptr.add((*header).nondet_program_size as usize);
1065 let consts_ptr = verify_program_ptr.add((*header).verify_program_size as usize);
1066 let temp_space = ((*header).temp_size as usize) << 2;
1067
1068 ::core::arch::asm!(
1069 "sub sp, sp, {temp_space}",
1070 "ecall",
1071 "add sp, sp, {temp_space}",
1072 temp_space = in(reg) temp_space,
1073 in("t0") ecall::BIGINT2,
1074 in("t1") nondet_program_ptr,
1075 in("t2") verify_program_ptr,
1076 in("t3") consts_ptr,
1077 in("a0") blob_ptr,
1078 in("a1") a1,
1079 $(in("a2") $a2,
1080 $(in("a3") $a3,
1081 $(in("a4") $a4,
1082 $(in("a5") $a5,
1083 $(in("a6") $a6)?
1084 )?
1085 )?
1086 )?
1087 )?
1088 );
1089 }
1090
1091 #[cfg(not(target_os = "zkvm"))]
1092 unimplemented!()
1093 }
1094 }
1095}
1096
1097impl_sys_bigint2!(sys_bigint2_1, a1);
1098impl_sys_bigint2!(sys_bigint2_2, a1, a2);
1099impl_sys_bigint2!(sys_bigint2_3, a1, a2, a3);
1100impl_sys_bigint2!(sys_bigint2_4, a1, a2, a3, a4);
1101impl_sys_bigint2!(sys_bigint2_5, a1, a2, a3, a4, a5);
1102impl_sys_bigint2!(sys_bigint2_6, a1, a2, a3, a4, a5, a6);