Skip to content

Commit

Permalink
Merge pull request #4382 from stacks-network/chore/ed25519-dalek-update
Browse files Browse the repository at this point in the history
Chore: ed25519 dalek update in `next`
  • Loading branch information
kantai authored Feb 15, 2024
2 parents 2dca32f + 41df072 commit 4227deb
Show file tree
Hide file tree
Showing 14 changed files with 1,077 additions and 970 deletions.
1,842 changes: 994 additions & 848 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ members = [
# Dependencies we want to keep the same between workspace members
[workspace.dependencies]
wsts = { version = "8.0", default-features = false }
ed25519-dalek = { version = "2.1.1", features = ["serde", "rand_core"] }
rand_core = "0.6"
rand = "0.8"
rand_chacha = "0.3.1"

# Use a bit more than default optimization for
# dev builds to speed up test execution
Expand Down
4 changes: 2 additions & 2 deletions clarity/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ name = "clarity"
path = "./src/libclarity.rs"

[dependencies]
rand = "0.7.3"
rand_chacha = "=0.2.2"
rand = { workspace = true }
rand_chacha = { workspace = true }
serde = "1"
serde_derive = "1"
serde_stacker = "0.1"
Expand Down
7 changes: 3 additions & 4 deletions stacks-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ name = "stacks_common"
path = "./src/libcommon.rs"

[dependencies]
rand = "0.7.3"
rand = { workspace = true }
serde = "1"
serde_derive = "1"
serde_stacker = "0.1"
Expand Down Expand Up @@ -55,8 +55,7 @@ version = "=0.24.2"
features = ["blob", "serde_json", "i128_blob", "bundled", "trace"]

[dependencies.ed25519-dalek]
version = "=1.0.0-pre.3"
features = ["serde"]
workspace = true

[dependencies.curve25519-dalek]
version = "=2.0.0"
Expand All @@ -70,7 +69,7 @@ features = ["std"]
rstest = "0.11.0"
rstest_reuse = "0.1.3"
assert-json-diff = "1.0.0"
rand_core = "0.6"
rand_core = { workspace = true }

[features]
default = ["developer-mode"]
Expand Down
2 changes: 1 addition & 1 deletion stacks-common/src/address/c32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ mod test {
fn old_c32_validation() {
for n in 0..5000 {
// random version
let random_version: u8 = rand::thread_rng().gen_range(0, 31);
let random_version: u8 = rand::thread_rng().gen_range(0..31);

// random 20 bytes
let random_bytes = rand::thread_rng().gen::<[u8; 20]>();
Expand Down
139 changes: 50 additions & 89 deletions stacks-common/src/util/vrf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,18 @@ use curve25519_dalek::constants::ED25519_BASEPOINT_POINT;
use curve25519_dalek::edwards::{CompressedEdwardsY, EdwardsPoint};
use curve25519_dalek::scalar::Scalar as ed25519_Scalar;
use ed25519_dalek::{
Keypair as VRFKeypair, PublicKey as ed25519_PublicKey, SecretKey as ed25519_PrivateKey,
SecretKey as EdDalekSecretKeyBytes, SigningKey as EdPrivateKey, VerifyingKey as EdPublicKey,
};
use rand;
use sha2::{Digest, Sha512};

use crate::util::hash::{hex_bytes, to_hex};

#[derive(Clone)]
pub struct VRFPublicKey(pub ed25519_PublicKey);
pub struct VRFPublicKey(pub ed25519_dalek::VerifyingKey);

pub struct VRFPrivateKey(pub ed25519_PrivateKey);
#[derive(Clone)]
pub struct VRFPrivateKey(pub ed25519_dalek::SigningKey);

impl serde::Serialize for VRFPublicKey {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
Expand All @@ -58,29 +59,6 @@ impl<'de> serde::Deserialize<'de> for VRFPublicKey {
}
}

// have to do Clone separately since ed25519_PrivateKey doesn't implement Clone
impl Clone for VRFPrivateKey {
fn clone(&self) -> VRFPrivateKey {
let bytes = self.to_bytes();
let pk = ed25519_PrivateKey::from_bytes(&bytes)
.expect("FATAL: could not do VRFPrivateKey round-trip");
VRFPrivateKey(pk)
}
}

impl Deref for VRFPublicKey {
type Target = ed25519_PublicKey;
fn deref(&self) -> &ed25519_PublicKey {
&self.0
}
}

impl DerefMut for VRFPublicKey {
fn deref_mut(&mut self) -> &mut ed25519_PublicKey {
&mut self.0
}
}

impl Debug for VRFPublicKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", &self.to_hex())
Expand Down Expand Up @@ -113,19 +91,6 @@ impl Hash for VRFPublicKey {
}
}

impl Deref for VRFPrivateKey {
type Target = ed25519_PrivateKey;
fn deref(&self) -> &ed25519_PrivateKey {
&self.0
}
}

impl DerefMut for VRFPrivateKey {
fn deref_mut(&mut self) -> &mut ed25519_PrivateKey {
&mut self.0
}
}

impl Debug for VRFPrivateKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", &self.to_hex())
Expand All @@ -149,71 +114,76 @@ impl Default for VRFPrivateKey {
impl VRFPrivateKey {
pub fn new() -> VRFPrivateKey {
let mut rng = rand::thread_rng();
let keypair: VRFKeypair = VRFKeypair::generate(&mut rng);
VRFPrivateKey(keypair.secret)
let signing_key = ed25519_dalek::SigningKey::generate(&mut rng);
VRFPrivateKey(signing_key)
}

pub fn from_hex(h: &str) -> Option<VRFPrivateKey> {
match hex_bytes(h) {
Ok(b) => match ed25519_PrivateKey::from_bytes(&b[..]) {
Ok(pk) => Some(VRFPrivateKey(pk)),
Err(_) => None,
},
Err(_) => None,
}
let bytes = hex_bytes(h).ok()?;
Self::from_bytes(bytes.as_slice())
}

pub fn from_bytes(b: &[u8]) -> Option<VRFPrivateKey> {
match ed25519_PrivateKey::from_bytes(b) {
Ok(pk) => Some(VRFPrivateKey(pk)),
Err(_) => None,
}
let signing_key = ed25519_dalek::SigningKey::try_from(b).ok()?;
Some(VRFPrivateKey(signing_key))
}

pub fn to_hex(&self) -> String {
to_hex(self.as_bytes())
}

pub fn as_bytes(&self) -> &[u8] {
self.0.as_bytes()
}

pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes()
}
}

impl VRFPublicKey {
pub fn from_private(pk: &VRFPrivateKey) -> VRFPublicKey {
VRFPublicKey(ed25519_PublicKey::from(&pk.0))
pub fn from_private(sk: &VRFPrivateKey) -> VRFPublicKey {
VRFPublicKey(sk.0.verifying_key())
}

/// Verify that a given byte string is a well-formed EdDSA public
/// key (i.e. it's a compressed Edwards point that is valid), and return
/// a VRFPublicKey if so
pub fn from_bytes(pubkey_bytes: &[u8]) -> Option<VRFPublicKey> {
match pubkey_bytes.len() {
32 => {
let mut pubkey_slice = [0; 32];
pubkey_slice.copy_from_slice(&pubkey_bytes[0..32]);

let checked_pubkey = CompressedEdwardsY(pubkey_slice);
match checked_pubkey.decompress() {
Some(_) => {}
None => {
// invalid
return None;
}
}

match ed25519_PublicKey::from_bytes(&pubkey_slice) {
Ok(key) => Some(VRFPublicKey(key)),
Err(_) => None,
}
}
_ => None,
let pubkey_slice = pubkey_bytes.try_into().ok()?;

// NOTE: `ed25519_dalek::VerifyingKey::from_bytes` docs say
// that this check must be performed by the caller, but as of
// latest, it actually performs the check as well. However,
// we do this check out of an abundance of caution because
// that's what the docs say to do!

let checked_pubkey = CompressedEdwardsY(pubkey_slice);
if checked_pubkey.decompress().is_none() {
// invalid
return None;
}

let key = ed25519_dalek::VerifyingKey::from_bytes(&pubkey_slice).ok()?;
Some(VRFPublicKey(key))
}

pub fn from_hex(h: &str) -> Option<VRFPublicKey> {
match hex_bytes(h) {
Ok(b) => VRF::check_public_key(&b),
Err(_) => None,
}
let bytes = hex_bytes(h).ok()?;
Self::from_bytes(bytes.as_slice())
}

pub fn to_hex(&self) -> String {
to_hex(self.as_bytes())
}

pub fn as_bytes(&self) -> &[u8] {
self.0.as_bytes()
}

pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes()
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -565,15 +535,6 @@ impl VRF {
// NOTE: this leverages constant-time comparison inherited from the Scalar impl
Ok(c_prime == *(proof.c()))
}

/// Verify that a given byte string is a well-formed EdDSA public key (i.e. it's a compressed
/// Edwards point that is valid).
pub fn check_public_key(pubkey_bytes: &Vec<u8>) -> Option<VRFPublicKey> {
match pubkey_bytes.len() {
32 => VRFPublicKey::from_bytes(&pubkey_bytes[..]),
_ => None,
}
}
}

#[cfg(test)]
Expand Down Expand Up @@ -714,14 +675,14 @@ mod tests {

#[test]
fn check_valid_public_key() {
let res1 = VRF::check_public_key(
let res1 = VRFPublicKey::from_bytes(
&hex_bytes("a366b51292bef4edd64063d9145c617fec373bceb0758e98cd72becd84d54c7a")
.unwrap()
.to_vec(),
);
assert!(res1.is_some());

let res2 = VRF::check_public_key(
let res2 = VRFPublicKey::from_bytes(
&hex_bytes("a366b51292bef4edd64063d9145c617fec373bceb0758e98cd72becd84d54c7b")
.unwrap()
.to_vec(),
Expand Down
9 changes: 4 additions & 5 deletions stackslib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ name = "blockstack-cli"
path = "src/blockstack_cli.rs"

[dependencies]
rand = "0.7.3"
rand_chacha = "=0.2.2"
rand = { workspace = true }
rand_core = { workspace = true }
rand_chacha = { workspace = true }
serde = "1"
serde_derive = "1"
serde_stacker = "0.1"
Expand All @@ -56,7 +57,6 @@ pox-locking = { path = "../pox-locking" }
libstackerdb = { path = "../libstackerdb" }
siphasher = "0.3.7"
wsts = {workspace = true}
rand_core = {workspace = true}
hashbrown = "0.14"

[target.'cfg(unix)'.dependencies]
Expand All @@ -81,8 +81,7 @@ version = "=0.24.2"
features = ["blob", "serde_json", "i128_blob", "bundled", "trace"]

[dependencies.ed25519-dalek]
version = "=1.0.0-pre.3"
features = ["serde"]
workspace = true

[dependencies.curve25519-dalek]
version = "=2.0.0"
Expand Down
4 changes: 2 additions & 2 deletions stackslib/src/burnchains/bitcoin/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ impl BitcoinIndexer {
}
Err(btc_error::ConnectionBroken) => {
// need to try again
backoff = 2.0 * backoff + (backoff * rng.gen_range(0.0, 1.0));
backoff = 2.0 * backoff + (backoff * rng.gen_range(0.0..1.0));
}
Err(e) => {
// propagate other network error
Expand All @@ -204,7 +204,7 @@ impl BitcoinIndexer {
"Failed to connect to peer {}:{}: {}",
&self.config.peer_host, self.config.peer_port, err_msg
);
backoff = 2.0 * backoff + (backoff * rng.gen_range(0.0, 1.0));
backoff = 2.0 * backoff + (backoff * rng.gen_range(0.0..1.0));
}
}

Expand Down
8 changes: 4 additions & 4 deletions stackslib/src/burnchains/tests/burnchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

use ed25519_dalek::Keypair as VRFKeypair;
use rand::rngs::ThreadRng;
use rand::thread_rng;
use serde::Serialize;
Expand Down Expand Up @@ -867,12 +866,13 @@ fn test_burn_snapshot_sequence() {

for i in 0..32 {
let mut csprng: ThreadRng = thread_rng();
let keypair: VRFKeypair = VRFKeypair::generate(&mut csprng);
let vrf_privkey = VRFPrivateKey(ed25519_dalek::SigningKey::generate(&mut csprng));
let vrf_pubkey = VRFPublicKey::from_private(&vrf_privkey);

let privkey_hex = to_hex(&keypair.secret.to_bytes());
let privkey_hex = vrf_privkey.to_hex();
leader_private_keys.push(privkey_hex);

let pubkey_hex = to_hex(&keypair.public.to_bytes());
let pubkey_hex = vrf_pubkey.to_hex();
leader_public_keys.push(pubkey_hex);

let bitcoin_privkey = Secp256k1PrivateKey::new();
Expand Down
4 changes: 2 additions & 2 deletions stackslib/src/chainstate/burn/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ impl SortitionHash {
if max < 2 {
return (0..max).collect();
}
let first = rng.gen_range(0, max);
let try_second = rng.gen_range(0, max - 1);
let first = rng.gen_range(0..max);
let try_second = rng.gen_range(0..(max - 1));
let second = if first == try_second {
// "swap" try_second with max
max - 1
Expand Down
Loading

0 comments on commit 4227deb

Please sign in to comment.