sp1_lib/io.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
#![allow(unused_unsafe)]
use crate::{syscall_hint_len, syscall_hint_read, syscall_write};
use serde::{de::DeserializeOwned, Serialize};
use std::{
alloc::Layout,
io::{Result, Write},
};
/// The file descriptor for public values.
pub const FD_PUBLIC_VALUES: u32 = 3;
/// The file descriptor for hints.
pub const FD_HINT: u32 = 4;
/// The file descriptor for the `ecreover` hook.
pub const FD_ECRECOVER_HOOK: u32 = 5;
/// A writer that writes to a file descriptor inside the zkVM.
struct SyscallWriter {
fd: u32,
}
impl Write for SyscallWriter {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
let nbytes = buf.len();
let write_buf = buf.as_ptr();
unsafe {
syscall_write(self.fd, write_buf, nbytes);
}
Ok(nbytes)
}
fn flush(&mut self) -> Result<()> {
Ok(())
}
}
/// Read a buffer from the input stream.
///
/// ### Examples
/// ```ignore
/// let data: Vec<u8> = sp1_zkvm::io::read_vec();
/// ```
pub fn read_vec() -> Vec<u8> {
// Round up to the nearest multiple of 4 so that the memory allocated is in whole words
let len = unsafe { syscall_hint_len() };
let capacity = (len + 3) / 4 * 4;
// Allocate a buffer of the required length that is 4 byte aligned
let layout = Layout::from_size_align(capacity, 4).expect("vec is too large");
let ptr = unsafe { std::alloc::alloc(layout) };
// SAFETY:
// 1. `ptr` was allocated using alloc
// 2. We assuume that the VM global allocator doesn't dealloc
// 3/6. Size is correct from above
// 4/5. Length is 0
// 7. Layout::from_size_align already checks this
let mut vec = unsafe { Vec::from_raw_parts(ptr, 0, capacity) };
// Read the vec into uninitialized memory. The syscall assumes the memory is uninitialized,
// which should be true because the allocator does not dealloc, so a new alloc should be fresh.
unsafe {
syscall_hint_read(ptr, len);
vec.set_len(len);
}
vec
}
/// Read a deserializable object from the input stream.
///
/// ### Examples
/// ```ignore
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Serialize, Deserialize)]
/// struct MyStruct {
/// a: u32,
/// b: u32,
/// }
///
/// let data: MyStruct = sp1_zkvm::io::read();
/// ```
pub fn read<T: DeserializeOwned>() -> T {
let vec = read_vec();
bincode::deserialize(&vec).expect("deserialization failed")
}
/// Commit a serializable object to the public values stream.
///
/// ### Examples
/// ```ignore
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Serialize, Deserialize)]
/// struct MyStruct {
/// a: u32,
/// b: u32,
/// }
///
/// let data = MyStruct {
/// a: 1,
/// b: 2,
/// };
/// sp1_zkvm::io::commit(&data);
/// ```
pub fn commit<T: Serialize>(value: &T) {
let writer = SyscallWriter { fd: FD_PUBLIC_VALUES };
bincode::serialize_into(writer, value).expect("serialization failed");
}
/// Commit bytes to the public values stream.
///
/// ### Examples
/// ```ignore
/// let data = vec![1, 2, 3, 4];
/// sp1_zkvm::io::commit_slice(&data);
/// ```
pub fn commit_slice(buf: &[u8]) {
let mut my_writer = SyscallWriter { fd: FD_PUBLIC_VALUES };
my_writer.write_all(buf).unwrap();
}
/// Hint a serializable object to the hint stream.
///
/// ### Examples
/// ```ignore
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Serialize, Deserialize)]
/// struct MyStruct {
/// a: u32,
/// b: u32,
/// }
///
/// let data = MyStruct {
/// a: 1,
/// b: 2,
/// };
/// sp1_zkvm::io::hint(&data);
/// ```
pub fn hint<T: Serialize>(value: &T) {
let writer = SyscallWriter { fd: FD_HINT };
bincode::serialize_into(writer, value).expect("serialization failed");
}
/// Hint bytes to the hint stream.
///
/// ### Examples
/// ```ignore
/// let data = vec![1, 2, 3, 4];
/// sp1_zkvm::io::hint_slice(&data);
/// ```
pub fn hint_slice(buf: &[u8]) {
let mut my_reader = SyscallWriter { fd: FD_HINT };
my_reader.write_all(buf).unwrap();
}
/// Write the data `buf` to the file descriptor `fd`.
///
/// ### Examples
/// ```ignore
/// let data = vec![1, 2, 3, 4];
/// sp1_zkvm::io::write(3, &data);
/// ```
pub fn write(fd: u32, buf: &[u8]) {
SyscallWriter { fd }.write_all(buf).unwrap();
}