use std::io; use curve25519_dalek::{ scalar::Scalar, edwards::{EdwardsPoint, CompressedEdwardsY}, }; pub const VARINT_CONTINUATION_MASK: u8 = 0b1000_0000; pub fn varint_len(varint: usize) -> usize { ((usize::try_from(usize::BITS - varint.leading_zeros()).unwrap().saturating_sub(1)) / 7) + 1 } pub fn write_byte(byte: &u8, w: &mut W) -> io::Result<()> { w.write_all(&[*byte]) } pub fn write_varint(varint: &u64, w: &mut W) -> io::Result<()> { let mut varint = *varint; while { let mut b = u8::try_from(varint & u64::from(!VARINT_CONTINUATION_MASK)).unwrap(); varint >>= 7; if varint != 0 { b |= VARINT_CONTINUATION_MASK; } write_byte(&b, w)?; varint != 0 } {} Ok(()) } pub fn write_scalar(scalar: &Scalar, w: &mut W) -> io::Result<()> { w.write_all(&scalar.to_bytes()) } pub fn write_point(point: &EdwardsPoint, w: &mut W) -> io::Result<()> { w.write_all(&point.compress().to_bytes()) } pub fn write_raw_vec io::Result<()>>( f: F, values: &[T], w: &mut W, ) -> io::Result<()> { for value in values { f(value, w)?; } Ok(()) } pub fn write_vec io::Result<()>>( f: F, values: &[T], w: &mut W, ) -> io::Result<()> { write_varint(&values.len().try_into().unwrap(), w)?; write_raw_vec(f, values, w) } pub fn read_bytes(r: &mut R) -> io::Result<[u8; N]> { let mut res = [0; N]; r.read_exact(&mut res)?; Ok(res) } pub fn read_byte(r: &mut R) -> io::Result { Ok(read_bytes::<_, 1>(r)?[0]) } pub fn read_u64(r: &mut R) -> io::Result { read_bytes(r).map(u64::from_le_bytes) } pub fn read_varint(r: &mut R) -> io::Result { let mut bits = 0; let mut res = 0; while { let b = read_byte(r)?; if (bits != 0) && (b == 0) { Err(io::Error::new(io::ErrorKind::Other, "non-canonical varint"))?; } if ((bits + 7) > 64) && (b >= (1 << (64 - bits))) { Err(io::Error::new(io::ErrorKind::Other, "varint overflow"))?; } res += u64::from(b & (!VARINT_CONTINUATION_MASK)) << bits; bits += 7; b & VARINT_CONTINUATION_MASK == VARINT_CONTINUATION_MASK } {} Ok(res) } // TODO: https://github.com/serai-dex/serai/issues/25 pub fn read_scalar(r: &mut R) -> io::Result { Scalar::from_canonical_bytes(read_bytes(r)?) .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "unreduced scalar")) } pub fn read_point(r: &mut R) -> io::Result { let bytes = read_bytes(r)?; CompressedEdwardsY(bytes) .decompress() // Ban torsioned points, and points which are either unreduced or -0 .filter(|point| point.is_torsion_free() && (point.compress().to_bytes() == bytes)) .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point")) } pub fn read_raw_vec io::Result>( f: F, len: usize, r: &mut R, ) -> io::Result> { let mut res = vec![]; for _ in 0 .. len { res.push(f(r)?); } Ok(res) } pub fn read_vec io::Result>( f: F, r: &mut R, ) -> io::Result> { read_raw_vec(f, read_varint(r)?.try_into().unwrap(), r) }