Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  field255.rs   Sprache: unbekannt

 
// Copyright (c) 2023 ISRG
// SPDX-License-Identifier: MPL-2.0

//! Finite field arithmetic for `GF(2^255 - 19)`.

use crate::{
    codec::{CodecError, Decode, Encode},
    field::{FieldElement, FieldElementVisitor, FieldError},
};
use fiat_crypto::curve25519_64::{
    fiat_25519_add, fiat_25519_carry, fiat_25519_carry_mul, fiat_25519_from_bytes,
    fiat_25519_loose_field_element, fiat_25519_opp, fiat_25519_relax, fiat_25519_selectznz,
    fiat_25519_sub, fiat_25519_tight_field_element, fiat_25519_to_bytes,
};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{
    convert::TryFrom,
    fmt::{self, Debug, Display, Formatter},
    io::{Cursor, Read},
    marker::PhantomData,
    mem::size_of,
    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use subtle::{
    Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess,
};

// `python3 -c "print(', '.join(hex(x) for x in (2**255-19).to_bytes(32, 'little')))"`
const MODULUS_LITTLE_ENDIAN: [u8; 32] = [
    0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
];

/// `GF(2^255 - 19)`, a 255-bit field.
#[derive(Clone, Copy)]
#[cfg_attr(docsrs, doc(cfg(feature = "experimental")))]
pub struct Field255(fiat_25519_tight_field_element);

impl Field255 {
    /// Attempts to instantiate a `Field255` from the first `Self::ENCODED_SIZE` bytes in the
    /// provided slice.
    ///
    /// # Errors
    ///
    /// An error is returned if the provided slice is not long enough to encode a field element or
    /// if the decoded value is greater than the field prime.
    fn try_from_bytes(bytes: &[u8], mask_top_bit: bool) -> Result<Self, FieldError> {
        if Self::ENCODED_SIZE > bytes.len() {
            return Err(FieldError::ShortRead);
        }

        let mut value = [0u8; Self::ENCODED_SIZE];
        value.copy_from_slice(&bytes[..Self::ENCODED_SIZE]);

        if mask_top_bit {
            value[31] &= 0b0111_1111;
        }

        // Walk through the bytes of the provided value from most significant to least,
        // and identify whether the first byte that differs from the field's modulus is less than
        // the corresponding byte or greater than the corresponding byte, in constant time. (Or
        // whether the provided value is equal to the field modulus.)
        let mut less_than_modulus = Choice::from(0u8);
        let mut greater_than_modulus = Choice::from(0u8);
        for (value_byte, modulus_byte) in value.iter().rev().zip(MODULUS_LITTLE_ENDIAN.iter().rev())
        {
            less_than_modulus |= value_byte.ct_lt(modulus_byte) & !greater_than_modulus;
            greater_than_modulus |= value_byte.ct_gt(modulus_byte) & !less_than_modulus;
        }

        if bool::from(!less_than_modulus) {
            return Err(FieldError::ModulusOverflow);
        }

        let mut output = fiat_25519_tight_field_element([0; 5]);
        fiat_25519_from_bytes(&mut output, &value);

        Ok(Field255(output))
    }
}

impl ConstantTimeEq for Field255 {
    fn ct_eq(&self, rhs: &Self) -> Choice {
        // The internal representation used by fiat-crypto is not 1-1 with the field, so it is
        // necessary to compare field elements via their canonical encodings.

        let mut self_encoded = [0; 32];
        fiat_25519_to_bytes(&mut self_encoded, &self.0);
        let mut rhs_encoded = [0; 32];
        fiat_25519_to_bytes(&mut rhs_encoded, &rhs.0);

        self_encoded.ct_eq(&rhs_encoded)
    }
}

impl ConditionallySelectable for Field255 {
    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
        let mut output = [0; 5];
        fiat_25519_selectznz(&mut output, choice.unwrap_u8(), &(a.0).0, &(b.0).0);
        Field255(fiat_25519_tight_field_element(output))
    }
}

impl PartialEq for Field255 {
    fn eq(&self, rhs: &Self) -> bool {
        self.ct_eq(rhs).into()
    }
}

impl Eq for Field255 {}

impl Add for Field255 {
    type Output = Field255;

    fn add(self, rhs: Self) -> Field255 {
        let mut loose_output = fiat_25519_loose_field_element([0; 5]);
        fiat_25519_add(&mut loose_output, &self.0, &rhs.0);
        let mut output = fiat_25519_tight_field_element([0; 5]);
        fiat_25519_carry(&mut output, &loose_output);
        Field255(output)
    }
}

impl AddAssign for Field255 {
    fn add_assign(&mut self, rhs: Self) {
        let mut loose_output = fiat_25519_loose_field_element([0; 5]);
        fiat_25519_add(&mut loose_output, &self.0, &rhs.0);
        fiat_25519_carry(&mut self.0, &loose_output);
    }
}

impl Sub for Field255 {
    type Output = Field255;

    fn sub(self, rhs: Self) -> Field255 {
        let mut loose_output = fiat_25519_loose_field_element([0; 5]);
        fiat_25519_sub(&mut loose_output, &self.0, &rhs.0);
        let mut output = fiat_25519_tight_field_element([0; 5]);
        fiat_25519_carry(&mut output, &loose_output);
        Field255(output)
    }
}

impl SubAssign for Field255 {
    fn sub_assign(&mut self, rhs: Self) {
        let mut loose_output = fiat_25519_loose_field_element([0; 5]);
        fiat_25519_sub(&mut loose_output, &self.0, &rhs.0);
        fiat_25519_carry(&mut self.0, &loose_output);
    }
}

impl Mul for Field255 {
    type Output = Field255;

    fn mul(self, rhs: Self) -> Field255 {
        let mut self_relaxed = fiat_25519_loose_field_element([0; 5]);
        fiat_25519_relax(&mut self_relaxed, &self.0);
        let mut rhs_relaxed = fiat_25519_loose_field_element([0; 5]);
        fiat_25519_relax(&mut rhs_relaxed, &rhs.0);
        let mut output = fiat_25519_tight_field_element([0; 5]);
        fiat_25519_carry_mul(&mut output, &self_relaxed, &rhs_relaxed);
        Field255(output)
    }
}

impl MulAssign for Field255 {
    fn mul_assign(&mut self, rhs: Self) {
        let mut self_relaxed = fiat_25519_loose_field_element([0; 5]);
        fiat_25519_relax(&mut self_relaxed, &self.0);
        let mut rhs_relaxed = fiat_25519_loose_field_element([0; 5]);
        fiat_25519_relax(&mut rhs_relaxed, &rhs.0);
        fiat_25519_carry_mul(&mut self.0, &self_relaxed, &rhs_relaxed);
    }
}

impl Div for Field255 {
    type Output = Field255;

    fn div(self, _rhs: Self) -> Self::Output {
        unimplemented!("Div is not implemented for Field255 because it's not needed yet")
    }
}

impl DivAssign for Field255 {
    fn div_assign(&mut self, _rhs: Self) {
        unimplemented!("DivAssign is not implemented for Field255 because it's not needed yet")
    }
}

impl Neg for Field255 {
    type Output = Field255;

    fn neg(self) -> Field255 {
        -&self
    }
}

impl<'a> Neg for &'a Field255 {
    type Output = Field255;

    fn neg(self) -> Field255 {
        let mut loose_output = fiat_25519_loose_field_element([0; 5]);
        fiat_25519_opp(&mut loose_output, &self.0);
        let mut output = fiat_25519_tight_field_element([0; 5]);
        fiat_25519_carry(&mut output, &loose_output);
        Field255(output)
    }
}

impl From<u64> for Field255 {
    fn from(value: u64) -> Self {
        let input_bytes = value.to_le_bytes();
        let mut field_bytes = [0u8; Self::ENCODED_SIZE];
        field_bytes[..input_bytes.len()].copy_from_slice(&input_bytes);
        Self::try_from_bytes(&field_bytes, false).unwrap()
    }
}

impl<'a> TryFrom<&'a [u8]> for Field255 {
    type Error = FieldError;

    fn try_from(bytes: &[u8]) -> Result<Self, FieldError> {
        Self::try_from_bytes(bytes, false)
    }
}

impl From<Field255> for [u8; Field255::ENCODED_SIZE] {
    fn from(element: Field255) -> Self {
        let mut array = [0; Field255::ENCODED_SIZE];
        fiat_25519_to_bytes(&mut array, &element.0);
        array
    }
}

impl From<Field255> for Vec<u8> {
    fn from(elem: Field255) -> Vec<u8> {
        <[u8; Field255::ENCODED_SIZE]>::from(elem).to_vec()
    }
}

impl Display for Field255 {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let encoded: [u8; Self::ENCODED_SIZE] = (*self).into();
        write!(f, "0x")?;
        for byte in encoded {
            write!(f, "{byte:02x}")?;
        }
        Ok(())
    }
}

impl Debug for Field255 {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        <Self as Display>::fmt(self, f)
    }
}

impl Serialize for Field255 {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let bytes: [u8; Self::ENCODED_SIZE] = (*self).into();
        serializer.serialize_bytes(&bytes)
    }
}

impl<'de> Deserialize<'de> for Field255 {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Field255, D::Error> {
        deserializer.deserialize_bytes(FieldElementVisitor {
            phantom: PhantomData,
        })
    }
}

impl Encode for Field255 {
    fn encode(&self, bytes: &mut Vec<u8>) -> Result<(), CodecError> {
        bytes.extend_from_slice(&<[u8; Self::ENCODED_SIZE]>::from(*self));
        Ok(())
    }

    fn encoded_len(&self) -> Option<usize> {
        Some(Self::ENCODED_SIZE)
    }
}

impl Decode for Field255 {
    fn decode(bytes: &mut Cursor<&[u8]>) -> Result<Self, CodecError> {
        let mut value = [0u8; Self::ENCODED_SIZE];
        bytes.read_exact(&mut value)?;
        Field255::try_from_bytes(&value, false).map_err(|e| {
            CodecError::Other(Box::new(e) as Box<dyn std::error::Error + 'static + Send + Sync>)
        })
    }
}

impl FieldElement for Field255 {
    const ENCODED_SIZE: usize = 32;

    fn inv(&self) -> Self {
        unimplemented!("Field255::inv() is not implemented because it's not needed yet")
    }

    fn try_from_random(bytes: &[u8]) -> Result<Self, FieldError> {
        Field255::try_from_bytes(bytes, true)
    }

    fn zero() -> Self {
        Field255(fiat_25519_tight_field_element([0, 0, 0, 0, 0]))
    }

    fn one() -> Self {
        Field255(fiat_25519_tight_field_element([1, 0, 0, 0, 0]))
    }
}

impl Default for Field255 {
    fn default() -> Self {
        Field255::zero()
    }
}

impl TryFrom<Field255> for u64 {
    type Error = FieldError;

    fn try_from(elem: Field255) -> Result<u64, FieldError> {
        const PREFIX_LEN: usize = size_of::<u64>();
        let mut le_bytes = [0; 32];

        fiat_25519_to_bytes(&mut le_bytes, &elem.0);
        if !bool::from(le_bytes[PREFIX_LEN..].ct_eq(&[0_u8; 32 - PREFIX_LEN])) {
            return Err(FieldError::IntegerTryFrom);
        }

        Ok(u64::from_le_bytes(
            le_bytes[..PREFIX_LEN].try_into().unwrap(),
        ))
    }
}

#[cfg(test)]
mod tests {
    use super::{Field255, MODULUS_LITTLE_ENDIAN};
    use crate::{
        codec::Encode,
        field::{
            test_utils::{field_element_test_common, TestFieldElementWithInteger},
            FieldElement, FieldError, Integer,
        },
    };
    use assert_matches::assert_matches;
    use fiat_crypto::curve25519_64::{
        fiat_25519_from_bytes, fiat_25519_tight_field_element, fiat_25519_to_bytes,
    };
    use num_bigint::BigUint;
    use once_cell::sync::Lazy;
    use std::convert::{TryFrom, TryInto};

    static MODULUS: Lazy<BigUint> = Lazy::new(|| BigUint::from_bytes_le(&MODULUS_LITTLE_ENDIAN));

    impl From<BigUint> for Field255 {
        fn from(value: BigUint) -> Self {
            let le_bytes_vec = (value % &*MODULUS).to_bytes_le();

            let mut le_bytes_array = [0u8; 32];
            le_bytes_array[..le_bytes_vec.len()].copy_from_slice(&le_bytes_vec);

            let mut output = fiat_25519_tight_field_element([0; 5]);
            fiat_25519_from_bytes(&mut output, &le_bytes_array);
            Field255(output)
        }
    }

    impl From<Field255> for BigUint {
        fn from(value: Field255) -> Self {
            let mut le_bytes = [0u8; 32];
            fiat_25519_to_bytes(&mut le_bytes, &value.0);
            BigUint::from_bytes_le(&le_bytes)
        }
    }

    impl Integer for BigUint {
        type TryFromUsizeError = <Self as TryFrom<usize>>::Error;

        type TryIntoU64Error = <Self as TryInto<u64>>::Error;

        fn zero() -> Self {
            Self::new(Vec::new())
        }

        fn one() -> Self {
            Self::new(Vec::from([1]))
        }
    }

    impl TestFieldElementWithInteger for Field255 {
        type TestInteger = BigUint;
        type IntegerTryFromError = <Self::TestInteger as TryFrom<usize>>::Error;
        type TryIntoU64Error = <Self::TestInteger as TryInto<u64>>::Error;

        fn pow(&self, _exp: Self::TestInteger) -> Self {
            unimplemented!("Field255::pow() is not implemented because it's not needed yet")
        }

        fn modulus() -> Self::TestInteger {
            MODULUS.clone()
        }
    }

    #[test]
    fn check_modulus() {
        let modulus = Field255::modulus();
        let element = Field255::from(modulus);
        // Note that these two objects represent the same field element, they encode to the same
        // canonical value (32 zero bytes), but they do not have the same internal representation.
        assert_eq!(element, Field255::zero());
    }

    #[test]
    fn check_identities() {
        let zero_bytes: [u8; 32] = Field255::zero().into();
        assert_eq!(zero_bytes, [0; 32]);
        let one_bytes: [u8; 32] = Field255::one().into();
        assert_eq!(
            one_bytes,
            [
                1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0
            ]
        );
    }

    #[test]
    fn encode_endianness() {
        let mut one_encoded = Vec::new();
        Field255::one().encode(&mut one_encoded).unwrap();
        assert_eq!(
            one_encoded,
            [
                1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0
            ]
        );
    }

    #[test]
    fn test_field255() {
        field_element_test_common::<Field255>();
    }

    #[test]
    fn try_from_bytes() {
        assert_matches!(
            Field255::try_from_bytes(
                &[
                    0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                    0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
                ],
                false,
            ),
            Err(FieldError::ModulusOverflow)
        );
        assert_matches!(
            Field255::try_from_bytes(
                &[
                    0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
                    0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
                ],
                false,
            ),
            Ok(_)
        );
        assert_matches!(
            Field255::try_from_bytes(
                &[
                    0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                    0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
                ],
                true,
            ),
            Ok(element) => assert_eq!(element + Field255::one(), Field255::zero())
        );
        assert_matches!(
            Field255::try_from_bytes(
                &[
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
                ],
                false
            ),
            Err(FieldError::ModulusOverflow)
        );
        assert_matches!(
            Field255::try_from_bytes(
                &[
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
                ],
                true
            ),
            Ok(element) => assert_eq!(element, Field255::zero())
        );
    }

    #[test]
    fn u64_conversion() {
        assert_eq!(Field255::from(0u64), Field255::zero());
        assert_eq!(Field255::from(1u64), Field255::one());

        let max_bytes: [u8; 32] = Field255::from(u64::MAX).into();
        assert_eq!(
            max_bytes,
            [
                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00
            ]
        );

        let want: u64 = 0xffffffffffffffff;
        assert_eq!(u64::try_from(Field255::from(want)).unwrap(), want);

        let want: u64 = 0x7000000000000001;
        assert_eq!(u64::try_from(Field255::from(want)).unwrap(), want);

        let want: u64 = 0x1234123412341234;
        assert_eq!(u64::try_from(Field255::from(want)).unwrap(), want);

        assert!(u64::try_from(Field255::try_from_bytes(&[1; 32], false).unwrap()).is_err());
        assert!(u64::try_from(Field255::try_from_bytes(&[2; 32], false).unwrap()).is_err());
    }

    #[test]
    fn formatting() {
        assert_eq!(
            format!("{}", Field255::zero()),
            "0x0000000000000000000000000000000000000000000000000000000000000000"
        );
        assert_eq!(
            format!("{}", Field255::one()),
            "0x0100000000000000000000000000000000000000000000000000000000000000"
        );
        assert_eq!(
            format!("{}", -Field255::one()),
            "0xecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f"
        );
        assert_eq!(
            format!("{:?}", Field255::zero()),
            "0x0000000000000000000000000000000000000000000000000000000000000000"
        );
        assert_eq!(
            format!("{:?}", Field255::one()),
            "0x0100000000000000000000000000000000000000000000000000000000000000"
        );
    }
}

[ Dauer der Verarbeitung: 0.34 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge