From 1e448dec2124c74d2014440dc53e9075bca8482e Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Sat, 22 Apr 2023 04:38:47 -0400 Subject: [PATCH] Add no_std support to transcript, dalek-ff-group, ed448, ciphersuite, multiexp, schnorr, and monero-generators transcript, dalek-ff-group, ed449, and ciphersuite are all usable with no_std alone. The rest additionally require alloc. Part of #279. --- .github/workflows/no-std.yml | 21 +++++++ Cargo.lock | 25 +++++++- Cargo.toml | 3 + coins/monero/generators/Cargo.toml | 15 +++-- coins/monero/generators/README.md | 2 + coins/monero/generators/src/lib.rs | 11 ++-- coins/monero/generators/src/varint.rs | 2 +- common/std-shims/Cargo.toml | 20 +++++++ common/std-shims/LICENSE | 21 +++++++ common/std-shims/README.md | 6 ++ common/std-shims/src/collections.rs | 7 +++ common/std-shims/src/io.rs | 85 +++++++++++++++++++++++++++ common/std-shims/src/lib.rs | 24 ++++++++ crypto/ciphersuite/Cargo.toml | 29 +++++---- crypto/ciphersuite/README.md | 3 + crypto/ciphersuite/src/ed448.rs | 3 +- crypto/ciphersuite/src/lib.md | 3 + crypto/ciphersuite/src/lib.rs | 12 ++-- crypto/dalek-ff-group/Cargo.toml | 20 ++++--- crypto/dalek-ff-group/README.md | 2 + crypto/ed448/Cargo.toml | 18 +++--- crypto/ed448/src/lib.rs | 2 +- crypto/ed448/src/point.rs | 22 +++++-- crypto/multiexp/Cargo.toml | 16 +++-- crypto/multiexp/README.md | 6 +- crypto/multiexp/src/batch.rs | 2 + crypto/multiexp/src/lib.rs | 5 ++ crypto/multiexp/src/straus.rs | 2 + crypto/schnorr/Cargo.toml | 18 ++++-- crypto/schnorr/README.md | 3 + crypto/schnorr/src/aggregate.rs | 5 +- crypto/schnorr/src/lib.rs | 9 ++- crypto/transcript/Cargo.toml | 14 ++--- crypto/transcript/README.md | 2 + tests/no-std/Cargo.toml | 33 +++++++++++ tests/no-std/LICENSE | 21 +++++++ tests/no-std/README.md | 3 + tests/no-std/src/lib.rs | 26 ++++++++ 38 files changed, 445 insertions(+), 76 deletions(-) create mode 100644 .github/workflows/no-std.yml create mode 100644 common/std-shims/Cargo.toml create mode 100644 common/std-shims/LICENSE create mode 100644 common/std-shims/README.md create mode 100644 common/std-shims/src/collections.rs create mode 100644 common/std-shims/src/io.rs create mode 100644 common/std-shims/src/lib.rs create mode 100644 tests/no-std/Cargo.toml create mode 100644 tests/no-std/LICENSE create mode 100644 tests/no-std/README.md create mode 100644 tests/no-std/src/lib.rs diff --git a/.github/workflows/no-std.yml b/.github/workflows/no-std.yml new file mode 100644 index 00000000..edf7fcd7 --- /dev/null +++ b/.github/workflows/no-std.yml @@ -0,0 +1,21 @@ +name: Tests + +on: + push: + branches: + - develop + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Build Dependencies + uses: ./.github/actions/build-dependencies + with: + github-token: ${{ inputs.github-token }} + + - name: Verify no-std builds + run: cd tests/no-std && cargo build --target wasm32-unknown-unknown diff --git a/Cargo.lock b/Cargo.lock index 3ac9b224..61b105c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1067,6 +1067,7 @@ dependencies = [ "rand_core 0.6.4", "sha2 0.10.6", "sha3", + "std-shims", "subtle", "zeroize", ] @@ -5099,7 +5100,6 @@ dependencies = [ "generic-array", "group 0.13.0", "hex", - "lazy_static", "rand_core 0.6.4", "rustversion", "subtle", @@ -5219,6 +5219,7 @@ dependencies = [ "group 0.13.0", "lazy_static", "sha3", + "std-shims", "subtle", ] @@ -5335,6 +5336,7 @@ dependencies = [ "k256", "rand_core 0.6.4", "rustversion", + "std-shims", "zeroize", ] @@ -8571,6 +8573,7 @@ dependencies = [ "multiexp", "rand_core 0.6.4", "sha2 0.10.6", + "std-shims", "zeroize", ] @@ -8798,6 +8801,19 @@ dependencies = [ name = "serai-db" version = "0.1.0" +[[package]] +name = "serai-no-std" +version = "0.1.0" +dependencies = [ + "ciphersuite", + "dalek-ff-group", + "flexible-transcript", + "minimal-ed448", + "monero-generators", + "multiexp", + "schnorr-signatures", +] + [[package]] name = "serai-node" version = "0.1.0" @@ -9905,6 +9921,13 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "std-shims" +version = "0.1.0" +dependencies = [ + "hashbrown 0.13.2", +] + [[package]] name = "string_cache" version = "0.8.7" diff --git a/Cargo.toml b/Cargo.toml index 4fcfa1f7..614426d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = [ + "common/std-shims", "common/zalloc", "common/db", @@ -43,6 +44,8 @@ members = [ "substrate/runtime", "substrate/node", + + "tests/no-std", ] # Always compile Monero (and a variety of dependencies) with optimizations due diff --git a/coins/monero/generators/Cargo.toml b/coins/monero/generators/Cargo.toml index 089acffb..9f646d73 100644 --- a/coins/monero/generators/Cargo.toml +++ b/coins/monero/generators/Cargo.toml @@ -12,13 +12,20 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [dependencies] +std-shims = { path = "../../../common/std-shims", version = "0.1", default-features = false } + lazy_static = "1" -subtle = "^2.4" +subtle = { version = "^2.4", default-features = false } -sha3 = "0.10" +sha3 = { version = "0.10", default-features = false } -curve25519-dalek = { version = "3", features = ["std"] } +curve25519-dalek = { version = "3", default-features = false } -group = "0.13" +group = { version = "0.13", default-features = false } dalek-ff-group = { path = "../../../crypto/dalek-ff-group", version = "0.3" } + +[features] +alloc = ["lazy_static/spin_no_std"] +std = ["std-shims/std"] +default = ["std"] diff --git a/coins/monero/generators/README.md b/coins/monero/generators/README.md index 5678f426..04941aa5 100644 --- a/coins/monero/generators/README.md +++ b/coins/monero/generators/README.md @@ -3,3 +3,5 @@ Generators used by Monero in both its Pedersen commitments and Bulletproofs(+). An implementation of Monero's `ge_fromfe_frombytes_vartime`, simply called `hash_to_point` here, is included, as needed to generate generators. + +This library is usable under no_std when the `alloc` feature is enabled. diff --git a/coins/monero/generators/src/lib.rs b/coins/monero/generators/src/lib.rs index 20a2740a..d3783e14 100644 --- a/coins/monero/generators/src/lib.rs +++ b/coins/monero/generators/src/lib.rs @@ -2,16 +2,15 @@ //! An implementation of Monero's `ge_fromfe_frombytes_vartime`, simply called //! `hash_to_point` here, is included, as needed to generate generators. +#![cfg_attr(not(feature = "std"), no_std)] + use lazy_static::lazy_static; use sha3::{Digest, Keccak256}; -use curve25519_dalek::{ - constants::ED25519_BASEPOINT_POINT, - edwards::{EdwardsPoint as DalekPoint, CompressedEdwardsY}, -}; +use curve25519_dalek::edwards::{EdwardsPoint as DalekPoint, CompressedEdwardsY}; -use group::Group; +use group::{Group, GroupEncoding}; use dalek_ff_group::EdwardsPoint; mod varint; @@ -27,7 +26,7 @@ fn hash(data: &[u8]) -> [u8; 32] { lazy_static! { /// Monero alternate generator `H`, used for amounts in Pedersen commitments. pub static ref H: DalekPoint = - CompressedEdwardsY(hash(&ED25519_BASEPOINT_POINT.compress().to_bytes())) + CompressedEdwardsY(hash(&EdwardsPoint::generator().to_bytes())) .decompress() .unwrap() .mul_by_cofactor(); diff --git a/coins/monero/generators/src/varint.rs b/coins/monero/generators/src/varint.rs index 632f658d..2e82816e 100644 --- a/coins/monero/generators/src/varint.rs +++ b/coins/monero/generators/src/varint.rs @@ -1,4 +1,4 @@ -use std::io::{self, Write}; +use std_shims::io::{self, Write}; const VARINT_CONTINUATION_MASK: u8 = 0b1000_0000; pub(crate) fn write_varint(varint: &u64, w: &mut W) -> io::Result<()> { diff --git a/common/std-shims/Cargo.toml b/common/std-shims/Cargo.toml new file mode 100644 index 00000000..a5c3a299 --- /dev/null +++ b/common/std-shims/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "std-shims" +version = "0.1.0" +description = "A series of std shims to make alloc more feasible" +license = "MIT" +repository = "https://github.com/serai-dex/serai/tree/develop/common/std-shims" +authors = ["Luke Parker "] +keywords = ["nostd", "no_std", "alloc", "io"] +edition = "2021" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +hashbrown = "0.13" + +[features] +std = [] +default = ["std"] diff --git a/common/std-shims/LICENSE b/common/std-shims/LICENSE new file mode 100644 index 00000000..e6bff13c --- /dev/null +++ b/common/std-shims/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Luke Parker + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/common/std-shims/README.md b/common/std-shims/README.md new file mode 100644 index 00000000..88f8eadd --- /dev/null +++ b/common/std-shims/README.md @@ -0,0 +1,6 @@ +# std shims + +A crate which passes through to std when the default `std` feature is enabled, +yet provides a series of shims when it isn't. + +`HashSet` and `HashMap` are provided via `hashbrown`. diff --git a/common/std-shims/src/collections.rs b/common/std-shims/src/collections.rs new file mode 100644 index 00000000..d3c74bad --- /dev/null +++ b/common/std-shims/src/collections.rs @@ -0,0 +1,7 @@ +#[cfg(feature = "std")] +pub use std::collections::*; + +#[cfg(not(feature = "std"))] +pub use alloc::collections::*; +#[cfg(not(feature = "std"))] +pub use hashbrown::{HashSet, HashMap}; diff --git a/common/std-shims/src/io.rs b/common/std-shims/src/io.rs new file mode 100644 index 00000000..ef98d1eb --- /dev/null +++ b/common/std-shims/src/io.rs @@ -0,0 +1,85 @@ +#[cfg(feature = "std")] +pub use std::io::*; + +#[cfg(not(feature = "std"))] +mod shims { + use core::fmt::{Debug, Formatter}; + use alloc::{boxed::Box, vec::Vec}; + + #[derive(Clone, Copy, PartialEq, Eq, Debug)] + pub enum ErrorKind { + UnexpectedEof, + Other, + } + + pub struct Error { + kind: ErrorKind, + error: Box, + } + + impl Debug for Error { + fn fmt(&self, fmt: &mut Formatter<'_>) -> core::result::Result<(), core::fmt::Error> { + fmt.debug_struct("Error").field("kind", &self.kind).finish_non_exhaustive() + } + } + + impl Error { + pub fn new(kind: ErrorKind, error: E) -> Error { + Error { kind, error: Box::new(error) } + } + + pub fn kind(&self) -> ErrorKind { + self.kind + } + + pub fn into_inner(self) -> Option> { + Some(self.error) + } + } + + pub type Result = core::result::Result; + + pub trait Read { + fn read(&mut self, buf: &mut [u8]) -> Result; + + fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> { + let read = self.read(buf)?; + if read != buf.len() { + Err(Error::new(ErrorKind::UnexpectedEof, "reader ran out of bytes"))?; + } + Ok(()) + } + } + + impl Read for &[u8] { + fn read(&mut self, buf: &mut [u8]) -> Result { + let mut read = 0; + if self.len() < buf.len() { + read = self.len(); + } + buf[.. read].copy_from_slice(&self[.. read]); + *self = &self[read ..]; + Ok(read) + } + } + + pub trait Write { + fn write(&mut self, buf: &[u8]) -> Result; + fn write_all(&mut self, buf: &[u8]) -> Result<()> { + if self.write(buf)? != buf.len() { + Err(Error::new(ErrorKind::UnexpectedEof, "writer ran out of bytes"))?; + } + Ok(()) + } + } + + impl Write for Vec { + fn write(&mut self, buf: &[u8]) -> Result { + self.extend(buf); + Ok(buf.len()) + } + } +} + +#[cfg(not(feature = "std"))] +pub use shims::*; diff --git a/common/std-shims/src/lib.rs b/common/std-shims/src/lib.rs new file mode 100644 index 00000000..e092e04d --- /dev/null +++ b/common/std-shims/src/lib.rs @@ -0,0 +1,24 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +#[allow(unused_imports)] +#[doc(hidden)] +#[macro_use] +pub extern crate alloc; + +pub mod collections; +pub mod io; + +pub mod str { + #[cfg(not(feature = "std"))] + pub use alloc::str::*; + #[cfg(feature = "std")] + pub use std::str::*; +} + +pub mod vec { + #[cfg(not(feature = "std"))] + pub use alloc::vec::*; + #[cfg(feature = "std")] + pub use std::vec::*; +} diff --git a/crypto/ciphersuite/Cargo.toml b/crypto/ciphersuite/Cargo.toml index 293b9830..91cd67b2 100644 --- a/crypto/ciphersuite/Cargo.toml +++ b/crypto/ciphersuite/Cargo.toml @@ -13,34 +13,39 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [dependencies] -rand_core = "0.6" +std-shims = { path = "../../common/std-shims", version = "0.1", default-features = false, optional = true } -zeroize = { version = "^1.5", features = ["zeroize_derive"] } -subtle = "^2.4" +rand_core = { version = "0.6", default-features = false } -digest = "0.10" +zeroize = { version = "^1.5", default-features = false } +subtle = { version = "^2.4", default-features = false } + +digest = { version = "0.10", default-features = false } transcript = { package = "flexible-transcript", path = "../transcript", version = "0.3" } -sha2 = { version = "0.10", optional = true } -sha3 = { version = "0.10", optional = true } +sha2 = { version = "0.10", default-features = false, optional = true } +sha3 = { version = "0.10", default-features = false, optional = true } -ff = { version = "0.13", features = ["bits"] } -group = "0.13" +ff = { version = "0.13", default-features = false, features = ["bits"] } +group = { version = "0.13", default-features = false } dalek-ff-group = { path = "../dalek-ff-group", version = "0.3", optional = true } -elliptic-curve = { version = "0.13", features = ["hash2curve"], optional = true } -p256 = { version = "^0.13.1", default-features = false, features = ["std", "arithmetic", "bits", "hash2curve"], optional = true } -k256 = { version = "^0.13.1", default-features = false, features = ["std", "arithmetic", "bits", "hash2curve"], optional = true } +elliptic-curve = { version = "0.13", default-features = false, features = ["hash2curve"], optional = true } +p256 = { version = "^0.13.1", default-features = false, features = ["arithmetic", "bits", "hash2curve"], optional = true } +k256 = { version = "^0.13.1", default-features = false, features = ["arithmetic", "bits", "hash2curve"], optional = true } minimal-ed448 = { path = "../ed448", version = "0.3", optional = true } [dev-dependencies] hex = "0.4" +rand_core = { version = "0.6", features = ["std"] } + ff-group-tests = { version = "0.13", path = "../ff-group-tests" } [features] -std = [] +alloc = ["std-shims"] +std = ["std-shims/std"] dalek = ["sha2", "dalek-ff-group"] ed25519 = ["dalek"] diff --git a/crypto/ciphersuite/README.md b/crypto/ciphersuite/README.md index 6af02ff4..bec62c18 100644 --- a/crypto/ciphersuite/README.md +++ b/crypto/ciphersuite/README.md @@ -8,6 +8,9 @@ culminating in commit [669d2dbffc1dafb82a09d9419ea182667115df06](https://github.com/serai-dex/serai/tree/669d2dbffc1dafb82a09d9419ea182667115df06). Any subsequent changes have not undergone auditing. +This library is usable under no_std. The `alloc` and `std` features enable +reading from the `io::Read` trait, shimmed by `std-shims` under `alloc`. + ### Secp256k1/P-256 Secp256k1 and P-256 are offered via [k256](https://crates.io/crates/k256) and diff --git a/crypto/ciphersuite/src/ed448.rs b/crypto/ciphersuite/src/ed448.rs index 6b36fb11..1c616ec4 100644 --- a/crypto/ciphersuite/src/ed448.rs +++ b/crypto/ciphersuite/src/ed448.rs @@ -75,8 +75,7 @@ impl Ciphersuite for Ed448 { fn test_ed448() { use ff::PrimeField; - // TODO: Enable once ed448 passes these tests - //ff_group_tests::group::test_prime_group_bits::(); + ff_group_tests::group::test_prime_group_bits::<_, Point>(&mut rand_core::OsRng); // Ideally, a test vector from RFC-8032 (not FROST) would be here // Unfortunately, the IETF draft doesn't provide any vectors for the derived challenges diff --git a/crypto/ciphersuite/src/lib.md b/crypto/ciphersuite/src/lib.md index 75eb2be9..9c6a5b4a 100644 --- a/crypto/ciphersuite/src/lib.md +++ b/crypto/ciphersuite/src/lib.md @@ -7,3 +7,6 @@ This library, except for the not recommended Ed448 ciphersuite, was culminating in commit [669d2dbffc1dafb82a09d9419ea182667115df06](https://github.com/serai-dex/serai/tree/669d2dbffc1dafb82a09d9419ea182667115df06). Any subsequent changes have not undergone auditing. + +This library is usable under no_std. The `alloc` and `std` features enable +reading from the `io::Read` trait, shimmed by `std-shims` under `alloc`. diff --git a/crypto/ciphersuite/src/lib.rs b/crypto/ciphersuite/src/lib.rs index 97ed2a7c..18ce1290 100644 --- a/crypto/ciphersuite/src/lib.rs +++ b/crypto/ciphersuite/src/lib.rs @@ -1,10 +1,10 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] -#![cfg_attr(not(feature = "std"), no_std)] #![doc = include_str!("lib.md")] +#![cfg_attr(not(feature = "std"), no_std)] use core::fmt::Debug; -#[cfg(feature = "std")] -use std::io::{self, Read}; +#[cfg(any(feature = "alloc", feature = "std"))] +use std_shims::io::{self, Read}; use rand_core::{RngCore, CryptoRng}; @@ -20,7 +20,7 @@ use group::{ Group, GroupOps, prime::PrimeGroup, }; -#[cfg(feature = "std")] +#[cfg(any(feature = "alloc", feature = "std"))] use group::GroupEncoding; #[cfg(feature = "dalek")] @@ -85,7 +85,7 @@ pub trait Ciphersuite: } /// Read a canonical scalar from something implementing std::io::Read. - #[cfg(feature = "std")] + #[cfg(any(feature = "alloc", feature = "std"))] #[allow(non_snake_case)] fn read_F(reader: &mut R) -> io::Result { let mut encoding = ::Repr::default(); @@ -99,7 +99,7 @@ pub trait Ciphersuite: } /// Read a canonical point from something implementing std::io::Read. - #[cfg(feature = "std")] + #[cfg(any(feature = "alloc", feature = "std"))] #[allow(non_snake_case)] fn read_G(reader: &mut R) -> io::Result { let mut encoding = ::Repr::default(); diff --git a/crypto/dalek-ff-group/Cargo.toml b/crypto/dalek-ff-group/Cargo.toml index 7f2517be..c4aaa7e4 100644 --- a/crypto/dalek-ff-group/Cargo.toml +++ b/crypto/dalek-ff-group/Cargo.toml @@ -15,20 +15,22 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] rustversion = "1" -zeroize = { version = "^1.5", features = ["zeroize_derive"] } -subtle = "^2.4" +zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] } +subtle = { version = "^2.4", default-features = false } -rand_core = "0.6" +rand_core = { version = "0.6", default-features = false } -digest = "0.10" +digest = { version = "0.10", default-features = false } -ff = "0.13" -group = "0.13" +ff = { version = "0.13", default-features = false, features = ["bits"] } +group = { version = "0.13", default-features = false } -crypto-bigint = "0.5" +crypto-bigint = { version = "0.5", default-features = false } -sha2 = "0.9" -curve25519-dalek = "^3.2" +sha2 = { version = "0.9", default-features = false } +# The default features are ["std", "u64_backend"] +curve25519-dalek = { version = "^3.2", default-features = false, features = ["alloc", "u64_backend"] } [dev-dependencies] +rand_core = { version = "0.6", features = ["std"] } ff-group-tests = { path = "../ff-group-tests" } diff --git a/crypto/dalek-ff-group/README.md b/crypto/dalek-ff-group/README.md index 631ad617..06b7bb3c 100644 --- a/crypto/dalek-ff-group/README.md +++ b/crypto/dalek-ff-group/README.md @@ -8,3 +8,5 @@ This library was culminating in commit [669d2dbffc1dafb82a09d9419ea182667115df06](https://github.com/serai-dex/serai/tree/669d2dbffc1dafb82a09d9419ea182667115df06). Any subsequent changes have not undergone auditing. + +This library is usable under no_std. diff --git a/crypto/ed448/Cargo.toml b/crypto/ed448/Cargo.toml index 779eddec..17f42c01 100644 --- a/crypto/ed448/Cargo.toml +++ b/crypto/ed448/Cargo.toml @@ -15,20 +15,20 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] rustversion = "1" -lazy_static = "1" +rand_core = { version = "0.6", default-features = false } -rand_core = "0.6" +zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] } +subtle = { version = "^2.4", default-features = false } -zeroize = { version = "^1.5", features = ["zeroize_derive"] } -subtle = "^2.4" +ff = { version = "0.13", default-features = false, features = ["bits"] } +group = { version = "0.13", default-features = false } -ff = "0.13" -group = "0.13" - -generic-array = "0.14" -crypto-bigint = { version = "0.5", features = ["zeroize"] } +generic-array = { version = "0.14", default-features = false } +crypto-bigint = { version = "0.5", default-features = false, features = ["zeroize"] } [dev-dependencies] hex = "0.4" +rand_core = { version = "0.6", features = ["std"] } + ff-group-tests = { path = "../ff-group-tests" } diff --git a/crypto/ed448/src/lib.rs b/crypto/ed448/src/lib.rs index ea315053..e596d399 100644 --- a/crypto/ed448/src/lib.rs +++ b/crypto/ed448/src/lib.rs @@ -1,6 +1,6 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] -#![no_std] #![doc = include_str!("../README.md")] +#![no_std] #[macro_use] mod backend; diff --git a/crypto/ed448/src/point.rs b/crypto/ed448/src/point.rs index a2ac08e2..d67196c9 100644 --- a/crypto/ed448/src/point.rs +++ b/crypto/ed448/src/point.rs @@ -3,8 +3,6 @@ use core::{ iter::Sum, }; -use lazy_static::lazy_static; - use rand_core::RngCore; use zeroize::Zeroize; @@ -34,6 +32,13 @@ const G_Y: FieldElement = FieldElement(Residue::new(&U512::from_be_hex(concat!( "05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14", )))); +const G_X: FieldElement = FieldElement(Residue::new(&U512::from_be_hex(concat!( + "00000000000000", + "00", + "4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324", + "a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e", +)))); + fn recover_x(y: FieldElement) -> CtOption { let ysq = y.square(); #[allow(non_snake_case)] @@ -56,9 +61,7 @@ pub struct Point { z: FieldElement, } -lazy_static! { - static ref G: Point = Point { x: recover_x(G_Y).unwrap(), y: G_Y, z: FieldElement::ONE }; -} +const G: Point = Point { x: G_X, y: G_Y, z: FieldElement::ONE }; impl ConstantTimeEq for Point { fn ct_eq(&self, other: &Self) -> Choice { @@ -184,7 +187,7 @@ impl Group for Point { Point { x: FieldElement::ZERO, y: FieldElement::ONE, z: FieldElement::ONE } } fn generator() -> Self { - *G + G } fn is_identity(&self) -> Choice { self.ct_eq(&Self::identity()) @@ -321,6 +324,13 @@ fn test_group() { ff_group_tests::group::test_prime_group_bits::<_, Point>(&mut rand_core::OsRng); } +#[test] +fn generator() { + assert!(G.x == G_X); + assert!(G.y == G_Y); + assert!(recover_x(G.y).unwrap() == G.x); +} + #[test] fn torsion() { use generic_array::GenericArray; diff --git a/crypto/multiexp/Cargo.toml b/crypto/multiexp/Cargo.toml index 6f19542d..b26969f6 100644 --- a/crypto/multiexp/Cargo.toml +++ b/crypto/multiexp/Cargo.toml @@ -15,18 +15,24 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] rustversion = "1" +std-shims = { path = "../../common/std-shims", version = "0.1", default-features = false } + zeroize = { version = "^1.5", features = ["zeroize_derive"] } -ff = "0.13" -group = "0.13" +ff = { version = "0.13", default-features = false, features = ["bits"] } +group = { version = "0.13", default-features = false } -rand_core = { version = "0.6", optional = true } +rand_core = { version = "0.6", default-features = false, optional = true } [dev-dependencies] -rand_core = "0.6" +rand_core = { version = "0.6", features = ["std"] } -k256 = { version = "^0.13.1", default-features = false, features = ["std", "arithmetic", "bits"] } +k256 = { version = "^0.13.1", default-features = false, features = ["arithmetic", "bits"] } dalek-ff-group = { path = "../dalek-ff-group" } [features] +std = ["std-shims/std"] + batch = ["rand_core"] + +default = ["std"] diff --git a/crypto/multiexp/README.md b/crypto/multiexp/README.md index b830c3fb..4ee3c56c 100644 --- a/crypto/multiexp/README.md +++ b/crypto/multiexp/README.md @@ -3,10 +3,14 @@ A multiexp implementation for ff/group implementing Straus and Pippenger. A batch verification API is also available via the "batch" feature, which enables secure multiexponentation batch verification given a series of values which -should sum to 0, identifying which doesn't via binary search if they don't. +should sum to the identity, identifying which doesn't via binary search if they +don't. This library was [audited by Cypher Stack in March 2023](https://github.com/serai-dex/serai/raw/e1bb2c191b7123fd260d008e31656d090d559d21/audits/Cypher%20Stack%20crypto%20March%202023/Audit.pdf), culminating in commit [669d2dbffc1dafb82a09d9419ea182667115df06](https://github.com/serai-dex/serai/tree/669d2dbffc1dafb82a09d9419ea182667115df06). Any subsequent changes have not undergone auditing. + +This library is usable under no_std, via alloc, when the default features are +disabled. diff --git a/crypto/multiexp/src/batch.rs b/crypto/multiexp/src/batch.rs index 7e6155ad..09c0ebce 100644 --- a/crypto/multiexp/src/batch.rs +++ b/crypto/multiexp/src/batch.rs @@ -1,3 +1,5 @@ +use std_shims::vec::Vec; + use rand_core::{RngCore, CryptoRng}; use zeroize::{Zeroize, Zeroizing}; diff --git a/crypto/multiexp/src/lib.rs b/crypto/multiexp/src/lib.rs index d5236e54..b660ebb7 100644 --- a/crypto/multiexp/src/lib.rs +++ b/crypto/multiexp/src/lib.rs @@ -1,7 +1,12 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc = include_str!("../README.md")] +#![cfg_attr(not(feature = "std"), no_std)] use core::ops::DerefMut; +#[cfg(not(feature = "std"))] +#[macro_use] +extern crate alloc; +use std_shims::vec::Vec; use zeroize::Zeroize; diff --git a/crypto/multiexp/src/straus.rs b/crypto/multiexp/src/straus.rs index e074d9f1..4eadd213 100644 --- a/crypto/multiexp/src/straus.rs +++ b/crypto/multiexp/src/straus.rs @@ -1,3 +1,5 @@ +use std_shims::vec::Vec; + use zeroize::Zeroize; use ff::PrimeFieldBits; diff --git a/crypto/schnorr/Cargo.toml b/crypto/schnorr/Cargo.toml index 07fa2487..4bb46c37 100644 --- a/crypto/schnorr/Cargo.toml +++ b/crypto/schnorr/Cargo.toml @@ -13,17 +13,27 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [dependencies] -rand_core = "0.6" +std-shims = { path = "../../common/std-shims", version = "0.1", default-features = false } + +rand_core = { version = "0.6", default-features = false } zeroize = { version = "^1.5", features = ["zeroize_derive"] } -transcript = { package = "flexible-transcript", path = "../transcript", version = "0.3" } +transcript = { package = "flexible-transcript", path = "../transcript", version = "0.3", default-features = false } -ciphersuite = { path = "../ciphersuite", version = "0.3" } -multiexp = { path = "../multiexp", version = "0.3", features = ["batch"] } +ciphersuite = { path = "../ciphersuite", version = "0.3", default-features = false, features = ["alloc"] } +multiexp = { path = "../multiexp", version = "0.3", default-features = false, features = ["batch"] } [dev-dependencies] hex = "0.4" + +rand_core = { version = "0.6", features = ["std"] } + sha2 = "0.10" + dalek-ff-group = { path = "../dalek-ff-group", version = "0.3" } ciphersuite = { path = "../ciphersuite", version = "0.3", features = ["ed25519"] } + +[features] +std = ["std-shims/std", "ciphersuite/std"] +default = ["std"] diff --git a/crypto/schnorr/README.md b/crypto/schnorr/README.md index baa0014d..e2c57cdc 100644 --- a/crypto/schnorr/README.md +++ b/crypto/schnorr/README.md @@ -14,3 +14,6 @@ This library was culminating in commit [669d2dbffc1dafb82a09d9419ea182667115df06](https://github.com/serai-dex/serai/tree/669d2dbffc1dafb82a09d9419ea182667115df06). Any subsequent changes have not undergone auditing. + +This library is usable under no_std, via alloc, when the default features are +disabled. diff --git a/crypto/schnorr/src/aggregate.rs b/crypto/schnorr/src/aggregate.rs index 2ec9170f..811e8aae 100644 --- a/crypto/schnorr/src/aggregate.rs +++ b/crypto/schnorr/src/aggregate.rs @@ -1,4 +1,7 @@ -use std::io::{self, Read, Write}; +use std_shims::{ + vec::Vec, + io::{self, Read, Write}, +}; use zeroize::Zeroize; diff --git a/crypto/schnorr/src/lib.rs b/crypto/schnorr/src/lib.rs index c7fd6278..77d033d0 100644 --- a/crypto/schnorr/src/lib.rs +++ b/crypto/schnorr/src/lib.rs @@ -1,8 +1,15 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc = include_str!("../README.md")] +#![cfg_attr(not(feature = "std"), no_std)] use core::ops::Deref; -use std::io::{self, Read, Write}; +#[cfg(not(feature = "std"))] +#[macro_use] +extern crate alloc; +use std_shims::{ + vec::Vec, + io::{self, Read, Write}, +}; use rand_core::{RngCore, CryptoRng}; diff --git a/crypto/transcript/Cargo.toml b/crypto/transcript/Cargo.toml index 601322db..a9db75ce 100644 --- a/crypto/transcript/Cargo.toml +++ b/crypto/transcript/Cargo.toml @@ -15,17 +15,17 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] rustversion = "1" -subtle = "^2.4" -zeroize = "^1.5" +subtle = { version = "^2.4", default-features = false } +zeroize = { version = "^1.5", default-features = false } -digest = "0.10" +digest = { version = "0.10", default-features = false, features = ["core-api"] } -blake2 = { version = "0.10", optional = true } -merlin = { version = "3", optional = true } +blake2 = { version = "0.10", default-features = false, optional = true } +merlin = { version = "3", default-features = false, optional = true } [dev-dependencies] -sha2 = "0.10" -blake2 = "0.10" +sha2 = { version = "0.10", default-features = false } +blake2 = { version = "0.10", default-features = false } [features] recommended = ["blake2"] diff --git a/crypto/transcript/README.md b/crypto/transcript/README.md index 3d9350cf..a8772a0a 100644 --- a/crypto/transcript/README.md +++ b/crypto/transcript/README.md @@ -31,3 +31,5 @@ This library was culminating in commit [669d2dbffc1dafb82a09d9419ea182667115df06](https://github.com/serai-dex/serai/tree/669d2dbffc1dafb82a09d9419ea182667115df06). Any subsequent changes have not undergone auditing. + +This library is usable under no_std. diff --git a/tests/no-std/Cargo.toml b/tests/no-std/Cargo.toml new file mode 100644 index 00000000..b85ccf0d --- /dev/null +++ b/tests/no-std/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "serai-no-std" +version = "0.1.0" +description = "A crate to test no-std builds of Serai crates work" +license = "MIT" +repository = "https://github.com/kayabaNerve/serai/tree/develop/common/std-shims" +authors = ["Luke Parker "] +keywords = ["nostd", "no_std", "alloc", "io"] +edition = "2021" +publish = false + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +flexible-transcript = { path = "../../crypto/transcript", features = ["recommended", "merlin"] } + +dalek-ff-group = { path = "../../crypto/dalek-ff-group" } +minimal-ed448 = { path = "../../crypto/ed448" } + +ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["alloc", "secp256k1", "p256", "ed25519", "ristretto", "ed448"] } + +multiexp = { path = "../../crypto/multiexp", default-features = false, features = ["batch"] } + +# dleq = { path = "../../crypto/dleq" } +schnorr-signatures = { path = "../../crypto/schnorr", default-features = false } + +# dkg = { path = "../../crypto/dkg" } +# modular-frost = { path = "../../crypto/frost" } +# frost-schnorrkel = { path = "../../crypto/schnorrkel" } + +monero-generators = { path = "../../coins/monero/generators", default-features = false, features = ["alloc"] } diff --git a/tests/no-std/LICENSE b/tests/no-std/LICENSE new file mode 100644 index 00000000..e6bff13c --- /dev/null +++ b/tests/no-std/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Luke Parker + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tests/no-std/README.md b/tests/no-std/README.md new file mode 100644 index 00000000..ac5e4e5d --- /dev/null +++ b/tests/no-std/README.md @@ -0,0 +1,3 @@ +# no-std tests + +A crate usable to test building various Serai crates in a no-std environment. diff --git a/tests/no-std/src/lib.rs b/tests/no-std/src/lib.rs new file mode 100644 index 00000000..6ff3e594 --- /dev/null +++ b/tests/no-std/src/lib.rs @@ -0,0 +1,26 @@ +#![no_std] + +pub use flexible_transcript::*; + +pub mod dalek { + pub use dalek_ff_group::*; +} +pub mod ed448 { + pub use minimal_ed448::*; +} + +pub use ciphersuite::*; + +pub use multiexp::*; + +// pub use dleq::*; +pub use schnorr_signatures::*; + +/* +pub use dkg::*; +pub use modular_frost::*; +pub use frost_schnorrkel::*; +*/ + +pub use monero_generators::*; +// pub use monero_serai::*;