Move masking of scalars in Curve25519 code to Rust.
This commit is contained in:
parent
03b9d14d15
commit
65ab723a19
@ -18,3 +18,4 @@ pub mod ed25519;
|
||||
pub mod x25519;
|
||||
|
||||
mod ops;
|
||||
mod scalar;
|
||||
|
@ -15,10 +15,18 @@
|
||||
//! EdDSA Signatures.
|
||||
|
||||
use super::ops::ELEM_LEN;
|
||||
use crate::digest;
|
||||
|
||||
mod digest;
|
||||
pub mod signing;
|
||||
pub mod verification;
|
||||
|
||||
/// The length of an Ed25519 public key.
|
||||
pub const ED25519_PUBLIC_KEY_LEN: usize = ELEM_LEN;
|
||||
|
||||
pub fn eddsa_digest(signature_r: &[u8], public_key: &[u8], msg: &[u8]) -> digest::Digest {
|
||||
let mut ctx = digest::Context::new(&digest::SHA512);
|
||||
ctx.update(signature_r);
|
||||
ctx.update(public_key);
|
||||
ctx.update(msg);
|
||||
ctx.finish()
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
use crate::digest;
|
||||
|
||||
use super::super::ops::{Scalar, UnreducedScalar, SCALAR_LEN};
|
||||
|
||||
pub fn eddsa_digest(signature_r: &[u8], public_key: &[u8], msg: &[u8]) -> digest::Digest {
|
||||
let mut ctx = digest::Context::new(&digest::SHA512);
|
||||
ctx.update(signature_r);
|
||||
ctx.update(public_key);
|
||||
ctx.update(msg);
|
||||
ctx.finish()
|
||||
}
|
||||
|
||||
pub fn digest_scalar(digest: digest::Digest) -> Scalar {
|
||||
let mut unreduced = [0u8; digest::SHA512_OUTPUT_LEN];
|
||||
unreduced.copy_from_slice(digest.as_ref());
|
||||
unsafe { GFp_x25519_sc_reduce(&mut unreduced) };
|
||||
let mut scalar = [0u8; SCALAR_LEN];
|
||||
scalar.copy_from_slice(&unreduced[..SCALAR_LEN]);
|
||||
scalar
|
||||
}
|
||||
extern "C" {
|
||||
fn GFp_x25519_sc_reduce(s: &mut UnreducedScalar);
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
|
||||
//! EdDSA Signatures.
|
||||
|
||||
use super::{super::ops::*, ED25519_PUBLIC_KEY_LEN};
|
||||
use super::{super::ops::*, eddsa_digest, ED25519_PUBLIC_KEY_LEN};
|
||||
use crate::{
|
||||
digest, error,
|
||||
io::der,
|
||||
@ -24,8 +24,6 @@ use crate::{
|
||||
use core::convert::TryInto;
|
||||
use untrusted;
|
||||
|
||||
use super::digest::*;
|
||||
|
||||
/// An Ed25519 key pair, for signing.
|
||||
pub struct Ed25519KeyPair {
|
||||
// RFC 8032 Section 5.1.6 calls this *s*.
|
||||
@ -155,23 +153,19 @@ impl Ed25519KeyPair {
|
||||
|
||||
fn from_seed_(seed: &Seed) -> Self {
|
||||
let h = digest::digest(&digest::SHA512, seed);
|
||||
let (scalar_encoded, prefix_encoded) = h.as_ref().split_at(SCALAR_LEN);
|
||||
let (private_scalar, private_prefix) = h.as_ref().split_at(SCALAR_LEN);
|
||||
|
||||
let mut scalar = [0u8; SCALAR_LEN];
|
||||
scalar.copy_from_slice(&scalar_encoded);
|
||||
unsafe { GFp_x25519_sc_mask(&mut scalar) };
|
||||
|
||||
let mut prefix = [0u8; PREFIX_LEN];
|
||||
prefix.copy_from_slice(prefix_encoded);
|
||||
let private_scalar =
|
||||
MaskedScalar::from_bytes_masked(private_scalar.try_into().unwrap()).into();
|
||||
|
||||
let mut a = ExtPoint::new_at_infinity();
|
||||
unsafe {
|
||||
GFp_x25519_ge_scalarmult_base(&mut a, &scalar);
|
||||
GFp_x25519_ge_scalarmult_base(&mut a, &private_scalar);
|
||||
}
|
||||
|
||||
Self {
|
||||
private_scalar: scalar,
|
||||
private_prefix: prefix,
|
||||
private_scalar,
|
||||
private_prefix: private_prefix.try_into().unwrap(),
|
||||
public_key: PublicKey(a.into_encoded_point()),
|
||||
}
|
||||
}
|
||||
@ -179,6 +173,15 @@ impl Ed25519KeyPair {
|
||||
/// Returns the signature of the message `msg`.
|
||||
pub fn sign(&self, msg: &[u8]) -> signature::Signature {
|
||||
signature::Signature::new(|signature_bytes| {
|
||||
extern "C" {
|
||||
fn GFp_x25519_sc_muladd(
|
||||
s: &mut [u8; SCALAR_LEN],
|
||||
a: &Scalar,
|
||||
b: &Scalar,
|
||||
c: &Scalar,
|
||||
);
|
||||
}
|
||||
|
||||
let (signature_bytes, _unused) = signature_bytes.split_at_mut(ELEM_LEN + SCALAR_LEN);
|
||||
let (signature_r, signature_s) = signature_bytes.split_at_mut(ELEM_LEN);
|
||||
let nonce = {
|
||||
@ -187,7 +190,7 @@ impl Ed25519KeyPair {
|
||||
ctx.update(msg);
|
||||
ctx.finish()
|
||||
};
|
||||
let nonce = digest_scalar(nonce);
|
||||
let nonce = Scalar::from_sha512_digest_reduced(nonce);
|
||||
|
||||
let mut r = ExtPoint::new_at_infinity();
|
||||
unsafe {
|
||||
@ -195,7 +198,7 @@ impl Ed25519KeyPair {
|
||||
}
|
||||
signature_r.copy_from_slice(&r.into_encoded_point());
|
||||
let hram_digest = eddsa_digest(signature_r, &self.public_key.as_ref(), msg);
|
||||
let hram = digest_scalar(hram_digest);
|
||||
let hram = Scalar::from_sha512_digest_reduced(hram_digest);
|
||||
unsafe {
|
||||
GFp_x25519_sc_muladd(
|
||||
signature_s.try_into().unwrap(),
|
||||
@ -243,9 +246,7 @@ fn unwrap_pkcs8(
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn GFp_x25519_ge_scalarmult_base(h: &mut ExtPoint, a: &Seed);
|
||||
fn GFp_x25519_sc_mask(a: &mut Scalar);
|
||||
fn GFp_x25519_sc_muladd(s: &mut Scalar, a: &Scalar, b: &Scalar, c: &Scalar);
|
||||
fn GFp_x25519_ge_scalarmult_base(h: &mut ExtPoint, a: &Scalar);
|
||||
}
|
||||
|
||||
type Prefix = [u8; PREFIX_LEN];
|
||||
|
@ -14,12 +14,10 @@
|
||||
|
||||
//! EdDSA Signatures.
|
||||
|
||||
use super::super::ops::*;
|
||||
use super::{super::ops::*, eddsa_digest};
|
||||
use crate::{error, sealed, signature};
|
||||
use untrusted;
|
||||
|
||||
use super::digest::*;
|
||||
use core::convert::TryInto;
|
||||
use untrusted;
|
||||
|
||||
/// Parameters for EdDSA signing and verification.
|
||||
pub struct EdDSAParameters;
|
||||
@ -57,16 +55,13 @@ impl signature::VerificationAlgorithm for EdDSAParameters {
|
||||
Ok((signature_r, signature_s))
|
||||
})?;
|
||||
|
||||
// Ensure `s` is not too large.
|
||||
if (signature_s[SCALAR_LEN - 1] & 0b11100000) != 0 {
|
||||
return Err(error::Unspecified);
|
||||
}
|
||||
let signature_s = Scalar::from_bytes_checked(*signature_s)?;
|
||||
|
||||
let mut a = ExtPoint::from_encoded_point_vartime(public_key)?;
|
||||
a.invert_vartime();
|
||||
|
||||
let h_digest = eddsa_digest(signature_r, public_key, msg.as_slice_less_safe());
|
||||
let h = digest_scalar(h_digest);
|
||||
let h = Scalar::from_sha512_digest_reduced(h_digest);
|
||||
|
||||
let mut r = Point::new_at_infinity();
|
||||
unsafe { GFp_x25519_ge_double_scalarmult_vartime(&mut r, &h, &a, &signature_s) };
|
||||
|
@ -15,6 +15,7 @@
|
||||
//! Elliptic curve operations on the birationally equivalent curves Curve25519
|
||||
//! and Edwards25519.
|
||||
|
||||
pub use super::scalar::{MaskedScalar, Scalar, SCALAR_LEN};
|
||||
use crate::{
|
||||
bssl, error,
|
||||
limb::{Limb, LIMB_BITS},
|
||||
@ -62,12 +63,6 @@ impl Elem<T> {
|
||||
pub type EncodedPoint = [u8; ELEM_LEN];
|
||||
pub const ELEM_LEN: usize = 32;
|
||||
|
||||
pub type Scalar = [u8; SCALAR_LEN];
|
||||
pub const SCALAR_LEN: usize = 32;
|
||||
|
||||
pub type UnreducedScalar = [u8; UNREDUCED_SCALAR_LEN];
|
||||
const UNREDUCED_SCALAR_LEN: usize = SCALAR_LEN * 2;
|
||||
|
||||
// Keep this in sync with `ge_p3` in curve25519/internal.h.
|
||||
#[repr(C)]
|
||||
pub struct ExtPoint {
|
||||
|
67
src/ec/curve25519/scalar.rs
Normal file
67
src/ec/curve25519/scalar.rs
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright 2015-2019 Brian Smith.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
||||
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
use crate::{digest, error};
|
||||
use core::convert::TryInto;
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct Scalar([u8; SCALAR_LEN]);
|
||||
|
||||
pub const SCALAR_LEN: usize = 32;
|
||||
|
||||
impl Scalar {
|
||||
// Constructs a `Scalar` from `bytes`, failing if `bytes` encodes a scalar
|
||||
// that not in the range [0, n).
|
||||
pub fn from_bytes_checked(bytes: [u8; SCALAR_LEN]) -> Result<Self, error::Unspecified> {
|
||||
// Ensure `s` is not too large.
|
||||
if (bytes[SCALAR_LEN - 1] & 0b11100000) != 0 {
|
||||
return Err(error::Unspecified);
|
||||
}
|
||||
Ok(Self(bytes))
|
||||
}
|
||||
|
||||
// Constructs a `Scalar` from `digest` reduced modulo n.
|
||||
pub fn from_sha512_digest_reduced(digest: digest::Digest) -> Self {
|
||||
extern "C" {
|
||||
fn GFp_x25519_sc_reduce(s: &mut UnreducedScalar);
|
||||
}
|
||||
let mut unreduced = [0u8; digest::SHA512_OUTPUT_LEN];
|
||||
unreduced.copy_from_slice(digest.as_ref());
|
||||
unsafe { GFp_x25519_sc_reduce(&mut unreduced) };
|
||||
Self((&unreduced[..SCALAR_LEN]).try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct MaskedScalar([u8; SCALAR_LEN]);
|
||||
|
||||
impl MaskedScalar {
|
||||
pub fn from_bytes_masked(bytes: [u8; SCALAR_LEN]) -> Self {
|
||||
extern "C" {
|
||||
fn GFp_x25519_sc_mask(a: &mut [u8; SCALAR_LEN]);
|
||||
}
|
||||
let mut r = Self(bytes);
|
||||
unsafe { GFp_x25519_sc_mask(&mut r.0) };
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MaskedScalar> for Scalar {
|
||||
fn from(MaskedScalar(scalar): MaskedScalar) -> Self {
|
||||
Self(scalar)
|
||||
}
|
||||
}
|
||||
|
||||
type UnreducedScalar = [u8; UNREDUCED_SCALAR_LEN];
|
||||
const UNREDUCED_SCALAR_LEN: usize = SCALAR_LEN * 2;
|
@ -14,7 +14,7 @@
|
||||
|
||||
//! X25519 Key agreement.
|
||||
|
||||
use super::ops;
|
||||
use super::{ops, scalar::SCALAR_LEN};
|
||||
use crate::{agreement, constant_time, cpu, ec, error, rand};
|
||||
use core::convert::TryInto;
|
||||
use untrusted;
|
||||
@ -62,7 +62,8 @@ fn x25519_public_from_private(
|
||||
#[cfg(target_arch = "arm")]
|
||||
let cpu_features = private_key.cpu_features;
|
||||
|
||||
let private_key = private_key.bytes_less_safe().try_into()?;
|
||||
let private_key: &[u8; SCALAR_LEN] = private_key.bytes_less_safe().try_into()?;
|
||||
let private_key = ops::MaskedScalar::from_bytes_masked(*private_key);
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
{
|
||||
@ -71,19 +72,19 @@ fn x25519_public_from_private(
|
||||
9, 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,
|
||||
];
|
||||
x25519_neon(public_out, private_key, &MONTGOMERY_BASE_POINT);
|
||||
x25519_neon(public_out, &private_key, &MONTGOMERY_BASE_POINT);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn GFp_x25519_public_from_private_generic(
|
||||
fn GFp_x25519_public_from_private_generic_masked(
|
||||
public_key_out: &mut PublicKey,
|
||||
private_key: &PrivateKey,
|
||||
);
|
||||
}
|
||||
unsafe {
|
||||
GFp_x25519_public_from_private_generic(public_out, private_key);
|
||||
GFp_x25519_public_from_private_generic_masked(public_out, &private_key);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -95,13 +96,14 @@ fn x25519_ecdh(
|
||||
peer_public_key: untrusted::Input,
|
||||
) -> Result<(), error::Unspecified> {
|
||||
let cpu_features = my_private_key.cpu_features;
|
||||
let my_private_key = my_private_key.bytes_less_safe().try_into()?;
|
||||
let my_private_key: &[u8; SCALAR_LEN] = my_private_key.bytes_less_safe().try_into()?;
|
||||
let my_private_key = ops::MaskedScalar::from_bytes_masked(*my_private_key);
|
||||
let peer_public_key: &[u8; PUBLIC_KEY_LEN] = peer_public_key.as_slice_less_safe().try_into()?;
|
||||
|
||||
#[cfg_attr(not(target_arch = "arm"), allow(unused_variables))]
|
||||
fn scalar_mult(
|
||||
out: &mut ops::EncodedPoint,
|
||||
scalar: &ops::Scalar,
|
||||
scalar: &ops::MaskedScalar,
|
||||
point: &ops::EncodedPoint,
|
||||
cpu_features: cpu::Features,
|
||||
) {
|
||||
@ -113,20 +115,20 @@ fn x25519_ecdh(
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn GFp_x25519_scalar_mult_generic(
|
||||
fn GFp_x25519_scalar_mult_generic_masked(
|
||||
out: &mut ops::EncodedPoint,
|
||||
scalar: &ops::Scalar,
|
||||
scalar: &ops::MaskedScalar,
|
||||
point: &ops::EncodedPoint,
|
||||
);
|
||||
}
|
||||
unsafe {
|
||||
GFp_x25519_scalar_mult_generic(out, scalar, point);
|
||||
GFp_x25519_scalar_mult_generic_masked(out, scalar, point);
|
||||
}
|
||||
}
|
||||
|
||||
scalar_mult(
|
||||
out.try_into()?,
|
||||
my_private_key,
|
||||
&my_private_key,
|
||||
peer_public_key,
|
||||
cpu_features,
|
||||
);
|
||||
@ -141,11 +143,11 @@ fn x25519_ecdh(
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
fn x25519_neon(out: &mut ops::EncodedPoint, scalar: &ops::Scalar, point: &ops::EncodedPoint) {
|
||||
fn x25519_neon(out: &mut ops::EncodedPoint, scalar: &ops::MaskedScalar, point: &ops::EncodedPoint) {
|
||||
extern "C" {
|
||||
fn GFp_x25519_NEON(
|
||||
out: &mut ops::EncodedPoint,
|
||||
scalar: &ops::Scalar,
|
||||
scalar: &ops::MaskedScalar,
|
||||
point: &ops::EncodedPoint,
|
||||
);
|
||||
}
|
||||
@ -154,8 +156,7 @@ fn x25519_neon(out: &mut ops::EncodedPoint, scalar: &ops::Scalar, point: &ops::E
|
||||
|
||||
const ELEM_AND_SCALAR_LEN: usize = ops::ELEM_LEN;
|
||||
|
||||
// An X25519 private key as an unmasked scalar.
|
||||
type PrivateKey = [u8; PRIVATE_KEY_LEN];
|
||||
type PrivateKey = ops::MaskedScalar;
|
||||
const PRIVATE_KEY_LEN: usize = ELEM_AND_SCALAR_LEN;
|
||||
|
||||
// An X25519 public key as an encoded Curve25519 point.
|
||||
|
18
third_party/fiat/curve25519.c
vendored
18
third_party/fiat/curve25519.c
vendored
@ -65,8 +65,6 @@
|
||||
#endif // BORINGSSL_CURVE25519_64BIT
|
||||
|
||||
|
||||
void GFp_x25519_sc_mask(uint8_t a[32]);
|
||||
|
||||
// Low-level intrinsic operations
|
||||
|
||||
static uint64_t load_3(const uint8_t *in) {
|
||||
@ -1793,15 +1791,14 @@ static void sc_muladd(uint8_t *s, const uint8_t *a, const uint8_t *b,
|
||||
}
|
||||
|
||||
|
||||
void GFp_x25519_scalar_mult_generic(uint8_t out[32],
|
||||
const uint8_t scalar[32],
|
||||
const uint8_t point[32]) {
|
||||
void GFp_x25519_scalar_mult_generic_masked(uint8_t out[32],
|
||||
const uint8_t scalar_masked[32],
|
||||
const uint8_t point[32]) {
|
||||
fe x1, x2, z2, x3, z3, tmp0, tmp1;
|
||||
fe_loose x2l, z2l, x3l, tmp0l, tmp1l;
|
||||
|
||||
uint8_t e[32];
|
||||
bytes_copy(e, scalar, 32);
|
||||
GFp_x25519_sc_mask(e);
|
||||
bytes_copy(e, scalar_masked, 32);
|
||||
// The following implementation was transcribed to Coq and proven to
|
||||
// correspond to unary scalar multiplication in affine coordinates given that
|
||||
// x1 != 0 is the x coordinate of some point on the curve. It was also checked
|
||||
@ -1872,11 +1869,10 @@ void GFp_x25519_scalar_mult_generic(uint8_t out[32],
|
||||
fe_tobytes(out, &x2);
|
||||
}
|
||||
|
||||
void GFp_x25519_public_from_private_generic(uint8_t out_public_value[32],
|
||||
const uint8_t private_key[32]) {
|
||||
void GFp_x25519_public_from_private_generic_masked(uint8_t out_public_value[32],
|
||||
const uint8_t private_key_masked[32]) {
|
||||
uint8_t e[32];
|
||||
bytes_copy(e, private_key, 32);
|
||||
GFp_x25519_sc_mask(e);
|
||||
bytes_copy(e, private_key_masked, 32);
|
||||
|
||||
ge_p3 A;
|
||||
GFp_x25519_ge_scalarmult_base(&A, e);
|
||||
|
Loading…
x
Reference in New Issue
Block a user