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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// SPDX-License-Identifier: Apache-2.0
//! DKG threshold attribute view.
//!
//! Implements [`ThresholdAttrView`] for the four DKG private-share codecs
//! introduced alongside the `bs-dkg` crate. The view reads its values out of
//! the four new [`AttrId::Dkg*`] attributes:
//!
//! - [`AttrId::DkgThreshold`] → [`threshold`](ThresholdAttrView::threshold)
//! - [`AttrId::DkgLimit`] → [`limit`](ThresholdAttrView::limit)
//! - [`AttrId::DkgIdentifier`] → [`identifier`](ThresholdAttrView::identifier)
//! - [`AttrId::DkgGroupPublicKey`] → [`threshold_data`](ThresholdAttrView::threshold_data)
use crate::Error;
use crate::error::AttributesError;
use crate::{AttrId, AttrView, Multikey, ThresholdAttrView, ThresholdKeyView};
use multi_trait::TryDecodeFrom;
use multi_util::Varuint;
/// Read-only DKG threshold view over a [`Multikey`].
pub(crate) struct View<'a> {
mk: &'a Multikey,
}
impl<'a> TryFrom<&'a Multikey> for View<'a> {
type Error = Error;
fn try_from(mk: &'a Multikey) -> Result<Self, Self::Error> {
Ok(Self { mk })
}
}
impl<'a> AttrView for View<'a> {
fn is_encrypted(&self) -> bool {
// A DKG share may itself be encrypted (the `KeyIsEncrypted` attribute is
// stamped on the multikey). Earlier revisions hardcoded `false`, which
// meant callers using `threshold_attr_view()` alone saw an unencrypted
// share even when it was sealed. Read the attribute directly so the
// status is authoritative regardless of which view the caller holds.
if let Some(v) = self.mk.attributes.get(&AttrId::KeyIsEncrypted) {
if let Ok((b, _)) = Varuint::<bool>::try_decode_from(v.as_slice()) {
return b.to_inner();
}
}
false
}
fn is_public_key(&self) -> bool {
false
}
fn is_secret_key(&self) -> bool {
// A DKG private share is a secret-bearing key share; treat it as a
// secret key for status purposes so callers gating on `is_secret_key()`
// (e.g. before signing or exporting) do not silently treat a
// secret share as public.
true
}
fn is_secret_key_share(&self) -> bool {
true
}
}
impl<'a> ThresholdAttrView for View<'a> {
fn threshold(&self) -> Result<usize, Error> {
let bytes = self
.mk
.attributes
.get(&AttrId::DkgThreshold)
.ok_or(AttributesError::MissingThreshold)?;
if bytes.len() < 2 {
return Err(AttributesError::MissingThreshold.into());
}
let v = u16::from_le_bytes([bytes[0], bytes[1]]);
Ok(v as usize)
}
fn limit(&self) -> Result<usize, Error> {
let bytes = self
.mk
.attributes
.get(&AttrId::DkgLimit)
.ok_or(AttributesError::MissingLimit)?;
if bytes.len() < 2 {
return Err(AttributesError::MissingLimit.into());
}
let v = u16::from_le_bytes([bytes[0], bytes[1]]);
Ok(v as usize)
}
fn identifier(&self) -> Result<&[u8], Error> {
let bytes = self
.mk
.attributes
.get(&AttrId::DkgIdentifier)
.ok_or(AttributesError::MissingShareIdentifier)?;
Ok(bytes.as_slice())
}
fn threshold_data(&self) -> Result<&[u8], Error> {
let bytes = self
.mk
.attributes
.get(&AttrId::DkgGroupPublicKey)
.ok_or(AttributesError::MissingThresholdData)?;
Ok(bytes.as_slice())
}
}
impl<'a> ThresholdKeyView for View<'a> {
/// Get the group public key bytes for the t-of-n key.
fn group_pubkey(&self) -> Result<Vec<u8>, Error> {
let bytes = self
.mk
.attributes
.get(&AttrId::DkgGroupPublicKey)
.ok_or(AttributesError::MissingThresholdData)?;
Ok(bytes.to_vec())
}
/// Returns `true` if the underlying Multikey is part of a threshold key.
fn is_threshold_key(&self) -> bool {
true
}
/// Number of participants `n` in the t-of-n scheme.
fn participant_count(&self) -> Result<u16, Error> {
let bytes = self
.mk
.attributes
.get(&AttrId::DkgLimit)
.ok_or(AttributesError::MissingLimit)?;
if bytes.len() < 2 {
return Err(AttributesError::MissingLimit.into());
}
Ok(u16::from_le_bytes([bytes[0], bytes[1]]))
}
/// Threshold `t` in the t-of-n scheme.
fn threshold(&self) -> Result<u16, Error> {
let bytes = self
.mk
.attributes
.get(&AttrId::DkgThreshold)
.ok_or(AttributesError::MissingThreshold)?;
if bytes.len() < 2 {
return Err(AttributesError::MissingThreshold.into());
}
Ok(u16::from_le_bytes([bytes[0], bytes[1]]))
}
/// VLAD bytes of the session owner.
fn owner_vlad(&self) -> Result<Vec<u8>, Error> {
let bytes = self
.mk
.attributes
.get(&AttrId::DkgOwnerId)
.ok_or(AttributesError::MissingShareIdentifier)?;
Ok(bytes.to_vec())
}
}