jam_std_common/crypto/
ed25519.rs1use super::concat;
2use crate::{availability::AvailabilityStatementHash, simple::TrancheIndex};
3use codec::{ConstEncodedLen, Decode, Encode, MaxEncodedLen};
4use ed25519_consensus::{Error as SignatureError, VerificationKey};
5use jam_types::{hex::HexDisplay, CoreIndex, HeaderHash, OpaqueEd25519Public, WorkReportHash};
6
7pub const SIGNATURE_LEN: usize = 64;
8#[derive(Clone, Copy, Eq, PartialEq)]
9pub struct Signature(pub ed25519_consensus::Signature);
10
11pub const PUBLIC_LEN: usize = 32;
12#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
13pub struct Public(pub ed25519_consensus::VerificationKeyBytes);
14impl Default for Public {
15 fn default() -> Self {
16 Self([0u8; PUBLIC_LEN].into())
17 }
18}
19impl From<OpaqueEd25519Public> for Public {
20 fn from(opaque: OpaqueEd25519Public) -> Self {
21 opaque.0.into()
22 }
23}
24impl From<Public> for OpaqueEd25519Public {
25 fn from(real: Public) -> Self {
26 Self(real.to_bytes())
27 }
28}
29
30pub const SECRET_LEN: usize = 32;
31#[derive(Clone)]
32pub struct Secret(pub ed25519_consensus::SigningKey);
33
34impl Signature {
35 pub fn null() -> Self {
36 Self([0u8; SIGNATURE_LEN].into())
37 }
38 pub fn to_bytes(self) -> [u8; SIGNATURE_LEN] {
39 self.0.to_bytes()
40 }
41 pub fn to_vec(self) -> Vec<u8> {
42 self.to_bytes().to_vec()
43 }
44}
45
46impl Encode for Signature {
47 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
48 self.0.to_bytes().encode_to(dest)
49 }
50 fn size_hint(&self) -> usize {
51 self.0.to_bytes().size_hint()
52 }
53}
54impl MaxEncodedLen for Signature {
55 fn max_encoded_len() -> usize {
56 SIGNATURE_LEN
57 }
58}
59impl ConstEncodedLen for Signature {}
60impl Decode for Signature {
61 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
62 Ok(Self(<[u8; SIGNATURE_LEN]>::decode(input)?.into()))
63 }
64}
65impl std::fmt::Debug for Signature {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 write!(f, "Signature")
68 }
69}
70impl From<Signature> for [u8; SIGNATURE_LEN] {
71 fn from(sig: Signature) -> Self {
72 sig.0.to_bytes()
73 }
74}
75
76impl Signature {
77 pub fn verify(&self, message: &Message, signer: &Public) -> Result<(), SignatureError> {
78 signer.verify(message, self)
79 }
80}
81
82impl std::fmt::Debug for Public {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 write!(f, "Pub({})", HexDisplay::from(self.as_bytes()))
85 }
86}
87impl std::hash::Hash for Public {
88 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
89 self.0.as_ref().hash(state)
90 }
91}
92impl Encode for Public {
93 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
94 AsRef::<[u8; PUBLIC_LEN]>::as_ref(&self).encode_to(dest)
95 }
96 fn size_hint(&self) -> usize {
97 PUBLIC_LEN
98 }
99}
100impl MaxEncodedLen for Public {
101 fn max_encoded_len() -> usize {
102 PUBLIC_LEN
103 }
104}
105impl ConstEncodedLen for Public {}
106
107impl Decode for Public {
108 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
109 Ok(<[u8; PUBLIC_LEN]>::decode(input)?.into())
110 }
111}
112impl From<[u8; PUBLIC_LEN]> for Public {
113 fn from(bytes: [u8; PUBLIC_LEN]) -> Self {
114 Self(ed25519_consensus::VerificationKeyBytes::from(bytes))
115 }
116}
117impl AsRef<[u8; PUBLIC_LEN]> for Public {
118 fn as_ref(&self) -> &[u8; PUBLIC_LEN] {
119 self.as_bytes()
120 }
121}
122impl From<Public> for [u8; PUBLIC_LEN] {
123 fn from(p: Public) -> Self {
124 p.0.into()
125 }
126}
127impl Public {
128 pub fn as_bytes(&self) -> &[u8; PUBLIC_LEN] {
129 self.0.as_bytes()
130 }
131
132 pub fn to_bytes(self) -> [u8; PUBLIC_LEN] {
133 *self.as_bytes()
134 }
135
136 pub fn verify(&self, message: &Message, signature: &Signature) -> Result<(), SignatureError> {
137 let key: VerificationKey = self.0.try_into()?;
138 message.using_encoded(|enc| key.verify(&signature.0, enc))
139 }
140}
141
142pub enum Message<'a> {
144 Assurance(AvailabilityStatementHash),
146 Guarantee(WorkReportHash),
148 Announcement(HeaderHash, TrancheIndex, &'a [(CoreIndex, WorkReportHash)]),
150 Judgement(bool, WorkReportHash),
152 X509(&'a [u8]),
154 Tls(&'a [u8]),
156}
157
158impl Message<'_> {
159 pub fn using_encoded<R>(&self, f: impl FnOnce(&[u8]) -> R) -> R {
161 match self {
162 Self::Assurance(hash) => f(concat(&mut [0; 13 + 32], &[b"jam_available", &hash.0])),
163 Self::Guarantee(hash) => f(concat(&mut [0; 13 + 32], &[b"jam_guarantee", &hash.0])),
164 Self::Announcement(anchor, tranche, reports) => {
165 let mut buf = Vec::with_capacity(13 + reports.len() * 34 + 32);
166 buf.extend_from_slice(b"jam_announce");
167 buf.extend_from_slice(&[*tranche]);
168 reports.iter().for_each(|t| {
169 t.encode_to(&mut buf);
170 });
171 buf.extend_from_slice(&anchor.0);
172 f(&buf)
173 },
174 Self::Judgement(true, hash) => f(concat(&mut [0; 9 + 32], &[b"jam_valid", &hash.0])),
175 Self::Judgement(false, hash) =>
176 f(concat(&mut [0; 11 + 32], &[b"jam_invalid", &hash.0])),
177 Self::X509(enc) | Self::Tls(enc) => {
178 assert!(!enc.starts_with(b"jam"));
185 f(enc)
186 },
187 }
188 }
189}
190
191#[cfg(any(test, feature = "rand"))]
192impl rand::distr::Distribution<Public> for rand::distr::StandardUniform {
193 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Public {
194 let bytes: [u8; PUBLIC_LEN] = rng.random();
195 bytes.into()
196 }
197}
198
199impl Eq for Secret {}
200impl PartialEq for Secret {
201 fn eq(&self, other: &Self) -> bool {
202 self.0.as_ref() == other.0.as_ref()
203 }
204}
205impl Encode for Secret {
206 fn encode_to<T: codec::Output + ?Sized>(&self, dest: &mut T) {
207 self.0.as_bytes().encode_to(dest)
208 }
209 fn size_hint(&self) -> usize {
210 SECRET_LEN
211 }
212}
213impl MaxEncodedLen for Secret {
214 fn max_encoded_len() -> usize {
215 SECRET_LEN
216 }
217}
218impl Decode for Secret {
219 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
220 Ok(Self(ed25519_consensus::SigningKey::from(<[u8; SECRET_LEN]>::decode(input)?)))
221 }
222}
223impl AsRef<[u8; SECRET_LEN]> for Secret {
224 fn as_ref(&self) -> &[u8; SECRET_LEN] {
225 self.as_bytes()
226 }
227}
228impl From<Secret> for [u8; SECRET_LEN] {
229 fn from(s: Secret) -> Self {
230 s.to_bytes()
231 }
232}
233
234impl Secret {
235 pub fn new(rng: &mut impl rand::CryptoRng) -> Self {
236 Self::from_seed(rand::Rng::random(rng))
237 }
238 pub fn from_seed(seed: [u8; SECRET_LEN]) -> Self {
239 Self(seed.into())
240 }
241 pub fn as_bytes(&self) -> &[u8; SECRET_LEN] {
242 self.0.as_bytes()
243 }
244 pub fn to_bytes(&self) -> [u8; SECRET_LEN] {
245 *self.as_bytes()
246 }
247 pub fn generate() -> Self {
248 Self::new(&mut rand::rng())
249 }
250 pub fn sign(&self, message: &Message) -> Signature {
251 message.using_encoded(|enc| Signature(self.0.sign(enc)))
252 }
253 pub fn public(&self) -> Public {
254 Public((&self.0).into())
255 }
256}