zebra_chain/orchard/
keys.rs
1use std::{fmt, io};
8
9use group::{ff::PrimeField, prime::PrimeCurveAffine, Group, GroupEncoding};
10use halo2::{
11 arithmetic::{Coordinates, CurveAffine},
12 pasta::pallas,
13};
14use rand_core::{CryptoRng, RngCore};
15
16use crate::{
17 error::RandError,
18 serialization::{
19 serde_helpers, ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize,
20 },
21};
22
23use super::sinsemilla::*;
24
25fn diversify_hash(d: &[u8]) -> pallas::Point {
34 let p = pallas_group_hash(b"z.cash:Orchard-gd", d);
35
36 if <bool>::from(p.is_identity()) {
37 pallas_group_hash(b"z.cash:Orchard-gd", b"")
38 } else {
39 p
40 }
41}
42
43#[derive(Copy, Clone, Eq, PartialEq)]
47#[cfg_attr(
48 any(test, feature = "proptest-impl"),
49 derive(proptest_derive::Arbitrary)
50)]
51pub struct Diversifier(pub(crate) [u8; 11]);
52
53impl fmt::Debug for Diversifier {
54 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
55 f.debug_tuple("Diversifier")
56 .field(&hex::encode(self.0))
57 .finish()
58 }
59}
60
61impl From<[u8; 11]> for Diversifier {
62 fn from(bytes: [u8; 11]) -> Self {
63 Self(bytes)
64 }
65}
66
67impl From<Diversifier> for [u8; 11] {
68 fn from(d: Diversifier) -> [u8; 11] {
69 d.0
70 }
71}
72
73impl From<Diversifier> for pallas::Point {
74 fn from(d: Diversifier) -> Self {
80 diversify_hash(&d.0)
81 }
82}
83
84impl PartialEq<[u8; 11]> for Diversifier {
85 fn eq(&self, other: &[u8; 11]) -> bool {
86 self.0 == *other
87 }
88}
89
90impl From<Diversifier> for pallas::Affine {
91 fn from(d: Diversifier) -> Self {
94 let projective_point = pallas::Point::from(d);
95 projective_point.into()
96 }
97}
98
99impl Diversifier {
100 pub fn new<T>(csprng: &mut T) -> Result<Self, RandError>
104 where
105 T: RngCore + CryptoRng,
106 {
107 let mut bytes = [0u8; 11];
108 csprng
109 .try_fill_bytes(&mut bytes)
110 .map_err(|_| RandError::FillBytes)?;
111
112 Ok(Self::from(bytes))
113 }
114}
115
116#[derive(Copy, Clone, PartialEq)]
129pub struct TransmissionKey(pub(crate) pallas::Affine);
130
131impl fmt::Debug for TransmissionKey {
132 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
133 let mut d = f.debug_struct("TransmissionKey");
134
135 let option: Option<Coordinates<pallas::Affine>> = self.0.coordinates().into();
136
137 match option {
138 Some(coordinates) => d
139 .field("x", &hex::encode(coordinates.x().to_repr()))
140 .field("y", &hex::encode(coordinates.y().to_repr()))
141 .finish(),
142 None => d
143 .field("x", &hex::encode(pallas::Base::zero().to_repr()))
144 .field("y", &hex::encode(pallas::Base::zero().to_repr()))
145 .finish(),
146 }
147 }
148}
149
150impl Eq for TransmissionKey {}
151
152impl From<TransmissionKey> for [u8; 32] {
153 fn from(pk_d: TransmissionKey) -> [u8; 32] {
154 pk_d.0.to_bytes()
155 }
156}
157
158impl PartialEq<[u8; 32]> for TransmissionKey {
159 fn eq(&self, other: &[u8; 32]) -> bool {
160 &self.0.to_bytes() == other
161 }
162}
163
164#[derive(Copy, Clone, Deserialize, PartialEq, Eq, Serialize)]
169pub struct EphemeralPublicKey(#[serde(with = "serde_helpers::Affine")] pub(crate) pallas::Affine);
170
171impl fmt::Debug for EphemeralPublicKey {
172 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
173 let mut d = f.debug_struct("EphemeralPublicKey");
174
175 let option: Option<Coordinates<pallas::Affine>> = self.0.coordinates().into();
176
177 match option {
178 Some(coordinates) => d
179 .field("x", &hex::encode(coordinates.x().to_repr()))
180 .field("y", &hex::encode(coordinates.y().to_repr()))
181 .finish(),
182 None => d
183 .field("x", &hex::encode(pallas::Base::zero().to_repr()))
184 .field("y", &hex::encode(pallas::Base::zero().to_repr()))
185 .finish(),
186 }
187 }
188}
189
190impl From<EphemeralPublicKey> for [u8; 32] {
191 fn from(epk: EphemeralPublicKey) -> [u8; 32] {
192 epk.0.to_bytes()
193 }
194}
195
196impl From<&EphemeralPublicKey> for [u8; 32] {
197 fn from(epk: &EphemeralPublicKey) -> [u8; 32] {
198 epk.0.to_bytes()
199 }
200}
201
202impl PartialEq<[u8; 32]> for EphemeralPublicKey {
203 fn eq(&self, other: &[u8; 32]) -> bool {
204 &self.0.to_bytes() == other
205 }
206}
207
208impl TryFrom<[u8; 32]> for EphemeralPublicKey {
209 type Error = &'static str;
210
211 fn try_from(bytes: [u8; 32]) -> Result<Self, Self::Error> {
226 let possible_point = pallas::Affine::from_bytes(&bytes);
227
228 if possible_point.is_some().into() {
229 let point = possible_point.unwrap();
230 if point.to_curve().is_identity().into() {
231 Err("pallas::Affine value for Orchard EphemeralPublicKey is the identity")
232 } else {
233 Ok(Self(possible_point.unwrap()))
234 }
235 } else {
236 Err("Invalid pallas::Affine value for Orchard EphemeralPublicKey")
237 }
238 }
239}
240
241impl ZcashSerialize for EphemeralPublicKey {
242 fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
243 writer.write_all(&<[u8; 32]>::from(self)[..])?;
244 Ok(())
245 }
246}
247
248impl ZcashDeserialize for EphemeralPublicKey {
249 fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
250 Self::try_from(reader.read_32_bytes()?).map_err(SerializationError::Parse)
251 }
252}