1#[cfg(target_os = "zkvm")]
16use core::arch::asm;
17use core::{cmp::min, ffi::CStr, ptr::null_mut, slice, str::Utf8Error};
18
19use num_enum::{FromPrimitive, IntoPrimitive};
20use paste::paste;
21
22use crate::WORD_SIZE;
23
24pub mod ecall {
25 pub const HALT: u32 = 0;
26 pub const INPUT: u32 = 1;
27 pub const SOFTWARE: u32 = 2;
28 pub const SHA: u32 = 3;
29 pub const BIGINT: u32 = 4;
30 pub const USER: u32 = 5;
31 pub const BIGINT2: u32 = 6;
32 pub const POSEIDON2: u32 = 7;
33}
34
35pub mod halt {
36 pub const TERMINATE: u32 = 0;
37 pub const PAUSE: u32 = 1;
38 pub const SPLIT: u32 = 2;
39}
40
41pub mod reg_abi {
42 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; }
77
78pub mod keccak_mode {
79 pub const KECCAK_PERMUTE: u32 = 0;
80 pub const KECCAK_PROVE: u32 = 1;
81}
82
83pub const DIGEST_WORDS: usize = 8;
84pub const DIGEST_BYTES: usize = WORD_SIZE * DIGEST_WORDS;
85
86pub const KECCACK_STATE_BYTES: usize = 200;
87pub const KECCACK_STATE_WORDS: usize = 200 / WORD_SIZE;
88pub const KECCACK_STATE_DWORDS: usize = 200 / 8;
89
90pub const IO_CHUNK_WORDS: usize = 4;
92
93pub const MAX_BUF_BYTES: usize = 4 * 1024;
96pub const MAX_BUF_WORDS: usize = MAX_BUF_BYTES / WORD_SIZE;
97pub const MAX_SHA_COMPRESS_BLOCKS: usize = 1000;
98
99pub mod bigint {
100 pub const OP_MULTIPLY: u32 = 0;
101
102 pub const WIDTH_BITS: usize = 256;
104
105 pub const WIDTH_BYTES: usize = WIDTH_BITS / 8;
107
108 pub const WIDTH_WORDS: usize = WIDTH_BYTES / crate::WORD_SIZE;
110}
111
112#[derive(Clone, Copy, Debug)]
114#[repr(transparent)]
115pub struct SyscallName(*const u8);
116
117#[macro_export]
125macro_rules! declare_syscall {
126 (
127 $(#[$meta:meta])*
128 $vis:vis $name:ident
129 ) => {
130 $(#[$meta])*
132 $vis const $name: $crate::syscall::SyscallName = match ::core::ffi::CStr::from_bytes_until_nul(
133 concat!(module_path!(), "::", stringify!($name), "\0").as_bytes(),
134 ) {
135 Ok(c_str) => match $crate::syscall::SyscallName::from_c_str(c_str) {
136 Ok(name) => name,
137 Err(_) => unreachable!(),
138 },
139 Err(_) => unreachable!(),
140 };
141 };
142}
143
144pub mod nr {
145 declare_syscall!(pub SYS_ARGC);
146 declare_syscall!(pub SYS_ARGV);
147 declare_syscall!(pub SYS_CYCLE_COUNT);
148 declare_syscall!(pub SYS_EXIT);
149 declare_syscall!(pub SYS_FORK);
150 declare_syscall!(pub SYS_GETENV);
151 declare_syscall!(pub SYS_KECCAK);
152 declare_syscall!(pub SYS_LOG);
153 declare_syscall!(pub SYS_PANIC);
154 declare_syscall!(pub SYS_PIPE);
155 #[deprecated]
156 pub const SYS_PROVE_KECCAK: crate::syscall::SyscallName = unsafe {
157 crate::syscall::SyscallName::from_bytes_with_nul(
158 c"risc0-zkvm-platform::syscall::SYS_PROVE_KECCAK".as_ptr() as *const u8,
159 )
160 };
161 declare_syscall!(pub SYS_PROVE_ZKR);
162 declare_syscall!(pub SYS_RANDOM);
163 declare_syscall!(pub SYS_READ);
164 declare_syscall!(pub SYS_VERIFY_INTEGRITY);
165 declare_syscall!(pub SYS_VERIFY_INTEGRITY2);
166 declare_syscall!(pub SYS_WRITE);
167}
168
169#[repr(usize)]
170#[derive(Copy, Clone, Debug, Eq, PartialEq, IntoPrimitive, FromPrimitive)]
171pub enum Syscall {
172 #[num_enum(catch_all)]
173 Unknown(usize) = 0,
174 Argc = 1,
175 Argv = 2,
176 CycleCount = 3,
177 Exit = 4,
178 Fork = 5,
179 Getenv = 6,
180 Keccak = 7,
181 Log = 8,
182 Panic = 9,
183 Pipe = 10,
184 Random = 11,
185 Read = 12,
186 User = 13,
187 VerifyIntegrity = 14,
188 VerifyIntegrity2 = 15,
189 Write = 16,
190 ProveZkr = 17,
191}
192
193impl SyscallName {
194 #[inline]
196 pub const fn from_c_str(c_str: &'static CStr) -> Result<Self, Utf8Error> {
197 match c_str.to_str() {
198 Ok(_) => Ok(unsafe { Self::from_bytes_with_nul(c_str.as_ptr().cast()) }),
199 Err(error) => Err(error),
200 }
201 }
202
203 pub const unsafe fn from_bytes_with_nul(ptr: *const u8) -> Self {
209 Self(ptr)
210 }
211
212 pub fn as_ptr(&self) -> *const u8 {
213 self.0
214 }
215
216 pub fn as_str(&self) -> &str {
217 core::str::from_utf8(unsafe { core::ffi::CStr::from_ptr(self.as_ptr().cast()).to_bytes() })
218 .unwrap()
219 }
220}
221
222impl AsRef<str> for SyscallName {
223 fn as_ref(&self) -> &str {
224 self.as_str()
225 }
226}
227
228#[repr(C)]
230pub struct Return(pub u32, pub u32);
231
232macro_rules! impl_syscall {
233 ($func_name:ident
234 $(, $a0:ident $(, $a1:ident $(, $a2: ident $(, $a3: ident $(, $a4: ident )? )? )? )? )?
237 ) => {
238 #[cfg_attr(feature = "export-syscalls", unsafe(no_mangle))]
244 #[deprecated]
245 pub unsafe extern "C" fn $func_name(
246 syscall_name: SyscallName,
247 from_host: *mut u32,
248 from_host_words: usize
249 $(,$a0: u32 $(,$a1: u32 $(,$a2: u32 $(,$a3: u32 $(,$a4: u32)? )? )? )? )?
250 ) -> Return {
251 unimplemented!();
252 }
253
254
255 paste! {
256 #[cfg_attr(feature = "export-syscalls", unsafe(no_mangle))]
262 pub unsafe extern "C" fn [<$func_name _nr>] (
263 syscall: usize,
264 syscall_name: SyscallName,
265 from_host: *mut u32,
266 from_host_words: usize
267 $(,$a0: u32 $(,$a1: u32 $(,$a2: u32 $(,$a3: u32 $(,$a4: u32)? )? )? )? )?
268 ) -> Return {
269 #[cfg(target_os = "zkvm")] {
270 let a0: u32;
271 let a1: u32;
272 unsafe {
273 ::core::arch::asm!(
274 "ecall",
275 in("t0") $crate::syscall::ecall::SOFTWARE,
276 in("t6") syscall,
277 inlateout("a0") from_host => a0,
278 inlateout("a1") from_host_words => a1,
279 in("a2") syscall_name.as_ptr()
280 $(,in("a3") $a0 $(,in("a4") $a1 $(,in("a5") $a2 $(,in("a6") $a3 $(,in("a7") $a4 )? )? )? )? )?
281 );
282 }
283 Return(a0, a1)
284 }
285 #[cfg(not(target_os = "zkvm"))]
286 unimplemented!()
287 }
288 }
289 }
290}
291
292impl_syscall!(syscall_0);
293impl_syscall!(syscall_1, a3);
294impl_syscall!(syscall_2, a3, a4);
295impl_syscall!(syscall_3, a3, a4, a5);
296impl_syscall!(syscall_4, a3, a4, a5, a6);
297impl_syscall!(syscall_5, a3, a4, a5, a6, a7);
298
299fn ecall_1(t0: u32, a0: u32, a1: u32) {
300 #[cfg(target_os = "zkvm")]
301 unsafe {
302 asm!(
303 "ecall",
304 in("t0") t0,
305 in("a0") a0,
306 in("a1") a1,
307 )
308 };
309 #[cfg(not(target_os = "zkvm"))]
310 {
311 core::hint::black_box((t0, a0, a1));
312 unimplemented!()
313 }
314}
315
316fn ecall_4(t0: u32, a0: u32, a1: u32, a2: u32, a3: u32, a4: u32) {
317 #[cfg(target_os = "zkvm")]
318 unsafe {
319 asm!(
320 "ecall",
321 in("t0") t0,
322 in("a0") a0,
323 in("a1") a1,
324 in("a2") a2,
325 in("a3") a3,
326 in("a4") a4,
327 )
328 };
329 #[cfg(not(target_os = "zkvm"))]
330 {
331 core::hint::black_box((t0, a0, a1, a2, a3, a4));
332 unimplemented!()
333 }
334}
335
336#[inline(never)]
344#[cfg_attr(feature = "export-syscalls", no_mangle)]
345pub extern "C" fn sys_halt(user_exit: u8, out_state: *const [u32; DIGEST_WORDS]) -> ! {
346 ecall_1(
347 ecall::HALT,
348 halt::TERMINATE | ((user_exit as u32) << 8),
349 out_state as u32,
350 );
351 unreachable!();
352}
353
354#[inline(never)]
362#[cfg_attr(feature = "export-syscalls", no_mangle)]
363pub unsafe extern "C" fn sys_pause(user_exit: u8, out_state: *const [u32; DIGEST_WORDS]) {
364 ecall_1(
365 ecall::HALT,
366 halt::PAUSE | ((user_exit as u32) << 8),
367 out_state as u32,
368 );
369}
370
371#[cfg_attr(feature = "export-syscalls", no_mangle)]
372pub extern "C" fn sys_input(index: u32) -> u32 {
373 let t0 = ecall::INPUT;
374 let index = index & 0x07;
375 #[cfg(target_os = "zkvm")]
376 unsafe {
377 let a0: u32;
378 asm!(
379 "ecall",
380 in("t0") t0,
381 inlateout("a0") index => a0,
382 );
383 a0
384 }
385 #[cfg(not(target_os = "zkvm"))]
386 {
387 core::hint::black_box((t0, index));
388 unimplemented!()
389 }
390}
391
392#[cfg_attr(feature = "export-syscalls", no_mangle)]
397#[cfg_attr(not(feature = "export-syscalls"), inline(always))]
398pub unsafe extern "C" fn sys_sha_compress(
399 out_state: *mut [u32; DIGEST_WORDS],
400 in_state: *const [u32; DIGEST_WORDS],
401 block1_ptr: *const [u32; DIGEST_WORDS],
402 block2_ptr: *const [u32; DIGEST_WORDS],
403) {
404 ecall_4(
405 ecall::SHA,
406 out_state as u32,
407 in_state as u32,
408 block1_ptr as u32,
409 block2_ptr as u32,
410 1,
411 );
412}
413
414#[cfg_attr(feature = "export-syscalls", no_mangle)]
418#[cfg_attr(not(feature = "export-syscalls"), inline(always))]
419pub unsafe extern "C" fn sys_sha_buffer(
420 out_state: *mut [u32; DIGEST_WORDS],
421 in_state: *const [u32; DIGEST_WORDS],
422 buf: *const u8,
423 count: u32,
424) {
425 let mut ptr = buf;
426 let mut count_remain = count;
427 let mut in_state = in_state;
428 while count_remain > 0 {
429 let count = min(count_remain, MAX_SHA_COMPRESS_BLOCKS as u32);
430 ecall_4(
431 ecall::SHA,
432 out_state as u32,
433 in_state as u32,
434 ptr as u32,
435 ptr.add(DIGEST_BYTES) as u32,
436 count,
437 );
438 count_remain -= count;
439 ptr = ptr.add(2 * DIGEST_BYTES * count as usize);
440 in_state = out_state;
441 }
442}
443
444#[cfg_attr(feature = "export-syscalls", no_mangle)]
449#[cfg_attr(not(feature = "export-syscalls"), inline(always))]
450pub unsafe extern "C" fn sys_poseidon2(
451 _state_addr: *mut [u32; DIGEST_WORDS],
452 _in_buf_addr: *const u8,
453 _out_buf_addr: *mut [u32; DIGEST_WORDS],
454 _bits_count: u32,
455) {
456 unimplemented!()
457}
458
459#[cfg_attr(feature = "export-syscalls", no_mangle)]
463#[cfg_attr(not(feature = "export-syscalls"), inline(always))]
464pub unsafe extern "C" fn sys_bigint(
465 result: *mut [u32; bigint::WIDTH_WORDS],
466 op: u32,
467 x: *const [u32; bigint::WIDTH_WORDS],
468 y: *const [u32; bigint::WIDTH_WORDS],
469 modulus: *const [u32; bigint::WIDTH_WORDS],
470) {
471 ecall_4(
472 ecall::BIGINT,
473 result as u32,
474 op,
475 x as u32,
476 y as u32,
477 modulus as u32,
478 );
479}
480
481#[cfg_attr(feature = "export-syscalls", no_mangle)]
485pub unsafe extern "C" fn sys_rand(recv_buf: *mut u32, words: usize) {
486 unsafe { syscall_0_nr(Syscall::Random.into(), nr::SYS_RANDOM, recv_buf, words) };
487}
488
489#[cfg_attr(feature = "export-syscalls", no_mangle)]
493pub unsafe extern "C" fn sys_panic(msg_ptr: *const u8, len: usize) -> ! {
494 unsafe {
495 syscall_2_nr(
496 Syscall::Panic.into(),
497 nr::SYS_PANIC,
498 null_mut(),
499 0,
500 msg_ptr as u32,
501 len as u32,
502 )
503 };
504
505 #[cfg(target_os = "zkvm")]
507 asm!("sw x0, 1(x0)");
508 unreachable!()
509}
510
511#[cfg_attr(feature = "export-syscalls", no_mangle)]
515pub unsafe extern "C" fn sys_log(msg_ptr: *const u8, len: usize) {
516 unsafe {
517 syscall_2_nr(
518 Syscall::Log.into(),
519 nr::SYS_LOG,
520 null_mut(),
521 0,
522 msg_ptr as u32,
523 len as u32,
524 )
525 };
526}
527
528#[cfg_attr(feature = "export-syscalls", no_mangle)]
529pub extern "C" fn sys_cycle_count() -> u64 {
530 let Return(hi, lo) = unsafe {
531 syscall_0_nr(
532 Syscall::CycleCount.into(),
533 nr::SYS_CYCLE_COUNT,
534 null_mut(),
535 0,
536 )
537 };
538 ((hi as u64) << 32) + lo as u64
539}
540
541#[allow(dead_code)]
542fn print(msg: &str) {
543 let msg = msg.as_bytes();
544 unsafe {
545 sys_log(msg.as_ptr(), msg.len());
546 }
547}
548
549#[cfg_attr(feature = "export-syscalls", unsafe(no_mangle))]
562pub unsafe extern "C" fn sys_read(fd: u32, recv_ptr: *mut u8, nbytes: usize) -> usize {
563 let Return(nbytes_read, final_word) = unsafe {
564 syscall_2_nr(
565 Syscall::Read.into(),
566 nr::SYS_READ,
567 recv_ptr as *mut u32,
568 nbytes,
569 fd,
570 nbytes as u32,
571 )
572 };
573
574 nbytes_read as usize
575}
576
577#[cfg_attr(feature = "export-syscalls", no_mangle)]
596pub unsafe extern "C" fn sys_read_words(fd: u32, recv_ptr: *mut u32, nwords: usize) -> usize {
597 let nbytes = nwords * WORD_SIZE;
598 let Return(nbytes_read, final_word) = unsafe {
599 syscall_2_nr(
600 Syscall::Read.into(),
601 nr::SYS_READ,
602 recv_ptr,
603 nbytes,
604 fd,
605 nbytes as u32,
606 )
607 };
608 nbytes_read as usize
609}
610
611#[cfg_attr(feature = "export-syscalls", no_mangle)]
615pub unsafe extern "C" fn sys_write(fd: u32, write_ptr: *const u8, nbytes: usize) {
616 unsafe {
617 syscall_3_nr(
618 Syscall::Write.into(),
619 nr::SYS_WRITE,
620 null_mut(),
621 0,
622 fd,
623 write_ptr as u32,
624 nbytes as u32,
625 )
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, _) = unsafe {
680 syscall_2_nr(
681 Syscall::Getenv.into(),
682 nr::SYS_GETENV,
683 out_words,
684 out_nwords,
685 varname as u32,
686 varname_len as u32,
687 )
688 };
689 if a0 == u32::MAX {
690 usize::MAX
691 } else {
692 a0 as usize
693 }
694}
695
696#[cfg_attr(feature = "export-syscalls", no_mangle)]
701pub extern "C" fn sys_argc() -> usize {
702 if cfg!(not(feature = "sys-args")) {
703 const MSG: &[u8] = "sys_argc is disabled; can be enabled with the sys-args feature flag on risc0-zkvm-platform".as_bytes();
704 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
705 }
706 let Return(a0, _) = unsafe { syscall_0_nr(Syscall::Argc.into(), nr::SYS_ARGC, null_mut(), 0) };
707 a0 as usize
708}
709
710#[cfg_attr(feature = "export-syscalls", no_mangle)]
728pub unsafe extern "C" fn sys_argv(
729 out_words: *mut u32,
730 out_nwords: usize,
731 arg_index: usize,
732) -> usize {
733 if cfg!(not(feature = "sys-args")) {
734 const MSG: &[u8] = "sys_argv is disabled; can be enabled with the sys-args feature flag on risc0-zkvm-platform".as_bytes();
735 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
736 }
737 let Return(a0, _) = unsafe {
738 syscall_1_nr(
739 Syscall::Argv.into(),
740 nr::SYS_ARGV,
741 out_words,
742 out_nwords,
743 arg_index as u32,
744 )
745 };
746 a0 as usize
747}
748
749#[cfg_attr(feature = "export-syscalls", no_mangle)]
750#[deprecated]
751pub extern "C" fn sys_alloc_words(nwords: usize) -> *mut u32 {
752 unsafe { sys_alloc_aligned(WORD_SIZE * nwords, WORD_SIZE) as *mut u32 }
753}
754
755#[cfg(all(feature = "export-syscalls", not(target_os = "zkvm")))]
759#[no_mangle]
760pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 {
761 unimplemented!("sys_alloc_aligned called outside of target_os = zkvm");
762}
763
764#[cfg(all(
768 feature = "export-syscalls",
769 feature = "heap-embedded-alloc",
770 target_os = "zkvm"
771))]
772#[no_mangle]
773pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 {
774 use core::alloc::GlobalAlloc;
775 crate::heap::embedded::HEAP.alloc(core::alloc::Layout::from_size_align(bytes, align).unwrap())
776}
777
778#[cfg(all(
782 feature = "export-syscalls",
783 not(feature = "heap-embedded-alloc"),
784 target_os = "zkvm"
785))]
786#[no_mangle]
787pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 {
788 crate::heap::bump::alloc_aligned(bytes, align)
789}
790
791#[cfg(feature = "export-syscalls")]
803#[no_mangle]
804pub unsafe extern "C" fn sys_verify_integrity(
805 claim_digest: *const [u32; DIGEST_WORDS],
806 control_root: *const [u32; DIGEST_WORDS],
807) {
808 let mut to_host = [0u32; DIGEST_WORDS * 2];
809 to_host[..DIGEST_WORDS].copy_from_slice(claim_digest.as_ref().unwrap_unchecked());
810 to_host[DIGEST_WORDS..].copy_from_slice(control_root.as_ref().unwrap_unchecked());
811
812 let Return(a0, _) = unsafe {
814 syscall_2_nr(
815 Syscall::VerifyIntegrity.into(),
816 nr::SYS_VERIFY_INTEGRITY,
817 null_mut(),
818 0,
819 to_host.as_ptr() as u32,
820 (DIGEST_BYTES * 2) as u32,
821 )
822 };
823
824 if a0 != 0 {
828 const MSG: &[u8] = "sys_verify_integrity returned error result".as_bytes();
829 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
830 }
831}
832
833#[cfg(feature = "export-syscalls")]
840#[no_mangle]
841pub unsafe extern "C" fn sys_verify_integrity2(
842 claim_digest: *const [u32; DIGEST_WORDS],
843 control_root: *const [u32; DIGEST_WORDS],
844) {
845 let mut to_host = [0u32; DIGEST_WORDS * 2];
846 to_host[..DIGEST_WORDS].copy_from_slice(claim_digest.as_ref().unwrap_unchecked());
847 to_host[DIGEST_WORDS..].copy_from_slice(control_root.as_ref().unwrap_unchecked());
848
849 let Return(a0, _) = unsafe {
851 syscall_2_nr(
852 Syscall::VerifyIntegrity2.into(),
853 nr::SYS_VERIFY_INTEGRITY2,
854 null_mut(),
855 0,
856 to_host.as_ptr() as u32,
857 (DIGEST_BYTES * 2) as u32,
858 )
859 };
860
861 if a0 != 0 {
865 const MSG: &[u8] = "sys_verify_integrity2 returned error result".as_bytes();
866 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
867 }
868}
869#[cfg(not(feature = "export-syscalls"))]
871extern "C" {
872 pub fn sys_alloc_aligned(nwords: usize, align: usize) -> *mut u8;
873}
874
875#[cfg(feature = "export-syscalls")]
888#[no_mangle]
889pub extern "C" fn sys_fork() -> i32 {
890 let Return(a0, _) = unsafe { syscall_0_nr(Syscall::Fork.into(), nr::SYS_FORK, null_mut(), 0) };
891 a0 as i32
892}
893
894#[cfg(feature = "export-syscalls")]
911#[no_mangle]
912pub unsafe extern "C" fn sys_pipe(pipefd: *mut u32) -> i32 {
913 let Return(a0, _) = unsafe { syscall_0_nr(Syscall::Pipe.into(), nr::SYS_PIPE, pipefd, 2) };
914 a0 as i32
915}
916
917#[cfg(feature = "export-syscalls")]
921#[no_mangle]
922pub extern "C" fn sys_exit(status: i32) -> ! {
923 let Return(a0, _) = unsafe { syscall_0_nr(Syscall::Exit.into(), nr::SYS_EXIT, null_mut(), 0) };
924 #[allow(clippy::empty_loop)]
925 loop {
926 }
929}
930
931#[cfg_attr(all(feature = "export-syscalls", feature = "unstable"), no_mangle)]
946#[stability::unstable]
947pub unsafe extern "C" fn sys_prove_zkr(
948 claim_digest: *const [u32; DIGEST_WORDS],
949 control_id: *const [u32; DIGEST_WORDS],
950 control_root: *const [u32; DIGEST_WORDS],
951 input: *const u32,
952 input_len: usize,
953) {
954 let Return(a0, _) = unsafe {
955 syscall_5_nr(
956 Syscall::ProveZkr.into(),
957 nr::SYS_PROVE_ZKR,
958 null_mut(),
959 0,
960 claim_digest as u32,
961 control_id as u32,
962 control_root as u32,
963 input as u32,
964 input_len as u32,
965 )
966 };
967
968 if a0 != 0 {
972 const MSG: &[u8] = "sys_prove_zkr returned error result".as_bytes();
973 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
974 }
975}
976
977#[cfg_attr(feature = "export-syscalls", no_mangle)]
981pub unsafe extern "C" fn sys_keccak(
982 in_state: *const [u64; KECCACK_STATE_DWORDS],
983 out_state: *mut [u64; KECCACK_STATE_DWORDS],
984) -> i32 {
985 let Return(a0, _) = unsafe {
986 syscall_3_nr(
987 Syscall::Keccak.into(),
988 nr::SYS_KECCAK,
989 out_state as *mut u32,
990 KECCACK_STATE_WORDS,
991 keccak_mode::KECCAK_PERMUTE,
992 in_state as u32,
993 0,
994 )
995 };
996 a0 as i32
997}
998
999#[cfg_attr(feature = "export-syscalls", no_mangle)]
1013pub unsafe extern "C" fn sys_prove_keccak(
1014 claim_digest: *const [u32; DIGEST_WORDS],
1015 control_root: *const [u32; DIGEST_WORDS],
1016) {
1017 let Return(a0, _) = unsafe {
1018 syscall_3_nr(
1019 Syscall::Keccak.into(),
1020 nr::SYS_KECCAK,
1021 null_mut(),
1022 0,
1023 keccak_mode::KECCAK_PROVE,
1024 claim_digest as u32,
1025 control_root as u32,
1026 )
1027 };
1028
1029 if a0 != 0 {
1033 const MSG: &[u8] = "sys_prove_keccak returned error result".as_bytes();
1034 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
1035 }
1036}
1037
1038#[repr(C)]
1039pub struct BigIntBlobHeader {
1040 pub nondet_program_size: u32,
1041 pub verify_program_size: u32,
1042 pub consts_size: u32,
1043 pub temp_size: u32,
1044}
1045
1046macro_rules! impl_sys_bigint2 {
1047 ($func_name:ident, $a1:ident
1048 $(, $a2: ident
1049 $(, $a3: ident
1050 $(, $a4: ident
1051 $(, $a5: ident
1052 $(, $a6: ident)?
1053 )?
1054 )?
1055 )?
1056 )?
1057 ) => {
1058 #[cfg_attr(feature = "export-syscalls", no_mangle)]
1064 pub unsafe extern "C" fn $func_name(blob_ptr: *const u8, a1: *const u32
1065 $(, $a2: *const u32
1066 $(, $a3: *const u32
1067 $(, $a4: *const u32
1068 $(, $a5: *const u32
1069 $(, $a6: *const u32)?
1070 )?
1071 )?
1072 )?
1073 )?
1074 ) {
1075 #[cfg(target_os = "zkvm")]
1076 {
1077 let header = blob_ptr as *const $crate::syscall::BigIntBlobHeader;
1078 let nondet_program_ptr = (header.add(1)) as *const u32;
1079 let verify_program_ptr = nondet_program_ptr.add((*header).nondet_program_size as usize);
1080 let consts_ptr = verify_program_ptr.add((*header).verify_program_size as usize);
1081 let temp_space = ((*header).temp_size as usize) << 2;
1082
1083 ::core::arch::asm!(
1084 "sub sp, sp, {temp_space}",
1085 "ecall",
1086 "add sp, sp, {temp_space}",
1087 temp_space = in(reg) temp_space,
1088 in("t0") ecall::BIGINT2,
1089 in("t1") nondet_program_ptr,
1090 in("t2") verify_program_ptr,
1091 in("t3") consts_ptr,
1092 in("a0") blob_ptr,
1093 in("a1") a1,
1094 $(in("a2") $a2,
1095 $(in("a3") $a3,
1096 $(in("a4") $a4,
1097 $(in("a5") $a5,
1098 $(in("a6") $a6)?
1099 )?
1100 )?
1101 )?
1102 )?
1103 );
1104 }
1105
1106 #[cfg(not(target_os = "zkvm"))]
1107 unimplemented!()
1108 }
1109 }
1110}
1111
1112impl_sys_bigint2!(sys_bigint2_1, a1);
1113impl_sys_bigint2!(sys_bigint2_2, a1, a2);
1114impl_sys_bigint2!(sys_bigint2_3, a1, a2, a3);
1115impl_sys_bigint2!(sys_bigint2_4, a1, a2, a3, a4);
1116impl_sys_bigint2!(sys_bigint2_5, a1, a2, a3, a4, a5);
1117impl_sys_bigint2!(sys_bigint2_6, a1, a2, a3, a4, a5, a6);