Skip to content

Commit

Permalink
Merge branch 'bump-ed25519' into add-audit-ci
Browse files Browse the repository at this point in the history
  • Loading branch information
Ekleog-NEAR committed Nov 18, 2023
2 parents 6119235 + 5bc803c commit e835e46
Show file tree
Hide file tree
Showing 11 changed files with 167 additions and 144 deletions.
204 changes: 112 additions & 92 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,14 @@ crossbeam = "0.8"
crossbeam-channel = "0.5.8"
crossbeam-queue = "0.3.8"
csv = "1.2.1"
curve25519-dalek = "3"
curve25519-dalek = { version = "4.1.1", features = ["rand_core"] }
derive-enum-from-into = "0.1.1"
derive_more = "0.99.9"
dirs = "4"
dynasm = "2.0"
dynasmrt = "2.0"
easy-ext = "0.2"
ed25519-dalek = "1"
ed25519-dalek = { version = "2.1.0", features = ["hazmat", "rand_core"] }
elastic-array = "0.11"
enum-map = "2.1.0"
enumset = "1.0"
Expand Down
11 changes: 4 additions & 7 deletions core/crypto/src/key_conversion.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::{signature, vrf, PublicKey};
use curve25519_dalek::edwards::{CompressedEdwardsY, EdwardsPoint};
use curve25519_dalek::ristretto::RistrettoPoint;
use curve25519_dalek::scalar::Scalar;
use std::mem::transmute;

pub fn is_valid_staking_key(public_key: &PublicKey) -> bool {
Expand All @@ -13,7 +12,7 @@ pub fn is_valid_staking_key(public_key: &PublicKey) -> bool {
}

pub fn convert_public_key(key: &signature::ED25519PublicKey) -> Option<vrf::PublicKey> {
let ep: EdwardsPoint = CompressedEdwardsY::from_slice(&key.0).decompress()?;
let ep: EdwardsPoint = CompressedEdwardsY::from_slice(&key.0).ok()?.decompress()?;
// All properly generated public keys are torsion-free. RistrettoPoint type can handle some values that are not torsion-free, but not all.
if !ep.is_torsion_free() {
return None;
Expand All @@ -24,11 +23,9 @@ pub fn convert_public_key(key: &signature::ED25519PublicKey) -> Option<vrf::Publ
}

pub fn convert_secret_key(key: &signature::ED25519SecretKey) -> vrf::SecretKey {
let b = ed25519_dalek::ExpandedSecretKey::from(
&ed25519_dalek::SecretKey::from_bytes(&key.0[..32]).unwrap(),
)
.to_bytes();
vrf::SecretKey::from_scalar(Scalar::from_bytes_mod_order(b[0..32].try_into().unwrap()))
let b = <&[u8; 32]>::try_from(&key.0[..32]).unwrap();
let s = ed25519_dalek::hazmat::ExpandedSecretKey::from(b).scalar;
vrf::SecretKey::from_scalar(s)
}

#[cfg(test)]
Expand Down
36 changes: 17 additions & 19 deletions core/crypto/src/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use borsh::{BorshDeserialize, BorshSerialize};
use ed25519_dalek::ed25519::signature::{Signer, Verifier};
use once_cell::sync::Lazy;
use primitive_types::U256;
use rand::rngs::OsRng;
use secp256k1::rand::rngs::OsRng;
use secp256k1::Message;
use std::convert::AsRef;
use std::fmt::{Debug, Display, Formatter};
Expand Down Expand Up @@ -305,19 +305,17 @@ impl SecretKey {
pub fn from_random(key_type: KeyType) -> SecretKey {
match key_type {
KeyType::ED25519 => {
let keypair = ed25519_dalek::Keypair::generate(&mut OsRng);
SecretKey::ED25519(ED25519SecretKey(keypair.to_bytes()))
}
KeyType::SECP256K1 => {
SecretKey::SECP256K1(secp256k1::SecretKey::new(&mut secp256k1::rand::rngs::OsRng))
let keypair = ed25519_dalek::SigningKey::generate(&mut OsRng);
SecretKey::ED25519(ED25519SecretKey(keypair.to_keypair_bytes()))
}
KeyType::SECP256K1 => SecretKey::SECP256K1(secp256k1::SecretKey::new(&mut OsRng)),
}
}

pub fn sign(&self, data: &[u8]) -> Signature {
match &self {
SecretKey::ED25519(secret_key) => {
let keypair = ed25519_dalek::Keypair::from_bytes(&secret_key.0).unwrap();
let keypair = ed25519_dalek::SigningKey::from_keypair_bytes(&secret_key.0).unwrap();
Signature::ED25519(keypair.sign(data))
}

Expand Down Expand Up @@ -508,13 +506,13 @@ impl Signature {
signature_data: &[u8],
) -> Result<Self, crate::errors::ParseSignatureError> {
match signature_type {
KeyType::ED25519 => Ok(Signature::ED25519(
ed25519_dalek::Signature::from_bytes(signature_data).map_err(|err| {
KeyType::ED25519 => Ok(Signature::ED25519(ed25519_dalek::Signature::from_bytes(
<&[u8; 64]>::try_from(signature_data).map_err(|err| {
crate::errors::ParseSignatureError::InvalidData {
error_message: err.to_string(),
}
})?,
)),
))),
KeyType::SECP256K1 => {
Ok(Signature::SECP256K1(Secp256K1Signature::try_from(signature_data).map_err(
|_| crate::errors::ParseSignatureError::InvalidData {
Expand All @@ -530,7 +528,7 @@ impl Signature {
pub fn verify(&self, data: &[u8], public_key: &PublicKey) -> bool {
match (&self, public_key) {
(Signature::ED25519(signature), PublicKey::ED25519(public_key)) => {
match ed25519_dalek::PublicKey::from_bytes(&public_key.0) {
match ed25519_dalek::VerifyingKey::from_bytes(&public_key.0) {
Err(_) => false,
Ok(public_key) => public_key.verify(data, signature).is_ok(),
}
Expand Down Expand Up @@ -598,10 +596,7 @@ impl BorshDeserialize for Signature {
KeyType::ED25519 => {
let array: [u8; ed25519_dalek::SIGNATURE_LENGTH] =
BorshDeserialize::deserialize_reader(rd)?;
Ok(Signature::ED25519(
ed25519_dalek::Signature::from_bytes(&array)
.map_err(|e| Error::new(ErrorKind::InvalidData, e.to_string()))?,
))
Ok(Signature::ED25519(ed25519_dalek::Signature::from_bytes(&array)))
}
KeyType::SECP256K1 => {
let array: [u8; 65] = BorshDeserialize::deserialize_reader(rd)?;
Expand All @@ -613,11 +608,15 @@ impl BorshDeserialize for Signature {

impl Display for Signature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
let buf;
let (key_type, key_data) = match self {
Signature::ED25519(signature) => (KeyType::ED25519, signature.as_ref()),
Signature::ED25519(signature) => {
buf = signature.to_bytes();
(KeyType::ED25519, &buf[..])
}
Signature::SECP256K1(signature) => (KeyType::SECP256K1, &signature.0[..]),
};
write!(f, "{}:{}", key_type, Bs58(key_data))
write!(f, "{}:{}", key_type, Bs58(&key_data))
}
}

Expand Down Expand Up @@ -647,8 +646,7 @@ impl FromStr for Signature {
Ok(match sig_type {
KeyType::ED25519 => {
let data = decode_bs58::<{ ed25519_dalek::SIGNATURE_LENGTH }>(sig_data)?;
let sig = ed25519_dalek::Signature::from_bytes(&data)
.map_err(|err| Self::Err::InvalidData { error_message: err.to_string() })?;
let sig = ed25519_dalek::Signature::from_bytes(&data);
Signature::ED25519(sig)
}
KeyType::SECP256K1 => Signature::SECP256K1(Secp256K1Signature(decode_bs58(sig_data)?)),
Expand Down
14 changes: 5 additions & 9 deletions core/crypto/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ use crate::signature::{ED25519PublicKey, ED25519SecretKey, KeyType, PublicKey, S
use crate::{InMemorySigner, Signature};
use near_account_id::AccountId;

fn ed25519_key_pair_from_seed(seed: &str) -> ed25519_dalek::Keypair {
fn ed25519_key_pair_from_seed(seed: &str) -> ed25519_dalek::SigningKey {
let seed_bytes = seed.as_bytes();
let len = std::cmp::min(ed25519_dalek::SECRET_KEY_LENGTH, seed_bytes.len());
let mut seed: [u8; ed25519_dalek::SECRET_KEY_LENGTH] = [b' '; ed25519_dalek::SECRET_KEY_LENGTH];
seed[..len].copy_from_slice(&seed_bytes[..len]);
let secret = ed25519_dalek::SecretKey::from_bytes(&seed).unwrap();
let public = ed25519_dalek::PublicKey::from(&secret);
ed25519_dalek::Keypair { secret, public }
ed25519_dalek::SigningKey::from_bytes(&seed)
}

fn secp256k1_secret_key_from_seed(seed: &str) -> secp256k1::SecretKey {
Expand All @@ -28,7 +26,7 @@ impl PublicKey {
match key_type {
KeyType::ED25519 => {
let keypair = ed25519_key_pair_from_seed(seed);
PublicKey::ED25519(ED25519PublicKey(keypair.public.to_bytes()))
PublicKey::ED25519(ED25519PublicKey(keypair.verifying_key().to_bytes()))
}
_ => unimplemented!(),
}
Expand All @@ -40,7 +38,7 @@ impl SecretKey {
match key_type {
KeyType::ED25519 => {
let keypair = ed25519_key_pair_from_seed(seed);
SecretKey::ED25519(ED25519SecretKey(keypair.to_bytes()))
SecretKey::ED25519(ED25519SecretKey(keypair.to_keypair_bytes()))
}
_ => SecretKey::SECP256K1(secp256k1_secret_key_from_seed(seed)),
}
Expand All @@ -53,9 +51,7 @@ impl Signature {
/// Empty signature that doesn't correspond to anything.
pub fn empty(key_type: KeyType) -> Self {
match key_type {
KeyType::ED25519 => {
Signature::ED25519(ed25519_dalek::Signature::from_bytes(&SIG).unwrap())
}
KeyType::ED25519 => Signature::ED25519(ed25519_dalek::Signature::from_bytes(&SIG)),
_ => unimplemented!(),
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/crypto/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl Packable for Scalar {
type Packed = [u8; 32];

fn unpack(data: &[u8; 32]) -> Option<Self> {
Scalar::from_canonical_bytes(*data)
Scalar::from_canonical_bytes(*data).into()
}

fn pack(&self) -> [u8; 32] {
Expand Down
6 changes: 3 additions & 3 deletions core/crypto/src/vrf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ impl PublicKey {
// manner.
#[allow(clippy::arithmetic_side_effects)]
fn basemul(s: Scalar) -> Point {
&s * &GT
&s * &*GT
}

fn safe_invert(s: Scalar) -> Scalar {
Scalar::conditional_select(&s, &Scalar::one(), s.ct_eq(&Scalar::zero())).invert()
Scalar::conditional_select(&s, &Scalar::ONE, s.ct_eq(&Scalar::ZERO)).invert()
}

impl SecretKey {
Expand Down Expand Up @@ -122,7 +122,7 @@ traits!(SecretKey, 32, |s| s.0.as_bytes(), "secret key");
mod tests {
use super::*;

use rand::rngs::OsRng;
use secp256k1::rand::rngs::OsRng;
use serde::{Deserialize, Serialize};
use serde_json::{from_str, to_string};

Expand Down
2 changes: 0 additions & 2 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ skip = [
{ name = "cfg-if", version = "=1.0.0" },

# `sha2`, `blake3` and `curve25519-dalek` need to be updated.
{ name = "block-buffer", version = "=0.9.0" },
{ name = "digest", version = "=0.9.0" },
{ name = "sha2", version = "=0.9.9" },

# Need this specific version of pwasm-utils for backwards-compatible
# stack limiting.
Expand Down
4 changes: 2 additions & 2 deletions runtime/near-vm-runner/src/logic/gas_counter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ use std::collections::HashMap;

#[inline]
pub fn with_ext_cost_counter(f: impl FnOnce(&mut HashMap<ExtCosts, u64>)) {
#[cfg(feature = "costs_counting")]
#[cfg(any(test, feature = "costs_counting"))]
{
thread_local! {
static EXT_COSTS_COUNTER: std::cell::RefCell<HashMap<ExtCosts, u64>> =
Default::default();
}
EXT_COSTS_COUNTER.with(|rc| f(&mut *rc.borrow_mut()));
}
#[cfg(not(feature = "costs_counting"))]
#[cfg(not(any(test, feature = "costs_counting")))]
let _ = f;
}

Expand Down
18 changes: 14 additions & 4 deletions runtime/near-vm-runner/src/logic/logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1157,23 +1157,33 @@ impl<'a> VMLogic<'a> {
msg: "invalid signature length".to_string(),
}));
}
match ed25519_dalek::Signature::from_bytes(&vec) {
Ok(signature) => signature,
// Sanity-check that was performed by ed25519-dalek in from_bytes before version 2,
// but was removed with version 2. It is not actually any good a check, but we need
// it to avoid costs changing.
if vec[ed25519_dalek::SIGNATURE_LENGTH - 1] & 0b1110_0000 != 0 {
return Ok(false as u64);
}
match <&[u8; 64]>::try_from(&vec[..]) {
Ok(b) => ed25519_dalek::Signature::from_bytes(b),
Err(_) => return Ok(false as u64),
}
};

let message = get_memory_or_register!(self, message_ptr, message_len)?;
self.gas_counter.pay_per(ed25519_verify_byte, message.len() as u64)?;

let public_key: ed25519_dalek::PublicKey = {
let public_key: ed25519_dalek::VerifyingKey = {
let vec = get_memory_or_register!(self, public_key_ptr, public_key_len)?;
if vec.len() != ed25519_dalek::PUBLIC_KEY_LENGTH {
return Err(VMLogicError::HostError(HostError::Ed25519VerifyInvalidInput {
msg: "invalid public key length".to_string(),
}));
}
match ed25519_dalek::PublicKey::from_bytes(&vec) {
let b = match <&[u8; 32]>::try_from(&vec[..]) {
Ok(b) => b,
Err(_) => return Ok(false as u64),
};
match ed25519_dalek::VerifyingKey::from_bytes(b) {
Ok(public_key) => public_key,
Err(_) => return Ok(false as u64),
}
Expand Down
10 changes: 7 additions & 3 deletions tools/mirror/src/key_mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,13 @@ fn map_ed25519(

ed25519_map_secret(&mut buf[..ed25519_dalek::SECRET_KEY_LENGTH], public, secret);

let secret_key =
ed25519_dalek::SecretKey::from_bytes(&buf[..ed25519_dalek::SECRET_KEY_LENGTH]).unwrap();
let public_key = ed25519_dalek::PublicKey::from(&secret_key);
let secret_key = ed25519_dalek::SigningKey::from_bytes(
<&[u8; ed25519_dalek::SECRET_KEY_LENGTH]>::try_from(
&buf[..ed25519_dalek::SECRET_KEY_LENGTH],
)
.unwrap(),
);
let public_key = ed25519_dalek::VerifyingKey::from(&secret_key);

buf[ed25519_dalek::SECRET_KEY_LENGTH..].copy_from_slice(public_key.as_bytes());
ED25519SecretKey(buf)
Expand Down

0 comments on commit e835e46

Please sign in to comment.