// SPDX-License-Identifier: MIT OR Apache-2.0 // Copyright (c) VexaHub and contributors. // Copyright (c) Meta Platforms, Inc. and affiliates. use core::ops::{Add, Mul}; use digest::block_api::BlockSizeUser; use digest::typenum::{IsLess, IsLessOrEqual, U256}; use digest::{FixedOutput, HashMarker}; use elliptic_curve::group::cofactor::CofactorGroup; use elliptic_curve::sec1::{FromSec1Point, ModulusSize, ToSec1Point}; use elliptic_curve::{ AffinePoint, Field, FieldBytes, FieldBytesSize, Group as _, ProjectivePoint, PublicKey, Scalar, SecretKey, }; use hash2curve::{ExpandMsgXmd, GroupDigest, MapToCurve, hash_to_scalar}; use hybrid_array::typenum::{IsGreaterOrEqual, Prod, Sum, True, U2}; use hybrid_array::{Array, ArraySize}; use rand_core::TryCryptoRng; use super::Group; use crate::{Error, InternalError, Result}; type ElemLen = as ModulusSize>::CompressedPointSize; type ScalarLen = FieldBytesSize; impl Group for C where C: GroupDigest, C::SecurityLevel: Mul, C::SecurityLevel: ArraySize, >::Output: ArraySize, ProjectivePoint: CofactorGroup + ToSec1Point, ScalarLen: ModulusSize, ScalarLen: ArraySize, ScalarLen: hybrid_array::typenum::NonZero, Scalar: elliptic_curve::ops::Reduce::Length>>, AffinePoint: FromSec1Point + ToSec1Point, // `VoprfClientLen`, `PoprfClientLen`, `VoprfServerLen`, `PoprfServerLen` ScalarLen: Add>, Sum, ElemLen>: ArraySize, // `ProofLen` ScalarLen: Add>, Sum, ScalarLen>: ArraySize, ElemLen: ArraySize, { type Elem = ProjectivePoint; type ElemLen = ElemLen; type Scalar = Scalar; type ScalarLen = ScalarLen; type SecurityLevel = C::SecurityLevel; // Implements the `hash_to_curve()` function from // https://www.rfc-editor.org/rfc/rfc9380.html#section-3 fn hash_to_curve(input: &[&[u8]], dst: &[&[u8]]) -> Result { Self::hash_from_bytes(input, dst).map_err(|_| InternalError::Input) } // Implements the `HashToScalar()` function fn hash_to_scalar(input: &[&[u8]], dst: &[&[u8]]) -> Result where H: BlockSizeUser + Default + FixedOutput + HashMarker, H::OutputSize: IsLess + IsLessOrEqual + IsGreaterOrEqual, Output = True>, { hash_to_scalar::, ::Length>(input, dst) .map_err(|_| InternalError::Input) } fn base_elem() -> Self::Elem { ProjectivePoint::::generator() } fn identity_elem() -> Self::Elem { ProjectivePoint::::identity() } fn serialize_elem(elem: Self::Elem) -> Array { let bytes = elem.to_sec1_point(true); let bytes = bytes.as_bytes(); let mut result = Array::default(); result[..bytes.len()].copy_from_slice(bytes); result } fn deserialize_elem(element_bits: &[u8]) -> Result { PublicKey::::from_sec1_bytes(element_bits) .map(|public_key| public_key.to_projective()) .map_err(|_| Error::Deserialization) } fn random_scalar(rng: &mut R) -> Result { loop { let mut bytes = FieldBytes::::default(); rng.try_fill_bytes(&mut bytes).map_err(|_| Error::Rng)?; if let Ok(key) = SecretKey::::from_slice(&bytes) { return Ok(*key.to_nonzero_scalar()); } } } fn invert_scalar(scalar: Self::Scalar) -> Self::Scalar { Option::from(scalar.invert()).unwrap() } fn is_zero_scalar(scalar: Self::Scalar) -> subtle::Choice { scalar.is_zero() } #[cfg(test)] fn zero_scalar() -> Self::Scalar { Scalar::::ZERO } fn serialize_scalar(scalar: Self::Scalar) -> Array { let bytes: FieldBytes = scalar.into(); let mut result = Array::::default(); result.as_mut_slice().copy_from_slice(bytes.as_ref()); result } fn deserialize_scalar(scalar_bits: &[u8]) -> Result { SecretKey::::from_slice(scalar_bits) .map(|secret_key| *secret_key.to_nonzero_scalar()) .map_err(|_| Error::Deserialization) } }