diff --git a/std/src/error.rs b/std/src/error.rs
index 18d5e5b..49419e3 100644
--- a/std/src/error.rs
+++ b/std/src/error.rs
@@ -1,27 +1,54 @@
 use crate::boxed::Box;
+use crate::fmt::{self, Debug, Display};
+use crate::string::String;
 
-#[cfg(feature = "std")]
-pub use std::error::Error;
-
-#[cfg(not(feature = "std"))]
 pub trait Error: core::fmt::Debug + core::fmt::Display {
     fn source(&self) -> Option<&(dyn Error + 'static)> {
         None
     }
 }
 
-#[cfg(not(feature = "std"))]
 impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
     fn from(err: E) -> Self {
         Box::new(err)
     }
 }
 
-#[cfg(not(feature = "std"))]
+impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> {
+    fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> {
+        Box::new(err)
+    }
+}
+
 impl<T: Error> Error for Box<T> {}
 
-#[cfg(not(feature = "std"))]
-impl Error for crate::string::String {}
+impl From<String> for Box<dyn Error + Send + Sync> {
+    #[inline]
+    fn from(err: String) -> Box<dyn Error + Send + Sync> {
+        struct StringError(String);
+
+        impl Error for StringError {}
+
+        impl Display for StringError {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                Display::fmt(&self.0, f)
+            }
+        }
 
-#[cfg(not(feature = "std"))]
-impl Error for crate::io::Error {}
+        // Purposefully skip printing "StringError(..)"
+        impl Debug for StringError {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                Debug::fmt(&self.0, f)
+            }
+        }
+
+        Box::new(StringError(err))
+    }
+}
+
+impl<'a> From<&'a str> for Box<dyn Error + Send + Sync> {
+    #[inline]
+    fn from(err: &'a str) -> Box<dyn Error + Send + Sync> {
+        From::from(String::from(err))
+    }
+}
diff --git a/std/src/io.rs b/std/src/io.rs
deleted file mode 100644
index a573d82..0000000
--- a/std/src/io.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-//! no-std io replacement
-use crate::{vec::Vec, cmp, mem, fmt};
-
-#[derive(Debug)]
-pub struct Error;
-
-impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        writeln!(f, "Error")
-    }
-}
-
-pub type Result<T> = core::result::Result<T, Error>;
-
-pub trait Read {
-    fn read_exact(&mut self, data: &mut [u8]) -> Result<()>;
-}
-
-pub trait Write {
-    fn write_all(&mut self, data: &[u8]) -> Result<()>;
-}
-
-impl<R: Read + ?Sized> Read for &mut R {
-    #[inline]
-    fn read_exact(&mut self, data: &mut [u8]) -> Result<()> {
-        (**self).read_exact(data)
-    }
-}
-
-impl Read for &[u8] {
-    fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
-        if buf.len() > self.len() {
-            return Err(Error);
-        }
-        let (a, b) = self.split_at(buf.len());
-
-        // First check if the amount of bytes we want to read is small:
-        // `copy_from_slice` will generally expand to a call to `memcpy`, and
-        // for a single byte the overhead is significant.
-        if buf.len() == 1 {
-            buf[0] = a[0];
-        } else {
-            buf.copy_from_slice(a);
-        }
-
-        *self = b;
-        Ok(())
-    }
-}
-
-impl<W: Write + ?Sized> Write for &mut W {
-    #[inline]
-    fn write_all(&mut self, data: &[u8]) -> Result<()> {
-        (**self).write_all(data)
-    }
-}
-
-impl Write for &mut [u8] {
-    #[inline]
-    fn write_all(&mut self, data: &[u8]) -> Result<()> {
-        let amt = cmp::min(data.len(), self.len());
-        let (a, b) = mem::replace(self, &mut []).split_at_mut(amt);
-        a.copy_from_slice(&data[..amt]);
-        *self = b;
-
-        if amt == data.len() {
-            Ok(())
-        } else {
-            Err(Error)
-        }
-    }
-}
-
-impl Write for Vec<u8> {
-    #[inline]
-    fn write_all(&mut self, buf: &[u8]) -> Result<()> {
-        self.extend_from_slice(buf);
-        Ok(())
-    }
-}
-
-/// This data structure is used as a workaround for current design of `ToBytes`
-/// which does not allow multiple writes to `&mut [u8]`.
-pub struct Cursor<T> {
-    inner: T,
-    pos: usize,
-}
-
-impl<T> Cursor<T> {
-    pub fn new(inner: T) -> Self {
-        Cursor { inner, pos: 0 }
-    }
-}
-
-impl Write for Cursor<&mut [u8]> {
-    fn write_all(&mut self, buf: &[u8]) -> Result<()> {
-        let to_copy = cmp::min(self.inner.len() - self.pos, buf.len());
-        self.inner[self.pos..self.pos + to_copy].copy_from_slice(buf);
-        self.pos += to_copy;
-        Ok(())
-    }
-}
-
-impl Read for Cursor<&mut [u8]> {
-    fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
-        let to_copy = cmp::min(self.inner.len() - self.pos, buf.len());
-        buf.copy_from_slice(&self.inner[self.pos..self.pos + to_copy]);
-        self.pos += to_copy;
-        Ok(())
-    }
-}
-
-impl Read for Cursor<&[u8]> {
-    fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
-        let to_copy = cmp::min(self.inner.len() - self.pos, buf.len());
-        buf.copy_from_slice(&self.inner[self.pos..self.pos + to_copy]);
-        self.pos += to_copy;
-        Ok(())
-    }
-}
diff --git a/std/src/io/error.rs b/std/src/io/error.rs
new file mode 100644
index 0000000..5c71ca8
--- /dev/null
+++ b/std/src/io/error.rs
@@ -0,0 +1,269 @@
+use crate::boxed::Box;
+use crate::convert::From;
+use crate::error;
+use crate::fmt;
+
+/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and
+/// associated traits.
+///
+/// Errors mostly originate from the underlying OS, but custom instances of
+/// `Error` can be created with crafted error messages and a particular value of
+/// [`ErrorKind`].
+///
+/// [`Read`]: crate::io::Read
+/// [`Write`]: crate::io::Write
+/// [`Seek`]: crate::io::Seek
+pub struct Error {
+    repr: Repr,
+}
+
+pub type Result<T> = core::result::Result<T, Error>;
+
+impl fmt::Debug for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(&self.repr, f)
+    }
+}
+
+enum Repr {
+    Simple(ErrorKind),
+    Custom(Box<Custom>),
+}
+
+#[derive(Debug)]
+struct Custom {
+    kind: ErrorKind,
+    error: Box<dyn error::Error + Send + Sync>,
+}
+
+/// A list specifying general categories of I/O error.
+///
+/// This list is intended to grow over time and it is not recommended to
+/// exhaustively match against it.
+///
+/// It is used with the [`io::Error`] type.
+///
+/// [`io::Error`]: Error
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[allow(deprecated)]
+#[non_exhaustive]
+pub enum ErrorKind {
+    /// An entity was not found, often a file.
+    NotFound,
+    /// The operation lacked the necessary privileges to complete.
+    PermissionDenied,
+    /// The connection was refused by the remote server.
+    ConnectionRefused,
+    /// The connection was reset by the remote server.
+    ConnectionReset,
+    /// The connection was aborted (terminated) by the remote server.
+    ConnectionAborted,
+    /// The network operation failed because it was not connected yet.
+    NotConnected,
+    /// A socket address could not be bound because the address is already in
+    /// use elsewhere.
+    AddrInUse,
+    /// A nonexistent interface was requested or the requested address was not
+    /// local.
+    AddrNotAvailable,
+    /// The operation failed because a pipe was closed.
+    BrokenPipe,
+    /// An entity already exists, often a file.
+    AlreadyExists,
+    /// The operation needs to block to complete, but the blocking operation was
+    /// requested to not occur.
+    WouldBlock,
+    /// A parameter was incorrect.
+    InvalidInput,
+    /// Data not valid for the operation were encountered.
+    ///
+    /// Unlike [`InvalidInput`], this typically means that the operation
+    /// parameters were valid, however the error was caused by malformed
+    /// input data.
+    ///
+    /// For example, a function that reads a file into a string will error with
+    /// `InvalidData` if the file's contents are not valid UTF-8.
+    ///
+    /// [`InvalidInput`]: ErrorKind::InvalidInput
+    InvalidData,
+    /// The I/O operation's timeout expired, causing it to be canceled.
+    TimedOut,
+    /// An error returned when an operation could not be completed because a
+    /// call to [`write`] returned [`Ok(0)`].
+    ///
+    /// This typically means that an operation could only succeed if it wrote a
+    /// particular number of bytes but only a smaller number of bytes could be
+    /// written.
+    ///
+    /// [`write`]: crate::io::Write::write
+    /// [`Ok(0)`]: Ok
+    WriteZero,
+    /// This operation was interrupted.
+    ///
+    /// Interrupted operations can typically be retried.
+    Interrupted,
+    /// Any I/O error not part of this list.
+    ///
+    /// Errors that are `Other` now may move to a different or a new
+    /// [`ErrorKind`] variant in the future. It is not recommended to match
+    /// an error against `Other` and to expect any additional characteristics,
+    /// e.g., a specific [`Error::raw_os_error`] return value.
+    Other,
+
+    /// An error returned when an operation could not be completed because an
+    /// "end of file" was reached prematurely.
+    ///
+    /// This typically means that an operation could only succeed if it read a
+    /// particular number of bytes but only a smaller number of bytes could be
+    /// read.
+    UnexpectedEof,
+}
+
+impl ErrorKind {
+    pub(crate) fn as_str(&self) -> &'static str {
+        match *self {
+            ErrorKind::NotFound => "entity not found",
+            ErrorKind::PermissionDenied => "permission denied",
+            ErrorKind::ConnectionRefused => "connection refused",
+            ErrorKind::ConnectionReset => "connection reset",
+            ErrorKind::ConnectionAborted => "connection aborted",
+            ErrorKind::NotConnected => "not connected",
+            ErrorKind::AddrInUse => "address in use",
+            ErrorKind::AddrNotAvailable => "address not available",
+            ErrorKind::BrokenPipe => "broken pipe",
+            ErrorKind::AlreadyExists => "entity already exists",
+            ErrorKind::WouldBlock => "operation would block",
+            ErrorKind::InvalidInput => "invalid input parameter",
+            ErrorKind::InvalidData => "invalid data",
+            ErrorKind::TimedOut => "timed out",
+            ErrorKind::WriteZero => "write zero",
+            ErrorKind::Interrupted => "operation interrupted",
+            ErrorKind::Other => "other os error",
+            ErrorKind::UnexpectedEof => "unexpected end of file",
+        }
+    }
+}
+
+/// Intended for use for errors not exposed to the user, where allocating onto
+/// the heap (for normal construction via Error::new) is too costly.
+impl From<ErrorKind> for Error {
+    /// Converts an [`ErrorKind`] into an [`Error`].
+    ///
+    /// This conversion allocates a new error with a simple representation of error kind.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use ark_std::io::{Error, ErrorKind};
+    ///
+    /// let not_found = ErrorKind::NotFound;
+    /// let error = Error::from(not_found);
+    /// assert_eq!("entity not found", format!("{}", error));
+    /// ```
+    #[inline]
+    fn from(kind: ErrorKind) -> Error {
+        Error {
+            repr: Repr::Simple(kind),
+        }
+    }
+}
+
+impl Error {
+    /// Creates a new I/O error from a known kind of error as well as an
+    /// arbitrary error payload.
+    ///
+    /// This function is used to generically create I/O errors which do not
+    /// originate from the OS itself. The `error` argument is an arbitrary
+    /// payload which will be contained in this [`Error`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use ark_std::io::{Error, ErrorKind};
+    ///
+    /// // errors can be created from strings
+    /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
+    ///
+    /// // errors can also be created from other errors
+    /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
+    /// ```
+    pub fn new<E>(kind: ErrorKind, error: E) -> Error
+    where
+        E: Into<Box<dyn error::Error + Send + Sync>>,
+    {
+        Self::_new(kind, error.into())
+    }
+
+    fn _new(kind: ErrorKind, error: Box<dyn error::Error + Send + Sync>) -> Error {
+        Error {
+            repr: Repr::Custom(Box::new(Custom { kind, error })),
+        }
+    }
+
+    pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> {
+        match self.repr {
+            Repr::Simple(..) => None,
+            Repr::Custom(ref c) => Some(&*c.error),
+        }
+    }
+
+    pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> {
+        match self.repr {
+            Repr::Simple(..) => None,
+            Repr::Custom(ref mut c) => Some(&mut *c.error),
+        }
+    }
+
+    /// Consumes the `Error`, returning its inner error (if any).
+    ///
+    /// If this [`Error`] was constructed via [`new`] then this function will
+    /// return [`Some`], otherwise it will return [`None`].
+    ///
+    /// [`new`]: Error::new
+    pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
+        match self.repr {
+            Repr::Simple(..) => None,
+            Repr::Custom(c) => Some(c.error),
+        }
+    }
+
+    /// Returns the corresponding [`ErrorKind`] for this error.
+    pub fn kind(&self) -> ErrorKind {
+        match self.repr {
+            Repr::Custom(ref c) => c.kind,
+            Repr::Simple(kind) => kind,
+        }
+    }
+}
+
+impl fmt::Debug for Repr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt),
+            Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
+        }
+    }
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.repr {
+            Repr::Custom(ref c) => c.error.fmt(fmt),
+            Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
+        }
+    }
+}
+
+impl error::Error for Error {
+    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+        match self.repr {
+            Repr::Simple(..) => None,
+            Repr::Custom(ref c) => c.error.source(),
+        }
+    }
+}
+
+fn _assert_error_is_sync_send() {
+    fn _is_sync_send<T: Sync + Send>() {}
+    _is_sync_send::<Error>();
+}
diff --git a/std/src/io/mod.rs b/std/src/io/mod.rs
new file mode 100644
index 0000000..9d8c22b
--- /dev/null
+++ b/std/src/io/mod.rs
@@ -0,0 +1,544 @@
+//! no-std io replacement
+use crate::{cmp, convert::TryInto, mem, vec::Vec};
+
+mod error;
+pub use error::*;
+
+pub mod prelude {
+    pub use super::{Read, Result, Write};
+}
+
+/// The `Read` trait allows for reading bytes from a source.
+///
+/// Implementors of the `Read` trait are called 'readers'.
+///
+/// Readers are defined by one required method, [`read()`]. Each call to [`read()`]
+/// will attempt to pull bytes from this source into a provided buffer. A
+/// number of other methods are implemented in terms of [`read()`], giving
+/// implementors a number of ways to read bytes while only needing to implement
+/// a single method.
+///
+/// Readers are intended to be composable with one another. Many implementors
+/// throughout [`ark_std::io`] take and provide types which implement the `Read`
+/// trait.
+///
+/// Please note that each call to [`read()`] may involve a system call, and
+/// therefore, using something that implements [`BufRead`], such as
+/// [`BufReader`], will be more efficient.
+///
+///
+/// Read from [`&str`] because [`&[u8]`][slice] implements `Read`:
+///
+/// ```no_run
+/// # use ark_std::io;
+/// use ark_std::io::prelude::*;
+///
+/// fn main() -> Result<()> {
+///     let mut b = "This string will be read".as_bytes();
+///     let mut buffer = [0; 10];
+///
+///     // read up to 10 bytes
+///     b.read(&mut buffer)?;
+///
+///     Ok(())
+/// }
+/// ```
+///
+/// [`read()`]: trait.Read.html#tymethod.read
+/// [`ark_std::io`]: ../../std/io/index.html
+/// [`BufRead`]: trait.BufRead.html
+/// [`BufReader`]: struct.BufReader.html
+/// [`&str`]: ../../std/primitive.str.html
+/// [slice]: ../../std/primitive.slice.html
+pub trait Read {
+    /// Pull some bytes from this source into the specified buffer, returning
+    /// how many bytes were read.
+    ///
+    /// This function does not provide any guarantees about whether it blocks
+    /// waiting for data, but if an object needs to block for a read but cannot
+    /// it will typically signal this via an [`Err`] return value.
+    ///
+    /// If the return value of this method is [`Ok(n)`], then it must be
+    /// guaranteed that `0 <= n <= buf.len()`. A nonzero `n` value indicates
+    /// that the buffer `buf` has been filled in with `n` bytes of data from this
+    /// source. If `n` is `0`, then it can indicate that the the buffer
+    /// specified was 0 bytes in length.
+    ///
+    /// No guarantees are provided about the contents of `buf` when this
+    /// function is called, implementations cannot rely on any property of the
+    /// contents of `buf` being true. It is recommended that implementations
+    /// only write data to `buf` instead of reading its contents.
+    ///
+    /// # Errors
+    ///
+    /// If this function encounters any form of I/O or other error, an error
+    /// variant will be returned. If an error is returned then it must be
+    /// guaranteed that no bytes were read.
+    ///
+    /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the read
+    /// operation should be retried if there is nothing else to do.
+    ///
+    fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
+
+    /// Read the exact number of bytes required to fill `buf`.
+    ///
+    /// This function reads as many bytes as necessary to completely fill the
+    /// specified buffer `buf`.
+    ///
+    /// No guarantees are provided about the contents of `buf` when this
+    /// function is called, implementations cannot rely on any property of the
+    /// contents of `buf` being true. It is recommended that implementations
+    /// only write data to `buf` instead of reading its contents.
+    ///
+    /// # Errors
+    ///
+    /// If this function encounters an error of the kind
+    /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
+    /// will continue.
+    ///
+    /// If any other read error is encountered then this function immediately
+    /// returns. The contents of `buf` are unspecified in this case.
+    ///
+    /// If this function returns an error, it is unspecified how many bytes it
+    /// has read, but it will never read more than would be necessary to
+    /// completely fill the buffer.
+    fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> {
+        while !buf.is_empty() {
+            match self.read(buf) {
+                Ok(0) => break,
+                Ok(n) => {
+                    let tmp = buf;
+                    buf = &mut tmp[n..];
+                }
+                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        if !buf.is_empty() {
+            Err(Error::new(
+                ErrorKind::UnexpectedEof,
+                "failed to fill whole buffer",
+            ))
+        } else {
+            Ok(())
+        }
+    }
+
+    /// Creates a "by reference" adaptor for this instance of `Read`.
+    ///
+    /// The returned adaptor also implements `Read` and will simply borrow this
+    /// current reader.
+    fn by_ref(&mut self) -> &mut Self
+    where
+        Self: Sized,
+    {
+        self
+    }
+}
+
+pub trait Write {
+    /// Write a buffer into this writer, returning how many bytes were written.
+    ///
+    /// This function will attempt to write the entire contents of `buf`, but
+    /// the entire write may not succeed, or the write may also generate an
+    /// error. A call to `write` represents *at most one* attempt to write to
+    /// any wrapped object.
+    ///
+    /// Calls to `write` are not guaranteed to block waiting for data to be
+    /// written, and a write which would otherwise block can be indicated through
+    /// an [`Err`] variant.
+    ///
+    /// If the return value is [`Ok(n)`] then it must be guaranteed that
+    /// `0 <= n <= buf.len()`. A return value of `0` typically means that the
+    /// underlying object is no longer able to accept bytes and will likely not
+    /// be able to in the future as well, or that the buffer provided is empty.
+    ///
+    /// # Errors
+    ///
+    /// Each call to `write` may generate an I/O error indicating that the
+    /// operation could not be completed. If an error is returned then no bytes
+    /// in the buffer were written to this writer.
+    ///
+    /// It is **not** considered an error if the entire buffer could not be
+    /// written to this writer.
+    ///
+    /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the
+    /// write operation should be retried if there is nothing else to do.
+    ///
+    /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+    /// [`Ok(n)`]:  ../../std/result/enum.Result.html#variant.Ok
+    /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+    fn write(&mut self, buf: &[u8]) -> Result<usize>;
+
+    /// Flush this output stream, ensuring that all intermediately buffered
+    /// contents reach their destination.
+    ///
+    /// # Errors
+    ///
+    /// It is considered an error if not all bytes could be written due to
+    /// I/O errors or EOF being reached.
+    ///
+    fn flush(&mut self) -> Result<()>;
+
+    /// Attempts to write an entire buffer into this writer.
+    ///
+    /// This method will continuously call [`write`] until there is no more data
+    /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
+    /// returned. This method will not return until the entire buffer has been
+    /// successfully written or such an error occurs. The first error that is
+    /// not of [`ErrorKind::Interrupted`] kind generated from this method will be
+    /// returned.
+    ///
+    /// # Errors
+    ///
+    /// This function will return the first error of
+    /// non-[`ErrorKind::Interrupted`] kind that [`write`] returns.
+    ///
+    /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+    /// [`write`]: #tymethod.write
+    fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
+        while !buf.is_empty() {
+            match self.write(buf) {
+                Ok(0) => {
+                    return Err(Error::new(
+                        ErrorKind::WriteZero,
+                        "failed to write whole buffer",
+                    ))
+                }
+                Ok(n) => buf = &buf[n..],
+                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        Ok(())
+    }
+
+    /// Creates a "by reference" adaptor for this instance of `Write`.
+    ///
+    /// The returned adaptor also implements `Write` and will simply borrow this
+    /// current writer.
+    fn by_ref(&mut self) -> &mut Self
+    where
+        Self: Sized,
+    {
+        self
+    }
+}
+
+impl<R: Read + ?Sized> Read for &mut R {
+    #[inline]
+    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
+        (**self).read(buf)
+    }
+
+    #[inline]
+    fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
+        (**self).read_exact(buf)
+    }
+}
+
+impl Read for &[u8] {
+    #[inline]
+    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
+        let amt = cmp::min(buf.len(), self.len());
+        let (a, b) = self.split_at(amt);
+
+        // First check if the amount of bytes we want to read is small:
+        // `copy_from_slice` will generally expand to a call to `memcpy`, and
+        // for a single byte the overhead is significant.
+        if amt == 1 {
+            buf[0] = a[0];
+        } else {
+            buf[..amt].copy_from_slice(a);
+        }
+
+        *self = b;
+        Ok(amt)
+    }
+
+    #[inline]
+    fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
+        if buf.len() > self.len() {
+            return Err(Error::new(
+                ErrorKind::UnexpectedEof,
+                "failed to fill whole buffer",
+            ));
+        }
+        let (a, b) = self.split_at(buf.len());
+
+        // First check if the amount of bytes we want to read is small:
+        // `copy_from_slice` will generally expand to a call to `memcpy`, and
+        // for a single byte the overhead is significant.
+        if buf.len() == 1 {
+            buf[0] = a[0];
+        } else {
+            buf.copy_from_slice(a);
+        }
+
+        *self = b;
+        Ok(())
+    }
+}
+
+impl<W: Write + ?Sized> Write for &mut W {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> Result<usize> {
+        (**self).write(buf)
+    }
+
+    #[inline]
+    fn flush(&mut self) -> Result<()> {
+        (**self).flush()
+    }
+
+    #[inline]
+    fn write_all(&mut self, buf: &[u8]) -> Result<()> {
+        (**self).write_all(buf)
+    }
+}
+
+impl Write for &mut [u8] {
+    fn write(&mut self, data: &[u8]) -> Result<usize> {
+        let amt = cmp::min(data.len(), self.len());
+        let (a, b) = mem::replace(self, &mut []).split_at_mut(amt);
+        a.copy_from_slice(&data[..amt]);
+        *self = b;
+        Ok(amt)
+    }
+
+    #[inline]
+    fn write_all(&mut self, data: &[u8]) -> Result<()> {
+        if self.write(data)? == data.len() {
+            Ok(())
+        } else {
+            Err(Error::new(
+                ErrorKind::WriteZero,
+                "failed to write whole buffer",
+            ))
+        }
+    }
+
+    #[inline]
+    fn flush(&mut self) -> Result<()> {
+        Ok(())
+    }
+}
+
+impl Write for Vec<u8> {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> Result<usize> {
+        self.extend_from_slice(buf);
+        Ok(buf.len())
+    }
+
+    #[inline]
+    fn write_all(&mut self, buf: &[u8]) -> Result<()> {
+        self.extend_from_slice(buf);
+        Ok(())
+    }
+
+    #[inline]
+    fn flush(&mut self) -> Result<()> {
+        Ok(())
+    }
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+/// This data structure is used as a workaround for current design of `ToBytes`
+/// which does not allow multiple writes to `&mut [u8]`.
+pub struct Cursor<T> {
+    inner: T,
+    pos: u64,
+}
+
+impl<T> Cursor<T> {
+    /// Creates a new cursor wrapping the provided underlying in-memory buffer.
+    ///
+    /// Cursor initial position is `0` even if underlying buffer (e.g., `Vec`)
+    /// is not empty. So writing to cursor starts with overwriting `Vec`
+    /// content, not with appending to it.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use ark_std::io::Cursor;
+    ///
+    /// let buff = Cursor::new(Vec::new());
+    /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+    /// # force_inference(&buff);
+    /// ```
+    pub fn new(inner: T) -> Self {
+        Cursor { inner, pos: 0 }
+    }
+
+    /// Consumes this cursor, returning the underlying value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use ark_std::io::Cursor;
+    ///
+    /// let buff = Cursor::new(Vec::new());
+    /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+    /// # force_inference(&buff);
+    ///
+    /// let vec = buff.into_inner();
+    /// ```
+    pub fn into_inner(self) -> T {
+        self.inner
+    }
+
+    /// Gets a reference to the underlying value in this cursor.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use ark_std::io::Cursor;
+    ///
+    /// let buff = Cursor::new(Vec::new());
+    /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+    /// # force_inference(&buff);
+    ///
+    /// let reference = buff.get_ref();
+    /// ```
+    pub fn get_ref(&self) -> &T {
+        &self.inner
+    }
+
+    /// Gets a mutable reference to the underlying value in this cursor.
+    ///
+    /// Care should be taken to avoid modifying the internal I/O state of the
+    /// underlying value as it may corrupt this cursor's position.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use ark_std::io::Cursor;
+    ///
+    /// let mut buff = Cursor::new(Vec::new());
+    /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+    /// # force_inference(&buff);
+    ///
+    /// let reference = buff.get_mut();
+    /// ```
+    pub fn get_mut(&mut self) -> &mut T {
+        &mut self.inner
+    }
+
+    /// Returns the current position of this cursor.
+    pub fn position(&self) -> u64 {
+        self.pos
+    }
+
+    /// Sets the position of this cursor.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use ark_std::io::Cursor;
+    ///
+    /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
+    ///
+    /// assert_eq!(buff.position(), 0);
+    ///
+    /// buff.set_position(2);
+    /// assert_eq!(buff.position(), 2);
+    ///
+    /// buff.set_position(4);
+    /// assert_eq!(buff.position(), 4);
+    /// ```
+    pub fn set_position(&mut self, pos: u64) {
+        self.pos = pos;
+    }
+}
+
+impl<T> Read for Cursor<T>
+where
+    T: AsRef<[u8]>,
+{
+    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
+        let n = Read::read(&mut self.get_buf()?, buf)?;
+        self.pos += n as u64;
+        Ok(n)
+    }
+
+    fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
+        let n = buf.len();
+        Read::read_exact(&mut self.get_buf()?, buf)?;
+        self.pos += n as u64;
+        Ok(())
+    }
+}
+
+impl<T> Cursor<T>
+where
+    T: AsRef<[u8]>,
+{
+    fn get_buf(&mut self) -> Result<&[u8]> {
+        let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64);
+        Ok(&self.inner.as_ref()[(amt as usize)..])
+    }
+}
+
+impl Write for Cursor<&mut [u8]> {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> Result<usize> {
+        slice_write(&mut self.pos, self.inner, buf)
+    }
+
+    #[inline]
+    fn flush(&mut self) -> Result<()> {
+        Ok(())
+    }
+}
+
+impl Write for Cursor<Vec<u8>> {
+    fn write(&mut self, buf: &[u8]) -> Result<usize> {
+        vec_write(&mut self.pos, &mut self.inner, buf)
+    }
+
+    #[inline]
+    fn flush(&mut self) -> Result<()> {
+        Ok(())
+    }
+}
+
+// Non-resizing write implementation
+#[inline]
+fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> Result<usize> {
+    let pos = cmp::min(*pos_mut, slice.len() as u64);
+    let amt = (&mut slice[(pos as usize)..]).write(buf)?;
+    *pos_mut += amt as u64;
+    Ok(amt)
+}
+
+fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> Result<usize> {
+    let pos: usize = (*pos_mut).try_into().map_err(|_| {
+        Error::new(
+            ErrorKind::InvalidInput,
+            "cursor position exceeds maximum possible vector length",
+        )
+    })?;
+    // Make sure the internal buffer is as least as big as where we
+    // currently are
+    let len = vec.len();
+    if len < pos {
+        // use `resize` so that the zero filling is as efficient as possible
+        vec.resize(pos, 0);
+    }
+    // Figure out what bytes will be used to overwrite what's currently
+    // there (left), and what will be appended on the end (right)
+    {
+        let space = vec.len() - pos;
+        let (left, right) = buf.split_at(cmp::min(space, buf.len()));
+        vec[pos..pos + left.len()].copy_from_slice(left);
+        vec.extend_from_slice(right);
+    }
+
+    // Bump us forward
+    *pos_mut = (pos + buf.len()) as u64;
+    Ok(buf.len())
+}
diff --git a/std/src/lib.rs b/std/src/lib.rs
index 6b16572..8eaa693 100644
--- a/std/src/lib.rs
+++ b/std/src/lib.rs
@@ -12,27 +12,26 @@ pub use core::*;
 
 #[cfg(not(feature = "std"))]
 pub mod fmt {
-    pub use core::fmt::*;
     pub use alloc::fmt::*;
-
+    pub use core::fmt::*;
 }
 
 #[cfg(not(feature = "std"))]
 pub mod borrow {
-    pub use core::borrow::*;
     pub use alloc::borrow::*;
+    pub use core::borrow::*;
 }
 
 #[cfg(not(feature = "std"))]
 pub mod slice {
-    pub use core::slice::*;
     pub use alloc::slice::*;
+    pub use core::slice::*;
 }
 
 #[cfg(not(feature = "std"))]
 pub mod str {
-    pub use core::str::*;
     pub use alloc::str::*;
+    pub use core::str::*;
 }
 
 #[cfg(not(feature = "std"))]