Skip to content

Commit

Permalink
Sassafras primitives (#1249)
Browse files Browse the repository at this point in the history
* Introduce Sassafras primitives

* Keystore workaround

* Fix doc

* Use  in keystore

* Improve bandersnatch vrf docs

* Apply review suggestions

* Update README

* Docs improvement

* Docs fix
  • Loading branch information
davxy authored and Daanvdplas committed Sep 11, 2023
1 parent ae27384 commit 8186fae
Show file tree
Hide file tree
Showing 12 changed files with 797 additions and 201 deletions.
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 <[email protected]>"]
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/polkadot-sdk/issues/41
Loading

0 comments on commit 8186fae

Please sign in to comment.