tp_keystore/
vrf.rs

1// This file is part of Tetcore.
2
3// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! VRF-specifc data types and helpers
19
20use codec::Encode;
21use merlin::Transcript;
22use schnorrkel::vrf::{VRFOutput, VRFProof};
23
24/// An enum whose variants represent possible
25/// accepted values to construct the VRF transcript
26#[derive(Clone, Encode)]
27#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
28pub enum VRFTranscriptValue {
29	/// Value is an array of bytes
30	Bytes(Vec<u8>),
31	/// Value is a u64 integer
32	U64(u64),
33}
34/// VRF Transcript data
35#[derive(Clone, Encode)]
36pub struct VRFTranscriptData {
37	/// The transcript's label
38	pub label: &'static [u8],
39	/// Additional data to be registered into the transcript
40	pub items: Vec<(&'static str, VRFTranscriptValue)>,
41}
42/// VRF signature data
43#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
44pub struct VRFSignature {
45	/// The VRFOutput serialized
46	pub output: VRFOutput,
47	/// The calculated VRFProof
48	pub proof: VRFProof,
49}
50
51/// Construct a `Transcript` object from data.
52///
53/// Returns `merlin::Transcript`
54pub fn make_transcript(data: VRFTranscriptData) -> Transcript {
55	let mut transcript = Transcript::new(data.label);
56	for (label, value) in data.items.into_iter() {
57		match value {
58			VRFTranscriptValue::Bytes(bytes) => {
59				transcript.append_message(label.as_bytes(), &bytes);
60			},
61			VRFTranscriptValue::U64(val) => {
62				transcript.append_u64(label.as_bytes(), val);
63			}
64		}
65	}
66	transcript
67}
68
69
70#[cfg(test)]
71mod tests {
72	use super::*;
73	use rand::RngCore;
74	use rand_chacha::{
75		rand_core::SeedableRng,
76		ChaChaRng,
77	};
78
79	#[test]
80	fn transcript_creation_matches() {
81		let mut orig_transcript = Transcript::new(b"My label");
82		orig_transcript.append_u64(b"one", 1);
83		orig_transcript.append_message(b"two", "test".as_bytes());
84
85		let new_transcript = make_transcript(VRFTranscriptData {
86			label: b"My label",
87			items: vec![
88				("one", VRFTranscriptValue::U64(1)),
89				("two", VRFTranscriptValue::Bytes("test".as_bytes().to_vec())),
90			],
91		});
92		let test = |t: Transcript| -> [u8; 16] {
93			let mut b = [0u8; 16];
94			t.build_rng()
95				.finalize(&mut ChaChaRng::from_seed([0u8;32]))
96				.fill_bytes(&mut b);
97			b
98		};
99		debug_assert!(test(orig_transcript) == test(new_transcript));
100	}
101}