1use codec::Encode;
21use merlin::Transcript;
22use schnorrkel::vrf::{VRFOutput, VRFProof};
23
24#[derive(Clone, Encode)]
27#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
28pub enum VRFTranscriptValue {
29 Bytes(Vec<u8>),
31 U64(u64),
33}
34#[derive(Clone, Encode)]
36pub struct VRFTranscriptData {
37 pub label: &'static [u8],
39 pub items: Vec<(&'static str, VRFTranscriptValue)>,
41}
42#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
44pub struct VRFSignature {
45 pub output: VRFOutput,
47 pub proof: VRFProof,
49}
50
51pub 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}