1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
pub use crate::BLAKE2B_HASH_SIZE;
use super::decode::decode;
use super::{is_lipmaa_required, Entry};
use crate::signature::Signature;
use crate::yamf_hash::new_blake2b;
use ed25519_dalek::{Keypair, Signer};
use snafu::{ensure, ResultExt};
pub mod error;
pub use error::*;
pub fn publish(
out: &mut [u8],
key_pair: &Keypair,
log_id: u64,
payload: &[u8],
is_end_of_feed: bool,
previous_seq_num: Option<u64>,
lipmaa_entry_bytes: Option<&[u8]>,
backlink_bytes: Option<&[u8]>,
) -> Result<usize, Error> {
let author = key_pair.public;
let payload_hash = new_blake2b(payload);
let payload_size = payload.len() as u64;
let seq_num = previous_seq_num.unwrap_or(0) + 1;
let mut entry: Entry<_, &[u8]> = Entry {
log_id,
is_end_of_feed,
payload_hash,
payload_size,
author,
seq_num,
backlink: None,
lipmaa_link: None,
sig: None,
};
if seq_num > 1 {
let backlink_entry = decode(&backlink_bytes.ok_or(Error::PublishWithoutBacklinkEntry)?[..])
.context(DecodeBacklinkEntry)?;
let lipmaa_entry = decode(&lipmaa_entry_bytes.ok_or(Error::PublishWithoutLipmaaEntry)?[..])
.context(DecodeLipmaaEntry)?;
ensure!(!backlink_entry.is_end_of_feed, PublishAfterEndOfFeed);
ensure!(
log_id == backlink_entry.log_id,
PublishWithIncorrectBacklinkLogId
);
ensure!(
author == backlink_entry.author,
PublishKeypairDidNotMatchBacklinkPublicKey
);
ensure!(
author == lipmaa_entry.author,
PublishKeypairDidNotMatchBacklinkPublicKey
);
ensure!(
log_id == lipmaa_entry.log_id,
PublishWithIncorrectLipmaaLinkLogId
);
let backlink = new_blake2b(backlink_bytes.ok_or(Error::PublishWithoutBacklinkEntry)?);
entry.backlink = Some(backlink);
if is_lipmaa_required(seq_num) {
let lipmaa_link =
new_blake2b(lipmaa_entry_bytes.ok_or(Error::PublishWithoutLipmaaEntry)?);
entry.lipmaa_link = Some(lipmaa_link);
}
}
let buff_size = entry.encode(out).context(EncodeEntryToOutBuffer {
buffer_size: out.len(),
})?;
let signature = key_pair.sign(&out[..buff_size]);
let sig_bytes = &signature.to_bytes()[..];
let signature = Signature(sig_bytes.into());
entry.sig = Some(signature);
entry.encode(out).context(EncodeEntryToOutBuffer {
buffer_size: out.len(),
})
}