// 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. use digest::core_api::BlockSizeUser; use digest::{FixedOutput, HashMarker}; use elliptic_curve::group::cofactor::CofactorGroup; use elliptic_curve::hash2curve::{ExpandMsgXmd, FromOkm, GroupDigest}; use elliptic_curve::sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint}; use elliptic_curve::{ AffinePoint, Field, FieldBytesSize, Group, ProjectivePoint, PublicKey, Scalar, SecretKey, }; use generic_array::typenum::{IsLess, IsLessOrEqual, U256}; use generic_array::GenericArray; use rand::{CryptoRng, RngCore}; use super::KeGroup; use crate::errors::{InternalError, ProtocolError}; use crate::key_exchange::tripledh::DiffieHellman; impl KeGroup for G where G: GroupDigest, FieldBytesSize: ModulusSize, AffinePoint: FromEncodedPoint + ToEncodedPoint, ProjectivePoint: CofactorGroup + ToEncodedPoint, Scalar: FromOkm, { type Pk = ProjectivePoint; type PkLen = as ModulusSize>::CompressedPointSize; type Sk = Scalar; type SkLen = FieldBytesSize; fn serialize_pk(pk: Self::Pk) -> GenericArray { GenericArray::clone_from_slice(pk.to_encoded_point(true).as_bytes()) } fn deserialize_pk(bytes: &[u8]) -> Result { PublicKey::::from_sec1_bytes(bytes) .map(|public_key| public_key.to_projective()) .map_err(|_| ProtocolError::SerializationError) } fn random_sk(rng: &mut R) -> Self::Sk { *SecretKey::::random(rng).to_nonzero_scalar() } // Implements the `HashToScalar()` function from // fn hash_to_scalar(input: &[&[u8]], dst: &[&[u8]]) -> Result where H: BlockSizeUser + Default + FixedOutput + HashMarker, H::OutputSize: IsLess + IsLessOrEqual, { Self::hash_to_scalar::>(input, dst) .map_err(|_| InternalError::HashToScalar) .and_then(|scalar| { if bool::from(scalar.is_zero()) { Err(InternalError::HashToScalar) } else { Ok(scalar) } }) } fn public_key(sk: Self::Sk) -> Self::Pk { ProjectivePoint::::generator() * sk } fn is_zero_scalar(scalar: Self::Sk) -> subtle::Choice { scalar.is_zero() } fn serialize_sk(sk: Self::Sk) -> GenericArray { sk.into() } fn deserialize_sk(bytes: &[u8]) -> Result { SecretKey::::from_slice(bytes) .map(|secret_key| *secret_key.to_nonzero_scalar()) .map_err(|_| ProtocolError::SerializationError) } } impl DiffieHellman for Scalar where G: GroupDigest, FieldBytesSize: ModulusSize, AffinePoint: FromEncodedPoint + ToEncodedPoint, ProjectivePoint: CofactorGroup + ToEncodedPoint, Scalar: FromOkm, { fn diffie_hellman( self, pk: ProjectivePoint, ) -> GenericArray as ModulusSize>::CompressedPointSize> { GenericArray::clone_from_slice((pk * self).to_encoded_point(true).as_bytes()) } }