Files
opaque-vx/src/group.rs
T

138 lines
5.0 KiB
Rust
Raw Normal View History

2020-06-05 09:35:14 -07:00
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
2020-07-22 11:58:00 -04:00
//! Defines the Group trait to specify the underlying prime order group used in
//! OPAQUE's OPRF
2021-01-25 13:20:36 -08:00
use crate::errors::InternalPakeError;
2020-06-05 09:35:14 -07:00
use curve25519_dalek::{
2021-01-25 13:20:36 -08:00
constants::RISTRETTO_BASEPOINT_POINT,
2020-06-05 09:35:14 -07:00
ristretto::{CompressedRistretto, RistrettoPoint},
scalar::Scalar,
};
use generic_array::{
typenum::{U32, U64},
ArrayLength, GenericArray,
};
2021-01-25 13:20:36 -08:00
use std::convert::TryInto;
2020-11-03 21:44:00 +00:00
2020-06-05 09:35:14 -07:00
use rand_core::{CryptoRng, RngCore};
use std::ops::Mul;
use zeroize::Zeroize;
/// A prime-order subgroup of a base field (EC, prime-order field ...). This
/// subgroup is noted additively — as in the draft RFC — in this trait.
pub trait Group: Sized + for<'a> Mul<&'a <Self as Group>::Scalar, Output = Self> {
/// The type of base field scalars
2021-01-25 13:20:36 -08:00
type Scalar: Zeroize + Clone;
2020-06-05 09:35:14 -07:00
/// The byte length necessary to represent scalars
type ScalarLen: ArrayLength<u8>;
2020-12-04 13:19:29 -08:00
/// Return a scalar from its fixed-length bytes representation
2020-06-05 09:35:14 -07:00
fn from_scalar_slice(
scalar_bits: &GenericArray<u8, Self::ScalarLen>,
) -> Result<Self::Scalar, InternalPakeError>;
/// picks a scalar at random
fn random_scalar<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Scalar;
/// Serializes a scalar to bytes
fn scalar_as_bytes(scalar: &Self::Scalar) -> &GenericArray<u8, Self::ScalarLen>;
/// The multiplicative inverse of this scalar
fn scalar_invert(scalar: &Self::Scalar) -> Self::Scalar;
/// The byte length necessary to represent group elements
type ElemLen: ArrayLength<u8>;
/// Return an element from its fixed-length bytes representation
fn from_element_slice(
element_bits: &GenericArray<u8, Self::ElemLen>,
) -> Result<Self, InternalPakeError>;
/// Serializes the `self` group element
fn to_arr(&self) -> GenericArray<u8, Self::ElemLen>;
2020-06-05 09:35:14 -07:00
/// Hashes points presumed to be uniformly random to the curve. The
/// impl is allowed to perform additional hashes if it needs to, but this
/// may not be necessary as this function is going to be called with the
/// output of a kdf.
type UniformBytesLen: ArrayLength<u8>;
2020-07-27 15:25:04 -07:00
2020-07-22 11:58:00 -04:00
/// Hashes a slice of pseudo-random bytes of the correct length to a curve point
2020-06-05 09:35:14 -07:00
fn hash_to_curve(uniform_bytes: &GenericArray<u8, Self::UniformBytesLen>) -> Self;
2021-01-25 13:20:36 -08:00
/// Get the base point for the group
fn base_point() -> Self;
/// Multiply the point by a scalar, represented as a slice
fn mult_by_slice(&self, scalar: &GenericArray<u8, Self::ScalarLen>) -> Self;
2020-06-05 09:35:14 -07:00
}
/// The implementation of such a subgroup for Ristretto
impl Group for RistrettoPoint {
type Scalar = Scalar;
type ScalarLen = U32;
fn from_scalar_slice(
scalar_bits: &GenericArray<u8, Self::ScalarLen>,
) -> Result<Self::Scalar, InternalPakeError> {
let mut bits = [0u8; 32];
bits.copy_from_slice(scalar_bits);
Ok(Scalar::from_bytes_mod_order(bits))
}
fn random_scalar<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Scalar {
2021-01-25 13:20:36 -08:00
#[cfg(not(test))]
{
let mut scalar_bytes = [0u8; 64];
rng.fill_bytes(&mut scalar_bytes);
Scalar::from_bytes_mod_order_wide(&scalar_bytes)
}
2021-01-25 13:20:36 -08:00
// Tests need an exact conversion from bytes to scalar, sampling only 32 bytes from rng
#[cfg(test)]
{
let mut scalar_bytes = [0u8; 32];
rng.fill_bytes(&mut scalar_bytes);
Scalar::from_bytes_mod_order(scalar_bytes)
}
2020-06-05 09:35:14 -07:00
}
fn scalar_as_bytes(scalar: &Self::Scalar) -> &GenericArray<u8, Self::ScalarLen> {
GenericArray::from_slice(scalar.as_bytes())
}
fn scalar_invert(scalar: &Self::Scalar) -> Self::Scalar {
scalar.invert()
}
// The byte length necessary to represent group elements
type ElemLen = U32;
fn from_element_slice(
element_bits: &GenericArray<u8, Self::ElemLen>,
) -> Result<Self, InternalPakeError> {
CompressedRistretto::from_slice(element_bits)
.decompress()
.ok_or(InternalPakeError::PointError)
2020-06-05 09:35:14 -07:00
}
// serialization of a group element
fn to_arr(&self) -> GenericArray<u8, Self::ElemLen> {
2020-06-05 09:35:14 -07:00
let c = self.compress();
*GenericArray::from_slice(c.as_bytes())
}
type UniformBytesLen = U64;
fn hash_to_curve(uniform_bytes: &GenericArray<u8, Self::UniformBytesLen>) -> Self {
// https://caniuse.rs/features/array_gt_32_impls
let bits: [u8; 64] = {
let mut bytes = [0u8; 64];
bytes.copy_from_slice(uniform_bytes);
bytes
};
RistrettoPoint::from_uniform_bytes(&bits)
2020-06-05 09:35:14 -07:00
}
2021-01-25 13:20:36 -08:00
fn base_point() -> Self {
RISTRETTO_BASEPOINT_POINT
2020-06-05 09:35:14 -07:00
}
2021-01-25 13:20:36 -08:00
fn mult_by_slice(&self, scalar: &GenericArray<u8, Self::ScalarLen>) -> Self {
let arr: [u8; 32] = scalar.as_slice().try_into().expect("Wrong length");
self * Scalar::from_bits(arr)
}
}