// Copyright (c) Meta Platforms, Inc. and affiliates. // // This source code is dual-licensed under either the MIT license found in the // LICENSE-MIT file in the root directory of this source tree or the Apache // License, Version 2.0 found in the LICENSE-APACHE file in the root directory // of this source tree. You may select, at your option, one of the above-listed // licenses. //! Defines the Group trait to specify the underlying prime order group mod elliptic_curve; #[cfg(feature = "ristretto255")] mod ristretto; use core::ops::{Add, Mul, Sub}; use digest::block_api::BlockSizeUser; use digest::{FixedOutput, HashMarker}; use hybrid_array::typenum::{IsGreaterOrEqual, IsLess, IsLessOrEqual, Prod, Sum, True, U2, U256}; use hybrid_array::{Array, ArraySize}; use rand_core::{TryCryptoRng, TryRng}; #[cfg(feature = "ristretto255")] pub use ristretto::Ristretto255; use subtle::{Choice, ConstantTimeEq}; use zeroize::Zeroize; use crate::{InternalError, Result}; /// A prime-order subgroup of a base field (EC, prime-order field ...). This /// subgroup is noted additively — as in the RFC — in this trait. pub trait Group where // `VoprfClientLen`, `PoprfClientLen`, `VoprfServerLen`, `PoprfServerLen` Self::ScalarLen: Add, Sum: ArraySize, // `ProofLen` Self::ScalarLen: Add, Sum: ArraySize, { /// The type of group elements type Elem: ConstantTimeEq + Copy + Zeroize + for<'a> Add<&'a Self::Elem, Output = Self::Elem> + for<'a> Mul<&'a Self::Scalar, Output = Self::Elem>; /// The byte length necessary to represent group elements type ElemLen: ArraySize + 'static; /// The type of base field scalars type Scalar: ConstantTimeEq + Copy + Zeroize + for<'a> Add<&'a Self::Scalar, Output = Self::Scalar> + for<'a> Mul<&'a Self::Scalar, Output = Self::Scalar> + for<'a> Sub<&'a Self::Scalar, Output = Self::Scalar>; /// The byte length necessary to represent scalars type ScalarLen: ArraySize + 'static; /// Security parameter `k` in bytes (i.e. `k / 8`), as defined in /// [RFC 9380 §8](https://www.rfc-editor.org/rfc/rfc9380#section-8). /// /// Used to enforce `H::OutputSize >= 2 * SecurityLevel` in /// `hash_to_curve` and `hash_to_scalar`, which corresponds to the /// `expand_message` requirement `len_in_bytes = 2 * k / 8`. type SecurityLevel: ArraySize; /// The OKM length for hash_to_scalar (>= ScalarLen, used by hash_to_field). type OkmLen: ArraySize + hybrid_array::typenum::NonZero; /// Transforms a password and domain separation tag (DST) into a curve point /// /// # Errors /// [`Error::Input`](crate::Error::Input) if the `input` is empty or longer /// then [`u16::MAX`]. fn hash_to_curve(input: &[&[u8]], dst: &[&[u8]]) -> Result where H: BlockSizeUser + Default + FixedOutput + HashMarker, H::OutputSize: IsLess + IsLessOrEqual, Self::SecurityLevel: Mul, H::OutputSize: IsGreaterOrEqual, Output = True>; /// Hashes a slice of pseudo-random bytes to a scalar /// /// # Errors /// [`Error::Input`](crate::Error::Input) if the `input` is empty or longer /// then [`u16::MAX`]. fn hash_to_scalar(input: &[&[u8]], dst: &[&[u8]]) -> Result where H: BlockSizeUser + Default + FixedOutput + HashMarker, H::OutputSize: IsLess + IsLessOrEqual, Self::SecurityLevel: Mul, H::OutputSize: IsGreaterOrEqual, Output = True>; /// Get the base point for the group fn base_elem() -> Self::Elem; /// Returns the identity group element fn identity_elem() -> Self::Elem; /// Returns `true` if the element is equal to the identity element fn is_identity_elem(elem: Self::Elem) -> Choice { Self::identity_elem().ct_eq(&elem) } /// Serializes the `self` group element fn serialize_elem(elem: Self::Elem) -> Array; /// Return an element from its fixed-length bytes representation. If the /// element is the identity element, return an error. /// /// # Errors /// [`Error::Deserialization`](crate::Error::Deserialization) if the element /// is not a valid point on the group or the identity element. fn deserialize_elem(element_bits: &[u8]) -> Result; /// Picks a scalar at random. /// /// # Errors /// [`Error::Rng`](crate::Error::Rng) if the random number generator fails. fn random_scalar(rng: &mut R) -> Result; /// The multiplicative inverse of this scalar fn invert_scalar(scalar: Self::Scalar) -> Self::Scalar; /// Returns `true` if the scalar is zero. fn is_zero_scalar(scalar: Self::Scalar) -> Choice; /// Returns the scalar representing zero #[cfg(test)] fn zero_scalar() -> Self::Scalar; /// Serializes a scalar to bytes fn serialize_scalar(scalar: Self::Scalar) -> Array; /// Return a scalar from its fixed-length bytes representation. If the /// scalar is zero or invalid, then return an error. /// /// # Errors /// [`Error::Deserialization`](crate::Error::Deserialization) if the scalar /// is not a valid point on the group or zero. fn deserialize_scalar(scalar_bits: &[u8]) -> Result; } #[cfg(test)] mod tests;