VRF refactory (#13889)

* First iteration to encapsulate schnorrkel and merlin usage

* Remove schnorkel direct dependency from BABE pallet

* Remove schnorrkel direct dependency from BABE client

* Trivial renaming for VrfTranscript data and value

* Better errors

* Expose a function to get a schnorrkel friendly transcript

* Keep the vrf signature stuff together (preventing some clones around)

* Fix tests

* Remove vrf agnostic transcript and define it as an associated type for VrfSigner and VrfVerifier

* Fix babe pallet mock

* Inner types are required to be public for polkadot

* Update client/consensus/babe/src/verification.rs

Co-authored-by: Koute <koute@users.noreply.github.com>

* Nit

* Remove Deref implementations

* make_bytes as a method

* Trigger CI

---------

Co-authored-by: Koute <koute@users.noreply.github.com>
This commit is contained in:
Davide Galassi
2023-04-19 11:11:47 +02:00
committed by GitHub
parent d9ad6feac0
commit bb394e08ac
28 changed files with 473 additions and 717 deletions
+4 -5
View File
@@ -16,10 +16,9 @@
// limitations under the License.
//! Keystore traits
pub mod testing;
pub mod vrf;
use crate::vrf::{VRFSignature, VRFTranscriptData};
pub mod testing;
use sp_core::{
crypto::{ByteArray, CryptoTypeId, KeyTypeId},
ecdsa, ed25519, sr25519,
@@ -87,8 +86,8 @@ pub trait Keystore: Send + Sync {
&self,
key_type: KeyTypeId,
public: &sr25519::Public,
transcript_data: VRFTranscriptData,
) -> Result<Option<VRFSignature>, Error>;
transcript: &sr25519::vrf::VrfTranscript,
) -> Result<Option<sr25519::vrf::VrfSignature>, Error>;
/// Returns all ed25519 public keys for the given key type.
fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec<ed25519::Public>;
+25 -23
View File
@@ -17,15 +17,13 @@
//! Types that should only be used for testing!
use crate::{Error, Keystore, KeystorePtr};
use sp_core::{
crypto::{ByteArray, KeyTypeId, Pair},
crypto::{ByteArray, KeyTypeId, Pair, VrfSigner},
ecdsa, ed25519, sr25519,
};
use crate::{
vrf::{make_transcript, VRFSignature, VRFTranscriptData},
Error, Keystore, KeystorePtr,
};
use parking_lot::RwLock;
use std::{collections::HashMap, sync::Arc};
@@ -100,6 +98,16 @@ impl MemoryKeystore {
let sig = self.pair::<T>(key_type, public).map(|pair| pair.sign(msg));
Ok(sig)
}
fn vrf_sign<T: Pair + VrfSigner>(
&self,
key_type: KeyTypeId,
public: &T::Public,
transcript: &T::VrfInput,
) -> Result<Option<T::VrfSignature>, Error> {
let sig = self.pair::<T>(key_type, public).map(|pair| pair.vrf_sign(transcript));
Ok(sig)
}
}
impl Keystore for MemoryKeystore {
@@ -128,14 +136,9 @@ impl Keystore for MemoryKeystore {
&self,
key_type: KeyTypeId,
public: &sr25519::Public,
transcript_data: VRFTranscriptData,
) -> Result<Option<VRFSignature>, Error> {
let sig = self.pair::<sr25519::Pair>(key_type, public).map(|pair| {
let transcript = make_transcript(transcript_data);
let (inout, proof, _) = pair.as_ref().vrf_sign(transcript);
VRFSignature { output: inout.to_output(), proof }
});
Ok(sig)
transcript: &sr25519::vrf::VrfTranscript,
) -> Result<Option<sr25519::vrf::VrfSignature>, Error> {
self.vrf_sign::<sr25519::Pair>(key_type, public, transcript)
}
fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec<ed25519::Public> {
@@ -225,7 +228,6 @@ impl Into<KeystorePtr> for MemoryKeystore {
#[cfg(test)]
mod tests {
use super::*;
use crate::vrf::VRFTranscriptValue;
use sp_core::{
sr25519,
testing::{ECDSA, ED25519, SR25519},
@@ -265,23 +267,23 @@ mod tests {
let secret_uri = "//Alice";
let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair");
let transcript_data = VRFTranscriptData {
label: b"Test",
items: vec![
("one", VRFTranscriptValue::U64(1)),
("two", VRFTranscriptValue::U64(2)),
("three", VRFTranscriptValue::Bytes("test".as_bytes().to_vec())),
let transcript = sr25519::vrf::VrfTranscript::new(
b"Test",
&[
(b"one", &1_u64.to_le_bytes()),
(b"two", &2_u64.to_le_bytes()),
(b"three", "test".as_bytes()),
],
};
);
let result = store.sr25519_vrf_sign(SR25519, &key_pair.public(), transcript_data.clone());
let result = store.sr25519_vrf_sign(SR25519, &key_pair.public(), &transcript);
assert!(result.unwrap().is_none());
store
.insert(SR25519, secret_uri, key_pair.public().as_ref())
.expect("Inserts unknown key");
let result = store.sr25519_vrf_sign(SR25519, &key_pair.public(), transcript_data);
let result = store.sr25519_vrf_sign(SR25519, &key_pair.public(), &transcript);
assert!(result.unwrap().is_some());
}
-94
View File
@@ -1,94 +0,0 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! VRF-specifc data types and helpers
use codec::Encode;
use merlin::Transcript;
use schnorrkel::vrf::{VRFOutput, VRFProof};
/// An enum whose variants represent possible
/// accepted values to construct the VRF transcript
#[derive(Clone, Encode)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub enum VRFTranscriptValue {
/// Value is an array of bytes
Bytes(Vec<u8>),
/// Value is a u64 integer
U64(u64),
}
/// VRF Transcript data
#[derive(Clone, Encode)]
pub struct VRFTranscriptData {
/// The transcript's label
pub label: &'static [u8],
/// Additional data to be registered into the transcript
pub items: Vec<(&'static str, VRFTranscriptValue)>,
}
/// VRF signature data
pub struct VRFSignature {
/// The VRFOutput serialized
pub output: VRFOutput,
/// The calculated VRFProof
pub proof: VRFProof,
}
/// Construct a `Transcript` object from data.
///
/// Returns `merlin::Transcript`
pub fn make_transcript(data: VRFTranscriptData) -> Transcript {
let mut transcript = Transcript::new(data.label);
for (label, value) in data.items.into_iter() {
match value {
VRFTranscriptValue::Bytes(bytes) => {
transcript.append_message(label.as_bytes(), &bytes);
},
VRFTranscriptValue::U64(val) => {
transcript.append_u64(label.as_bytes(), val);
},
}
}
transcript
}
#[cfg(test)]
mod tests {
use super::*;
use rand::RngCore;
use rand_chacha::{rand_core::SeedableRng, ChaChaRng};
#[test]
fn transcript_creation_matches() {
let mut orig_transcript = Transcript::new(b"My label");
orig_transcript.append_u64(b"one", 1);
orig_transcript.append_message(b"two", "test".as_bytes());
let new_transcript = make_transcript(VRFTranscriptData {
label: b"My label",
items: vec![
("one", VRFTranscriptValue::U64(1)),
("two", VRFTranscriptValue::Bytes("test".as_bytes().to_vec())),
],
});
let test = |t: Transcript| -> [u8; 16] {
let mut b = [0u8; 16];
t.build_rng().finalize(&mut ChaChaRng::from_seed([0u8; 32])).fill_bytes(&mut b);
b
};
debug_assert!(test(orig_transcript) == test(new_transcript));
}
}