diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 22da38136f..308ac78871 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -3942,6 +3942,7 @@ dependencies = [ "parking_lot 0.10.0", "serde", "sp-consensus-babe", + "sp-consensus-vrf", "sp-core", "sp-inherents", "sp-io", @@ -5893,6 +5894,7 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-consensus-babe", + "sp-consensus-vrf", "sp-core", "sp-inherents", "sp-io", @@ -7095,10 +7097,10 @@ name = "sp-consensus-babe" version = "0.8.0-alpha.4" dependencies = [ "parity-scale-codec", - "schnorrkel", "sp-api", "sp-application-crypto", "sp-consensus", + "sp-consensus-vrf", "sp-inherents", "sp-runtime", "sp-std", @@ -7116,6 +7118,17 @@ dependencies = [ "sp-std", ] +[[package]] +name = "sp-consensus-vrf" +version = "0.8.0-alpha.4" +dependencies = [ + "parity-scale-codec", + "schnorrkel", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "sp-core" version = "2.0.0-alpha.4" diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml index 5af37839ad..5a88ed28dd 100644 --- a/substrate/Cargo.toml +++ b/substrate/Cargo.toml @@ -118,6 +118,7 @@ members = [ "primitives/consensus/babe", "primitives/consensus/common", "primitives/consensus/pow", + "primitives/consensus/vrf", "primitives/core", "primitives/debug-derive", "primitives/storage", diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index ba219a1890..58728a507b 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -84,7 +84,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. spec_version: 240, - impl_version: 0, + impl_version: 1, apis: RUNTIME_API_VERSIONS, }; diff --git a/substrate/client/consensus/babe/Cargo.toml b/substrate/client/consensus/babe/Cargo.toml index 5486342ef7..ec5e3cbbb7 100644 --- a/substrate/client/consensus/babe/Cargo.toml +++ b/substrate/client/consensus/babe/Cargo.toml @@ -9,7 +9,6 @@ homepage = "https://substrate.dev" repository = "https://github.com/paritytech/substrate/" documentation = "https://docs.rs/sc-consensus-babe" - [dependencies] codec = { package = "parity-scale-codec", version = "1.2.0", features = ["derive"] } sp-consensus-babe = { version = "0.8.0-alpha.4", path = "../../../primitives/consensus/babe" } @@ -32,6 +31,7 @@ sp-api = { version = "2.0.0-alpha.4", path = "../../../primitives/api" } sp-block-builder = { version = "2.0.0-alpha.4", path = "../../../primitives/block-builder" } sp-blockchain = { version = "2.0.0-alpha.4", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.8.0-alpha.4", path = "../../../primitives/consensus/common" } +sp-consensus-vrf = { version = "0.8.0-alpha.4", path = "../../../primitives/consensus/vrf" } sc-consensus-uncles = { version = "0.8.0-alpha.4", path = "../uncles" } sc-consensus-slots = { version = "0.8.0-alpha.4", path = "../slots" } sp-runtime = { version = "2.0.0-alpha.4", path = "../../../primitives/runtime" } diff --git a/substrate/client/consensus/babe/src/authorship.rs b/substrate/client/consensus/babe/src/authorship.rs index a01ea63bbe..fb7be52766 100644 --- a/substrate/client/consensus/babe/src/authorship.rs +++ b/substrate/client/consensus/babe/src/authorship.rs @@ -22,6 +22,7 @@ use sp_consensus_babe::{ SlotNumber, AuthorityPair, BabeConfiguration }; use sp_consensus_babe::digests::PreDigest; +use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof}; use sp_core::{U256, blake2_256}; use codec::Encode; use schnorrkel::vrf::VRFInOut; @@ -201,8 +202,8 @@ fn claim_primary_slot( .map(|s| { PreDigest::Primary { slot_number, - vrf_output: s.0.to_output(), - vrf_proof: s.1, + vrf_output: VRFOutput(s.0.to_output()), + vrf_proof: VRFProof(s.1), authority_index: authority_index as u32, } }); diff --git a/substrate/client/consensus/babe/src/verification.rs b/substrate/client/consensus/babe/src/verification.rs index 70418b8aea..1eb73588a8 100644 --- a/substrate/client/consensus/babe/src/verification.rs +++ b/substrate/client/consensus/babe/src/verification.rs @@ -15,11 +15,11 @@ // along with Substrate. If not, see . //! Verification for BABE headers. -use schnorrkel::vrf::{VRFOutput, VRFProof}; use sp_runtime::{traits::Header, traits::DigestItemFor}; use sp_core::{Pair, Public}; use sp_consensus_babe::{AuthoritySignature, SlotNumber, AuthorityIndex, AuthorityPair, AuthorityId}; use sp_consensus_babe::digests::{PreDigest, CompatibleDigestItem}; +use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof}; use sc_consensus_slots::CheckedHeader; use log::{debug, trace}; use super::{find_pre_digest, babe_err, Epoch, BlockT, Error}; diff --git a/substrate/frame/babe/Cargo.toml b/substrate/frame/babe/Cargo.toml index 28f3d98701..4cf7c13cd6 100644 --- a/substrate/frame/babe/Cargo.toml +++ b/substrate/frame/babe/Cargo.toml @@ -22,7 +22,8 @@ pallet-timestamp = { version = "2.0.0-alpha.4", default-features = false, path = sp-timestamp = { version = "2.0.0-alpha.4", default-features = false, path = "../../primitives/timestamp" } pallet-session = { version = "2.0.0-alpha.4", default-features = false, path = "../session" } sp-consensus-babe = { version = "0.8.0-alpha.4", default-features = false, path = "../../primitives/consensus/babe" } -sp-io ={ path = "../../primitives/io", default-features = false , version = "2.0.0-alpha.4"} +sp-consensus-vrf = { version = "0.8.0-alpha.4", default-features = false, path = "../../primitives/consensus/vrf" } +sp-io = { path = "../../primitives/io", default-features = false , version = "2.0.0-alpha.4"} [dev-dependencies] lazy_static = "1.4.0" @@ -45,6 +46,7 @@ std = [ "sp-timestamp/std", "sp-inherents/std", "sp-consensus-babe/std", + "sp-consensus-vrf/std", "pallet-session/std", "sp-io/std", ] diff --git a/substrate/frame/babe/src/lib.rs b/substrate/frame/babe/src/lib.rs index 29e8625419..27a471f6f8 100644 --- a/substrate/frame/babe/src/lib.rs +++ b/substrate/frame/babe/src/lib.rs @@ -39,7 +39,8 @@ use sp_consensus_babe::{ inherents::{INHERENT_IDENTIFIER, BabeInherentData}, digests::{NextEpochDescriptor, RawPreDigest}, }; -pub use sp_consensus_babe::{AuthorityId, VRF_OUTPUT_LENGTH, PUBLIC_KEY_LENGTH}; +use sp_consensus_vrf::schnorrkel; +pub use sp_consensus_babe::{AuthorityId, VRF_OUTPUT_LENGTH, RANDOMNESS_LENGTH, PUBLIC_KEY_LENGTH}; #[cfg(all(feature = "std", test))] mod tests; @@ -96,12 +97,9 @@ impl EpochChangeTrigger for SameAuthoritiesForever { } } -/// The length of the BABE randomness -pub const RANDOMNESS_LENGTH: usize = 32; - const UNDER_CONSTRUCTION_SEGMENT_LENGTH: usize = 256; -type MaybeVrf = Option<[u8; 32 /* VRF_OUTPUT_LENGTH */]>; +type MaybeVrf = Option; decl_storage! { trait Store for Module as Babe { @@ -131,10 +129,10 @@ decl_storage! { // NOTE: the following fields don't use the constants to define the // array size because the metadata API currently doesn't resolve the // variable to its underlying value. - pub Randomness get(fn randomness): [u8; 32 /* RANDOMNESS_LENGTH */]; + pub Randomness get(fn randomness): schnorrkel::Randomness; /// Next epoch randomness. - NextRandomness: [u8; 32 /* RANDOMNESS_LENGTH */]; + NextRandomness: schnorrkel::Randomness; /// Randomness under construction. /// @@ -146,7 +144,7 @@ decl_storage! { /// We reset all segments and return to `0` at the beginning of every /// epoch. SegmentIndex build(|_| 0): u32; - UnderConstruction: map hasher(twox_64_concat) u32 => Vec<[u8; 32 /* VRF_OUTPUT_LENGTH */]>; + UnderConstruction: map hasher(twox_64_concat) u32 => Vec; /// Temporary value (cleared at block finalization) which is `Some` /// if per-block initialization has already been called for current block. @@ -210,7 +208,7 @@ impl FindAuthor for Module { { for (id, mut data) in digests.into_iter() { if id == BABE_ENGINE_ID { - let pre_digest = RawPreDigest::decode(&mut data).ok()?; + let pre_digest: RawPreDigest = RawPreDigest::decode(&mut data).ok()?; return Some(match pre_digest { RawPreDigest::Primary { authority_index, .. } => authority_index, @@ -373,7 +371,7 @@ impl Module { >::deposit_log(log.into()) } - fn deposit_vrf_output(vrf_output: &[u8; VRF_OUTPUT_LENGTH]) { + fn deposit_vrf_output(vrf_output: &schnorrkel::RawVRFOutput) { let segment_idx = ::get(); let mut segment = ::get(&segment_idx); if segment.len() < UNDER_CONSTRUCTION_SEGMENT_LENGTH { @@ -383,7 +381,7 @@ impl Module { } else { // move onto the next segment and update the index. let segment_idx = segment_idx + 1; - ::insert(&segment_idx, &vec![*vrf_output]); + ::insert(&segment_idx, &vec![vrf_output.clone()]); ::put(&segment_idx); } } @@ -396,7 +394,7 @@ impl Module { return; } - let maybe_pre_digest = >::digest() + let maybe_pre_digest: Option = >::digest() .logs .iter() .filter_map(|s| s.as_pre_runtime()) @@ -446,7 +444,7 @@ impl Module { /// Call this function exactly once when an epoch changes, to update the /// randomness. Returns the new randomness. - fn randomness_change_epoch(next_epoch_index: u64) -> [u8; RANDOMNESS_LENGTH] { + fn randomness_change_epoch(next_epoch_index: u64) -> schnorrkel::Randomness { let this_randomness = NextRandomness::get(); let segment_idx: u32 = ::mutate(|s| sp_std::mem::replace(s, 0)); @@ -513,11 +511,11 @@ impl pallet_session::OneSessionHandler for Module { // // an optional size hint as to how many VRF outputs there were may be provided. fn compute_randomness( - last_epoch_randomness: [u8; RANDOMNESS_LENGTH], + last_epoch_randomness: schnorrkel::Randomness, epoch_index: u64, - rho: impl Iterator, + rho: impl Iterator, rho_size_hint: Option, -) -> [u8; RANDOMNESS_LENGTH] { +) -> schnorrkel::Randomness { let mut s = Vec::with_capacity(40 + rho_size_hint.unwrap_or(0) * VRF_OUTPUT_LENGTH); s.extend_from_slice(&last_epoch_randomness); s.extend_from_slice(&epoch_index.to_le_bytes()); diff --git a/substrate/frame/babe/src/tests.rs b/substrate/frame/babe/src/tests.rs index 84f8166b10..3fcb78ae5f 100644 --- a/substrate/frame/babe/src/tests.rs +++ b/substrate/frame/babe/src/tests.rs @@ -19,6 +19,7 @@ use super::*; use mock::{new_test_ext, Babe, System}; use sp_runtime::{traits::OnFinalize, testing::{Digest, DigestItem}}; +use sp_consensus_vrf::schnorrkel::{RawVRFOutput, RawVRFProof}; use pallet_session::ShouldEndSession; const EMPTY_RANDOMNESS: [u8; 32] = [ @@ -31,8 +32,8 @@ const EMPTY_RANDOMNESS: [u8; 32] = [ fn make_pre_digest( authority_index: sp_consensus_babe::AuthorityIndex, slot_number: sp_consensus_babe::SlotNumber, - vrf_output: [u8; sp_consensus_babe::VRF_OUTPUT_LENGTH], - vrf_proof: [u8; sp_consensus_babe::VRF_PROOF_LENGTH], + vrf_output: RawVRFOutput, + vrf_proof: RawVRFProof, ) -> Digest { let digest_data = sp_consensus_babe::digests::RawPreDigest::Primary { authority_index, @@ -70,12 +71,12 @@ fn check_module() { fn first_block_epoch_zero_start() { new_test_ext(vec![0, 1, 2, 3]).execute_with(|| { let genesis_slot = 100; - let first_vrf = [1; 32]; + let first_vrf = RawVRFOutput([1; 32]); let pre_digest = make_pre_digest( 0, genesis_slot, - first_vrf, - [0xff; 64], + first_vrf.clone(), + RawVRFProof([0xff; 64]), ); assert_eq!(Babe::genesis_slot(), 0); diff --git a/substrate/primitives/consensus/babe/Cargo.toml b/substrate/primitives/consensus/babe/Cargo.toml index a948a30f2d..f7581601e5 100644 --- a/substrate/primitives/consensus/babe/Cargo.toml +++ b/substrate/primitives/consensus/babe/Cargo.toml @@ -12,9 +12,9 @@ repository = "https://github.com/paritytech/substrate/" sp-application-crypto = { version = "2.0.0-alpha.4", default-features = false, path = "../../application-crypto" } codec = { package = "parity-scale-codec", version = "1.2.0", default-features = false } sp-std = { version = "2.0.0-alpha.4", default-features = false, path = "../../std" } -schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"], optional = true } sp-api = { version = "2.0.0-alpha.4", default-features = false, path = "../../api" } sp-consensus = { version = "0.8.0-alpha.4", optional = true, path = "../common" } +sp-consensus-vrf = { version = "0.8.0-alpha.4", path = "../vrf", default-features = false } sp-inherents = { version = "2.0.0-alpha.4", default-features = false, path = "../../inherents" } sp-runtime = { version = "2.0.0-alpha.4", default-features = false, path = "../../runtime" } sp-timestamp = { version = "2.0.0-alpha.4", default-features = false, path = "../../timestamp" } @@ -25,9 +25,9 @@ std = [ "sp-application-crypto/std", "codec/std", "sp-std/std", - "schnorrkel", "sp-api/std", "sp-consensus", + "sp-consensus-vrf/std", "sp-inherents/std", "sp-runtime/std", "sp-timestamp/std", diff --git a/substrate/primitives/consensus/babe/src/digests.rs b/substrate/primitives/consensus/babe/src/digests.rs index 7ec0f9b977..fca0c3a7b3 100644 --- a/substrate/primitives/consensus/babe/src/digests.rs +++ b/substrate/primitives/consensus/babe/src/digests.rs @@ -18,92 +18,35 @@ #[cfg(feature = "std")] use super::{BABE_ENGINE_ID, AuthoritySignature}; -#[cfg(not(feature = "std"))] -use super::{VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH}; use super::{AuthorityId, AuthorityIndex, SlotNumber, BabeAuthorityWeight}; #[cfg(feature = "std")] use sp_runtime::{DigestItem, generic::OpaqueDigestItemId}; #[cfg(feature = "std")] -use std::fmt::Debug; +use std::{fmt::Debug, convert::{TryFrom, TryInto}}; use codec::{Decode, Encode}; #[cfg(feature = "std")] -use codec::{Codec, Input, Error}; -#[cfg(feature = "std")] -use schnorrkel::{ - SignatureError, errors::MultiSignatureStage, - vrf::{VRFProof, VRFOutput, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH} -}; +use codec::Codec; use sp_std::vec::Vec; - +use sp_consensus_vrf::schnorrkel::{self, Randomness}; +#[cfg(feature = "std")] +use sp_consensus_vrf::schnorrkel::SignatureError; /// A BABE pre-runtime digest. This contains all data required to validate a /// block and for the BABE runtime module. Slots can be assigned to a primary /// (VRF based) and to a secondary (slot number based). -#[cfg(feature = "std")] -#[derive(Clone, Debug)] -pub enum PreDigest { - /// A primary VRF-based slot assignment. - Primary { - /// VRF output - vrf_output: VRFOutput, - /// VRF proof - vrf_proof: VRFProof, - /// Authority index - authority_index: super::AuthorityIndex, - /// Slot number - slot_number: SlotNumber, - }, - /// A secondary deterministic slot assignment. - Secondary { - /// Authority index - authority_index: super::AuthorityIndex, - /// Slot number - slot_number: SlotNumber, - }, -} - -#[cfg(feature = "std")] -impl PreDigest { - /// Returns the slot number of the pre digest. - pub fn authority_index(&self) -> AuthorityIndex { - match self { - PreDigest::Primary { authority_index, .. } => *authority_index, - PreDigest::Secondary { authority_index, .. } => *authority_index, - } - } - - /// Returns the slot number of the pre digest. - pub fn slot_number(&self) -> SlotNumber { - match self { - PreDigest::Primary { slot_number, .. } => *slot_number, - PreDigest::Secondary { slot_number, .. } => *slot_number, - } - } - - /// Returns the weight _added_ by this digest, not the cumulative weight - /// of the chain. - pub fn added_weight(&self) -> crate::BabeBlockWeight { - match self { - PreDigest::Primary { .. } => 1, - PreDigest::Secondary { .. } => 0, - } - } -} - -/// A raw version of `BabePreDigest`, usable on `no_std`. -#[derive(Copy, Clone, Encode, Decode)] -pub enum RawPreDigest { +#[derive(Clone, Debug, Encode, Decode)] +pub enum RawPreDigest { /// A primary VRF-based slot assignment. #[codec(index = "1")] Primary { /// Authority index - authority_index: AuthorityIndex, + authority_index: super::AuthorityIndex, /// Slot number slot_number: SlotNumber, /// VRF output - vrf_output: [u8; VRF_OUTPUT_LENGTH], + vrf_output: VRFOutput, /// VRF proof - vrf_proof: [u8; VRF_PROOF_LENGTH], + vrf_proof: VRFProof, }, /// A secondary deterministic slot assignment. #[codec(index = "2")] @@ -114,13 +57,25 @@ pub enum RawPreDigest { /// are assigned based on slot number and epoch randomness. But including /// it makes things easier for higher-level users of the chain data to /// be aware of the author of a secondary-slot block. - authority_index: AuthorityIndex, + authority_index: super::AuthorityIndex, /// Slot number slot_number: SlotNumber, }, } -impl RawPreDigest { +#[cfg(feature = "std")] +/// A BABE pre-runtime digest for std. +pub type PreDigest = RawPreDigest; + +impl RawPreDigest { + /// Returns the slot number of the pre digest. + pub fn authority_index(&self) -> AuthorityIndex { + match self { + RawPreDigest::Primary { authority_index, .. } => *authority_index, + RawPreDigest::Secondary { authority_index, .. } => *authority_index, + } + } + /// Returns the slot number of the pre digest. pub fn slot_number(&self) -> SlotNumber { match self { @@ -128,65 +83,36 @@ impl RawPreDigest { RawPreDigest::Secondary { slot_number, .. } => *slot_number, } } -} -#[cfg(feature = "std")] -impl Encode for PreDigest { - fn encode(&self) -> Vec { - let raw = match self { - PreDigest::Primary { - vrf_output, - vrf_proof, - authority_index, - slot_number, - } => { - RawPreDigest::Primary { - vrf_output: *vrf_output.as_bytes(), - vrf_proof: vrf_proof.to_bytes(), - authority_index: *authority_index, - slot_number: *slot_number, - } - }, - PreDigest::Secondary { - authority_index, - slot_number, - } => { - RawPreDigest::Secondary { - authority_index: *authority_index, - slot_number: *slot_number, - } - }, - }; - - codec::Encode::encode(&raw) + /// Returns the weight _added_ by this digest, not the cumulative weight + /// of the chain. + pub fn added_weight(&self) -> crate::BabeBlockWeight { + match self { + RawPreDigest::Primary { .. } => 1, + RawPreDigest::Secondary { .. } => 0, + } } } #[cfg(feature = "std")] -impl codec::EncodeLike for PreDigest {} +impl TryFrom for PreDigest { + type Error = SignatureError; -#[cfg(feature = "std")] -impl Decode for PreDigest { - fn decode(i: &mut R) -> Result { - let pre_digest = match Decode::decode(i)? { - RawPreDigest::Primary { vrf_output, vrf_proof, authority_index, slot_number } => { - // Verify (at compile time) that the sizes in babe_primitives are correct - let _: [u8; super::VRF_OUTPUT_LENGTH] = vrf_output; - let _: [u8; super::VRF_PROOF_LENGTH] = vrf_proof; - - PreDigest::Primary { - vrf_proof: VRFProof::from_bytes(&vrf_proof).map_err(convert_error)?, - vrf_output: VRFOutput::from_bytes(&vrf_output).map_err(convert_error)?, + fn try_from(raw: RawPreDigest) -> Result { + Ok(match raw { + RawPreDigest::Primary { authority_index, slot_number, vrf_output, vrf_proof } => + RawPreDigest::Primary { + authority_index, + slot_number, + vrf_output: vrf_output.try_into()?, + vrf_proof: vrf_proof.try_into()?, + }, + RawPreDigest::Secondary { authority_index, slot_number } => + RawPreDigest::Secondary { authority_index, slot_number, } - }, - RawPreDigest::Secondary { authority_index, slot_number } => { - PreDigest::Secondary { authority_index, slot_number } - }, - }; - - Ok(pre_digest) + }) } } @@ -198,7 +124,7 @@ pub struct NextEpochDescriptor { pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, /// The value of randomness to use for the slot-assignment. - pub randomness: [u8; VRF_OUTPUT_LENGTH], + pub randomness: Randomness, } /// A digest item which is usable with BABE consensus. @@ -248,34 +174,3 @@ impl CompatibleDigestItem for DigestItem where }) } } - -#[cfg(feature = "std")] -fn convert_error(e: SignatureError) -> codec::Error { - use SignatureError::*; - use MultiSignatureStage::*; - match e { - EquationFalse => "Signature error: `EquationFalse`".into(), - PointDecompressionError => "Signature error: `PointDecompressionError`".into(), - ScalarFormatError => "Signature error: `ScalarFormatError`".into(), - NotMarkedSchnorrkel => "Signature error: `NotMarkedSchnorrkel`".into(), - BytesLengthError { .. } => "Signature error: `BytesLengthError`".into(), - MuSigAbsent { musig_stage: Commitment } => - "Signature error: `MuSigAbsent` at stage `Commitment`".into(), - MuSigAbsent { musig_stage: Reveal } => - "Signature error: `MuSigAbsent` at stage `Reveal`".into(), - MuSigAbsent { musig_stage: Cosignature } => - "Signature error: `MuSigAbsent` at stage `Commitment`".into(), - MuSigInconsistent { musig_stage: Commitment, duplicate: true } => - "Signature error: `MuSigInconsistent` at stage `Commitment` on duplicate".into(), - MuSigInconsistent { musig_stage: Commitment, duplicate: false } => - "Signature error: `MuSigInconsistent` at stage `Commitment` on not duplicate".into(), - MuSigInconsistent { musig_stage: Reveal, duplicate: true } => - "Signature error: `MuSigInconsistent` at stage `Reveal` on duplicate".into(), - MuSigInconsistent { musig_stage: Reveal, duplicate: false } => - "Signature error: `MuSigInconsistent` at stage `Reveal` on not duplicate".into(), - MuSigInconsistent { musig_stage: Cosignature, duplicate: true } => - "Signature error: `MuSigInconsistent` at stage `Cosignature` on duplicate".into(), - MuSigInconsistent { musig_stage: Cosignature, duplicate: false } => - "Signature error: `MuSigInconsistent` at stage `Cosignature` on not duplicate".into(), - } -} diff --git a/substrate/primitives/consensus/babe/src/lib.rs b/substrate/primitives/consensus/babe/src/lib.rs index 392dcb560b..33701860d1 100644 --- a/substrate/primitives/consensus/babe/src/lib.rs +++ b/substrate/primitives/consensus/babe/src/lib.rs @@ -22,6 +22,10 @@ pub mod digests; pub mod inherents; +pub use sp_consensus_vrf::schnorrkel::{ + Randomness, VRF_PROOF_LENGTH, VRF_OUTPUT_LENGTH, RANDOMNESS_LENGTH +}; + use codec::{Encode, Decode}; use sp_std::vec::Vec; use sp_runtime::{ConsensusEngineId, RuntimeDebug}; @@ -50,12 +54,6 @@ pub type AuthorityId = app::Public; /// The `ConsensusEngineId` of BABE. pub const BABE_ENGINE_ID: ConsensusEngineId = *b"BABE"; -/// The length of the VRF output -pub const VRF_OUTPUT_LENGTH: usize = 32; - -/// The length of the VRF proof -pub const VRF_PROOF_LENGTH: usize = 64; - /// The length of the public key pub const PUBLIC_KEY_LENGTH: usize = 32; @@ -115,7 +113,7 @@ pub struct BabeConfiguration { pub genesis_authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, /// The randomness for the genesis epoch. - pub randomness: [u8; VRF_OUTPUT_LENGTH], + pub randomness: Randomness, /// Whether this chain should run with secondary slots, which are assigned /// in round-robin manner. diff --git a/substrate/primitives/consensus/vrf/Cargo.toml b/substrate/primitives/consensus/vrf/Cargo.toml new file mode 100644 index 0000000000..dc2631d270 --- /dev/null +++ b/substrate/primitives/consensus/vrf/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "sp-consensus-vrf" +version = "0.8.0-alpha.4" +authors = ["Parity Technologies "] +description = "Primitives for VRF based consensus" +edition = "2018" +license = "GPL-3.0" + +[dependencies] +codec = { version = "1.0.0", package = "parity-scale-codec", default-features = false } +schnorrkel = { version = "0.9.1", features = ["preaudit_deprecated"], optional = true } +sp-std = { version = "2.0.0-alpha.4", path = "../../std", default-features = false } +sp-core = { version = "2.0.0-alpha.4", path = "../../core", default-features = false } +sp-runtime = { version = "2.0.0-alpha.4", default-features = false, path = "../../runtime" } + +[features] +default = ["std"] +std = [ + "codec/std", + "schnorrkel", + "sp-std/std", + "sp-core/std", + "sp-runtime/std", +] diff --git a/substrate/primitives/consensus/vrf/src/lib.rs b/substrate/primitives/consensus/vrf/src/lib.rs new file mode 100644 index 0000000000..4ec6e376d6 --- /dev/null +++ b/substrate/primitives/consensus/vrf/src/lib.rs @@ -0,0 +1,20 @@ +// Copyright 2019-2020 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Primitives for VRF-based consensus engines. +#![cfg_attr(not(feature = "std"), no_std)] + +pub mod schnorrkel; diff --git a/substrate/primitives/consensus/vrf/src/schnorrkel.rs b/substrate/primitives/consensus/vrf/src/schnorrkel.rs new file mode 100644 index 0000000000..e4ae68ced4 --- /dev/null +++ b/substrate/primitives/consensus/vrf/src/schnorrkel.rs @@ -0,0 +1,249 @@ +// Copyright 2019-2020 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Schnorrkel-based VRF. + +use codec::{Encode, Decode}; +use sp_core::U512; +use sp_runtime::RuntimeDebug; +use sp_std::ops::{Deref, DerefMut}; +#[cfg(feature = "std")] +use std::convert::TryFrom; +#[cfg(feature = "std")] +use codec::EncodeLike; +#[cfg(feature = "std")] +use schnorrkel::errors::MultiSignatureStage; + +#[cfg(feature = "std")] +pub use schnorrkel::{SignatureError, vrf::{VRF_PROOF_LENGTH, VRF_OUTPUT_LENGTH}}; + +/// The length of the VRF proof. +#[cfg(not(feature = "std"))] +pub const VRF_PROOF_LENGTH: usize = 64; + +/// The length of the VRF output. +#[cfg(not(feature = "std"))] +pub const VRF_OUTPUT_LENGTH: usize = 32; + +/// The length of the Randomness. +pub const RANDOMNESS_LENGTH: usize = VRF_OUTPUT_LENGTH; + +/// Raw VRF output. +#[derive(Clone, Copy, Eq, PartialEq, RuntimeDebug, Encode, Decode)] +pub struct RawVRFOutput(pub [u8; VRF_OUTPUT_LENGTH]); + +impl Deref for RawVRFOutput { + type Target = [u8; VRF_OUTPUT_LENGTH]; + fn deref(&self) -> &Self::Target { &self.0 } +} + +impl DerefMut for RawVRFOutput { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } +} + +/// VRF output type available for `std` environment, suitable for schnorrkel operations. +#[cfg(feature = "std")] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct VRFOutput(pub schnorrkel::vrf::VRFOutput); + +#[cfg(feature = "std")] +impl Deref for VRFOutput { + type Target = schnorrkel::vrf::VRFOutput; + fn deref(&self) -> &Self::Target { &self.0 } +} + +#[cfg(feature = "std")] +impl DerefMut for VRFOutput { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } +} + +#[cfg(feature = "std")] +impl Encode for VRFOutput { + fn encode(&self) -> Vec { + self.0.as_bytes().encode() + } +} + +#[cfg(feature = "std")] +impl EncodeLike for VRFOutput { } + +#[cfg(feature = "std")] +impl Decode for VRFOutput { + fn decode(i: &mut R) -> Result { + let decoded = <[u8; VRF_OUTPUT_LENGTH]>::decode(i)?; + Ok(Self(schnorrkel::vrf::VRFOutput::from_bytes(&decoded).map_err(convert_error)?)) + } +} + +#[cfg(feature = "std")] +impl TryFrom<[u8; VRF_OUTPUT_LENGTH]> for VRFOutput { + type Error = SignatureError; + + fn try_from(raw: [u8; VRF_OUTPUT_LENGTH]) -> Result { + schnorrkel::vrf::VRFOutput::from_bytes(&raw).map(VRFOutput) + } +} + +#[cfg(feature = "std")] +impl TryFrom for VRFOutput { + type Error = SignatureError; + + fn try_from(raw: RawVRFOutput) -> Result { + schnorrkel::vrf::VRFOutput::from_bytes(&raw.0).map(VRFOutput) + } +} + +#[cfg(feature = "std")] +impl From for RawVRFOutput { + fn from(output: VRFOutput) -> RawVRFOutput { + RawVRFOutput(output.to_bytes()) + } +} + +/// Raw VRF proof. +#[derive(Clone, Copy, Encode, Decode)] +pub struct RawVRFProof(pub [u8; VRF_PROOF_LENGTH]); + +impl Deref for RawVRFProof { + type Target = [u8; VRF_PROOF_LENGTH]; + fn deref(&self) -> &Self::Target { &self.0 } +} + +impl DerefMut for RawVRFProof { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } +} + +#[cfg(feature = "std")] +impl std::fmt::Debug for RawVRFProof { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", &self) + } +} + +impl core::cmp::PartialEq for RawVRFProof { + fn eq(&self, other: &Self) -> bool { + self == other + } +} + +impl core::cmp::Eq for RawVRFProof { } + +/// VRF proof type available for `std` environment, suitable for schnorrkel operations. +#[cfg(feature = "std")] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct VRFProof(pub schnorrkel::vrf::VRFProof); + +#[cfg(feature = "std")] +impl PartialOrd for VRFProof { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +#[cfg(feature = "std")] +impl Ord for VRFProof { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + U512::from(self.0.to_bytes()).cmp(&U512::from(other.0.to_bytes())) + } +} + +#[cfg(feature = "std")] +impl Deref for VRFProof { + type Target = schnorrkel::vrf::VRFProof; + fn deref(&self) -> &Self::Target { &self.0 } +} + +#[cfg(feature = "std")] +impl DerefMut for VRFProof { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } +} + +#[cfg(feature = "std")] +impl Encode for VRFProof { + fn encode(&self) -> Vec { + self.0.to_bytes().encode() + } +} + +#[cfg(feature = "std")] +impl EncodeLike for VRFProof { } + +#[cfg(feature = "std")] +impl Decode for VRFProof { + fn decode(i: &mut R) -> Result { + let decoded = <[u8; VRF_PROOF_LENGTH]>::decode(i)?; + Ok(Self(schnorrkel::vrf::VRFProof::from_bytes(&decoded).map_err(convert_error)?)) + } +} + +#[cfg(feature = "std")] +impl TryFrom<[u8; VRF_PROOF_LENGTH]> for VRFProof { + type Error = SignatureError; + + fn try_from(raw: [u8; VRF_PROOF_LENGTH]) -> Result { + schnorrkel::vrf::VRFProof::from_bytes(&raw).map(VRFProof) + } +} + +#[cfg(feature = "std")] +impl TryFrom for VRFProof { + type Error = SignatureError; + + fn try_from(raw: RawVRFProof) -> Result { + schnorrkel::vrf::VRFProof::from_bytes(&raw.0).map(VRFProof) + } +} + +#[cfg(feature = "std")] +impl From for RawVRFProof { + fn from(output: VRFProof) -> RawVRFProof { + RawVRFProof(output.to_bytes()) + } +} + +#[cfg(feature = "std")] +fn convert_error(e: SignatureError) -> codec::Error { + use SignatureError::*; + use MultiSignatureStage::*; + match e { + EquationFalse => "Signature error: `EquationFalse`".into(), + PointDecompressionError => "Signature error: `PointDecompressionError`".into(), + ScalarFormatError => "Signature error: `ScalarFormatError`".into(), + NotMarkedSchnorrkel => "Signature error: `NotMarkedSchnorrkel`".into(), + BytesLengthError { .. } => "Signature error: `BytesLengthError`".into(), + MuSigAbsent { musig_stage: Commitment } => + "Signature error: `MuSigAbsent` at stage `Commitment`".into(), + MuSigAbsent { musig_stage: Reveal } => + "Signature error: `MuSigAbsent` at stage `Reveal`".into(), + MuSigAbsent { musig_stage: Cosignature } => + "Signature error: `MuSigAbsent` at stage `Commitment`".into(), + MuSigInconsistent { musig_stage: Commitment, duplicate: true } => + "Signature error: `MuSigInconsistent` at stage `Commitment` on duplicate".into(), + MuSigInconsistent { musig_stage: Commitment, duplicate: false } => + "Signature error: `MuSigInconsistent` at stage `Commitment` on not duplicate".into(), + MuSigInconsistent { musig_stage: Reveal, duplicate: true } => + "Signature error: `MuSigInconsistent` at stage `Reveal` on duplicate".into(), + MuSigInconsistent { musig_stage: Reveal, duplicate: false } => + "Signature error: `MuSigInconsistent` at stage `Reveal` on not duplicate".into(), + MuSigInconsistent { musig_stage: Cosignature, duplicate: true } => + "Signature error: `MuSigInconsistent` at stage `Cosignature` on duplicate".into(), + MuSigInconsistent { musig_stage: Cosignature, duplicate: false } => + "Signature error: `MuSigInconsistent` at stage `Cosignature` on not duplicate".into(), + } +} + +/// Schnorrkel randomness value. Same size as `VRFOutput`. +pub type Randomness = [u8; RANDOMNESS_LENGTH]; diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index 79380a6fc6..8d5ad7daae 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -74,7 +74,7 @@ pub mod testing; pub mod tasks; pub use self::hash::{H160, H256, H512, convert_hash}; -pub use self::uint::U256; +pub use self::uint::{U256, U512}; pub use changes_trie::{ChangesTrieConfiguration, ChangesTrieConfigurationRange}; #[cfg(feature = "full_crypto")] pub use crypto::{DeriveJunction, Pair, Public}; diff --git a/substrate/primitives/core/src/uint.rs b/substrate/primitives/core/src/uint.rs index 54ed7ca317..e666137c08 100644 --- a/substrate/primitives/core/src/uint.rs +++ b/substrate/primitives/core/src/uint.rs @@ -16,7 +16,7 @@ //! An unsigned fixed-size integer. -pub use primitive_types::U256; +pub use primitive_types::{U256, U512}; #[cfg(test)] mod tests {