Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed

- Replace removed `CtOption::into_option` with `Option::from`
- Reject non-boolean values in `Choice` wrapper (`From<u8>` masks input, `Serializable::from_bytes` and rkyv `CheckBytes` reject values other than 0/1)

### Changed

Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ test: ## Run tests (std + no_std)
@cargo test --no-default-features

clippy: ## Run clippy
@cargo clippy --all-features -- -D warnings
@cargo clippy --all-features --features rkyv/size_32 -- -D warnings

fmt: ## Format code
@cargo +nightly fmt --all

check: ## Type-check
@cargo check --all-features
@cargo check --all-features --features rkyv/size_32

doc: ## Generate docs
@cargo doc --no-deps
Expand Down
112 changes: 101 additions & 11 deletions src/dusk/choice.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
use core::convert::Infallible;
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) DUSK NETWORK. All rights reserved.

use dusk_bytes::Serializable;
use dusk_bytes::{Error as BytesError, Serializable};
use subtle::ConditionallySelectable;

#[cfg(feature = "rkyv-impl")]
use bytecheck::CheckBytes;
#[cfg(feature = "rkyv-impl")]
use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};

/// Wrapper for a [`subtle::Choice`]
#[derive(Copy, Clone, Debug)]
#[cfg_attr(
feature = "rkyv-impl",
derive(Archive, RkyvSerialize, RkyvDeserialize),
archive_attr(derive(CheckBytes))
)]
#[cfg_attr(feature = "rkyv-impl", derive(Archive, RkyvSerialize, RkyvDeserialize))]
pub struct Choice(u8);

impl Choice {
Expand All @@ -30,12 +28,15 @@ impl ConditionallySelectable for Choice {
}

impl Serializable<1> for Choice {
type Error = Infallible;
type Error = BytesError;

fn from_bytes(buf: &[u8; Self::SIZE]) -> Result<Self, Self::Error>
where
Self: Sized,
{
if buf[0] > 1 {
return Err(BytesError::InvalidData);
}
Ok(Self(buf[0]))
}

Expand All @@ -46,7 +47,7 @@ impl Serializable<1> for Choice {

impl From<u8> for Choice {
fn from(int: u8) -> Self {
Self(int)
Self(int & 1)
}
}

Expand All @@ -73,3 +74,92 @@ impl From<Choice> for bool {
subtle::Choice::from(c.0).into()
}
}

#[cfg(feature = "rkyv-impl")]
const _: () = {
use bytecheck::CheckBytes;

impl<C: ?Sized> CheckBytes<C> for ArchivedChoice {
type Error = bytecheck::StructCheckError;

unsafe fn check_bytes<'a>(
value: *const Self,
_context: &mut C,
) -> Result<&'a Self, Self::Error> {
let byte = (*value).0;
if byte > 1 {
return Err(bytecheck::StructCheckError {
field_name: "0",
inner: bytecheck::ErrorBox::new(bytecheck::BoolCheckError {
invalid_value: byte,
}),
});
}
Ok(&*value)
}
}
};

#[cfg(test)]
mod tests {
use super::*;
use dusk_bytes::Serializable;

#[test]
fn from_u8_masks_input() {
assert_eq!(Choice::from(0u8).unwrap_u8(), 0);
assert_eq!(Choice::from(1u8).unwrap_u8(), 1);
assert_eq!(Choice::from(2u8).unwrap_u8(), 0);
assert_eq!(Choice::from(3u8).unwrap_u8(), 1);
assert_eq!(Choice::from(255u8).unwrap_u8(), 1);
}

#[test]
fn serializable_rejects_invalid() {
assert!(Choice::from_bytes(&[0]).is_ok());
assert!(Choice::from_bytes(&[1]).is_ok());
assert!(Choice::from_bytes(&[2]).is_err());
assert!(Choice::from_bytes(&[255]).is_err());
}

#[cfg(feature = "rkyv-impl")]
mod rkyv_tests {
use super::*;
use bytecheck::CheckBytes;
use rkyv::ser::serializers::AllocSerializer;
use rkyv::ser::Serializer;
use rkyv::{archived_root, Archived};

#[test]
fn rkyv_round_trip_valid() {
for val in [0u8, 1u8] {
let choice = Choice(val);
let mut serializer = AllocSerializer::<256>::default();
serializer
.serialize_value(&choice)
.expect("failed to serialize");
let bytes = serializer.into_serializer().into_inner();
let archived = unsafe { archived_root::<Choice>(&bytes) };
assert_eq!(archived.0, val);
// Validate via CheckBytes
let ptr = archived as *const Archived<Choice>;
let result =
unsafe { <Archived<Choice> as CheckBytes<()>>::check_bytes(ptr, &mut ()) };
assert!(result.is_ok());
}
}

#[test]
fn rkyv_rejects_invalid_choice() {
for invalid in [2u8, 128, 255] {
let ptr = &invalid as *const u8 as *const Archived<Choice>;
let result =
unsafe { <Archived<Choice> as CheckBytes<()>>::check_bytes(ptr, &mut ()) };
assert!(
result.is_err(),
"expected rkyv validation to reject byte {invalid}"
);
}
}
}
}
12 changes: 6 additions & 6 deletions src/dusk/multiscalar_mul.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,10 @@ fn to_radix_2w_size_hint(w: usize) -> usize {
debug_assert!(w <= 8);

let digits_count = match w {
6 => (256 + w - 1) / w,
7 => (256 + w - 1) / w,
6 => 256_usize.div_ceil(w),
7 => 256_usize.div_ceil(w),
// See comment in to_radix_2w on handling the terminal carry.
8 => (256 + w - 1) / w + 1,
8 => 256_usize.div_ceil(w) + 1,
_ => panic!("invalid radix parameter"),
};

Expand All @@ -140,8 +140,8 @@ fn to_radix_2w(scalar: &Scalar, w: usize) -> [i8; 43] {

let mut carry = 0u64;
let mut digits = [0i8; 43];
let digits_count = (256 + w - 1) / w;
for i in 0..digits_count {
let digits_count = 256_usize.div_ceil(w);
for (i, digit) in digits[..digits_count].iter_mut().enumerate() {
// Construct a buffer of bits of the scalar, starting at `bit_offset`.
let bit_offset = i * w;
let u64_idx = bit_offset / 64;
Expand All @@ -161,7 +161,7 @@ fn to_radix_2w(scalar: &Scalar, w: usize) -> [i8; 43] {

// Recenter coefficients from [0,2^w) to [-2^w/2, 2^w/2)
carry = (coef + (radix / 2)) >> w;
digits[i] = ((coef as i64) - (carry << w) as i64) as i8;
*digit = ((coef as i64) - (carry << w) as i64) as i8;
}

// When w < 8, we can fold the final carry onto the last digit d,
Expand Down
2 changes: 2 additions & 0 deletions src/fp.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! This module provides an implementation of the BLS12-381 base field `GF(p)`
//! where `p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab`

#![allow(clippy::needless_borrow, clippy::needless_lifetimes)]

mod dusk;

use core::fmt;
Expand Down
1 change: 1 addition & 0 deletions src/fp12.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(clippy::needless_lifetimes)]
use crate::fp::*;
use crate::fp2::*;
use crate::fp6::*;
Expand Down
2 changes: 2 additions & 0 deletions src/fp2.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! This module implements arithmetic over the quadratic extension field Fp2.

#![allow(clippy::needless_borrow, clippy::needless_lifetimes)]

#[cfg(feature = "serde")]
mod dusk;

Expand Down
2 changes: 1 addition & 1 deletion src/fp2/dusk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ mod serde_support {
c1 = Some(map.next_value()?);
}
}
field => return Err(SerdeError::unknown_field(field, &FIELDS)),
field => return Err(SerdeError::unknown_field(field, FIELDS)),
}
}
Ok(Fp2 {
Expand Down
1 change: 1 addition & 0 deletions src/fp6.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(clippy::needless_lifetimes)]
#[cfg(feature = "serde")]
mod dusk;

Expand Down
2 changes: 1 addition & 1 deletion src/fp6/dusk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ mod serde_support {
c2 = Some(map.next_value()?);
}
}
field => return Err(SerdeError::unknown_field(field, &FIELDS)),
field => return Err(SerdeError::unknown_field(field, FIELDS)),
}
}
Ok(Fp6 {
Expand Down
2 changes: 2 additions & 0 deletions src/g1.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! This module provides an implementation of the $\mathbb{G}_1$ group of BLS12-381.

#![allow(clippy::needless_lifetimes, unused_attributes)]

mod dusk;

use core::borrow::Borrow;
Expand Down
2 changes: 2 additions & 0 deletions src/g2.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! This module provides an implementation of the $\mathbb{G}_2$ group of BLS12-381.

#![allow(clippy::needless_borrow, clippy::needless_lifetimes, unused_attributes)]

mod dusk;

use core::borrow::Borrow;
Expand Down
2 changes: 2 additions & 0 deletions src/hash_to_curve/expand_msg.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! This module implements message expansion consistent with the
//! hash-to-curve RFC drafts 7 through 10

#![allow(clippy::manual_div_ceil, clippy::needless_borrows_for_generic_args)]

use core::{
fmt::{self, Debug, Formatter},
marker::PhantomData,
Expand Down
8 changes: 4 additions & 4 deletions src/notes/design.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@
//!
//! ## Nontrivial third root of unity
//!
//! To use the fast subgroup check algorithm for $\mathbb{G_1}$ from https://eprint.iacr.org/2019/814.pdf and
//! https://eprint.iacr.org/2021/1130, it is necessary to find a nontrivial cube root of
//! To use the fast subgroup check algorithm for $\mathbb{G_1}$ from <https://eprint.iacr.org/2019/814.pdf> and
//! <https://eprint.iacr.org/2021/1130>, it is necessary to find a nontrivial cube root of
//! unity β in Fp to define the endomorphism:
//! $$(x, y) \rightarrow (\beta x, y)$$
//! which is equivalent to
Expand All @@ -88,8 +88,8 @@
//!
//! ## Psi
//!
//! To use the fast subgroup check algorithm for $\mathbb{G_2}$ from https://eprint.iacr.org/2019/814.pdf and
//! https://eprint.iacr.org/2021/1130, it is necessary to find the endomorphism:
//! To use the fast subgroup check algorithm for $\mathbb{G_2}$ from <https://eprint.iacr.org/2019/814.pdf> and
//! <https://eprint.iacr.org/2021/1130>, it is necessary to find the endomorphism:
//!
//! $$(x, y, z) \rightarrow (x^q \psi_x, y^q \psi_y, z^q)$$
//!
Expand Down
1 change: 1 addition & 0 deletions src/pairings.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(clippy::needless_lifetimes, unused_attributes)]
#[cfg(all(feature = "alloc", feature = "pairing"))]
mod dusk;

Expand Down
2 changes: 1 addition & 1 deletion src/pairings/dusk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ mod serde_support {
coeffs = Some(map.next_value()?);
}
}
field => return Err(SerdeError::unknown_field(field, &FIELDS)),
field => return Err(SerdeError::unknown_field(field, FIELDS)),
}
}
Ok(G2Prepared {
Expand Down
2 changes: 2 additions & 0 deletions src/scalar.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! This module provides an implementation of the BLS12-381 scalar field $\mathbb{F}_q$
//! where `q = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001`

#![allow(clippy::needless_borrow, clippy::needless_lifetimes, unused_attributes)]

mod dusk;

use core::fmt;
Expand Down
Loading
Loading