mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-05-03 12:23:44 +02:00
Optimize SIDH code for about a 25% speed improvement.
This commit is contained in:
parent
c7b2a3703e
commit
184c4aede1
14 changed files with 358 additions and 120 deletions
|
@ -17,7 +17,7 @@ pub mod random;
|
||||||
pub mod secret;
|
pub mod secret;
|
||||||
pub mod hex;
|
pub mod hex;
|
||||||
pub mod varint;
|
pub mod varint;
|
||||||
pub mod sidh;
|
pub mod sidhp751;
|
||||||
|
|
||||||
pub use aes_gmac_siv;
|
pub use aes_gmac_siv;
|
||||||
pub use rand_core;
|
pub use rand_core;
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
// - Erkan Tairi <erkan.tairi@gmail.com>
|
// - Erkan Tairi <erkan.tairi@gmail.com>
|
||||||
//
|
//
|
||||||
|
|
||||||
use crate::sidh::field::PrimeFieldElement;
|
use crate::sidhp751::field::PrimeFieldElement;
|
||||||
use crate::sidh::fp::Fp751Element;
|
use crate::sidhp751::fp::Fp751Element;
|
||||||
|
|
||||||
/// The x-coordinate of `P_A = [3^239](11, oddsqrt(11^3 + 11))` on `E_0(F_p)`.
|
/// The x-coordinate of `P_A = [3^239](11, oddsqrt(11^3 + 11))` on `E_0(F_p)`.
|
||||||
pub const AFFINE_X_PA: PrimeFieldElement = PrimeFieldElement{ A: Fp751Element([0x27914862, 0xd56fe526, 0x96b5baea, 0x1fad60dc, 0xbf07ab91, 0x1e137d0, 0x52161964, 0x404d3e92, 0xcd09a337, 0x3c5385e4, 0x69e4af73, 0x44764267, 0x989dfe33, 0x9790c6db, 0xd2aa8b5e, 0xe06e1c04, 0xedea73b9, 0x38c08185, 0xa4396ca6, 0xaa41f678, 0x2229e9a0, 0x92b9259b, 0x26818be0, 0x2f93]) };
|
pub const AFFINE_X_PA: PrimeFieldElement = PrimeFieldElement{ A: Fp751Element([0x27914862, 0xd56fe526, 0x96b5baea, 0x1fad60dc, 0xbf07ab91, 0x1e137d0, 0x52161964, 0x404d3e92, 0xcd09a337, 0x3c5385e4, 0x69e4af73, 0x44764267, 0x989dfe33, 0x9790c6db, 0xd2aa8b5e, 0xe06e1c04, 0xedea73b9, 0x38c08185, 0xa4396ca6, 0xaa41f678, 0x2229e9a0, 0x92b9259b, 0x26818be0, 0x2f93]) };
|
|
@ -9,9 +9,9 @@
|
||||||
//! This module contains internal curve representation and operations
|
//! This module contains internal curve representation and operations
|
||||||
//! for SIDH, which is not part of the public API.
|
//! for SIDH, which is not part of the public API.
|
||||||
|
|
||||||
use crate::sidh::fp::Fp751Element;
|
use crate::sidhp751::fp::Fp751Element;
|
||||||
use crate::sidh::field::{PrimeFieldElement, ExtensionFieldElement};
|
use crate::sidhp751::field::{PrimeFieldElement, ExtensionFieldElement};
|
||||||
use crate::sidh::constants::*;
|
use crate::sidhp751::constants::*;
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::ops::Neg;
|
use std::ops::Neg;
|
||||||
|
@ -19,6 +19,7 @@ use subtle::{ConditionallySelectable, Choice};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use quickcheck::{Gen, Arbitrary};
|
use quickcheck::{Gen, Arbitrary};
|
||||||
|
use std::mem::zeroed;
|
||||||
|
|
||||||
// Macro to assign tuples, as Rust does not allow tuples as lvalue.
|
// Macro to assign tuples, as Rust does not allow tuples as lvalue.
|
||||||
macro_rules! assign{
|
macro_rules! assign{
|
||||||
|
@ -41,17 +42,20 @@ const CONST_256: ExtensionFieldElement = ExtensionFieldElement {
|
||||||
/// A point on the projective line `P^1(F_{p^2})`.
|
/// A point on the projective line `P^1(F_{p^2})`.
|
||||||
///
|
///
|
||||||
/// This is used to work projectively with the curve coefficients.
|
/// This is used to work projectively with the curve coefficients.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub struct ProjectiveCurveParameters {
|
pub struct ProjectiveCurveParameters {
|
||||||
pub A: ExtensionFieldElement,
|
pub A: ExtensionFieldElement,
|
||||||
pub C: ExtensionFieldElement,
|
pub C: ExtensionFieldElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
struct CachedCurveParameters {
|
struct CachedCurveParameters {
|
||||||
Aplus2C: ExtensionFieldElement,
|
Aplus2C: ExtensionFieldElement,
|
||||||
C4: ExtensionFieldElement,
|
C4: ExtensionFieldElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
struct CachedTripleCurveParameters {
|
struct CachedTripleCurveParameters {
|
||||||
Aminus2C: ExtensionFieldElement,
|
Aminus2C: ExtensionFieldElement,
|
||||||
C2: ExtensionFieldElement,
|
C2: ExtensionFieldElement,
|
||||||
|
@ -79,7 +83,9 @@ impl ProjectiveCurveParameters {
|
||||||
C: ExtensionFieldElement::one()
|
C: ExtensionFieldElement::one()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recover the curve parameters from three points on the curve.
|
/// Recover the curve parameters from three points on the curve.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn recover_curve_parameters(affine_xP: &ExtensionFieldElement, affine_xQ: &ExtensionFieldElement, affine_xQmP: &ExtensionFieldElement) ->
|
pub fn recover_curve_parameters(affine_xP: &ExtensionFieldElement, affine_xQ: &ExtensionFieldElement, affine_xQmP: &ExtensionFieldElement) ->
|
||||||
ProjectiveCurveParameters
|
ProjectiveCurveParameters
|
||||||
{
|
{
|
||||||
|
@ -101,6 +107,7 @@ impl ProjectiveCurveParameters {
|
||||||
|
|
||||||
ProjectiveCurveParameters{ A: a, C: c }
|
ProjectiveCurveParameters{ A: a, C: c }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the j-invariant of the given curve.
|
/// Compute the j-invariant of the given curve.
|
||||||
pub fn j_invariant(&self) -> ExtensionFieldElement {
|
pub fn j_invariant(&self) -> ExtensionFieldElement {
|
||||||
let a = &self.A;
|
let a = &self.A;
|
||||||
|
@ -122,7 +129,9 @@ impl ProjectiveCurveParameters {
|
||||||
|
|
||||||
v0
|
v0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute cached parameters `A + 2C, 4C`.
|
/// Compute cached parameters `A + 2C, 4C`.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn cached_params(&self) -> CachedCurveParameters {
|
fn cached_params(&self) -> CachedCurveParameters {
|
||||||
let mut Aplus2C = &self.C + &self.C; // = 2*C
|
let mut Aplus2C = &self.C + &self.C; // = 2*C
|
||||||
let C4 = &Aplus2C + &Aplus2C; // = 4*C
|
let C4 = &Aplus2C + &Aplus2C; // = 4*C
|
||||||
|
@ -130,7 +139,9 @@ impl ProjectiveCurveParameters {
|
||||||
|
|
||||||
CachedCurveParameters{ Aplus2C, C4 }
|
CachedCurveParameters{ Aplus2C, C4 }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute cached parameters `A - 2C, 2C`.
|
/// Compute cached parameters `A - 2C, 2C`.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn cached_triple_params(&self) -> CachedTripleCurveParameters {
|
fn cached_triple_params(&self) -> CachedTripleCurveParameters {
|
||||||
let C2 = &self.C + &self.C; // = 2*C
|
let C2 = &self.C + &self.C; // = 2*C
|
||||||
let Aminus2C = &self.A - &C2; // = A -2*C
|
let Aminus2C = &self.A - &C2; // = A -2*C
|
||||||
|
@ -143,6 +154,7 @@ impl ProjectiveCurveParameters {
|
||||||
///
|
///
|
||||||
/// This represents a point on the (Kummer line) of a Montgomery curve. The
|
/// This represents a point on the (Kummer line) of a Montgomery curve. The
|
||||||
/// curve is specified by a ProjectiveCurveParameters struct.
|
/// curve is specified by a ProjectiveCurveParameters struct.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub struct ProjectivePoint {
|
pub struct ProjectivePoint {
|
||||||
pub X: ExtensionFieldElement,
|
pub X: ExtensionFieldElement,
|
||||||
|
@ -181,9 +193,11 @@ impl Arbitrary for ProjectivePoint {
|
||||||
impl ProjectivePoint {
|
impl ProjectivePoint {
|
||||||
/// Creates a new zero `ProejctivePoint`.
|
/// Creates a new zero `ProejctivePoint`.
|
||||||
pub fn new() -> ProjectivePoint {
|
pub fn new() -> ProjectivePoint {
|
||||||
ProjectivePoint{ X: ExtensionFieldElement::zero(), Z: ExtensionFieldElement::zero() }
|
unsafe { zeroed() }
|
||||||
|
//ProjectivePoint{ X: ExtensionFieldElement::zero(), Z: ExtensionFieldElement::zero() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn from_affine_prime_field(x: &PrimeFieldElement) -> ProjectivePoint {
|
pub fn from_affine_prime_field(x: &PrimeFieldElement) -> ProjectivePoint {
|
||||||
let _X = ExtensionFieldElement{ A: x.A, B: ExtensionFieldElement::zero().B };
|
let _X = ExtensionFieldElement{ A: x.A, B: ExtensionFieldElement::zero().B };
|
||||||
ProjectivePoint{
|
ProjectivePoint{
|
||||||
|
@ -203,13 +217,16 @@ impl ProjectivePoint {
|
||||||
let affine_x = &self.Z.inv() * &self.X;
|
let affine_x = &self.Z.inv() * &self.X;
|
||||||
affine_x
|
affine_x
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if both sides are equal. Takes variable time.
|
/// Returns true if both sides are equal. Takes variable time.
|
||||||
pub fn vartime_eq(&self, _rhs: &ProjectivePoint) -> bool {
|
pub fn vartime_eq(&self, _rhs: &ProjectivePoint) -> bool {
|
||||||
let t0 = &self.X * &_rhs.Z;
|
let t0 = &self.X * &_rhs.Z;
|
||||||
let t1 = &self.Z * &_rhs.X;
|
let t1 = &self.Z * &_rhs.X;
|
||||||
t0.vartime_eq(&t1)
|
t0.vartime_eq(&t1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given `xP = x(P), xQ = x(Q)`, and `xPmQ = x(P-Q)`, compute `xR = x(P+Q)`.
|
/// Given `xP = x(P), xQ = x(Q)`, and `xPmQ = x(P-Q)`, compute `xR = x(P+Q)`.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn add(&self, xQ: &ProjectivePoint, xPmQ: &ProjectivePoint) -> ProjectivePoint {
|
fn add(&self, xQ: &ProjectivePoint, xPmQ: &ProjectivePoint) -> ProjectivePoint {
|
||||||
let xP = *self;
|
let xP = *self;
|
||||||
// Algorithm 1 of Costello-Smith.
|
// Algorithm 1 of Costello-Smith.
|
||||||
|
@ -225,7 +242,9 @@ impl ProjectivePoint {
|
||||||
|
|
||||||
ProjectivePoint{ X: x, Z: z }
|
ProjectivePoint{ X: x, Z: z }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given `xP = x(P)` and cached curve parameters `Aplus2C = A + 2*C, C4 = 4*C`, compute `xQ = x([2]P)`.
|
/// Given `xP = x(P)` and cached curve parameters `Aplus2C = A + 2*C, C4 = 4*C`, compute `xQ = x([2]P)`.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn double(&self, curve: &CachedCurveParameters) -> ProjectivePoint {
|
fn double(&self, curve: &CachedCurveParameters) -> ProjectivePoint {
|
||||||
let xP = *self;
|
let xP = *self;
|
||||||
// Algorithm 2 of Costello-Smith, amended to work with projective curve coefficients.
|
// Algorithm 2 of Costello-Smith, amended to work with projective curve coefficients.
|
||||||
|
@ -243,9 +262,11 @@ impl ProjectivePoint {
|
||||||
// = ((X+Z)^2(X-Z)^2 : (4XZ((a + 2)/4) + (X-Z)^2)4XZ )
|
// = ((X+Z)^2(X-Z)^2 : (4XZ((a + 2)/4) + (X-Z)^2)4XZ )
|
||||||
ProjectivePoint{ X: x, Z: z }
|
ProjectivePoint{ X: x, Z: z }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the x-coordinate of `2P` and `P+Q` from the x-coordinate of `P, Q` and `P-Q`.
|
/// Calculates the x-coordinate of `2P` and `P+Q` from the x-coordinate of `P, Q` and `P-Q`.
|
||||||
// Params: `C4 = 4*C` and `Aplus2C = (A+2C)`
|
// Params: `C4 = 4*C` and `Aplus2C = (A+2C)`
|
||||||
// Cost: 8M+4S+8A in `Fp2`
|
// Cost: 8M+4S+8A in `Fp2`
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn dbl_add(&self, xQ: &ProjectivePoint, xPmQ: &ProjectivePoint, params: &CachedCurveParameters) ->
|
fn dbl_add(&self, xQ: &ProjectivePoint, xPmQ: &ProjectivePoint, params: &CachedCurveParameters) ->
|
||||||
(ProjectivePoint, ProjectivePoint)
|
(ProjectivePoint, ProjectivePoint)
|
||||||
{
|
{
|
||||||
|
@ -281,17 +302,21 @@ impl ProjectivePoint {
|
||||||
|
|
||||||
(x2P, xPaddQ)
|
(x2P, xPaddQ)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given the curve parameters, `xP = x(P)`, and `k >= 0`, compute `xQ = x([2^k]P)`.
|
/// Given the curve parameters, `xP = x(P)`, and `k >= 0`, compute `xQ = x([2^k]P)`.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn pow2k(&self, curve: &ProjectiveCurveParameters, k: u32) -> ProjectivePoint {
|
pub fn pow2k(&self, curve: &ProjectiveCurveParameters, k: u32) -> ProjectivePoint {
|
||||||
let cached_params = curve.cached_params();
|
let cached_params = curve.cached_params();
|
||||||
let mut xQ = *self;
|
let mut xQ = *self;
|
||||||
for _ in 0..k { xQ = xQ.double(&cached_params); }
|
for _ in 0..k { xQ = xQ.double(&cached_params); }
|
||||||
xQ
|
xQ
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses the efficient Montgomery tripling formulas from FLOR-SIDH-x64
|
// Uses the efficient Montgomery tripling formulas from FLOR-SIDH-x64
|
||||||
// Reference: A faster SW implementation of SIDH (github.com/armfazh/flor-sidh-x64).
|
// Reference: A faster SW implementation of SIDH (github.com/armfazh/flor-sidh-x64).
|
||||||
/// Given `xP = x(P)` and cached tripling curve parameters `Aminus2C = A - 2*C, C2 = 2*C`, compute `xQ = x([3]P)`.
|
/// Given `xP = x(P)` and cached tripling curve parameters `Aminus2C = A - 2*C, C2 = 2*C`, compute `xQ = x([3]P)`.
|
||||||
/// Returns `xQ` to allow chaining.
|
/// Returns `xQ` to allow chaining.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn triple(&self, curve: &CachedTripleCurveParameters) -> ProjectivePoint {
|
fn triple(&self, curve: &CachedTripleCurveParameters) -> ProjectivePoint {
|
||||||
let xP = *self;
|
let xP = *self;
|
||||||
let (x1, z1) = (&xP.X, &xP.Z);
|
let (x1, z1) = (&xP.X, &xP.Z);
|
||||||
|
@ -319,19 +344,23 @@ impl ProjectivePoint {
|
||||||
|
|
||||||
ProjectivePoint{ X: x, Z: z }
|
ProjectivePoint{ X: x, Z: z }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given the curve parameters, `xP = x(P)`, and `k >= 0`, compute `xQ = x([3^k]P)`.
|
/// Given the curve parameters, `xP = x(P)`, and `k >= 0`, compute `xQ = x([3^k]P)`.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn pow3k(&self, curve: &ProjectiveCurveParameters, k: u32) -> ProjectivePoint {
|
pub fn pow3k(&self, curve: &ProjectiveCurveParameters, k: u32) -> ProjectivePoint {
|
||||||
let cached_params = curve.cached_triple_params();
|
let cached_params = curve.cached_triple_params();
|
||||||
let mut xQ = *self;
|
let mut xQ = *self;
|
||||||
for _ in 0..k { xQ = xQ.triple(&cached_params); }
|
for _ in 0..k { xQ = xQ.triple(&cached_params); }
|
||||||
xQ
|
xQ
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given `x(P)` and a scalar `m` in little-endian bytes, compute `x([m]P)` using the
|
/// Given `x(P)` and a scalar `m` in little-endian bytes, compute `x([m]P)` using the
|
||||||
/// Montgomery ladder. This is described in Algorithm 8 of Costello-Smith.
|
/// Montgomery ladder. This is described in Algorithm 8 of Costello-Smith.
|
||||||
///
|
///
|
||||||
/// This function's execution time is dependent only on the byte-length of the
|
/// This function's execution time is dependent only on the byte-length of the
|
||||||
/// input scalar. All scalars of the same input length execute in uniform time.
|
/// input scalar. All scalars of the same input length execute in uniform time.
|
||||||
/// The scalar can be padded with zero bytes to ensure a uniform length.
|
/// The scalar can be padded with zero bytes to ensure a uniform length.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn scalar_mul(&self, curve: &ProjectiveCurveParameters, scalar: &[u8]) -> ProjectivePoint {
|
fn scalar_mul(&self, curve: &ProjectiveCurveParameters, scalar: &[u8]) -> ProjectivePoint {
|
||||||
let xP = *self;
|
let xP = *self;
|
||||||
let cached_params = curve.cached_params();
|
let cached_params = curve.cached_params();
|
||||||
|
@ -357,12 +386,14 @@ impl ProjectivePoint {
|
||||||
let xQ = x0;
|
let xQ = x0;
|
||||||
xQ
|
xQ
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given `P = (x_P, y_P)` in affine coordinates, as well as projective points
|
/// Given `P = (x_P, y_P)` in affine coordinates, as well as projective points
|
||||||
/// `x(Q), x(R) = x(P+Q)`, all in the prime-field subgroup of the starting curve
|
/// `x(Q), x(R) = x(P+Q)`, all in the prime-field subgroup of the starting curve
|
||||||
/// `E_0(F_p)`, use the Okeya-Sakurai coordinate recovery strategy to recover `Q =
|
/// `E_0(F_p)`, use the Okeya-Sakurai coordinate recovery strategy to recover `Q =
|
||||||
/// (X_Q : Y_Q : Z_Q)`.
|
/// (X_Q : Y_Q : Z_Q)`.
|
||||||
///
|
///
|
||||||
/// This is Algorithm 5 of Costello-Smith, with the constants `a = 0, b = 1` hardcoded.
|
/// This is Algorithm 5 of Costello-Smith, with the constants `a = 0, b = 1` hardcoded.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn okeya_sakurai_coordinate_recovery(affine_xP: &PrimeFieldElement, affine_yP: &PrimeFieldElement,
|
fn okeya_sakurai_coordinate_recovery(affine_xP: &PrimeFieldElement, affine_yP: &PrimeFieldElement,
|
||||||
xQ: &ProjectivePrimeFieldPoint, xR: &ProjectivePrimeFieldPoint) ->
|
xQ: &ProjectivePrimeFieldPoint, xR: &ProjectivePrimeFieldPoint) ->
|
||||||
(PrimeFieldElement, PrimeFieldElement, PrimeFieldElement)
|
(PrimeFieldElement, PrimeFieldElement, PrimeFieldElement)
|
||||||
|
@ -387,6 +418,7 @@ impl ProjectivePoint {
|
||||||
|
|
||||||
(X_Q, Y_Q, Z_Q)
|
(X_Q, Y_Q, Z_Q)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given `x(P), x(Q), x(P-Q)`, as well as a scalar m in little-endian bytes,
|
/// Given `x(P), x(Q), x(P-Q)`, as well as a scalar m in little-endian bytes,
|
||||||
/// compute `x(P + [m]Q)` using the "three-point ladder" of de Feo, Jao, and Plut.
|
/// compute `x(P + [m]Q)` using the "three-point ladder" of de Feo, Jao, and Plut.
|
||||||
///
|
///
|
||||||
|
@ -427,6 +459,7 @@ impl ProjectivePoint {
|
||||||
//
|
//
|
||||||
// return x2
|
// return x2
|
||||||
//
|
//
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn three_point_ladder(xP: &ProjectivePoint, xQ: &ProjectivePoint, xPmQ: &ProjectivePoint,
|
pub fn three_point_ladder(xP: &ProjectivePoint, xQ: &ProjectivePoint, xPmQ: &ProjectivePoint,
|
||||||
curve: &ProjectiveCurveParameters, scalar: &[u8]) -> ProjectivePoint
|
curve: &ProjectiveCurveParameters, scalar: &[u8]) -> ProjectivePoint
|
||||||
{
|
{
|
||||||
|
@ -457,8 +490,10 @@ impl ProjectivePoint {
|
||||||
let xR = x2;
|
let xR = x2;
|
||||||
xR
|
xR
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Right-to-left point multiplication, which given the x-coordinate
|
/// Right-to-left point multiplication, which given the x-coordinate
|
||||||
/// of `P, Q` and `P-Q` calculates the x-coordinate of `R=P+[k]Q`.
|
/// of `P, Q` and `P-Q` calculates the x-coordinate of `R=P+[k]Q`.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn right_to_left_ladder(xP: &ProjectivePoint, xQ: &ProjectivePoint, xPmQ: &ProjectivePoint,
|
pub fn right_to_left_ladder(xP: &ProjectivePoint, xQ: &ProjectivePoint, xPmQ: &ProjectivePoint,
|
||||||
curve: &ProjectiveCurveParameters, scalar: &[u8]) -> ProjectivePoint
|
curve: &ProjectiveCurveParameters, scalar: &[u8]) -> ProjectivePoint
|
||||||
{
|
{
|
||||||
|
@ -482,8 +517,10 @@ impl ProjectivePoint {
|
||||||
let xR = R1;
|
let xR = R1;
|
||||||
xR
|
xR
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given the affine x-coordinate `affine_xP` of `P`, compute the x-coordinate
|
/// Given the affine x-coordinate `affine_xP` of `P`, compute the x-coordinate
|
||||||
/// `x(\tau(P)-P) of \tau(P)-P`.
|
/// `x(\tau(P)-P) of \tau(P)-P`.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn distort_and_difference(affine_xP: &PrimeFieldElement) -> ProjectivePoint {
|
pub fn distort_and_difference(affine_xP: &PrimeFieldElement) -> ProjectivePoint {
|
||||||
let mut t0 = affine_xP.square(); // = x_P^2
|
let mut t0 = affine_xP.square(); // = x_P^2
|
||||||
let t1 = &PrimeFieldElement::one() + &t0; // = x_P^2 + 1
|
let t1 = &PrimeFieldElement::one() + &t0; // = x_P^2 + 1
|
||||||
|
@ -496,6 +533,7 @@ impl ProjectivePoint {
|
||||||
let xR = ProjectivePoint{ X: x, Z: z };
|
let xR = ProjectivePoint{ X: x, Z: z };
|
||||||
xR
|
xR
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given an affine point `P = (x_P, y_P)` in the prime-field subgroup of the
|
/// Given an affine point `P = (x_P, y_P)` in the prime-field subgroup of the
|
||||||
/// starting curve `E_0(F_p)`, together with a secret scalar `m`, compute `x(P+[m]Q)`,
|
/// starting curve `E_0(F_p)`, together with a secret scalar `m`, compute `x(P+[m]Q)`,
|
||||||
/// where `Q = \tau(P)` is the image of `P` under the distortion map.
|
/// where `Q = \tau(P)` is the image of `P` under the distortion map.
|
||||||
|
@ -589,6 +627,7 @@ impl ProjectivePoint {
|
||||||
// These formulas could probably be combined with the formulas for y-recover
|
// These formulas could probably be combined with the formulas for y-recover
|
||||||
// and computed more efficiently, but efficiency isn't the biggest concern
|
// and computed more efficiently, but efficiency isn't the biggest concern
|
||||||
// here, since the bulk of the cost is already in the ladder.
|
// here, since the bulk of the cost is already in the ladder.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn secret_point(affine_xP: &PrimeFieldElement, affine_yP: &PrimeFieldElement, scalar: &[u8]) -> ProjectivePoint {
|
pub fn secret_point(affine_xP: &PrimeFieldElement, affine_yP: &PrimeFieldElement, scalar: &[u8]) -> ProjectivePoint {
|
||||||
let mut xQ = ProjectivePrimeFieldPoint::from_affine(affine_xP);
|
let mut xQ = ProjectivePrimeFieldPoint::from_affine(affine_xP);
|
||||||
xQ.X = (&xQ.X).neg();
|
xQ.X = (&xQ.X).neg();
|
||||||
|
@ -653,6 +692,7 @@ impl ProjectivePoint {
|
||||||
///
|
///
|
||||||
/// This represents a point on the (Kummer line) of the prime-field subgroup of
|
/// This represents a point on the (Kummer line) of the prime-field subgroup of
|
||||||
/// the base curve `E_0(F_p)`, defined by `E_0 : y^2 = x^3 + x`.
|
/// the base curve `E_0(F_p)`, defined by `E_0 : y^2 = x^3 + x`.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
struct ProjectivePrimeFieldPoint {
|
struct ProjectivePrimeFieldPoint {
|
||||||
X: PrimeFieldElement,
|
X: PrimeFieldElement,
|
||||||
|
@ -691,7 +731,8 @@ impl Arbitrary for ProjectivePrimeFieldPoint {
|
||||||
impl ProjectivePrimeFieldPoint {
|
impl ProjectivePrimeFieldPoint {
|
||||||
/// Creates a new zero `ProjectivePrimeFieldPoint`.
|
/// Creates a new zero `ProjectivePrimeFieldPoint`.
|
||||||
pub fn new() -> ProjectivePrimeFieldPoint {
|
pub fn new() -> ProjectivePrimeFieldPoint {
|
||||||
ProjectivePrimeFieldPoint{ X: PrimeFieldElement::zero(), Z: PrimeFieldElement::zero() }
|
unsafe { zeroed() }
|
||||||
|
//ProjectivePrimeFieldPoint{ X: PrimeFieldElement::zero(), Z: PrimeFieldElement::zero() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_affine(x: &PrimeFieldElement) -> ProjectivePrimeFieldPoint {
|
pub fn from_affine(x: &PrimeFieldElement) -> ProjectivePrimeFieldPoint {
|
||||||
|
@ -702,16 +743,18 @@ impl ProjectivePrimeFieldPoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_affine(&self) -> PrimeFieldElement {
|
pub fn to_affine(&self) -> PrimeFieldElement {
|
||||||
let affine_x = &self.Z.inv() * &self.X;
|
&self.Z.inv() * &self.X
|
||||||
affine_x
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if both sides are equal. Takes variable time.
|
/// Returns true if both sides are equal. Takes variable time.
|
||||||
pub fn vartime_eq(&self, _rhs: &ProjectivePrimeFieldPoint) -> bool {
|
pub fn vartime_eq(&self, _rhs: &ProjectivePrimeFieldPoint) -> bool {
|
||||||
let t0 = &self.X * &_rhs.Z;
|
let t0 = &self.X * &_rhs.Z;
|
||||||
let t1 = &self.Z * &_rhs.X;
|
let t1 = &self.Z * &_rhs.X;
|
||||||
t0.vartime_eq(&t1)
|
t0.vartime_eq(&t1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given `xP = x(P), xQ = x(Q)`, and `xPmQ = x(P-Q)`, compute `xR = x(P+Q)`.
|
/// Given `xP = x(P), xQ = x(Q)`, and `xPmQ = x(P-Q)`, compute `xR = x(P+Q)`.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn add(&self, xQ: &ProjectivePrimeFieldPoint, xPmQ: &ProjectivePrimeFieldPoint) ->
|
fn add(&self, xQ: &ProjectivePrimeFieldPoint, xPmQ: &ProjectivePrimeFieldPoint) ->
|
||||||
ProjectivePrimeFieldPoint
|
ProjectivePrimeFieldPoint
|
||||||
{
|
{
|
||||||
|
@ -729,10 +772,12 @@ impl ProjectivePrimeFieldPoint {
|
||||||
|
|
||||||
ProjectivePrimeFieldPoint{ X: x, Z: z }
|
ProjectivePrimeFieldPoint{ X: x, Z: z }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given `xP = x(P)` and cached curve parameter `aPlus2Over4 = (a+2)/4, compute xQ = x([2]P)`.
|
/// Given `xP = x(P)` and cached curve parameter `aPlus2Over4 = (a+2)/4, compute xQ = x([2]P)`.
|
||||||
//
|
//
|
||||||
// Note that we don't use projective curve coefficients here because we only
|
// Note that we don't use projective curve coefficients here because we only
|
||||||
// ever use a fixed curve (in our case, the base curve E_0).
|
// ever use a fixed curve (in our case, the base curve E_0).
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn double(&self, aPlus2Over4: &PrimeFieldElement) -> ProjectivePrimeFieldPoint {
|
fn double(&self, aPlus2Over4: &PrimeFieldElement) -> ProjectivePrimeFieldPoint {
|
||||||
let xP = *self;
|
let xP = *self;
|
||||||
// Algorithm 2 of Costello-Smith
|
// Algorithm 2 of Costello-Smith
|
||||||
|
@ -747,11 +792,13 @@ impl ProjectivePrimeFieldPoint {
|
||||||
// = ((X+Z)^2(X-Z)^2 : (4XZ((a + 2)/4) + (X-Z)^2)4XZ )
|
// = ((X+Z)^2(X-Z)^2 : (4XZ((a + 2)/4) + (X-Z)^2)4XZ )
|
||||||
ProjectivePrimeFieldPoint{ X: x, Z: z }
|
ProjectivePrimeFieldPoint{ X: x, Z: z }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the x-coordinate of `2P` and `P+Q` from the x-coordinate of `P, Q` and `P-Q`.
|
/// Calculates the x-coordinate of `2P` and `P+Q` from the x-coordinate of `P, Q` and `P-Q`.
|
||||||
// Assumptions:
|
// Assumptions:
|
||||||
// aPlus2Over2 = (A+2)/4.
|
// aPlus2Over2 = (A+2)/4.
|
||||||
// z(P-Q) = 1, the Z-coordinate of P-Q is equal to 1.
|
// z(P-Q) = 1, the Z-coordinate of P-Q is equal to 1.
|
||||||
// Cost: 6M+4S+8A in Fp
|
// Cost: 6M+4S+8A in Fp
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn dbl_add(&self, xQ: &ProjectivePrimeFieldPoint, xPmQ: &ProjectivePrimeFieldPoint, aPlus2Over4: &PrimeFieldElement) ->
|
fn dbl_add(&self, xQ: &ProjectivePrimeFieldPoint, xPmQ: &ProjectivePrimeFieldPoint, aPlus2Over4: &PrimeFieldElement) ->
|
||||||
(ProjectivePrimeFieldPoint, ProjectivePrimeFieldPoint)
|
(ProjectivePrimeFieldPoint, ProjectivePrimeFieldPoint)
|
||||||
{
|
{
|
||||||
|
@ -785,6 +832,7 @@ impl ProjectivePrimeFieldPoint {
|
||||||
|
|
||||||
(x2P, xPaddQ)
|
(x2P, xPaddQ)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given `x(P)` and a scalar m in little-endian bytes, compute `x([m]P), x([m+1]P)`
|
/// Given `x(P)` and a scalar m in little-endian bytes, compute `x([m]P), x([m+1]P)`
|
||||||
/// using the Montgomery ladder. This is described in Algorithm 8 of Costello-Smith.
|
/// using the Montgomery ladder. This is described in Algorithm 8 of Costello-Smith.
|
||||||
///
|
///
|
||||||
|
@ -794,6 +842,7 @@ impl ProjectivePrimeFieldPoint {
|
||||||
/// This function's execution time is dependent only on the byte-length of the input
|
/// This function's execution time is dependent only on the byte-length of the input
|
||||||
/// scalar. All scalars of the same input length execute in uniform time.
|
/// scalar. All scalars of the same input length execute in uniform time.
|
||||||
/// The scalar can be padded with zero bytes to ensure a uniform length.
|
/// The scalar can be padded with zero bytes to ensure a uniform length.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn scalar_mul_prime_field(&self, aPlus2Over4: &PrimeFieldElement, scalar: &[u8]) -> (ProjectivePrimeFieldPoint, ProjectivePrimeFieldPoint)
|
fn scalar_mul_prime_field(&self, aPlus2Over4: &PrimeFieldElement, scalar: &[u8]) -> (ProjectivePrimeFieldPoint, ProjectivePrimeFieldPoint)
|
||||||
{
|
{
|
||||||
let xP = *self;
|
let xP = *self;
|
||||||
|
@ -831,6 +880,7 @@ impl ProjectivePrimeFieldPoint {
|
||||||
// sage: X3, Y3, Z3 = 3*P
|
// sage: X3, Y3, Z3 = 3*P
|
||||||
// sage: m = 96550223052359874398280314003345143371473380422728857598463622014420884224892
|
// sage: m = 96550223052359874398280314003345143371473380422728857598463622014420884224892
|
||||||
//
|
//
|
||||||
|
#[allow(non_snake_case)]
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
|
@ -9,11 +9,12 @@
|
||||||
//! This module contains finite field arithmetic functionality for SIDH,
|
//! This module contains finite field arithmetic functionality for SIDH,
|
||||||
//! which is not part of the public API.
|
//! which is not part of the public API.
|
||||||
|
|
||||||
use crate::sidh::fp::*;
|
use crate::sidhp751::fp::*;
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use std::cmp::{Eq, PartialEq};
|
use std::cmp::{Eq, PartialEq};
|
||||||
|
use std::mem::zeroed;
|
||||||
use std::ops::*;
|
use std::ops::*;
|
||||||
|
|
||||||
use subtle::ConditionallySelectable;
|
use subtle::ConditionallySelectable;
|
||||||
|
@ -28,6 +29,7 @@ use quickcheck::{Arbitrary, Gen};
|
||||||
//-----------------------------------------------------------------------------//
|
//-----------------------------------------------------------------------------//
|
||||||
|
|
||||||
/// Represents an element of the extension field `F_{p^2}`.
|
/// Represents an element of the extension field `F_{p^2}`.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub struct ExtensionFieldElement {
|
pub struct ExtensionFieldElement {
|
||||||
/// This field element is in Montgomery form, so that the value `A` is
|
/// This field element is in Montgomery form, so that the value `A` is
|
||||||
|
@ -177,11 +179,13 @@ impl Arbitrary for ExtensionFieldElement {
|
||||||
impl ExtensionFieldElement {
|
impl ExtensionFieldElement {
|
||||||
/// Construct a zero `ExtensionFieldElement`.
|
/// Construct a zero `ExtensionFieldElement`.
|
||||||
pub fn zero() -> ExtensionFieldElement {
|
pub fn zero() -> ExtensionFieldElement {
|
||||||
ExtensionFieldElement{
|
unsafe { zeroed() }
|
||||||
A: Fp751Element([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
|
//ExtensionFieldElement{
|
||||||
B: Fp751Element([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
|
// A: Fp751Element([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
|
||||||
}
|
// B: Fp751Element([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a one `ExtensionFieldElement`.
|
/// Construct a one `ExtensionFieldElement`.
|
||||||
pub fn one() -> ExtensionFieldElement {
|
pub fn one() -> ExtensionFieldElement {
|
||||||
ExtensionFieldElement{
|
ExtensionFieldElement{
|
||||||
|
@ -189,6 +193,7 @@ impl ExtensionFieldElement {
|
||||||
B: Fp751Element([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
|
B: Fp751Element([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set output to `1/x`.
|
/// Set output to `1/x`.
|
||||||
pub fn inv(&self) -> ExtensionFieldElement {
|
pub fn inv(&self) -> ExtensionFieldElement {
|
||||||
let a = &self.A;
|
let a = &self.A;
|
||||||
|
@ -227,6 +232,7 @@ impl ExtensionFieldElement {
|
||||||
B: _b
|
B: _b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set (y1, y2, y3) = (1/x1, 1/x2, 1/x3).
|
// Set (y1, y2, y3) = (1/x1, 1/x2, 1/x3).
|
||||||
//
|
//
|
||||||
// All xi, yi must be distinct.
|
// All xi, yi must be distinct.
|
||||||
|
@ -244,6 +250,7 @@ impl ExtensionFieldElement {
|
||||||
|
|
||||||
(_y1, _y2, _y3)
|
(_y1, _y2, _y3)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the output to `x^2`.
|
/// Set the output to `x^2`.
|
||||||
pub fn square(&self) -> ExtensionFieldElement {
|
pub fn square(&self) -> ExtensionFieldElement {
|
||||||
let a = &self.A;
|
let a = &self.A;
|
||||||
|
@ -268,11 +275,13 @@ impl ExtensionFieldElement {
|
||||||
B: _b
|
B: _b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if both sides are equal. Takes variable time.
|
/// Returns true if both sides are equal. Takes variable time.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn vartime_eq(&self, _rhs: &ExtensionFieldElement) -> bool {
|
pub fn vartime_eq(&self, _rhs: &ExtensionFieldElement) -> bool {
|
||||||
(&self.A == &_rhs.A) && (&self.B == &_rhs.B)
|
(&self.A == &_rhs.A) && (&self.B == &_rhs.B)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the input to wire format.
|
/// Convert the input to wire format.
|
||||||
pub fn to_bytes(&self) -> [u8; 188] {
|
pub fn to_bytes(&self) -> [u8; 188] {
|
||||||
let mut bytes = [0u8; 188];
|
let mut bytes = [0u8; 188];
|
||||||
|
@ -280,6 +289,7 @@ impl ExtensionFieldElement {
|
||||||
bytes[94..188].clone_from_slice(&self.B.to_bytes());
|
bytes[94..188].clone_from_slice(&self.B.to_bytes());
|
||||||
bytes
|
bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read 188 bytes into the given `ExtensionFieldElement`.
|
/// Read 188 bytes into the given `ExtensionFieldElement`.
|
||||||
pub fn from_bytes(bytes: &[u8]) -> ExtensionFieldElement {
|
pub fn from_bytes(bytes: &[u8]) -> ExtensionFieldElement {
|
||||||
assert!(bytes.len() >= 188, "Too short input to ExtensionFieldElement from_bytes, expected 188 bytes");
|
assert!(bytes.len() >= 188, "Too short input to ExtensionFieldElement from_bytes, expected 188 bytes");
|
||||||
|
@ -294,6 +304,7 @@ impl ExtensionFieldElement {
|
||||||
//-----------------------------------------------------------------------------//
|
//-----------------------------------------------------------------------------//
|
||||||
|
|
||||||
/// Represents an element of the prime field `F_p`.
|
/// Represents an element of the prime field `F_p`.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub struct PrimeFieldElement {
|
pub struct PrimeFieldElement {
|
||||||
/// This field element is in Montgomery form, so that the value `A` is
|
/// This field element is in Montgomery form, so that the value `A` is
|
||||||
|
@ -396,16 +407,19 @@ impl Arbitrary for PrimeFieldElement {
|
||||||
impl PrimeFieldElement {
|
impl PrimeFieldElement {
|
||||||
/// Construct a zero `PrimeFieldElement`.
|
/// Construct a zero `PrimeFieldElement`.
|
||||||
pub fn zero() -> PrimeFieldElement {
|
pub fn zero() -> PrimeFieldElement {
|
||||||
PrimeFieldElement{
|
unsafe { zeroed() }
|
||||||
A: Fp751Element([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
|
//PrimeFieldElement{
|
||||||
}
|
// A: Fp751Element([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a one `PrimeFieldElement`.
|
/// Construct a one `PrimeFieldElement`.
|
||||||
pub fn one() -> PrimeFieldElement {
|
pub fn one() -> PrimeFieldElement {
|
||||||
PrimeFieldElement{
|
PrimeFieldElement{
|
||||||
A: Fp751Element([0x249ad, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x83100000, 0x375c6c66, 0x5527b1e4, 0x3f4f24d0, 0x697797bf, 0xac5c4e2e, 0xc89db7b2, 0xd2076956, 0x4ca4b439, 0x7512c7e9, 0x10f7926c, 0x24bce5e2, 0x2d5b]),
|
A: Fp751Element([0x249ad, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x83100000, 0x375c6c66, 0x5527b1e4, 0x3f4f24d0, 0x697797bf, 0xac5c4e2e, 0xc89db7b2, 0xd2076956, 0x4ca4b439, 0x7512c7e9, 0x10f7926c, 0x24bce5e2, 0x2d5b]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the output to `x^2`.
|
/// Set the output to `x^2`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn square(&self) -> PrimeFieldElement {
|
pub fn square(&self) -> PrimeFieldElement {
|
||||||
|
@ -416,12 +430,14 @@ impl PrimeFieldElement {
|
||||||
|
|
||||||
PrimeFieldElement{ A: _a }
|
PrimeFieldElement{ A: _a }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Raise self to `2^(2^k)`-th power, for `k >= 1`, by repeated squarings.
|
/// Raise self to `2^(2^k)`-th power, for `k >= 1`, by repeated squarings.
|
||||||
fn pow2k(&self, k: u8) -> PrimeFieldElement {
|
fn pow2k(&self, k: u8) -> PrimeFieldElement {
|
||||||
let mut result = self.square();
|
let mut result = self.square();
|
||||||
for _ in 1..k { result = result.square(); }
|
for _ in 1..k { result = result.square(); }
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set output to `x^((p-3)/4)`. If `x` is square, this is `1/sqrt(x)`.
|
/// Set output to `x^((p-3)/4)`. If `x` is square, this is `1/sqrt(x)`.
|
||||||
fn p34(&self) -> PrimeFieldElement {
|
fn p34(&self) -> PrimeFieldElement {
|
||||||
// Sliding-window strategy computed with Sage, awk, sed, and tr.
|
// Sliding-window strategy computed with Sage, awk, sed, and tr.
|
||||||
|
@ -455,6 +471,7 @@ impl PrimeFieldElement {
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set output to `sqrt(x)`, if x is a square. If `x` is nonsquare output is undefined.
|
/// Set output to `sqrt(x)`, if x is a square. If `x` is nonsquare output is undefined.
|
||||||
fn sqrt(&self) -> PrimeFieldElement {
|
fn sqrt(&self) -> PrimeFieldElement {
|
||||||
let mut result = self.p34(); // result = (y^2)^((p-3)/4) = y^((p-3)/2)
|
let mut result = self.p34(); // result = (y^2)^((p-3)/4) = y^((p-3)/2)
|
||||||
|
@ -462,6 +479,7 @@ impl PrimeFieldElement {
|
||||||
// Now result^2 = y^(p+1) = y^2 = x, so result = sqrt(x).
|
// Now result^2 = y^(p+1) = y^2 = x, so result = sqrt(x).
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set output to `1/x`.
|
/// Set output to `1/x`.
|
||||||
pub fn inv(&self) -> PrimeFieldElement {
|
pub fn inv(&self) -> PrimeFieldElement {
|
||||||
let mut result = self.square(); // result = x^2
|
let mut result = self.square(); // result = x^2
|
||||||
|
@ -470,7 +488,9 @@ impl PrimeFieldElement {
|
||||||
result = &result * self; // result = x^(p-2)
|
result = &result * self; // result = x^(p-2)
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if both sides are equal. Takes variable time.
|
/// Returns true if both sides are equal. Takes variable time.
|
||||||
|
#[inline(always)]
|
||||||
pub fn vartime_eq(&self, _rhs: &PrimeFieldElement) -> bool {
|
pub fn vartime_eq(&self, _rhs: &PrimeFieldElement) -> bool {
|
||||||
&self.A == &_rhs.A
|
&self.A == &_rhs.A
|
||||||
}
|
}
|
||||||
|
@ -652,12 +672,12 @@ impl Fp751X2 {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn checklt238(scalar: &[u8; 48], result: &mut u32) {
|
pub fn checklt238(scalar: &[u8; 48], result: &mut u32) {
|
||||||
crate::sidh::fp::checklt238(scalar, result);
|
crate::sidhp751::fp::checklt238(scalar, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn mulby3(scalar: &mut [u8; 48]) {
|
pub fn mulby3(scalar: &mut [u8; 48]) {
|
||||||
crate::sidh::fp::mulby3(scalar);
|
crate::sidhp751::fp::mulby3(scalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
use crate::random::SecureRandom;
|
use crate::random::SecureRandom;
|
||||||
|
|
||||||
use std::mem::size_of;
|
use std::mem::{size_of, MaybeUninit, zeroed};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::ops::Neg;
|
use std::ops::Neg;
|
||||||
|
|
||||||
|
@ -40,28 +40,13 @@ const P751: [u32; FP751_NUM_WORDS] = [4294967295, 4294967295, 4294967295, 429496
|
||||||
const P751P1: [u32; FP751_NUM_WORDS] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4004511744, 1241020584, 3823933061, 335006838, 3667237658, 3605784694, 139368551, 1555191624, 2237838596, 2545605734, 236097695, 3577870108, 28645];
|
const P751P1: [u32; FP751_NUM_WORDS] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4004511744, 1241020584, 3823933061, 335006838, 3667237658, 3605784694, 139368551, 1555191624, 2237838596, 2545605734, 236097695, 3577870108, 28645];
|
||||||
const P751X2: [u32; FP751_NUM_WORDS] = [4294967294, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 3714056191, 2482041169, 3352898826, 670013677, 3039508020, 2916602093, 278737103, 3110383248, 180709896, 796244173, 472195391, 2860772920, 57291];
|
const P751X2: [u32; FP751_NUM_WORDS] = [4294967294, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 3714056191, 2482041169, 3352898826, 670013677, 3039508020, 2916602093, 278737103, 3110383248, 180709896, 796244173, 472195391, 2860772920, 57291];
|
||||||
|
|
||||||
// Return 1 if x != 0, and 0 otherwise.
|
fn digit_x_digit(a: u32, b: u32, c: &mut [u32; 2]) {
|
||||||
#[inline(always)]
|
#[allow(non_upper_case_globals)]
|
||||||
fn is_digit_nonzero_ct(x: &u32) -> u32 {
|
const sizeof_u32: u32 = size_of::<u32>() as u32;
|
||||||
((x | ((0 as u32).wrapping_sub(*x))) >> (RADIX-1)) as u32
|
#[allow(non_upper_case_globals)]
|
||||||
}
|
const mask_low: u32 = <u32>::MAX >> (sizeof_u32 * 4);
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
// Return 1 if x = 0, and 0 otherwise.
|
const mask_high: u32 = <u32>::MAX << (sizeof_u32 * 4);
|
||||||
#[inline(always)]
|
|
||||||
fn is_digit_zero_ct(x: &u32) -> u32 {
|
|
||||||
(1 ^ is_digit_nonzero_ct(x)) as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return 1 if x < y, and 0 otherwise.
|
|
||||||
#[inline(always)]
|
|
||||||
fn is_digit_lessthan_ct(x: &u32, y: &u32) -> u32 {
|
|
||||||
((x ^ ((x ^ y) | ((x.wrapping_sub(*y)) ^ y))) >> (RADIX-1)) as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
fn digit_x_digit(a: &u32, b: &u32, c: &mut [u32]) {
|
|
||||||
let sizeof_u32 = size_of::<u32>() as u32;
|
|
||||||
let mask_low = <u32>::max_value() >> (sizeof_u32 * 4);
|
|
||||||
let mask_high = <u32>::max_value() << (sizeof_u32 * 4);
|
|
||||||
|
|
||||||
let al = a & mask_low;
|
let al = a & mask_low;
|
||||||
let ah = a >> (sizeof_u32 * 4);
|
let ah = a >> (sizeof_u32 * 4);
|
||||||
|
@ -72,78 +57,73 @@ fn digit_x_digit(a: &u32, b: &u32, c: &mut [u32]) {
|
||||||
let albh = al * bh;
|
let albh = al * bh;
|
||||||
let ahbl = ah * bl;
|
let ahbl = ah * bl;
|
||||||
let ahbh = ah * bh;
|
let ahbh = ah * bh;
|
||||||
c[0] = albl & mask_low;
|
let c0 = albl & mask_low;
|
||||||
|
|
||||||
let mut res1 = albl >> (sizeof_u32 * 4);
|
let mut res1 = albl >> (sizeof_u32 * 4);
|
||||||
let mut res2 = ahbl & mask_low;
|
let mut res2 = ahbl & mask_low;
|
||||||
let mut res3 = albh & mask_low;
|
let mut res3 = albh & mask_low;
|
||||||
let mut temp = res1 + res2 + res3;
|
let mut temp = res1 + res2 + res3;
|
||||||
let mut carry = temp >> (sizeof_u32 * 4);
|
let mut carry = temp >> (sizeof_u32 * 4);
|
||||||
c[0] ^= temp << (sizeof_u32 * 4);
|
c[0] = c0 ^ (temp << (sizeof_u32 * 4));
|
||||||
|
|
||||||
res1 = ahbl >> (sizeof_u32 * 4);
|
res1 = ahbl >> (sizeof_u32 * 4);
|
||||||
res2 = albh >> (sizeof_u32 * 4);
|
res2 = albh >> (sizeof_u32 * 4);
|
||||||
res3 = ahbh & mask_low;
|
res3 = ahbh & mask_low;
|
||||||
temp = res1 + res2 + res3 + carry;
|
temp = res1 + res2 + res3 + carry;
|
||||||
c[1] = temp & mask_low;
|
let c1 = temp & mask_low;
|
||||||
carry = temp & mask_high;
|
carry = temp & mask_high;
|
||||||
c[1] ^= (ahbh & mask_high) + carry;
|
c[1] = c1 ^ ((ahbh & mask_high) + carry);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn mul(multiplier: &u32, multiplicant: &u32, uv: &mut [u32]) {
|
fn mul(multiplier: u32, multiplicant: u32, uv: &mut [u32; 2]) {
|
||||||
digit_x_digit(multiplier, multiplicant, uv);
|
digit_x_digit(multiplier, multiplicant, uv);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn addc(carry_in: &u32, addend1: &u32, addend2: &u32) -> (u32, u32) {
|
fn addc(carry_in: u32, addend1: u32, addend2: u32) -> (u32, u32) {
|
||||||
let temp = addend1.wrapping_add(*carry_in);
|
//let sum = (addend1 as u64) + (addend2 as u64) + (carry_in as u64);
|
||||||
|
//((sum > u32::MAX as u64) as u32, sum as u32)
|
||||||
|
let temp = addend1.wrapping_add(carry_in);
|
||||||
let sum = addend2.wrapping_add(temp);
|
let sum = addend2.wrapping_add(temp);
|
||||||
let carry_out = (is_digit_lessthan_ct(&temp, carry_in)) | is_digit_lessthan_ct(&sum, &temp);
|
((temp < carry_in) as u32 | (sum < temp) as u32, sum)
|
||||||
(carry_out, sum)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn subc(borrow_in: &u32, minuend: &u32, subtrahend: &u32) -> (u32, u32) {
|
fn subc(borrow_in: u32, minuend: u32, subtrahend: u32) -> (u32, u32) {
|
||||||
let temp = minuend.wrapping_sub(*subtrahend);
|
let temp = minuend.wrapping_sub(subtrahend);
|
||||||
let borrow = (is_digit_lessthan_ct(minuend, subtrahend)) | (borrow_in & is_digit_zero_ct(&temp));
|
let borrow = ((minuend < subtrahend) as u32) | (borrow_in & (temp == 0) as u32);
|
||||||
let difference = temp.wrapping_sub(*borrow_in);
|
let difference = temp.wrapping_sub(borrow_in);
|
||||||
let borrow_out = borrow;
|
(borrow, difference)
|
||||||
(borrow_out, difference)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn fpadd751(x: &Fp751Element, y: &Fp751Element, z: &mut Fp751Element) {
|
pub fn fpadd751(x: &Fp751Element, y: &Fp751Element, z: &mut Fp751Element) {
|
||||||
let mut carry: u32 = 0;
|
let mut carry: u32 = 0;
|
||||||
|
|
||||||
for i in 0..FP751_NUM_WORDS {
|
for i in 0..FP751_NUM_WORDS {
|
||||||
assign!{(carry, z.0[i]) = addc(&carry, &x.0[i], &y.0[i])};
|
assign!{(carry, z.0[i]) = addc(carry, x.0[i], y.0[i])};
|
||||||
}
|
}
|
||||||
|
|
||||||
carry = 0;
|
carry = 0;
|
||||||
for i in 0..FP751_NUM_WORDS {
|
for i in 0..FP751_NUM_WORDS {
|
||||||
assign!{(carry, z.0[i]) = subc(&carry, &z.0[i], &P751X2[i])};
|
assign!{(carry, z.0[i]) = subc(carry, z.0[i], P751X2[i])};
|
||||||
}
|
}
|
||||||
let mask = (0 as u32).wrapping_sub(carry);
|
let mask = (0 as u32).wrapping_sub(carry);
|
||||||
|
|
||||||
carry = 0;
|
carry = 0;
|
||||||
for i in 0..FP751_NUM_WORDS {
|
for i in 0..FP751_NUM_WORDS {
|
||||||
assign!{(carry, z.0[i]) = addc(&carry, &z.0[i], &(P751X2[i] & mask))};
|
assign!{(carry, z.0[i]) = addc(carry, z.0[i], (P751X2[i] & mask))};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn fpsub751(x: &Fp751Element, y: &Fp751Element, z: &mut Fp751Element) {
|
pub fn fpsub751(x: &Fp751Element, y: &Fp751Element, z: &mut Fp751Element) {
|
||||||
let mut borrow: u32 = 0;
|
let mut borrow: u32 = 0;
|
||||||
|
|
||||||
for i in 0..FP751_NUM_WORDS {
|
for i in 0..FP751_NUM_WORDS {
|
||||||
assign!{(borrow, z.0[i]) = subc(&borrow, &x.0[i], &y.0[i])};
|
assign!{(borrow, z.0[i]) = subc(borrow, x.0[i], y.0[i])};
|
||||||
}
|
}
|
||||||
let mask = (0 as u32).wrapping_sub(borrow);
|
let mask = (0 as u32).wrapping_sub(borrow);
|
||||||
|
|
||||||
borrow = 0;
|
borrow = 0;
|
||||||
for i in 0..FP751_NUM_WORDS {
|
for i in 0..FP751_NUM_WORDS {
|
||||||
assign!{(borrow, z.0[i]) = addc(&borrow, &z.0[i], &(P751X2[i] & mask))};
|
assign!{(borrow, z.0[i]) = addc(borrow, z.0[i], (P751X2[i] & mask))};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,14 +131,15 @@ pub fn mul751(x: &Fp751Element, y: &Fp751Element, z: &mut Fp751X2) {
|
||||||
let mut t: u32 = 0;
|
let mut t: u32 = 0;
|
||||||
let mut u: u32 = 0;
|
let mut u: u32 = 0;
|
||||||
let mut v: u32 = 0;
|
let mut v: u32 = 0;
|
||||||
|
#[allow(non_snake_case)]
|
||||||
let mut UV = [0u32; 2];
|
let mut UV = [0u32; 2];
|
||||||
let mut carry: u32 = 0;
|
let mut carry: u32 = 0;
|
||||||
|
|
||||||
for i in 0..FP751_NUM_WORDS {
|
for i in 0..FP751_NUM_WORDS {
|
||||||
for j in 0..(i+1) {
|
for j in 0..(i+1) {
|
||||||
mul(&x.0[j], &y.0[i-j], &mut UV[..]);
|
mul(x.0[j], y.0[i - j], &mut UV);
|
||||||
assign!{(carry, v) = addc(&0, &UV[0], &v)};
|
assign! {(carry, v) = addc(0, UV[0], v)};
|
||||||
assign!{(carry, u) = addc(&carry, &UV[1], &u)};
|
assign! {(carry, u) = addc(carry, UV[1], u)};
|
||||||
t += carry;
|
t += carry;
|
||||||
}
|
}
|
||||||
z.0[i] = v;
|
z.0[i] = v;
|
||||||
|
@ -169,9 +150,9 @@ pub fn mul751(x: &Fp751Element, y: &Fp751Element, z: &mut Fp751X2) {
|
||||||
|
|
||||||
for i in FP751_NUM_WORDS..(2*FP751_NUM_WORDS-1) {
|
for i in FP751_NUM_WORDS..(2*FP751_NUM_WORDS-1) {
|
||||||
for j in (i-FP751_NUM_WORDS+1)..FP751_NUM_WORDS {
|
for j in (i-FP751_NUM_WORDS+1)..FP751_NUM_WORDS {
|
||||||
mul(&x.0[j], &y.0[i-j], &mut UV[..]);
|
mul(x.0[j], y.0[i-j], &mut UV);
|
||||||
assign!{(carry, v) = addc(&0, &UV[0], &v)};
|
assign!{(carry, v) = addc(0, UV[0], v)};
|
||||||
assign!{(carry, u) = addc(&carry, &UV[1], &u)};
|
assign!{(carry, u) = addc(carry, UV[1], u)};
|
||||||
t += carry;
|
t += carry;
|
||||||
}
|
}
|
||||||
z.0[i] = v;
|
z.0[i] = v;
|
||||||
|
@ -186,6 +167,7 @@ pub fn rdc751(x: &Fp751X2, z: &mut Fp751Element) {
|
||||||
let mut t: u32 = 0;
|
let mut t: u32 = 0;
|
||||||
let mut u: u32 = 0;
|
let mut u: u32 = 0;
|
||||||
let mut v: u32 = 0;
|
let mut v: u32 = 0;
|
||||||
|
#[allow(non_snake_case)]
|
||||||
let mut UV = [0u32; 2];
|
let mut UV = [0u32; 2];
|
||||||
let mut carry: u32 = 0;
|
let mut carry: u32 = 0;
|
||||||
let mut count = P751_ZERO_WORDS;
|
let mut count = P751_ZERO_WORDS;
|
||||||
|
@ -197,14 +179,14 @@ pub fn rdc751(x: &Fp751X2, z: &mut Fp751Element) {
|
||||||
for i in 0..FP751_NUM_WORDS {
|
for i in 0..FP751_NUM_WORDS {
|
||||||
for j in 0..i {
|
for j in 0..i {
|
||||||
if j < (((i+1) as u32).wrapping_sub(P751_ZERO_WORDS as u32) as usize) {
|
if j < (((i+1) as u32).wrapping_sub(P751_ZERO_WORDS as u32) as usize) {
|
||||||
mul(&z.0[j], &P751P1[i-j], &mut UV[..]);
|
mul(z.0[j], P751P1[i-j], &mut UV);
|
||||||
assign!{(carry, v) = addc(&0, &UV[0], &v)};
|
assign!{(carry, v) = addc(0, UV[0], v)};
|
||||||
assign!{(carry, u) = addc(&carry, &UV[1], &u)};
|
assign!{(carry, u) = addc(carry, UV[1], u)};
|
||||||
t += carry;
|
t += carry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assign!{(carry, v) = addc(&0, &v, &x.0[i])};
|
assign!{(carry, v) = addc(0, v, x.0[i])};
|
||||||
assign!{(carry, u) = addc(&carry, &u, &0)};
|
assign!{(carry, u) = addc(carry, u, 0)};
|
||||||
|
|
||||||
t += carry;
|
t += carry;
|
||||||
z.0[i] = v;
|
z.0[i] = v;
|
||||||
|
@ -219,14 +201,14 @@ pub fn rdc751(x: &Fp751X2, z: &mut Fp751Element) {
|
||||||
}
|
}
|
||||||
for j in (i-FP751_NUM_WORDS+1)..FP751_NUM_WORDS {
|
for j in (i-FP751_NUM_WORDS+1)..FP751_NUM_WORDS {
|
||||||
if j < (FP751_NUM_WORDS-count) {
|
if j < (FP751_NUM_WORDS-count) {
|
||||||
mul(&z.0[j], &P751P1[i-j], &mut UV[..]);
|
mul(z.0[j], P751P1[i-j], &mut UV);
|
||||||
assign!{(carry, v) = addc(&0, &UV[0], &v)};
|
assign!{(carry, v) = addc(0, UV[0], v)};
|
||||||
assign!{(carry, u) = addc(&carry, &UV[1], &u)};
|
assign!{(carry, u) = addc(carry, UV[1], u)};
|
||||||
t += carry;
|
t += carry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assign!{(carry, v) = addc(&0, &v, &x.0[i])};
|
assign!{(carry, v) = addc(0, v, x.0[i])};
|
||||||
assign!{(carry, u) = addc(&carry, &u, &0)};
|
assign!{(carry, u) = addc(carry, u, 0)};
|
||||||
|
|
||||||
t += carry;
|
t += carry;
|
||||||
z.0[i-FP751_NUM_WORDS] = v;
|
z.0[i-FP751_NUM_WORDS] = v;
|
||||||
|
@ -234,55 +216,49 @@ pub fn rdc751(x: &Fp751X2, z: &mut Fp751Element) {
|
||||||
u = t;
|
u = t;
|
||||||
t = 0;
|
t = 0;
|
||||||
}
|
}
|
||||||
assign!{(carry, v) = addc(&0, &v, &x.0[2*FP751_NUM_WORDS-1])};
|
assign!{(carry, v) = addc(0, v, x.0[2*FP751_NUM_WORDS-1])};
|
||||||
z.0[FP751_NUM_WORDS-1] = v;
|
z.0[FP751_NUM_WORDS-1] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn srdc751(x: &mut Fp751Element) {
|
pub fn srdc751(x: &mut Fp751Element) {
|
||||||
let mut borrow: u32 = 0;
|
let mut borrow: u32 = 0;
|
||||||
|
|
||||||
for i in 0..FP751_NUM_WORDS {
|
for i in 0..FP751_NUM_WORDS {
|
||||||
assign!{(borrow, x.0[i]) = subc(&borrow, &x.0[i], &P751[i])};
|
assign!{(borrow, x.0[i]) = subc(borrow, x.0[i], P751[i])};
|
||||||
}
|
}
|
||||||
let mask = (0 as u32).wrapping_sub(borrow);
|
let mask = (0 as u32).wrapping_sub(borrow);
|
||||||
|
|
||||||
borrow = 0;
|
borrow = 0;
|
||||||
for i in 0..FP751_NUM_WORDS {
|
for i in 0..FP751_NUM_WORDS {
|
||||||
assign!{(borrow, x.0[i]) = addc(&borrow, &x.0[i], &(P751[i] & mask))};
|
assign!{(borrow, x.0[i]) = addc(borrow, x.0[i], (P751[i] & mask))};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn mp_add751(x: &Fp751Element, y: &Fp751Element, z: &mut Fp751Element) {
|
pub fn mp_add751(x: &Fp751Element, y: &Fp751Element, z: &mut Fp751Element) {
|
||||||
let mut carry: u32 = 0;
|
let mut carry: u32 = 0;
|
||||||
|
|
||||||
for i in 0..FP751_NUM_WORDS {
|
for i in 0..FP751_NUM_WORDS {
|
||||||
assign!{(carry, z.0[i]) = addc(&carry, &x.0[i], &y.0[i])};
|
assign!{(carry, z.0[i]) = addc(carry, x.0[i], y.0[i])};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn mp_add751x2(x: &Fp751X2, y: &Fp751X2, z: &mut Fp751X2) {
|
pub fn mp_add751x2(x: &Fp751X2, y: &Fp751X2, z: &mut Fp751X2) {
|
||||||
let mut carry: u32 = 0;
|
let mut carry: u32 = 0;
|
||||||
|
|
||||||
for i in 0..(FP751_NUM_WORDS*2) {
|
for i in 0..(FP751_NUM_WORDS*2) {
|
||||||
assign!{(carry, z.0[i]) = addc(&carry, &x.0[i], &y.0[i])};
|
assign!{(carry, z.0[i]) = addc(carry, x.0[i], y.0[i])};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn mp_sub751x2(x: &Fp751X2, y: &Fp751X2, z: &mut Fp751X2) {
|
pub fn mp_sub751x2(x: &Fp751X2, y: &Fp751X2, z: &mut Fp751X2) {
|
||||||
let mut borrow: u32 = 0;
|
let mut borrow: u32 = 0;
|
||||||
|
|
||||||
for i in 0..(FP751_NUM_WORDS*2) {
|
for i in 0..(FP751_NUM_WORDS*2) {
|
||||||
assign!{(borrow, z.0[i]) = subc(&borrow, &x.0[i], &y.0[i])};
|
assign!{(borrow, z.0[i]) = subc(borrow, x.0[i], y.0[i])};
|
||||||
}
|
}
|
||||||
let mask = (0 as u32).wrapping_sub(borrow);
|
let mask = (0 as u32).wrapping_sub(borrow);
|
||||||
|
|
||||||
borrow = 0;
|
borrow = 0;
|
||||||
for i in FP751_NUM_WORDS..(FP751_NUM_WORDS*2) {
|
for i in FP751_NUM_WORDS..(FP751_NUM_WORDS*2) {
|
||||||
assign!{(borrow, z.0[i]) = addc(&borrow, &z.0[i], &(P751[i-FP751_NUM_WORDS] & mask))};
|
assign!{(borrow, z.0[i]) = addc(borrow, z.0[i], (P751[i-FP751_NUM_WORDS] & mask))};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,7 +279,7 @@ pub fn checklt238(scalar: &[u8; 48], result: &mut u32) {
|
||||||
let mut borrow: u32 = 0;
|
let mut borrow: u32 = 0;
|
||||||
|
|
||||||
for i in 0..12 {
|
for i in 0..12 {
|
||||||
assign!{(borrow, ignored) = subc(&borrow, &three238[i], &scalar_u32[i])};
|
assign!{(borrow, ignored) = subc(borrow, three238[i], scalar_u32[i])};
|
||||||
}
|
}
|
||||||
let mask = (0 as u32).wrapping_sub(borrow);
|
let mask = (0 as u32).wrapping_sub(borrow);
|
||||||
*result = mask;
|
*result = mask;
|
||||||
|
@ -324,10 +300,10 @@ pub fn mulby3(scalar: &mut [u8; 48]) {
|
||||||
let mut carry: u32 = 0;
|
let mut carry: u32 = 0;
|
||||||
let temp = scalar_u32;
|
let temp = scalar_u32;
|
||||||
for i in 0..12 {
|
for i in 0..12 {
|
||||||
assign!{(carry, scalar_u32[i]) = addc(&carry, &scalar_u32[i], &temp[i])};
|
assign!{(carry, scalar_u32[i]) = addc(carry, scalar_u32[i], temp[i])};
|
||||||
}
|
}
|
||||||
for i in 0..12 {
|
for i in 0..12 {
|
||||||
assign!{(carry, scalar_u32[i]) = addc(&carry, &scalar_u32[i], &temp[i])};
|
assign!{(carry, scalar_u32[i]) = addc(carry, scalar_u32[i], temp[i])};
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0..48 {
|
for i in 0..48 {
|
||||||
|
@ -346,11 +322,11 @@ pub struct Fp751ElementDist;
|
||||||
impl ConditionallySelectable for Fp751Element {
|
impl ConditionallySelectable for Fp751Element {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
||||||
let mut bytes = [0_u32; FP751_NUM_WORDS];
|
let mut bytes = unsafe { MaybeUninit::<Fp751Element>::uninit().assume_init() };
|
||||||
for i in 0..FP751_NUM_WORDS {
|
for i in 0..FP751_NUM_WORDS {
|
||||||
bytes[i] = u32::conditional_select(&a.0[i], &b.0[i], choice);
|
bytes.0[i] = u32::conditional_select(&a.0[i], &b.0[i], choice);
|
||||||
}
|
}
|
||||||
Fp751Element(bytes)
|
bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -398,14 +374,17 @@ impl Arbitrary for Fp751Element {
|
||||||
|
|
||||||
impl Fp751Element {
|
impl Fp751Element {
|
||||||
/// Construct a new zero `Fp751Element`.
|
/// Construct a new zero `Fp751Element`.
|
||||||
|
#[inline(always)]
|
||||||
pub fn zero() -> Fp751Element {
|
pub fn zero() -> Fp751Element {
|
||||||
Fp751Element([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0])
|
unsafe { zeroed() }
|
||||||
|
//Fp751Element([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given an `Fp751Element` in Montgomery form, convert to little-endian bytes.
|
/// Given an `Fp751Element` in Montgomery form, convert to little-endian bytes.
|
||||||
pub fn to_bytes(&self) -> [u8; 94] {
|
pub fn to_bytes(&self) -> [u8; 94] {
|
||||||
let mut bytes = [0u8; 94];
|
let mut bytes = [0u8; 94];
|
||||||
let mut a = Fp751Element::zero();
|
let mut a = Fp751Element::zero();
|
||||||
|
#[allow(non_snake_case)]
|
||||||
let mut aR = Fp751X2::zero();
|
let mut aR = Fp751X2::zero();
|
||||||
//let one = Fp751Element([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
//let one = Fp751Element([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||||
|
|
||||||
|
@ -440,6 +419,7 @@ impl Fp751Element {
|
||||||
a.0[j as usize] |= (bytes[i as usize] as u32) << (8 * k);
|
a.0[j as usize] |= (bytes[i as usize] as u32) << (8 * k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
let aRR = &a * &MONTGOMERY_RSQ; // = a*R*R
|
let aRR = &a * &MONTGOMERY_RSQ; // = a*R*R
|
||||||
let output = aRR.reduce(); // = a*R mod p
|
let output = aRR.reduce(); // = a*R mod p
|
||||||
output
|
output
|
||||||
|
@ -457,9 +437,11 @@ impl Debug for Fp751X2 {
|
||||||
|
|
||||||
impl Fp751X2 {
|
impl Fp751X2 {
|
||||||
// Construct a zero `Fp751X2`.
|
// Construct a zero `Fp751X2`.
|
||||||
|
#[inline(always)]
|
||||||
pub fn zero() -> Fp751X2 {
|
pub fn zero() -> Fp751X2 {
|
||||||
Fp751X2([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
unsafe { zeroed() }
|
||||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0])
|
//Fp751X2([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
// 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,16 +9,18 @@
|
||||||
//! This module contains internal isogeny representation and operations
|
//! This module contains internal isogeny representation and operations
|
||||||
//! for SIDH, which is not part of the public API.
|
//! for SIDH, which is not part of the public API.
|
||||||
|
|
||||||
use crate::sidh::field::ExtensionFieldElement;
|
use crate::sidhp751::field::ExtensionFieldElement;
|
||||||
use crate::sidh::curve::{ProjectiveCurveParameters, ProjectivePoint};
|
use crate::sidhp751::curve::{ProjectiveCurveParameters, ProjectivePoint};
|
||||||
|
|
||||||
/// Represents a 3-isogeny phi, holding the data necessary to evaluate phi.
|
/// Represents a 3-isogeny phi, holding the data necessary to evaluate phi.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct ThreeIsogeny {
|
pub struct ThreeIsogeny {
|
||||||
pub X: ExtensionFieldElement,
|
pub X: ExtensionFieldElement,
|
||||||
pub Z: ExtensionFieldElement,
|
pub Z: ExtensionFieldElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
impl ThreeIsogeny {
|
impl ThreeIsogeny {
|
||||||
/// Given a three-torsion point `x3 = x(P_3)` on the curve `E_(A:C)`, construct the
|
/// Given a three-torsion point `x3 = x(P_3)` on the curve `E_(A:C)`, construct the
|
||||||
/// three-isogeny `phi : E_(A:C) -> E_(A:C)/<P_3> = E_(A':C')`.
|
/// three-isogeny `phi : E_(A:C) -> E_(A:C)/<P_3> = E_(A':C')`.
|
||||||
|
@ -45,6 +47,7 @@ impl ThreeIsogeny {
|
||||||
|
|
||||||
(codomain, isogeny)
|
(codomain, isogeny)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a 3-isogeny phi and a point `xP = x(P)`, compute `x(Q)`, the x-coordinate
|
/// Given a 3-isogeny phi and a point `xP = x(P)`, compute `x(Q)`, the x-coordinate
|
||||||
/// of the image `Q = phi(P)` of `P` under `phi : E_(A:C) -> E_(A':C')`.
|
/// of the image `Q = phi(P)` of `P` under `phi : E_(A:C) -> E_(A':C')`.
|
||||||
///
|
///
|
||||||
|
@ -72,6 +75,7 @@ impl ThreeIsogeny {
|
||||||
/// Represents a 4-isogeny phi, holding the data necessary to evaluate phi.
|
/// Represents a 4-isogeny phi, holding the data necessary to evaluate phi.
|
||||||
//
|
//
|
||||||
// See compute_four_isogeny for more details.
|
// See compute_four_isogeny for more details.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct FourIsogeny {
|
pub struct FourIsogeny {
|
||||||
pub Xsq_plus_Zsq : ExtensionFieldElement,
|
pub Xsq_plus_Zsq : ExtensionFieldElement,
|
||||||
|
@ -81,6 +85,7 @@ pub struct FourIsogeny {
|
||||||
pub Zpow4 : ExtensionFieldElement,
|
pub Zpow4 : ExtensionFieldElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
impl FourIsogeny {
|
impl FourIsogeny {
|
||||||
/// Given a four-torsion point `x4 = x(P_4)` on the curve `E_(A:C)`, compute the
|
/// Given a four-torsion point `x4 = x(P_4)` on the curve `E_(A:C)`, compute the
|
||||||
/// coefficients of the codomain `E_(A':C')` of the four-isogeny `phi : E_(A:C) ->
|
/// coefficients of the codomain `E_(A':C')` of the four-isogeny `phi : E_(A:C) ->
|
||||||
|
@ -118,6 +123,7 @@ impl FourIsogeny {
|
||||||
|
|
||||||
(codomain, isogeny)
|
(codomain, isogeny)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a 4-isogeny phi and a point `xP = x(P)`, compute `x(Q)`, the x-coordinate
|
/// Given a 4-isogeny phi and a point `xP = x(P)`, compute `x(Q)`, the x-coordinate
|
||||||
/// of the image `Q = phi(P)` of `P` under `phi : E_(A:C) -> E_(A':C')`.
|
/// of the image `Q = phi(P)` of `P` under `phi : E_(A:C) -> E_(A':C')`.
|
||||||
//
|
//
|
||||||
|
@ -160,12 +166,14 @@ impl FourIsogeny {
|
||||||
/// Represents a 4-isogeny phi.
|
/// Represents a 4-isogeny phi.
|
||||||
//
|
//
|
||||||
// See compute_four_isogeny for details.
|
// See compute_four_isogeny for details.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct FirstFourIsogeny {
|
pub struct FirstFourIsogeny {
|
||||||
pub A: ExtensionFieldElement,
|
pub A: ExtensionFieldElement,
|
||||||
pub C: ExtensionFieldElement,
|
pub C: ExtensionFieldElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
impl FirstFourIsogeny {
|
impl FirstFourIsogeny {
|
||||||
/// Compute the "first" four-isogeny from the given curve.
|
/// Compute the "first" four-isogeny from the given curve.
|
||||||
//
|
//
|
||||||
|
@ -183,6 +191,7 @@ impl FirstFourIsogeny {
|
||||||
|
|
||||||
(codomain, isogeny)
|
(codomain, isogeny)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a 4-isogeny phi and a point `xP = x(P)`, compute `x(Q)`, the x-coordinate
|
/// Given a 4-isogeny phi and a point `xP = x(P)`, compute `x(Q)`, the x-coordinate
|
||||||
/// of the image `Q = phi(P)` of `P` under `phi : E_(A:C) -> E_(A':C')`.
|
/// of the image `Q = phi(P)` of `P` under `phi : E_(A:C) -> E_(A':C')`.
|
||||||
//
|
//
|
||||||
|
@ -210,10 +219,11 @@ impl FirstFourIsogeny {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::sidh::fp::Fp751Element;
|
use crate::sidhp751::fp::Fp751Element;
|
||||||
|
|
||||||
// Test the first four-isogeny from the base curve E_0(F_{p^2}).
|
// Test the first four-isogeny from the base curve E_0(F_{p^2}).
|
||||||
#[test]
|
#[test]
|
|
@ -23,4 +23,6 @@ pub(crate) mod fp;
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
#[allow(unused_assignments)]
|
#[allow(unused_assignments)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub mod sidh;
|
mod sidh;
|
||||||
|
|
||||||
|
pub use sidh::*;
|
|
@ -6,11 +6,11 @@
|
||||||
// - Erkan Tairi <erkan.tairi@gmail.com>
|
// - Erkan Tairi <erkan.tairi@gmail.com>
|
||||||
//
|
//
|
||||||
|
|
||||||
use crate::sidh::field::ExtensionFieldElement;
|
use crate::sidhp751::field::ExtensionFieldElement;
|
||||||
use crate::sidh::curve::{ProjectiveCurveParameters, ProjectivePoint};
|
use crate::sidhp751::curve::{ProjectiveCurveParameters, ProjectivePoint};
|
||||||
use crate::sidh::isogeny::*;
|
use crate::sidhp751::isogeny::*;
|
||||||
use crate::sidh::constants::*;
|
use crate::sidhp751::constants::*;
|
||||||
use crate::sidh::fp::*;
|
use crate::sidhp751::fp::*;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::random::SecureRandom;
|
use crate::random::SecureRandom;
|
||||||
|
|
||||||
|
@ -34,7 +34,6 @@ pub const SHARED_SECRET_SIZE: usize = 188;
|
||||||
const MAX_INT_POINTS_ALICE: usize = 8;
|
const MAX_INT_POINTS_ALICE: usize = 8;
|
||||||
const MAX_INT_POINTS_BOB: usize = 10;
|
const MAX_INT_POINTS_BOB: usize = 10;
|
||||||
|
|
||||||
|
|
||||||
const MAX_ALICE: usize = 185;
|
const MAX_ALICE: usize = 185;
|
||||||
/// Alice's isogeny strategy.
|
/// Alice's isogeny strategy.
|
||||||
pub const ALICE_ISOGENY_STRATEGY: [u8; MAX_ALICE] = [0, 1, 1, 2, 2, 2, 3, 4, 4, 4, 4, 5, 5,
|
pub const ALICE_ISOGENY_STRATEGY: [u8; MAX_ALICE] = [0, 1, 1, 2, 2, 2, 3, 4, 4, 4, 4, 5, 5,
|
||||||
|
@ -66,6 +65,7 @@ pub const BOB_ISOGENY_STRATEGY: [u8; MAX_BOB] = [0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4
|
||||||
97, 97];
|
97, 97];
|
||||||
|
|
||||||
/// Alice's public key.
|
/// Alice's public key.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct SIDHPublicKeyAlice {
|
pub struct SIDHPublicKeyAlice {
|
||||||
pub affine_xP : ExtensionFieldElement,
|
pub affine_xP : ExtensionFieldElement,
|
||||||
|
@ -75,6 +75,7 @@ pub struct SIDHPublicKeyAlice {
|
||||||
|
|
||||||
impl SIDHPublicKeyAlice {
|
impl SIDHPublicKeyAlice {
|
||||||
/// Read a public key from a byte slice. The input must be at least 564 bytes long.
|
/// Read a public key from a byte slice. The input must be at least 564 bytes long.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn from_bytes(bytes: &[u8]) -> SIDHPublicKeyAlice {
|
pub fn from_bytes(bytes: &[u8]) -> SIDHPublicKeyAlice {
|
||||||
assert!(bytes.len() >= 564, "Too short input to SIDH public key from_bytes, expected 564 bytes");
|
assert!(bytes.len() >= 564, "Too short input to SIDH public key from_bytes, expected 564 bytes");
|
||||||
let affine_xP = ExtensionFieldElement::from_bytes(&bytes[0..188]);
|
let affine_xP = ExtensionFieldElement::from_bytes(&bytes[0..188]);
|
||||||
|
@ -93,6 +94,7 @@ impl SIDHPublicKeyAlice {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bob's public key.
|
/// Bob's public key.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct SIDHPublicKeyBob {
|
pub struct SIDHPublicKeyBob {
|
||||||
pub affine_xP : ExtensionFieldElement,
|
pub affine_xP : ExtensionFieldElement,
|
||||||
|
@ -102,6 +104,7 @@ pub struct SIDHPublicKeyBob {
|
||||||
|
|
||||||
impl SIDHPublicKeyBob {
|
impl SIDHPublicKeyBob {
|
||||||
/// Read a public key from a byte slice. The input must be at least 564 bytes long.
|
/// Read a public key from a byte slice. The input must be at least 564 bytes long.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn from_bytes(bytes: &[u8]) -> SIDHPublicKeyBob {
|
pub fn from_bytes(bytes: &[u8]) -> SIDHPublicKeyBob {
|
||||||
assert!(bytes.len() >= 564, "Too short input to SIDH public key from_bytes, expected 564 bytes");
|
assert!(bytes.len() >= 564, "Too short input to SIDH public key from_bytes, expected 564 bytes");
|
||||||
let affine_xP = ExtensionFieldElement::from_bytes(&bytes[0..188]);
|
let affine_xP = ExtensionFieldElement::from_bytes(&bytes[0..188]);
|
||||||
|
@ -142,6 +145,7 @@ impl Arbitrary for SIDHSecretKeyAlice {
|
||||||
|
|
||||||
impl SIDHSecretKeyAlice {
|
impl SIDHSecretKeyAlice {
|
||||||
/// Compute the corresponding public key for the given secret key.
|
/// Compute the corresponding public key for the given secret key.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn public_key(&self) -> SIDHPublicKeyAlice {
|
pub fn public_key(&self) -> SIDHPublicKeyAlice {
|
||||||
let mut xP = ProjectivePoint::from_affine_prime_field(&AFFINE_X_PB); // = ( x_P : 1) = x(P_B)
|
let mut xP = ProjectivePoint::from_affine_prime_field(&AFFINE_X_PB); // = ( x_P : 1) = x(P_B)
|
||||||
let mut xQ = ProjectivePoint::from_affine_prime_field(&AFFINE_X_PB); //
|
let mut xQ = ProjectivePoint::from_affine_prime_field(&AFFINE_X_PB); //
|
||||||
|
@ -199,7 +203,9 @@ impl SIDHSecretKeyAlice {
|
||||||
|
|
||||||
SIDHPublicKeyAlice{ affine_xP, affine_xQ, affine_xQmP }
|
SIDHPublicKeyAlice{ affine_xP, affine_xQ, affine_xQmP }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute (Alice's view of) a shared secret using Alice's secret key and Bob's public key.
|
/// Compute (Alice's view of) a shared secret using Alice's secret key and Bob's public key.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn shared_secret(&self, bob_public: &SIDHPublicKeyBob) -> [u8; SHARED_SECRET_SIZE] {
|
pub fn shared_secret(&self, bob_public: &SIDHPublicKeyBob) -> [u8; SHARED_SECRET_SIZE] {
|
||||||
let current_curve = ProjectiveCurveParameters::recover_curve_parameters(&bob_public.affine_xP, &bob_public.affine_xQ, &bob_public.affine_xQmP);
|
let current_curve = ProjectiveCurveParameters::recover_curve_parameters(&bob_public.affine_xP, &bob_public.affine_xQ, &bob_public.affine_xQmP);
|
||||||
let xP = ProjectivePoint::from_affine(&bob_public.affine_xP);
|
let xP = ProjectivePoint::from_affine(&bob_public.affine_xP);
|
||||||
|
@ -264,6 +270,7 @@ impl Arbitrary for SIDHSecretKeyBob {
|
||||||
|
|
||||||
impl SIDHSecretKeyBob {
|
impl SIDHSecretKeyBob {
|
||||||
/// Compute the public key corresponding to the secret key.
|
/// Compute the public key corresponding to the secret key.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn public_key(&self) -> SIDHPublicKeyBob {
|
pub fn public_key(&self) -> SIDHPublicKeyBob {
|
||||||
let mut xP = ProjectivePoint::from_affine_prime_field(&AFFINE_X_PA); // = ( x_P : 1) = x(P_A)
|
let mut xP = ProjectivePoint::from_affine_prime_field(&AFFINE_X_PA); // = ( x_P : 1) = x(P_A)
|
||||||
let mut xQ = ProjectivePoint::from_affine_prime_field(&AFFINE_X_PA); //
|
let mut xQ = ProjectivePoint::from_affine_prime_field(&AFFINE_X_PA); //
|
||||||
|
@ -315,7 +322,9 @@ impl SIDHSecretKeyBob {
|
||||||
|
|
||||||
SIDHPublicKeyBob{ affine_xP, affine_xQ, affine_xQmP }
|
SIDHPublicKeyBob{ affine_xP, affine_xQ, affine_xQmP }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute (Bob's view of) a shared secret using Bob's secret key and Alice's public key.
|
/// Compute (Bob's view of) a shared secret using Bob's secret key and Alice's public key.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn shared_secret(&self, alice_public: &SIDHPublicKeyAlice) -> [u8; SHARED_SECRET_SIZE] {
|
pub fn shared_secret(&self, alice_public: &SIDHPublicKeyAlice) -> [u8; SHARED_SECRET_SIZE] {
|
||||||
let mut current_curve = ProjectiveCurveParameters::recover_curve_parameters(&alice_public.affine_xP, &alice_public.affine_xQ, &alice_public.affine_xQmP);
|
let mut current_curve = ProjectiveCurveParameters::recover_curve_parameters(&alice_public.affine_xP, &alice_public.affine_xQ, &alice_public.affine_xQmP);
|
||||||
let xP = ProjectivePoint::from_affine(&alice_public.affine_xP);
|
let xP = ProjectivePoint::from_affine(&alice_public.affine_xP);
|
||||||
|
@ -416,6 +425,7 @@ mod test {
|
||||||
// Perform Alice's (2-isogeny) key generation, using the slow but simple multiplication-based strategy.
|
// Perform Alice's (2-isogeny) key generation, using the slow but simple multiplication-based strategy.
|
||||||
//
|
//
|
||||||
// This function just exists to ensure that the fast isogeny-tree strategy works correctly.
|
// This function just exists to ensure that the fast isogeny-tree strategy works correctly.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn alice_keygen_slow(secret_key: &SIDHSecretKeyAlice) -> SIDHPublicKeyAlice {
|
pub fn alice_keygen_slow(secret_key: &SIDHSecretKeyAlice) -> SIDHPublicKeyAlice {
|
||||||
let mut xP = ProjectivePoint::from_affine_prime_field(&AFFINE_X_PB); // = ( x_P : 1) = x(P_B)
|
let mut xP = ProjectivePoint::from_affine_prime_field(&AFFINE_X_PB); // = ( x_P : 1) = x(P_B)
|
||||||
let mut xQ = ProjectivePoint::from_affine_prime_field(&AFFINE_X_PB); //
|
let mut xQ = ProjectivePoint::from_affine_prime_field(&AFFINE_X_PB); //
|
||||||
|
@ -452,9 +462,11 @@ mod test {
|
||||||
|
|
||||||
SIDHPublicKeyAlice{ affine_xP, affine_xQ, affine_xQmP }
|
SIDHPublicKeyAlice{ affine_xP, affine_xQ, affine_xQmP }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform Bob's (3-isogeny) key generation, using the slow but simple multiplication-based strategy.
|
// Perform Bob's (3-isogeny) key generation, using the slow but simple multiplication-based strategy.
|
||||||
//
|
//
|
||||||
// This function just exists to ensure that the fast isogeny-tree strategy works correctly.
|
// This function just exists to ensure that the fast isogeny-tree strategy works correctly.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn bob_keygen_slow(secret_key: &SIDHSecretKeyBob) -> SIDHPublicKeyBob {
|
pub fn bob_keygen_slow(secret_key: &SIDHSecretKeyBob) -> SIDHPublicKeyBob {
|
||||||
let mut xP = ProjectivePoint::from_affine_prime_field(&AFFINE_X_PA); // = ( x_P : 1) = x(P_A)
|
let mut xP = ProjectivePoint::from_affine_prime_field(&AFFINE_X_PA); // = ( x_P : 1) = x(P_A)
|
||||||
let mut xQ = ProjectivePoint::from_affine_prime_field(&AFFINE_X_PA); //
|
let mut xQ = ProjectivePoint::from_affine_prime_field(&AFFINE_X_PA); //
|
||||||
|
@ -484,9 +496,11 @@ mod test {
|
||||||
|
|
||||||
SIDHPublicKeyBob{ affine_xP, affine_xQ, affine_xQmP }
|
SIDHPublicKeyBob{ affine_xP, affine_xQ, affine_xQmP }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform Alice's key agreement, using the slow but simple multiplication-based strategy.
|
// Perform Alice's key agreement, using the slow but simple multiplication-based strategy.
|
||||||
//
|
//
|
||||||
// This function just exists to ensure that the fast isogeny-tree strategy works correctly.
|
// This function just exists to ensure that the fast isogeny-tree strategy works correctly.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn alice_shared_secret_slow(bob_public: &SIDHPublicKeyBob, alice_secret: &SIDHSecretKeyAlice) -> [u8; SHARED_SECRET_SIZE] {
|
pub fn alice_shared_secret_slow(bob_public: &SIDHPublicKeyBob, alice_secret: &SIDHSecretKeyAlice) -> [u8; SHARED_SECRET_SIZE] {
|
||||||
let current_curve = ProjectiveCurveParameters::recover_curve_parameters(&bob_public.affine_xP, &bob_public.affine_xQ, &bob_public.affine_xQmP);
|
let current_curve = ProjectiveCurveParameters::recover_curve_parameters(&bob_public.affine_xP, &bob_public.affine_xQ, &bob_public.affine_xQmP);
|
||||||
let xP = ProjectivePoint::from_affine(&bob_public.affine_xP);
|
let xP = ProjectivePoint::from_affine(&bob_public.affine_xP);
|
||||||
|
@ -513,9 +527,11 @@ mod test {
|
||||||
let shared_secret = j_inv.to_bytes();
|
let shared_secret = j_inv.to_bytes();
|
||||||
shared_secret
|
shared_secret
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform Bob's key agreement, using the slow but simple multiplication-based strategy.
|
// Perform Bob's key agreement, using the slow but simple multiplication-based strategy.
|
||||||
//
|
//
|
||||||
// This function just exists to ensure that the fast isogeny-tree strategy works correctly.
|
// This function just exists to ensure that the fast isogeny-tree strategy works correctly.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
pub fn bob_shared_secret_slow(alice_public: &SIDHPublicKeyAlice, bob_secret: &SIDHSecretKeyBob) -> [u8; SHARED_SECRET_SIZE] {
|
pub fn bob_shared_secret_slow(alice_public: &SIDHPublicKeyAlice, bob_secret: &SIDHSecretKeyBob) -> [u8; SHARED_SECRET_SIZE] {
|
||||||
let mut current_curve = ProjectiveCurveParameters::recover_curve_parameters(&alice_public.affine_xP, &alice_public.affine_xQ, &alice_public.affine_xQmP);
|
let mut current_curve = ProjectiveCurveParameters::recover_curve_parameters(&alice_public.affine_xP, &alice_public.affine_xQ, &alice_public.affine_xQmP);
|
||||||
let xP = ProjectivePoint::from_affine(&alice_public.affine_xP);
|
let xP = ProjectivePoint::from_affine(&alice_public.affine_xP);
|
||||||
|
@ -593,6 +609,7 @@ mod test {
|
||||||
QuickCheck::new().max_tests(8).quickcheck(shared_secrets_match as fn(SIDHSecretKeyAlice, SIDHSecretKeyBob) -> bool);
|
QuickCheck::new().max_tests(8).quickcheck(shared_secrets_match as fn(SIDHSecretKeyAlice, SIDHSecretKeyBob) -> bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
#[test]
|
#[test]
|
||||||
fn alice_keygen_fast_vs_slow() {
|
fn alice_keygen_fast_vs_slow() {
|
||||||
// m_A = 2*randint(0,2^371)
|
// m_A = 2*randint(0,2^371)
|
||||||
|
@ -610,6 +627,7 @@ mod test {
|
||||||
"\nExpected affine_xQmP = {:?}\nfound {:?}", fast_pubkey.affine_xQmP, slow_pubkey.affine_xQmP);
|
"\nExpected affine_xQmP = {:?}\nfound {:?}", fast_pubkey.affine_xQmP, slow_pubkey.affine_xQmP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
#[test]
|
#[test]
|
||||||
fn bob_keygen_fast_vs_slow() {
|
fn bob_keygen_fast_vs_slow() {
|
||||||
// m_B = 3*randint(0,3^238)
|
// m_B = 3*randint(0,3^238)
|
||||||
|
@ -627,6 +645,7 @@ mod test {
|
||||||
"\nExpected affine_xQmP = {:?}\nfound {:?}", fast_pubkey.affine_xQmP, slow_pubkey.affine_xQmP);
|
"\nExpected affine_xQmP = {:?}\nfound {:?}", fast_pubkey.affine_xQmP, slow_pubkey.affine_xQmP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
#[test]
|
#[test]
|
||||||
fn shared_secret() {
|
fn shared_secret() {
|
||||||
// m_A = 2*randint(0,2^371)
|
// m_A = 2*randint(0,2^371)
|
||||||
|
@ -653,6 +672,7 @@ mod test {
|
||||||
"\nShared secret mismatch: Alice (slow) has {:?}\nBob (fast) has {:?}", &alice_shared_secret_slow[..], &bob_shared_secret_fast[..]);
|
"\nShared secret mismatch: Alice (slow) has {:?}\nBob (fast) has {:?}", &alice_shared_secret_slow[..], &bob_shared_secret_fast[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
#[test]
|
#[test]
|
||||||
fn secret_point() {
|
fn secret_point() {
|
||||||
// m_A = 2*randint(0,2^371)
|
// m_A = 2*randint(0,2^371)
|
|
@ -0,0 +1,88 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* (c)2021 ZeroTier, Inc.
|
||||||
|
* https://www.zerotier.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::sync::atomic::AtomicU32;
|
||||||
|
|
||||||
|
use zerotier_core_crypto::c25519::C25519KeyPair;
|
||||||
|
use zerotier_core_crypto::hash::SHA384_HASH_SIZE;
|
||||||
|
use zerotier_core_crypto::p521::P521KeyPair;
|
||||||
|
use zerotier_core_crypto::random::SecureRandom;
|
||||||
|
use zerotier_core_crypto::secret::Secret;
|
||||||
|
use zerotier_core_crypto::sidhp751::{SIDHPublicKeyAlice, SIDHPublicKeyBob, SIDHSecretKeyAlice, SIDHSecretKeyBob};
|
||||||
|
|
||||||
|
use crate::vl1::Address;
|
||||||
|
use crate::vl1::protocol::EPHEMERAL_SECRET_SIDH_TTL;
|
||||||
|
use crate::vl1::symmetricsecret::SymmetricSecret;
|
||||||
|
|
||||||
|
const EPHEMERAL_CIPHER_C25519: u8 = 1;
|
||||||
|
const EPHEMERAL_CIPHER_P521: u8 = 2;
|
||||||
|
const EPHEMERAL_CIPHER_SIDH_P751: u8 = 3;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
enum SIDHSecretKey {
|
||||||
|
Alice(SIDHPublicKeyAlice, SIDHSecretKeyAlice),
|
||||||
|
Bob(SIDHPublicKeyBob, SIDHSecretKeyBob)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SIDHSecretKey {
|
||||||
|
/// Generate a SIDH key pair.
|
||||||
|
///
|
||||||
|
/// SIDH is weird. A key exchange must involve one participant taking a role
|
||||||
|
/// canonically called Alice and the other wearing the Bob hat, because math.
|
||||||
|
///
|
||||||
|
/// If our local address is less than the remote address, we take the Alice role.
|
||||||
|
/// Otherwise if it's greater or equal we take the Bob role.
|
||||||
|
///
|
||||||
|
/// Everything works as long as the two sides take opposite roles. There is no
|
||||||
|
/// security implication in one side always taking one role.
|
||||||
|
pub fn generate(local_address: Address, remote_address: Address) -> SIDHSecretKey {
|
||||||
|
let mut rng = SecureRandom::get();
|
||||||
|
if local_address < remote_address {
|
||||||
|
let (p, s) = zerotier_core_crypto::sidh::sidh::generate_alice_keypair(&mut rng);
|
||||||
|
SIDHSecretKey::Alice(p, s)
|
||||||
|
} else {
|
||||||
|
let (p, s) = zerotier_core_crypto::sidh::sidh::generate_bob_keypair(&mut rng);
|
||||||
|
SIDHSecretKey::Bob(p, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An ephemeral secret key negotiated to implement forward secrecy.
|
||||||
|
pub struct EphemeralSecret {
|
||||||
|
timestamp_ticks: i64,
|
||||||
|
c25519: C25519KeyPair,
|
||||||
|
p521: P521KeyPair,
|
||||||
|
sidhp751: SIDHSecretKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EphemeralSecret {
|
||||||
|
/// Create a new ephemeral secret key.
|
||||||
|
///
|
||||||
|
/// This contains key pairs for the asymmetric key agreement algorithms used and a
|
||||||
|
/// timestamp used to enforce TTL.
|
||||||
|
pub fn new(time_ticks: i64, local_address: Address, remote_address: Address) -> Self {
|
||||||
|
EphemeralSecret {
|
||||||
|
timestamp_ticks: time_ticks,
|
||||||
|
c25519: C25519KeyPair::generate(true),
|
||||||
|
p521: P521KeyPair::generate(true).expect("NIST P-521 key pair generation failed"),
|
||||||
|
sidhp751: SIDHSecretKey::generate(local_address, remote_address),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a public version of this ephemeral secret to share with our counterparty.
|
||||||
|
pub fn public(&self) -> Vec<u8> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EphemeralSymmetricSecret {
|
||||||
|
secret: SymmetricSecret,
|
||||||
|
agreement_timestamp_ticks: i64,
|
||||||
|
local_secret_timestamp_ticks: i64,
|
||||||
|
encrypt_uses: AtomicU32,
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ pub(crate) mod mac;
|
||||||
pub(crate) mod fragmentedpacket;
|
pub(crate) mod fragmentedpacket;
|
||||||
pub(crate) mod whoisqueue;
|
pub(crate) mod whoisqueue;
|
||||||
pub(crate) mod ephemeral;
|
pub(crate) mod ephemeral;
|
||||||
|
pub(crate) mod symmetricsecret;
|
||||||
|
|
||||||
pub use address::Address;
|
pub use address::Address;
|
||||||
pub use mac::MAC;
|
pub use mac::MAC;
|
||||||
|
|
|
@ -49,6 +49,18 @@ pub const KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K1: u8 = b'1';
|
||||||
/// KBKDF usage label for acknowledgement of a shared secret.
|
/// KBKDF usage label for acknowledgement of a shared secret.
|
||||||
pub const KBKDF_KEY_USAGE_LABEL_EPHEMERAL_ACK: u8 = b'A';
|
pub const KBKDF_KEY_USAGE_LABEL_EPHEMERAL_ACK: u8 = b'A';
|
||||||
|
|
||||||
|
/// Try to re-key ephemeral keys after this time.
|
||||||
|
pub const EPHEMERAL_SECRET_REKEY_AFTER_TIME: i64 = 1000 * 60 * 60; // 1 hour
|
||||||
|
|
||||||
|
/// Maximum number of times to use an ephemeral secret before trying to replace it.
|
||||||
|
pub const EPHEMERAL_SECRET_REKEY_AFTER_USES: u32 = 536870912; // 1/4 the NIST security limit
|
||||||
|
|
||||||
|
/// Ephemeral secret reject after time.
|
||||||
|
pub const EPHEMERAL_SECRET_REJECT_AFTER_TIME: i64 = EPHEMERAL_SECRET_REKEY_AFTER_TIME * 2;
|
||||||
|
|
||||||
|
/// Ephemeral secret reject after uses.
|
||||||
|
pub const EPHEMERAL_SECRET_REJECT_AFTER_USES: u32 = 2147483648; // NIST security limit
|
||||||
|
|
||||||
/// Length of an address in bytes.
|
/// Length of an address in bytes.
|
||||||
pub const ADDRESS_SIZE: usize = 5;
|
pub const ADDRESS_SIZE: usize = 5;
|
||||||
|
|
||||||
|
|
53
zerotier-network-hypervisor/src/vl1/symmetricsecret.rs
Normal file
53
zerotier-network-hypervisor/src/vl1/symmetricsecret.rs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* (c)2021 ZeroTier, Inc.
|
||||||
|
* https://www.zerotier.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
|
use zerotier_core_crypto::aes_gmac_siv::{AesCtr, AesGmacSiv};
|
||||||
|
use zerotier_core_crypto::hash::SHA384_HASH_SIZE;
|
||||||
|
use zerotier_core_crypto::kbkdf::zt_kbkdf_hmac_sha384;
|
||||||
|
use zerotier_core_crypto::secret::Secret;
|
||||||
|
|
||||||
|
use crate::util::pool::{Pool, PoolFactory};
|
||||||
|
use crate::vl1::protocol::{KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K0, KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K1, KBKDF_KEY_USAGE_LABEL_HELLO_DICTIONARY_ENCRYPT, KBKDF_KEY_USAGE_LABEL_PACKET_HMAC};
|
||||||
|
|
||||||
|
pub struct AesGmacSivPoolFactory(Secret<SHA384_HASH_SIZE>, Secret<SHA384_HASH_SIZE>);
|
||||||
|
|
||||||
|
impl PoolFactory<AesGmacSiv> for AesGmacSivPoolFactory {
|
||||||
|
#[inline(always)]
|
||||||
|
fn create(&self) -> AesGmacSiv { AesGmacSiv::new(&self.0.0[0..32], &self.1.0[0..32]) }
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn reset(&self, obj: &mut AesGmacSiv) { obj.reset(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A symmetric secret key negotiated between peers.
|
||||||
|
///
|
||||||
|
/// This contains the key and several sub-keys and ciphers keyed with sub-keys.
|
||||||
|
pub struct SymmetricSecret {
|
||||||
|
pub key: Secret<SHA384_HASH_SIZE>,
|
||||||
|
pub packet_hmac_key: Secret<SHA384_HASH_SIZE>,
|
||||||
|
pub hello_dictionary_keyed_cipher: Mutex<AesCtr>,
|
||||||
|
pub aes_gmac_siv: Pool<AesGmacSiv, AesGmacSivPoolFactory>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SymmetricSecret {
|
||||||
|
pub fn new(base_key: Secret<SHA384_HASH_SIZE>) -> SymmetricSecret {
|
||||||
|
let usage_packet_hmac = zt_kbkdf_hmac_sha384(&base_key.0, KBKDF_KEY_USAGE_LABEL_PACKET_HMAC, 0, 0);
|
||||||
|
let usage_hello_dictionary_key = zt_kbkdf_hmac_sha384(&base_key.0, KBKDF_KEY_USAGE_LABEL_HELLO_DICTIONARY_ENCRYPT, 0, 0);
|
||||||
|
let aes_factory = AesGmacSivPoolFactory(
|
||||||
|
zt_kbkdf_hmac_sha384(&base_key.0, KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K0, 0, 0),
|
||||||
|
zt_kbkdf_hmac_sha384(&base_key.0, KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K1, 0, 0));
|
||||||
|
SymmetricSecret {
|
||||||
|
key: base_key,
|
||||||
|
packet_hmac_key: usage_packet_hmac,
|
||||||
|
hello_dictionary_keyed_cipher: Mutex::new(AesCtr::new(&usage_hello_dictionary_key.0[0..32])),
|
||||||
|
aes_gmac_siv: Pool::new(2, aes_factory),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue