Skip to content

Commit

Permalink
Touchups
Browse files Browse the repository at this point in the history
  • Loading branch information
nickray committed Mar 21, 2021
1 parent 632ccb6 commit 4a94a24
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 106 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "p256-cortex-m4"
description = "Idiomatic, misuse-resistent bindings to P256-Cortex-M4"
version = "0.1.0-alpha.2"
version = "0.1.0-alpha.3"
authors = ["Nicolas Stalder <[email protected]>"]
edition = "2018"
license = "MIT"
Expand Down
102 changes: 58 additions & 44 deletions src/cortex_m4.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::convert::TryInto;
use core::{convert::TryInto, mem::MaybeUninit};

use rand_core::{CryptoRng, RngCore};
use zeroize::{Zeroize, Zeroizing};
Expand Down Expand Up @@ -205,13 +205,26 @@ impl SecretKey {
}

impl PublicKey {
/// Decode assuming `bytes` is x-coordinate then y-coordinate, both big-endian 32B arrays.
///
/// In other words, the uncompressed SEC1 format, without the leading 0x04 byte tag.
pub fn from_untagged_bytes(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 64 {
return Err(Error);
}
let mut sec1_bytes = [4u8; 65];
sec1_bytes[1..].copy_from_slice(bytes);
Self::from_sec1_bytes(&sec1_bytes)
}

/// Decode `PublicKey` (compressed or uncompressed) from the
/// `Elliptic-Curve-Point-to-Octet-String` encoding in [SEC 1][sec-1] (section 2.3.3)
///
/// This is the left-inverse of both `to_compressed_bytes` and `to_uncompressed_bytes`.
///
/// [sec-1]: http://www.secg.org/sec1-v2.pdf
pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> {
// NB: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#initializing-a-struct-field-by-field
let mut public = PublicKey {
x: [0u32; 8],
y: [0u32; 8],
Expand All @@ -228,49 +241,45 @@ impl PublicKey {
}
}

/// Decode assuming `bytes` is x-coordinate then y-coordinate, both big-endian 32B arrays.
///
/// In other words, the uncompressed SEC1 format, without the leading 0x04 byte.
pub fn from_untagged_bytes(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 64 {
return Err(Error);
}
let mut sec1_bytes = [4u8; 65];
sec1_bytes[1..].copy_from_slice(bytes);
Self::from_sec1_bytes(&sec1_bytes)
/// Raw encoding, x-coordinate then y-coordinate.
pub fn to_untagged_bytes(&self) -> [u8; 64] {
self.to_uncompressed_sec1_bytes()[1..].try_into().unwrap()
}

/// Compressed encoding: `02 || Px` if Py is even and `03 || Px` if Py is odd
pub fn to_compressed_bytes(&self) -> [u8; 33] {
let mut bytes = [0u8; 33];
unsafe { p256_cortex_m4_sys::p256_point_to_octet_string_compressed(
&mut bytes[0] as *mut _,
&self.x[0] as *const _,
&self.y[0] as *const _,
) };
bytes
pub fn to_compressed_sec1_bytes(&self) -> [u8; 33] {
let mut bytes = MaybeUninit::<[u8; 33]>::uninit();
unsafe {
p256_cortex_m4_sys::p256_point_to_octet_string_uncompressed(
bytes.as_mut_ptr() as *mut _,
&self.x[0] as *const _,
&self.y[0] as *const _,
);
bytes.assume_init()
}
}

/// Uncompressed encoding: `04 || Px || Py`.
pub fn to_uncompressed_bytes(&self) -> [u8; 65] {
let mut bytes = [0u8; 65];
unsafe { p256_cortex_m4_sys::p256_point_to_octet_string_uncompressed(
&mut bytes[0] as *mut _,
&self.x[0] as *const _,
&self.y[0] as *const _,
) };
bytes
pub fn to_uncompressed_sec1_bytes(&self) -> [u8; 65] {
let mut bytes = MaybeUninit::<[u8; 65]>::uninit();
unsafe {
p256_cortex_m4_sys::p256_point_to_octet_string_uncompressed(
bytes.as_mut_ptr() as *mut _,
&self.x[0] as *const _,
&self.y[0] as *const _,
);
bytes.assume_init()
}
}

/// Big-endian representation of x-coordinate.
pub fn x(&self) -> [u8; 32] {
self.to_uncompressed_bytes()[1..33].try_into().unwrap()

self.to_uncompressed_sec1_bytes()[1..33].try_into().unwrap()
}

/// Big-endian representation of x-coordinate.
pub fn y(&self) -> [u8; 32] {
self.to_uncompressed_bytes()[33..].try_into().unwrap()
self.to_uncompressed_sec1_bytes()[33..].try_into().unwrap()
}

/// Verify signature on message assumed to be hashed, if needed.
Expand All @@ -297,24 +306,28 @@ impl PublicKey {
impl Signature {
/// Big-endian representation of r.
fn r(&self) -> [u8; 32] {
let mut r = [0u8; 32];
unsafe { p256_cortex_m4_sys::p256_convert_endianness(
&mut r[0] as *mut u8 as *mut _,
&self.r[0] as *const u32 as *const _,
32,
) };
r
let mut r = MaybeUninit::<[u8; 32]>::uninit();
unsafe {
p256_cortex_m4_sys::p256_convert_endianness(
r.as_mut_ptr() as *mut u8 as *mut _,
&self.r[0] as *const u32 as *const _,
32,
);
r.assume_init()
}
}

/// Big-endian representation of s.
fn s(&self) -> [u8; 32] {
let mut s = [0u8; 32];
unsafe { p256_cortex_m4_sys::p256_convert_endianness(
&mut s[0] as *mut u8 as *mut _,
&self.s[0] as *const u32 as *const _,
32,
) };
s
let mut s = MaybeUninit::<[u8; 32]>::uninit();
unsafe {
p256_cortex_m4_sys::p256_convert_endianness(
s.as_mut_ptr() as *mut u8 as *mut _,
&self.s[0] as *const u32 as *const _,
32,
);
s.assume_init()
}
}

/// Decode signature as big-endian r, then big-endian s, without framing.
Expand All @@ -326,6 +339,7 @@ impl Signature {
return Err(Error);
}

// NB: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#initializing-a-struct-field-by-field
let mut signature = Signature {
r: [0u32; 8],
s: [0u32; 8],
Expand Down
97 changes: 36 additions & 61 deletions src/fallback.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use core::convert::TryInto;

use ecdsa::hazmat::{SignPrimitive, VerifyPrimitive};
use elliptic_curve::sec1::ToEncodedPoint;
use rand_core::{CryptoRng, RngCore};

use crate::{Error, Result};
Expand Down Expand Up @@ -79,10 +81,6 @@ impl SecretKey {

/// Attempt at unraveling the traits in `p256`.
pub fn sign_prehashed(&self, prehashed_message: &[u8], rng: impl CryptoRng + RngCore) -> Signature {
// use p256::ecdsa::signature::Signer;
// let signature = signer.sign(message);
// signature

let prehashed_message_as_scalar = p256::Scalar::from_bytes_reduced(prehashed_message.try_into().unwrap());
let mut rng = rng;
let static_scalar = p256::Scalar::from_bytes_reduced(&self.0.to_bytes());
Expand All @@ -91,7 +89,6 @@ impl SecretKey {
let ephemeral_scalar = p256::Scalar::from_bytes_reduced(&ephemeral_secret.to_bytes());
let blinded_scalar = p256::BlindedScalar::new(ephemeral_scalar, &mut rng);

use ecdsa::hazmat::SignPrimitive;
if let Ok(signature) = static_scalar.try_sign_prehashed(
&blinded_scalar,
&prehashed_message_as_scalar,
Expand All @@ -113,30 +110,17 @@ impl SecretKey {

/// ECDH key agreement.
pub fn agree(&self, other: &PublicKey) -> SharedSecret {

let shared_secret = elliptic_curve::ecdh::diffie_hellman(
SharedSecret(elliptic_curve::ecdh::diffie_hellman(
self.0.secret_scalar(),
other.0.as_affine(),
);

SharedSecret(shared_secret)
))
}
}

impl PublicKey {
/// Decode `PublicKey` (compressed or uncompressed) from the
/// `Elliptic-Curve-Point-to-Octet-String` encoding in [SEC 1][sec-1] (section 2.3.3)
///
/// This is the left-inverse of both `to_compressed_bytes` and `to_uncompressed_bytes`.
///
/// [sec-1]: http://www.secg.org/sec1-v2.pdf
pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> {
Ok(PublicKey(p256::PublicKey::from_sec1_bytes(bytes)?))
}

/// Decode assuming `bytes` is x-coordinate then y-coordinate, both big-endian 32B arrays.
///
/// In other words, the uncompressed SEC1 format, without the leading 0x04 byte.
/// In other words, the uncompressed SEC1 format, without the leading 0x04 byte tag.
pub fn from_untagged_bytes(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 64 {
return Err(Error);
Expand All @@ -146,39 +130,44 @@ impl PublicKey {
Self::from_sec1_bytes(&sec1_bytes)
}

/// Decode `PublicKey` (compressed or uncompressed) from the
/// `Elliptic-Curve-Point-to-Octet-String` encoding in [SEC 1][sec-1] (section 2.3.3)
///
/// This is the left-inverse of both `to_compressed_bytes` and `to_uncompressed_bytes`.
///
/// [sec-1]: http://www.secg.org/sec1-v2.pdf
pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> {
Ok(PublicKey(p256::PublicKey::from_sec1_bytes(bytes)?))
}

/// Raw encoding, x-coordinate then y-coordinate.
pub fn to_untagged_bytes(&self) -> [u8; 64] {
self.0.to_encoded_point(false).as_ref()[1..].as_ref().try_into().unwrap()
}

/// Compressed encoding: `02 || Px` if Py is even and `03 || Px` if Py is odd
pub fn to_compressed_bytes(&self) -> [u8; 33] {
use elliptic_curve::sec1::ToEncodedPoint;
let encoded_point = self.0.to_encoded_point(true);
let mut bytes = [0u8; 33];
bytes.copy_from_slice(encoded_point.as_bytes());
bytes
pub fn to_compressed_sec1_bytes(&self) -> [u8; 33] {
self.0.to_encoded_point(true).as_ref().try_into().unwrap()
}

/// Uncompressed encoding: `04 || Px || Py`.
pub fn to_uncompressed_bytes(&self) -> [u8; 65] {
use elliptic_curve::sec1::ToEncodedPoint;
let encoded_point = self.0.to_encoded_point(false);
let mut bytes = [0u8; 65];
bytes.copy_from_slice(encoded_point.as_bytes());
bytes
pub fn to_uncompressed_sec1_bytes(&self) -> [u8; 65] {
self.0.to_encoded_point(false).as_ref().try_into().unwrap()
}

/// Big-endian representation of x-coordinate.
pub fn x(&self) -> [u8; 32] {
self.to_uncompressed_bytes()[1..33].try_into().unwrap()
self.0.to_encoded_point(false).as_ref()[1..33].try_into().unwrap()
}

/// Big-endian representation of x-coordinate.
pub fn y(&self) -> [u8; 32] {
self.to_uncompressed_bytes()[33..].try_into().unwrap()
self.0.to_encoded_point(false).as_ref()[33..].try_into().unwrap()
}

/// Verify signature on message assumed to be hashed, if needed.
pub fn verify_prehashed(&self, prehashed_message: &[u8], signature: &Signature) -> bool {
let prehashed_message_as_scalar = p256::Scalar::from_bytes_reduced(prehashed_message.try_into().unwrap());
use ecdsa::hazmat::VerifyPrimitive;

self.0.as_affine().verify_prehashed(&prehashed_message_as_scalar, &signature.0).is_ok()
}

Expand All @@ -194,27 +183,15 @@ impl PublicKey {
}

impl Signature {
// /// Big-endian representation of r.
// pub fn r(&self) -> [u8; 32] {
// let mut r = [0u8; 32];
// unsafe { p256_cortex_m4_sys::p256_convert_endianness(
// &mut r[0] as *mut u8 as *mut _,
// &self.r[0] as *const u32 as *const _,
// 32,
// ) };
// r
// }

// /// Big-endian representation of s.
// pub fn s(&self) -> [u8; 32] {
// let mut s = [0u8; 32];
// unsafe { p256_cortex_m4_sys::p256_convert_endianness(
// &mut s[0] as *mut u8 as *mut _,
// &self.s[0] as *const u32 as *const _,
// 32,
// ) };
// s
// }
/// Big-endian representation of r.
pub fn r(&self) -> [u8; 32] {
self.0.r().as_ref().to_bytes().into()
}

/// Big-endian representation of s.
pub fn s(&self) -> [u8; 32] {
self.0.s().as_ref().to_bytes().into()
}

/// Decode signature as big-endian r, then big-endian s, without framing.
///
Expand All @@ -226,9 +203,7 @@ impl Signature {

/// Encode signature from big-endian r, then big-endian s, without framing.
pub fn to_bytes(&self) -> [u8; 64] {
let mut bytes = [0u8; 64];
bytes.copy_from_slice(self.0.as_ref());
bytes
self.0.as_ref().try_into().unwrap()
}

/// Decode signature from ASN.1 DER
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ pub struct Error;
/// Result type.
pub type Result<T> = core::result::Result<T, Error>;

// pub mod traits;

/// Convenience function, calculates SHA256 hash digest of a slice of bytes.
#[cfg(feature = "prehash")]
#[cfg_attr(docsrs, doc(cfg(feature = "prehash")))]
Expand Down

0 comments on commit 4a94a24

Please sign in to comment.