Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sassafras primitives #1249

Merged
merged 14 commits into from
Aug 31, 2023
15 changes: 15 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ members = [
"substrate/primitives/consensus/common",
"substrate/primitives/consensus/grandpa",
"substrate/primitives/consensus/pow",
"substrate/primitives/consensus/sassafras",
"substrate/primitives/consensus/slots",
"substrate/primitives/core",
"substrate/primitives/core/hashing",
Expand Down
248 changes: 122 additions & 126 deletions substrate/client/keystore/src/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@

use parking_lot::RwLock;
use sp_application_crypto::{AppCrypto, AppPair, IsWrappedBy};
#[cfg(feature = "bandersnatch-experimental")]
use sp_core::bandersnatch;
#[cfg(feature = "bls-experimental")]
use sp_core::{bls377, bls381};
use sp_core::{
crypto::{ByteArray, ExposeSecret, KeyTypeId, Pair as CorePair, SecretString, VrfSecret},
ecdsa, ed25519, sr25519,
Expand All @@ -36,6 +32,14 @@ use std::{
sync::Arc,
};

sp_keystore::bandersnatch_experimental_enabled! {
use sp_core::bandersnatch;
}

sp_keystore::bls_experimental_enabled! {
use sp_core::{bls377, bls381};
}

use crate::{Error, Result};

/// A local based keystore that is either memory-based or filesystem-based.
Expand Down Expand Up @@ -132,6 +136,25 @@ impl LocalKeystore {
}

impl Keystore for LocalKeystore {
fn insert(
&self,
key_type: KeyTypeId,
suri: &str,
public: &[u8],
) -> std::result::Result<(), ()> {
self.0.write().insert(key_type, suri, public).map_err(|_| ())
}

fn keys(&self, key_type: KeyTypeId) -> std::result::Result<Vec<Vec<u8>>, TraitError> {
self.0.read().raw_public_keys(key_type).map_err(|e| e.into())
}

fn has_keys(&self, public_keys: &[(Vec<u8>, KeyTypeId)]) -> bool {
public_keys
.iter()
.all(|(p, t)| self.0.read().key_phrase_by_type(p, *t).ok().flatten().is_some())
}

fn sr25519_public_keys(&self, key_type: KeyTypeId) -> Vec<sr25519::Public> {
self.public_keys::<sr25519::Pair>(key_type)
}
Expand Down Expand Up @@ -236,140 +259,113 @@ impl Keystore for LocalKeystore {
Ok(sig)
}

#[cfg(feature = "bandersnatch-experimental")]
fn bandersnatch_public_keys(&self, key_type: KeyTypeId) -> Vec<bandersnatch::Public> {
self.public_keys::<bandersnatch::Pair>(key_type)
}

/// Generate a new pair compatible with the 'bandersnatch' signature scheme.
///
/// If `[seed]` is `Some` then the key will be ephemeral and stored in memory.
#[cfg(feature = "bandersnatch-experimental")]
fn bandersnatch_generate_new(
&self,
key_type: KeyTypeId,
seed: Option<&str>,
) -> std::result::Result<bandersnatch::Public, TraitError> {
self.generate_new::<bandersnatch::Pair>(key_type, seed)
}

#[cfg(feature = "bandersnatch-experimental")]
fn bandersnatch_sign(
&self,
key_type: KeyTypeId,
public: &bandersnatch::Public,
msg: &[u8],
) -> std::result::Result<Option<bandersnatch::Signature>, TraitError> {
self.sign::<bandersnatch::Pair>(key_type, public, msg)
}

#[cfg(feature = "bandersnatch-experimental")]
fn bandersnatch_vrf_sign(
&self,
key_type: KeyTypeId,
public: &bandersnatch::Public,
data: &bandersnatch::vrf::VrfSignData,
) -> std::result::Result<Option<bandersnatch::vrf::VrfSignature>, TraitError> {
self.vrf_sign::<bandersnatch::Pair>(key_type, public, data)
}
sp_keystore::bandersnatch_experimental_enabled! {
fn bandersnatch_public_keys(&self, key_type: KeyTypeId) -> Vec<bandersnatch::Public> {
self.public_keys::<bandersnatch::Pair>(key_type)
}

#[cfg(feature = "bandersnatch-experimental")]
fn bandersnatch_vrf_output(
&self,
key_type: KeyTypeId,
public: &bandersnatch::Public,
input: &bandersnatch::vrf::VrfInput,
) -> std::result::Result<Option<bandersnatch::vrf::VrfOutput>, TraitError> {
self.vrf_output::<bandersnatch::Pair>(key_type, public, input)
}
/// Generate a new pair compatible with the 'bandersnatch' signature scheme.
///
/// If `[seed]` is `Some` then the key will be ephemeral and stored in memory.
fn bandersnatch_generate_new(
&self,
key_type: KeyTypeId,
seed: Option<&str>,
) -> std::result::Result<bandersnatch::Public, TraitError> {
self.generate_new::<bandersnatch::Pair>(key_type, seed)
}

#[cfg(feature = "bandersnatch-experimental")]
fn bandersnatch_ring_vrf_sign(
&self,
key_type: KeyTypeId,
public: &bandersnatch::Public,
data: &bandersnatch::vrf::VrfSignData,
prover: &bandersnatch::ring_vrf::RingProver,
) -> std::result::Result<Option<bandersnatch::ring_vrf::RingVrfSignature>, TraitError> {
let sig = self
.0
.read()
.key_pair_by_type::<bandersnatch::Pair>(public, key_type)?
.map(|pair| pair.ring_vrf_sign(data, prover));
Ok(sig)
}
fn bandersnatch_sign(
&self,
key_type: KeyTypeId,
public: &bandersnatch::Public,
msg: &[u8],
) -> std::result::Result<Option<bandersnatch::Signature>, TraitError> {
self.sign::<bandersnatch::Pair>(key_type, public, msg)
}

#[cfg(feature = "bls-experimental")]
fn bls381_public_keys(&self, key_type: KeyTypeId) -> Vec<bls381::Public> {
self.public_keys::<bls381::Pair>(key_type)
}
fn bandersnatch_vrf_sign(
&self,
key_type: KeyTypeId,
public: &bandersnatch::Public,
data: &bandersnatch::vrf::VrfSignData,
) -> std::result::Result<Option<bandersnatch::vrf::VrfSignature>, TraitError> {
self.vrf_sign::<bandersnatch::Pair>(key_type, public, data)
}

#[cfg(feature = "bls-experimental")]
/// Generate a new pair compatible with the 'bls381' signature scheme.
///
/// If `[seed]` is `Some` then the key will be ephemeral and stored in memory.
fn bls381_generate_new(
&self,
key_type: KeyTypeId,
seed: Option<&str>,
) -> std::result::Result<bls381::Public, TraitError> {
self.generate_new::<bls381::Pair>(key_type, seed)
}
fn bandersnatch_vrf_output(
&self,
key_type: KeyTypeId,
public: &bandersnatch::Public,
input: &bandersnatch::vrf::VrfInput,
) -> std::result::Result<Option<bandersnatch::vrf::VrfOutput>, TraitError> {
self.vrf_output::<bandersnatch::Pair>(key_type, public, input)
}

#[cfg(feature = "bls-experimental")]
fn bls381_sign(
&self,
key_type: KeyTypeId,
public: &bls381::Public,
msg: &[u8],
) -> std::result::Result<Option<bls381::Signature>, TraitError> {
self.sign::<bls381::Pair>(key_type, public, msg)
fn bandersnatch_ring_vrf_sign(
&self,
key_type: KeyTypeId,
public: &bandersnatch::Public,
data: &bandersnatch::vrf::VrfSignData,
prover: &bandersnatch::ring_vrf::RingProver,
) -> std::result::Result<Option<bandersnatch::ring_vrf::RingVrfSignature>, TraitError> {
let sig = self
.0
.read()
.key_pair_by_type::<bandersnatch::Pair>(public, key_type)?
.map(|pair| pair.ring_vrf_sign(data, prover));
Ok(sig)
}
}

#[cfg(feature = "bls-experimental")]
fn bls377_public_keys(&self, key_type: KeyTypeId) -> Vec<bls377::Public> {
self.public_keys::<bls377::Pair>(key_type)
}
sp_keystore::bls_experimental_enabled! {
fn bls381_public_keys(&self, key_type: KeyTypeId) -> Vec<bls381::Public> {
self.public_keys::<bls381::Pair>(key_type)
}

#[cfg(feature = "bls-experimental")]
/// Generate a new pair compatible with the 'bls377' signature scheme.
///
/// If `[seed]` is `Some` then the key will be ephemeral and stored in memory.
fn bls377_generate_new(
&self,
key_type: KeyTypeId,
seed: Option<&str>,
) -> std::result::Result<bls377::Public, TraitError> {
self.generate_new::<bls377::Pair>(key_type, seed)
}
/// Generate a new pair compatible with the 'bls381' signature scheme.
///
/// If `[seed]` is `Some` then the key will be ephemeral and stored in memory.
fn bls381_generate_new(
&self,
key_type: KeyTypeId,
seed: Option<&str>,
) -> std::result::Result<bls381::Public, TraitError> {
self.generate_new::<bls381::Pair>(key_type, seed)
}

#[cfg(feature = "bls-experimental")]
fn bls377_sign(
&self,
key_type: KeyTypeId,
public: &bls377::Public,
msg: &[u8],
) -> std::result::Result<Option<bls377::Signature>, TraitError> {
self.sign::<bls377::Pair>(key_type, public, msg)
}
fn bls381_sign(
&self,
key_type: KeyTypeId,
public: &bls381::Public,
msg: &[u8],
) -> std::result::Result<Option<bls381::Signature>, TraitError> {
self.sign::<bls381::Pair>(key_type, public, msg)
}

fn insert(
&self,
key_type: KeyTypeId,
suri: &str,
public: &[u8],
) -> std::result::Result<(), ()> {
self.0.write().insert(key_type, suri, public).map_err(|_| ())
}
fn bls377_public_keys(&self, key_type: KeyTypeId) -> Vec<bls377::Public> {
self.public_keys::<bls377::Pair>(key_type)
}

fn keys(&self, key_type: KeyTypeId) -> std::result::Result<Vec<Vec<u8>>, TraitError> {
self.0.read().raw_public_keys(key_type).map_err(|e| e.into())
}
/// Generate a new pair compatible with the 'bls377' signature scheme.
///
/// If `[seed]` is `Some` then the key will be ephemeral and stored in memory.
fn bls377_generate_new(
&self,
key_type: KeyTypeId,
seed: Option<&str>,
) -> std::result::Result<bls377::Public, TraitError> {
self.generate_new::<bls377::Pair>(key_type, seed)
}

fn has_keys(&self, public_keys: &[(Vec<u8>, KeyTypeId)]) -> bool {
public_keys
.iter()
.all(|(p, t)| self.0.read().key_phrase_by_type(p, *t).ok().flatten().is_some())
fn bls377_sign(
&self,
key_type: KeyTypeId,
public: &bls377::Public,
msg: &[u8],
) -> std::result::Result<Option<bls377::Signature>, TraitError> {
self.sign::<bls377::Pair>(key_type, public, msg)
}
}
}

Expand Down
50 changes: 50 additions & 0 deletions substrate/primitives/consensus/sassafras/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[package]
name = "sp-consensus-sassafras"
version = "0.3.4-dev"
authors = ["Parity Technologies <admin@parity.io>"]
description = "Primitives for Sassafras consensus"
edition = "2021"
license = "Apache-2.0"
homepage = "https://substrate.io"
repository = "https://github.com/paritytech/substrate/"
documentation = "https://docs.rs/sp-consensus-sassafras"
readme = "README.md"
publish = false

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
scale-codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false }
scale-info = { version = "2.5.0", default-features = false, features = ["derive"] }
serde = { version = "1.0.163", default-features = false, features = ["derive"], optional = true }
sp-api = { version = "4.0.0-dev", default-features = false, path = "../../api" }
sp-application-crypto = { version = "23.0.0", default-features = false, path = "../../application-crypto", features = ["bandersnatch-experimental"] }
sp-consensus-slots = { version = "0.10.0-dev", default-features = false, path = "../slots" }
sp-core = { version = "21.0.0", default-features = false, path = "../../core", features = ["bandersnatch-experimental"] }
sp-runtime = { version = "24.0.0", default-features = false, path = "../../runtime" }
sp-std = { version = "8.0.0", default-features = false, path = "../../std" }

[features]
default = [ "std" ]
std = [
"scale-codec/std",
"scale-info/std",
"serde/std",
"sp-api/std",
"sp-application-crypto/std",
"sp-consensus-slots/std",
"sp-core/std",
"sp-runtime/std",
"sp-std/std",
]

# Serde support without relying on std features.
serde = [
"dep:serde",
"scale-info/serde",
"sp-application-crypto/serde",
"sp-consensus-slots/serde",
"sp-core/serde",
"sp-runtime/serde",
]
12 changes: 12 additions & 0 deletions substrate/primitives/consensus/sassafras/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Primitives for SASSAFRAS.

# ⚠️ WARNING ⚠️

The crate interfaces and structures are highly experimental and may be subject
to significant changes.

Depends on upstream experimental feature: `bandersnatch-experimental`.

These structs were mostly extracted from the main SASSAFRAS protocol PR: https://github.com/paritytech/substrate/pull/11879.

Tracking issue: https://github.com/paritytech/substrate/issues/11515.
Loading