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: &str = "";
157 #[deprecated]
158 pub const SYS_PROVE_ZKR: &str = "";
159 declare_syscall!(pub SYS_RANDOM);
160 declare_syscall!(pub SYS_READ);
161 declare_syscall!(pub SYS_VERIFY_INTEGRITY);
162 declare_syscall!(pub SYS_VERIFY_INTEGRITY2);
163 declare_syscall!(pub SYS_WRITE);
164}
165
166#[repr(usize)]
167#[derive(Copy, Clone, Debug, Eq, PartialEq, IntoPrimitive, FromPrimitive)]
168pub enum Syscall {
169 #[num_enum(catch_all)]
170 Unknown(usize) = 0,
171 Argc = 1,
172 Argv = 2,
173 CycleCount = 3,
174 Exit = 4,
175 Fork = 5,
176 Getenv = 6,
177 Keccak = 7,
178 Log = 8,
179 Panic = 9,
180 Pipe = 10,
181 Random = 11,
182 Read = 12,
183 User = 13,
184 VerifyIntegrity = 14,
185 VerifyIntegrity2 = 15,
186 Write = 16,
187 ProveZkr = 17,
188}
189
190impl SyscallName {
191 #[inline]
193 pub const fn from_c_str(c_str: &'static CStr) -> Result<Self, Utf8Error> {
194 match c_str.to_str() {
195 Ok(_) => Ok(unsafe { Self::from_bytes_with_nul(c_str.as_ptr().cast()) }),
196 Err(error) => Err(error),
197 }
198 }
199
200 pub const unsafe fn from_bytes_with_nul(ptr: *const u8) -> Self {
206 Self(ptr)
207 }
208
209 pub fn as_ptr(&self) -> *const u8 {
210 self.0
211 }
212
213 pub fn as_str(&self) -> &str {
214 core::str::from_utf8(unsafe { core::ffi::CStr::from_ptr(self.as_ptr().cast()).to_bytes() })
215 .unwrap()
216 }
217}
218
219impl AsRef<str> for SyscallName {
220 fn as_ref(&self) -> &str {
221 self.as_str()
222 }
223}
224
225#[repr(C)]
227pub struct Return(pub u32, pub u32);
228
229macro_rules! impl_syscall {
230 ($func_name:ident
231 $(, $a0:ident $(, $a1:ident $(, $a2: ident $(, $a3: ident $(, $a4: ident )? )? )? )? )?
234 ) => {
235 #[cfg_attr(feature = "export-syscalls", unsafe(no_mangle))]
241 #[deprecated]
242 pub unsafe extern "C" fn $func_name(
243 syscall_name: SyscallName,
244 from_host: *mut u32,
245 from_host_words: usize
246 $(,$a0: u32 $(,$a1: u32 $(,$a2: u32 $(,$a3: u32 $(,$a4: u32)? )? )? )? )?
247 ) -> Return {
248 unimplemented!();
249 }
250
251
252 paste! {
253 #[cfg_attr(feature = "export-syscalls", unsafe(no_mangle))]
259 pub unsafe extern "C" fn [<$func_name _nr>] (
260 syscall: usize,
261 syscall_name: SyscallName,
262 from_host: *mut u32,
263 from_host_words: usize
264 $(,$a0: u32 $(,$a1: u32 $(,$a2: u32 $(,$a3: u32 $(,$a4: u32)? )? )? )? )?
265 ) -> Return {
266 #[cfg(target_os = "zkvm")] {
267 let a0: u32;
268 let a1: u32;
269 unsafe {
270 ::core::arch::asm!(
271 "ecall",
272 in("t0") $crate::syscall::ecall::SOFTWARE,
273 in("t6") syscall,
274 inlateout("a0") from_host => a0,
275 inlateout("a1") from_host_words => a1,
276 in("a2") syscall_name.as_ptr()
277 $(,in("a3") $a0 $(,in("a4") $a1 $(,in("a5") $a2 $(,in("a6") $a3 $(,in("a7") $a4 )? )? )? )? )?
278 );
279 }
280 Return(a0, a1)
281 }
282 #[cfg(not(target_os = "zkvm"))]
283 unimplemented!()
284 }
285 }
286 }
287}
288
289impl_syscall!(syscall_0);
290impl_syscall!(syscall_1, a3);
291impl_syscall!(syscall_2, a3, a4);
292impl_syscall!(syscall_3, a3, a4, a5);
293impl_syscall!(syscall_4, a3, a4, a5, a6);
294impl_syscall!(syscall_5, a3, a4, a5, a6, a7);
295
296fn ecall_1(t0: u32, a0: u32, a1: u32) {
297 #[cfg(target_os = "zkvm")]
298 unsafe {
299 asm!(
300 "ecall",
301 in("t0") t0,
302 in("a0") a0,
303 in("a1") a1,
304 )
305 };
306 #[cfg(not(target_os = "zkvm"))]
307 {
308 core::hint::black_box((t0, a0, a1));
309 unimplemented!()
310 }
311}
312
313fn ecall_3(t0: u32, a0: u32, a1: u32, a2: u32, a3: u32) {
314 #[cfg(target_os = "zkvm")]
315 unsafe {
316 asm!(
317 "ecall",
318 in("t0") t0,
319 in("a0") a0,
320 in("a1") a1,
321 in("a2") a2,
322 in("a3") a3,
323 )
324 };
325 #[cfg(not(target_os = "zkvm"))]
326 {
327 core::hint::black_box((t0, a0, a1, a2, a3));
328 unimplemented!()
329 }
330}
331
332fn ecall_4(t0: u32, a0: u32, a1: u32, a2: u32, a3: u32, a4: u32) {
333 #[cfg(target_os = "zkvm")]
334 unsafe {
335 asm!(
336 "ecall",
337 in("t0") t0,
338 in("a0") a0,
339 in("a1") a1,
340 in("a2") a2,
341 in("a3") a3,
342 in("a4") a4,
343 )
344 };
345 #[cfg(not(target_os = "zkvm"))]
346 {
347 core::hint::black_box((t0, a0, a1, a2, a3, a4));
348 unimplemented!()
349 }
350}
351
352#[inline(never)]
360#[cfg_attr(feature = "export-syscalls", no_mangle)]
361pub extern "C" fn sys_halt(user_exit: u8, out_state: *const [u32; DIGEST_WORDS]) -> ! {
362 ecall_1(
363 ecall::HALT,
364 halt::TERMINATE | ((user_exit as u32) << 8),
365 out_state as u32,
366 );
367 unreachable!();
368}
369
370#[inline(never)]
378#[cfg_attr(feature = "export-syscalls", no_mangle)]
379pub unsafe extern "C" fn sys_pause(user_exit: u8, out_state: *const [u32; DIGEST_WORDS]) {
380 ecall_1(
381 ecall::HALT,
382 halt::PAUSE | ((user_exit as u32) << 8),
383 out_state as u32,
384 );
385}
386
387#[cfg_attr(feature = "export-syscalls", no_mangle)]
388pub extern "C" fn sys_input(index: u32) -> u32 {
389 let t0 = ecall::INPUT;
390 let index = index & 0x07;
391 #[cfg(target_os = "zkvm")]
392 unsafe {
393 let a0: u32;
394 asm!(
395 "ecall",
396 in("t0") t0,
397 inlateout("a0") index => a0,
398 );
399 a0
400 }
401 #[cfg(not(target_os = "zkvm"))]
402 {
403 core::hint::black_box((t0, index));
404 unimplemented!()
405 }
406}
407
408#[cfg_attr(feature = "export-syscalls", no_mangle)]
413#[cfg_attr(not(feature = "export-syscalls"), inline(always))]
414pub unsafe extern "C" fn sys_sha_compress(
415 out_state: *mut [u32; DIGEST_WORDS],
416 in_state: *const [u32; DIGEST_WORDS],
417 block1_ptr: *const [u32; DIGEST_WORDS],
418 block2_ptr: *const [u32; DIGEST_WORDS],
419) {
420 ecall_4(
421 ecall::SHA,
422 out_state as u32,
423 in_state as u32,
424 block1_ptr as u32,
425 block2_ptr as u32,
426 1,
427 );
428}
429
430#[cfg_attr(feature = "export-syscalls", no_mangle)]
434#[cfg_attr(not(feature = "export-syscalls"), inline(always))]
435pub unsafe extern "C" fn sys_sha_buffer(
436 out_state: *mut [u32; DIGEST_WORDS],
437 in_state: *const [u32; DIGEST_WORDS],
438 buf: *const u8,
439 count: u32,
440) {
441 let mut ptr = buf;
442 let mut count_remain = count;
443 let mut in_state = in_state;
444 while count_remain > 0 {
445 let count = min(count_remain, MAX_SHA_COMPRESS_BLOCKS as u32);
446 ecall_4(
447 ecall::SHA,
448 out_state as u32,
449 in_state as u32,
450 ptr as u32,
451 ptr.add(DIGEST_BYTES) as u32,
452 count,
453 );
454 count_remain -= count;
455 ptr = ptr.add(2 * DIGEST_BYTES * count as usize);
456 in_state = out_state;
457 }
458}
459
460#[cfg_attr(feature = "export-syscalls", no_mangle)]
465#[cfg_attr(not(feature = "export-syscalls"), inline(always))]
466pub unsafe extern "C" fn sys_poseidon2(
467 state_addr: *mut [u32; DIGEST_WORDS],
468 in_buf_addr: *const u8,
469 out_buf_addr: *mut [u32; DIGEST_WORDS],
470 bits_count: u32,
471) {
472 debug_assert!(state_addr as usize % WORD_SIZE == 0);
473 debug_assert!(in_buf_addr as usize % WORD_SIZE == 0);
474 debug_assert!(out_buf_addr as usize % WORD_SIZE == 0);
475
476 ecall_3(
477 ecall::POSEIDON2,
478 state_addr as u32 / WORD_SIZE as u32,
479 in_buf_addr as u32 / WORD_SIZE as u32,
480 out_buf_addr as u32 / WORD_SIZE as u32,
481 bits_count,
482 );
483}
484
485#[cfg_attr(feature = "export-syscalls", no_mangle)]
489#[cfg_attr(not(feature = "export-syscalls"), inline(always))]
490pub unsafe extern "C" fn sys_bigint(
491 result: *mut [u32; bigint::WIDTH_WORDS],
492 op: u32,
493 x: *const [u32; bigint::WIDTH_WORDS],
494 y: *const [u32; bigint::WIDTH_WORDS],
495 modulus: *const [u32; bigint::WIDTH_WORDS],
496) {
497 ecall_4(
498 ecall::BIGINT,
499 result as u32,
500 op,
501 x as u32,
502 y as u32,
503 modulus as u32,
504 );
505}
506
507#[cfg_attr(feature = "export-syscalls", no_mangle)]
511pub unsafe extern "C" fn sys_rand(recv_buf: *mut u32, words: usize) {
512 unsafe { syscall_0_nr(Syscall::Random.into(), nr::SYS_RANDOM, recv_buf, words) };
513}
514
515#[cfg_attr(feature = "export-syscalls", no_mangle)]
519pub unsafe extern "C" fn sys_panic(msg_ptr: *const u8, len: usize) -> ! {
520 unsafe {
521 syscall_2_nr(
522 Syscall::Panic.into(),
523 nr::SYS_PANIC,
524 null_mut(),
525 0,
526 msg_ptr as u32,
527 len as u32,
528 )
529 };
530
531 #[cfg(target_os = "zkvm")]
533 asm!("sw x0, 1(x0)");
534 unreachable!()
535}
536
537#[cfg_attr(feature = "export-syscalls", no_mangle)]
541pub unsafe extern "C" fn sys_log(msg_ptr: *const u8, len: usize) {
542 unsafe {
543 syscall_2_nr(
544 Syscall::Log.into(),
545 nr::SYS_LOG,
546 null_mut(),
547 0,
548 msg_ptr as u32,
549 len as u32,
550 )
551 };
552}
553
554#[cfg_attr(feature = "export-syscalls", no_mangle)]
555pub extern "C" fn sys_cycle_count() -> u64 {
556 let Return(hi, lo) = unsafe {
557 syscall_0_nr(
558 Syscall::CycleCount.into(),
559 nr::SYS_CYCLE_COUNT,
560 null_mut(),
561 0,
562 )
563 };
564 ((hi as u64) << 32) + lo as u64
565}
566
567#[allow(dead_code)]
568fn print(msg: &str) {
569 let msg = msg.as_bytes();
570 unsafe {
571 sys_log(msg.as_ptr(), msg.len());
572 }
573}
574
575#[cfg_attr(feature = "export-syscalls", unsafe(no_mangle))]
588pub unsafe extern "C" fn sys_read(fd: u32, recv_ptr: *mut u8, nbytes: usize) -> usize {
589 let Return(nbytes_read, final_word) = unsafe {
590 syscall_2_nr(
591 Syscall::Read.into(),
592 nr::SYS_READ,
593 recv_ptr as *mut u32,
594 nbytes,
595 fd,
596 nbytes as u32,
597 )
598 };
599
600 nbytes_read as usize
601}
602
603#[cfg_attr(feature = "export-syscalls", no_mangle)]
622pub unsafe extern "C" fn sys_read_words(fd: u32, recv_ptr: *mut u32, nwords: usize) -> usize {
623 let nbytes = nwords * WORD_SIZE;
624 let Return(nbytes_read, final_word) = unsafe {
625 syscall_2_nr(
626 Syscall::Read.into(),
627 nr::SYS_READ,
628 recv_ptr,
629 nbytes,
630 fd,
631 nbytes as u32,
632 )
633 };
634 nbytes_read as usize
635}
636
637#[cfg_attr(feature = "export-syscalls", no_mangle)]
641pub unsafe extern "C" fn sys_write(fd: u32, write_ptr: *const u8, nbytes: usize) {
642 unsafe {
643 syscall_3_nr(
644 Syscall::Write.into(),
645 nr::SYS_WRITE,
646 null_mut(),
647 0,
648 fd,
649 write_ptr as u32,
650 nbytes as u32,
651 )
652 };
653}
654
655const ALLOWED_ENV_VARNAMES: &[&[u8]] = &[
659 b"RUST_BACKTRACE",
660 b"RUST_LIB_BACKTRACE",
661 b"RISC0_KECCAK_PO2",
662];
663
664#[cfg_attr(feature = "export-syscalls", no_mangle)]
682pub unsafe extern "C" fn sys_getenv(
683 out_words: *mut u32,
684 out_nwords: usize,
685 varname: *const u8,
686 varname_len: usize,
687) -> usize {
688 if cfg!(not(feature = "sys-getenv")) {
689 let mut allowed = false;
690 for allowed_varname in ALLOWED_ENV_VARNAMES {
691 let varname_buf = unsafe { slice::from_raw_parts(varname, varname_len) };
692 if *allowed_varname == varname_buf {
693 allowed = true;
694 break;
695 }
696 }
697 if !allowed {
698 const MSG_1: &[u8] = "sys_getenv not enabled for var".as_bytes();
699 unsafe { sys_log(MSG_1.as_ptr(), MSG_1.len()) };
700 unsafe { sys_log(varname, varname_len) };
701 const MSG_2: &[u8] = "sys_getenv is disabled; can be enabled with the sys-getenv feature flag on risc0-zkvm-platform".as_bytes();
702 unsafe { sys_panic(MSG_2.as_ptr(), MSG_2.len()) };
703 }
704 }
705 let Return(a0, _) = unsafe {
706 syscall_2_nr(
707 Syscall::Getenv.into(),
708 nr::SYS_GETENV,
709 out_words,
710 out_nwords,
711 varname as u32,
712 varname_len as u32,
713 )
714 };
715 if a0 == u32::MAX {
716 usize::MAX
717 } else {
718 a0 as usize
719 }
720}
721
722#[cfg_attr(feature = "export-syscalls", no_mangle)]
727pub extern "C" fn sys_argc() -> usize {
728 if cfg!(not(feature = "sys-args")) {
729 const MSG: &[u8] = "sys_argc is disabled; can be enabled with the sys-args feature flag on risc0-zkvm-platform".as_bytes();
730 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
731 }
732 let Return(a0, _) = unsafe { syscall_0_nr(Syscall::Argc.into(), nr::SYS_ARGC, null_mut(), 0) };
733 a0 as usize
734}
735
736#[cfg_attr(feature = "export-syscalls", no_mangle)]
754pub unsafe extern "C" fn sys_argv(
755 out_words: *mut u32,
756 out_nwords: usize,
757 arg_index: usize,
758) -> usize {
759 if cfg!(not(feature = "sys-args")) {
760 const MSG: &[u8] = "sys_argv is disabled; can be enabled with the sys-args feature flag on risc0-zkvm-platform".as_bytes();
761 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
762 }
763 let Return(a0, _) = unsafe {
764 syscall_1_nr(
765 Syscall::Argv.into(),
766 nr::SYS_ARGV,
767 out_words,
768 out_nwords,
769 arg_index as u32,
770 )
771 };
772 a0 as usize
773}
774
775#[cfg_attr(feature = "export-syscalls", no_mangle)]
776#[deprecated]
777pub extern "C" fn sys_alloc_words(nwords: usize) -> *mut u32 {
778 unsafe { sys_alloc_aligned(WORD_SIZE * nwords, WORD_SIZE) as *mut u32 }
779}
780
781#[cfg(all(feature = "export-syscalls", not(target_os = "zkvm")))]
785#[no_mangle]
786pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 {
787 unimplemented!("sys_alloc_aligned called outside of target_os = zkvm");
788}
789
790#[cfg(all(
794 feature = "export-syscalls",
795 feature = "heap-embedded-alloc",
796 target_os = "zkvm"
797))]
798#[no_mangle]
799pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 {
800 use core::alloc::GlobalAlloc;
801 crate::heap::embedded::HEAP.alloc(core::alloc::Layout::from_size_align(bytes, align).unwrap())
802}
803
804#[cfg(all(
808 feature = "export-syscalls",
809 not(feature = "heap-embedded-alloc"),
810 target_os = "zkvm"
811))]
812#[no_mangle]
813pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 {
814 crate::heap::bump::alloc_aligned(bytes, align)
815}
816
817#[cfg(feature = "export-syscalls")]
829#[no_mangle]
830pub unsafe extern "C" fn sys_verify_integrity(
831 claim_digest: *const [u32; DIGEST_WORDS],
832 control_root: *const [u32; DIGEST_WORDS],
833) {
834 let mut to_host = [0u32; DIGEST_WORDS * 2];
835 to_host[..DIGEST_WORDS].copy_from_slice(claim_digest.as_ref().unwrap_unchecked());
836 to_host[DIGEST_WORDS..].copy_from_slice(control_root.as_ref().unwrap_unchecked());
837
838 let Return(a0, _) = unsafe {
840 syscall_2_nr(
841 Syscall::VerifyIntegrity.into(),
842 nr::SYS_VERIFY_INTEGRITY,
843 null_mut(),
844 0,
845 to_host.as_ptr() as u32,
846 (DIGEST_BYTES * 2) as u32,
847 )
848 };
849
850 if a0 != 0 {
854 const MSG: &[u8] = "sys_verify_integrity returned error result".as_bytes();
855 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
856 }
857}
858
859#[cfg(feature = "export-syscalls")]
866#[no_mangle]
867pub unsafe extern "C" fn sys_verify_integrity2(
868 claim_digest: *const [u32; DIGEST_WORDS],
869 control_root: *const [u32; DIGEST_WORDS],
870) {
871 let mut to_host = [0u32; DIGEST_WORDS * 2];
872 to_host[..DIGEST_WORDS].copy_from_slice(claim_digest.as_ref().unwrap_unchecked());
873 to_host[DIGEST_WORDS..].copy_from_slice(control_root.as_ref().unwrap_unchecked());
874
875 let Return(a0, _) = unsafe {
877 syscall_2_nr(
878 Syscall::VerifyIntegrity2.into(),
879 nr::SYS_VERIFY_INTEGRITY2,
880 null_mut(),
881 0,
882 to_host.as_ptr() as u32,
883 (DIGEST_BYTES * 2) as u32,
884 )
885 };
886
887 if a0 != 0 {
891 const MSG: &[u8] = "sys_verify_integrity2 returned error result".as_bytes();
892 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
893 }
894}
895#[cfg(not(feature = "export-syscalls"))]
897extern "C" {
898 pub fn sys_alloc_aligned(nwords: usize, align: usize) -> *mut u8;
899}
900
901#[cfg(feature = "export-syscalls")]
914#[no_mangle]
915pub extern "C" fn sys_fork() -> i32 {
916 let Return(a0, _) = unsafe { syscall_0_nr(Syscall::Fork.into(), nr::SYS_FORK, null_mut(), 0) };
917 a0 as i32
918}
919
920#[cfg(feature = "export-syscalls")]
937#[no_mangle]
938pub unsafe extern "C" fn sys_pipe(pipefd: *mut u32) -> i32 {
939 let Return(a0, _) = unsafe { syscall_0_nr(Syscall::Pipe.into(), nr::SYS_PIPE, pipefd, 2) };
940 a0 as i32
941}
942
943#[cfg(feature = "export-syscalls")]
947#[no_mangle]
948pub extern "C" fn sys_exit(status: i32) -> ! {
949 let Return(a0, _) = unsafe { syscall_0_nr(Syscall::Exit.into(), nr::SYS_EXIT, null_mut(), 0) };
950 #[allow(clippy::empty_loop)]
951 loop {
952 }
955}
956
957#[cfg_attr(feature = "export-syscalls", no_mangle)]
961pub unsafe extern "C" fn sys_keccak(
962 in_state: *const [u64; KECCACK_STATE_DWORDS],
963 out_state: *mut [u64; KECCACK_STATE_DWORDS],
964) -> i32 {
965 let Return(a0, _) = unsafe {
966 syscall_3_nr(
967 Syscall::Keccak.into(),
968 nr::SYS_KECCAK,
969 out_state as *mut u32,
970 KECCACK_STATE_WORDS,
971 keccak_mode::KECCAK_PERMUTE,
972 in_state as u32,
973 0,
974 )
975 };
976 a0 as i32
977}
978
979#[cfg_attr(feature = "export-syscalls", no_mangle)]
993pub unsafe extern "C" fn sys_prove_keccak(
994 claim_digest: *const [u32; DIGEST_WORDS],
995 control_root: *const [u32; DIGEST_WORDS],
996) {
997 let Return(a0, _) = unsafe {
998 syscall_3_nr(
999 Syscall::Keccak.into(),
1000 nr::SYS_KECCAK,
1001 null_mut(),
1002 0,
1003 keccak_mode::KECCAK_PROVE,
1004 claim_digest as u32,
1005 control_root as u32,
1006 )
1007 };
1008
1009 if a0 != 0 {
1013 const MSG: &[u8] = "sys_prove_keccak returned error result".as_bytes();
1014 unsafe { sys_panic(MSG.as_ptr(), MSG.len()) };
1015 }
1016}
1017
1018#[repr(C)]
1019pub struct BigIntBlobHeader {
1020 pub nondet_program_size: u32,
1021 pub verify_program_size: u32,
1022 pub consts_size: u32,
1023 pub temp_size: u32,
1024}
1025
1026macro_rules! impl_sys_bigint2 {
1027 ($func_name:ident, $a1:ident
1028 $(, $a2: ident
1029 $(, $a3: ident
1030 $(, $a4: ident
1031 $(, $a5: ident
1032 $(, $a6: ident)?
1033 )?
1034 )?
1035 )?
1036 )?
1037 ) => {
1038 #[cfg_attr(feature = "export-syscalls", no_mangle)]
1044 pub unsafe extern "C" fn $func_name(blob_ptr: *const u8, a1: *const u32
1045 $(, $a2: *const u32
1046 $(, $a3: *const u32
1047 $(, $a4: *const u32
1048 $(, $a5: *const u32
1049 $(, $a6: *const u32)?
1050 )?
1051 )?
1052 )?
1053 )?
1054 ) {
1055 #[cfg(target_os = "zkvm")]
1056 {
1057 let header = blob_ptr as *const $crate::syscall::BigIntBlobHeader;
1058 let nondet_program_ptr = (header.add(1)) as *const u32;
1059 let verify_program_ptr = nondet_program_ptr.add((*header).nondet_program_size as usize);
1060 let consts_ptr = verify_program_ptr.add((*header).verify_program_size as usize);
1061 let temp_space = ((*header).temp_size as usize) << 2;
1062
1063 ::core::arch::asm!(
1064 "sub sp, sp, {temp_space}",
1065 "ecall",
1066 "add sp, sp, {temp_space}",
1067 temp_space = in(reg) temp_space,
1068 in("t0") ecall::BIGINT2,
1069 in("t1") nondet_program_ptr,
1070 in("t2") verify_program_ptr,
1071 in("t3") consts_ptr,
1072 in("a0") blob_ptr,
1073 in("a1") a1,
1074 $(in("a2") $a2,
1075 $(in("a3") $a3,
1076 $(in("a4") $a4,
1077 $(in("a5") $a5,
1078 $(in("a6") $a6)?
1079 )?
1080 )?
1081 )?
1082 )?
1083 );
1084 }
1085
1086 #[cfg(not(target_os = "zkvm"))]
1087 unimplemented!()
1088 }
1089 }
1090}
1091
1092impl_sys_bigint2!(sys_bigint2_1, a1);
1093impl_sys_bigint2!(sys_bigint2_2, a1, a2);
1094impl_sys_bigint2!(sys_bigint2_3, a1, a2, a3);
1095impl_sys_bigint2!(sys_bigint2_4, a1, a2, a3, a4);
1096impl_sys_bigint2!(sys_bigint2_5, a1, a2, a3, a4, a5);
1097impl_sys_bigint2!(sys_bigint2_6, a1, a2, a3, a4, a5, a6);