rite_model/params/
sharing.rs1use schemars::{JsonSchema, Schema, SchemaGenerator};
4use serde::{Deserialize, Serialize};
5use serde_json::json;
6
7use super::schema::{add_rule, names, property};
8use crate::{RevealFormat, SharingScheme, bip39};
9
10#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
12#[serde(deny_unknown_fields)]
13#[schemars(transform = phrase_lengths)]
14#[non_exhaustive]
15pub struct RevealParams {
16 pub message: String,
19 #[serde(default)]
22 pub format: Option<RevealFormat>,
23 #[serde(default)]
25 pub note: Option<String>,
26 #[serde(default)]
31 #[schemars(range(min = 1))]
32 pub length: Option<u64>,
33}
34
35fn phrase_lengths(schema: &mut Schema) {
37 let format = RevealFormat::Bip39;
38 add_rule(
39 schema,
40 json!({
41 "if": {
42 "properties": { "format": { "const": format.as_str() } },
43 "required": ["format"],
44 },
45 "then": {
46 "properties": {
47 "length": {
48 "enum": bip39::phrase_lengths().collect::<Vec<_>>(),
49 "x-message": format!(
50 "'length' counts words for '{format}', and a phrase has {} words",
51 bip39::PHRASE_LENGTHS
52 ),
53 }
54 }
55 },
56 }),
57 );
58}
59
60#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
62#[serde(deny_unknown_fields)]
63#[schemars(transform = longer_than_a_header)]
64#[non_exhaustive]
65pub struct EnterShareParams {
66 pub message: String,
68 #[serde(default)]
71 #[schemars(schema_with = "share_formats")]
72 pub format: Option<RevealFormat>,
73 #[serde(default)]
75 pub note: Option<String>,
76 #[serde(default)]
80 pub length: Option<u64>,
81}
82
83fn share_formats(_: &mut SchemaGenerator) -> Schema {
86 let (words, bytes): (Vec<RevealFormat>, Vec<RevealFormat>) = RevealFormat::ALL
87 .iter()
88 .partition(|format| format.is_words());
89 let mut schema = names(bytes.iter().map(|format| format.as_str()));
90 let words: Vec<&str> = words.iter().map(|format| format.as_str()).collect();
91 schema.insert(
92 "allOf".to_string(),
93 json!([{
94 "not": { "enum": words },
95 "x-message": format!(
96 "a share is written in {}; words are for the secret the shares combine into",
97 crate::types::either(bytes.iter().map(|format| format.as_str()))
98 ),
99 }]),
100 );
101 schema
102}
103
104fn longer_than_a_header(schema: &mut Schema) {
106 let header = SharingScheme::RiteSssV1.header_len();
107 property(schema, "length").insert(
109 "allOf".to_string(),
110 json!([{
111 "minimum": header.saturating_add(1),
112 "x-message": format!(
113 "'length' is a share's secret plus {header} header bytes, so it is longer \
114 than {header}"
115 ),
116 }]),
117 );
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
122#[serde(deny_unknown_fields)]
123#[schemars(transform = share_limits)]
124#[non_exhaustive]
125pub struct SplitSecretParams {
126 #[serde(default)]
129 pub scheme: Option<SharingScheme>,
130 #[schemars(range(min = 2))]
134 pub threshold: u8,
135 #[schemars(range(min = 2))]
140 pub shares: u8,
141}
142
143const DEFAULT_SHARING_SCHEME: SharingScheme = SharingScheme::RiteSssV1;
145
146fn share_limits(schema: &mut Schema) {
151 let largest = SharingScheme::ALL
152 .iter()
153 .map(|scheme| scheme.max_shares())
154 .max()
155 .unwrap_or(u8::MAX);
156 add_rule(
157 schema,
158 json!({
159 "properties": {
160 "threshold": { "maximum": largest },
161 "shares": { "maximum": largest },
162 }
163 }),
164 );
165 for &scheme in SharingScheme::ALL {
166 let max = scheme.max_shares();
167 let names_it = if scheme == DEFAULT_SHARING_SCHEME {
168 json!({ "properties": { "scheme": { "const": scheme.as_str() } } })
169 } else {
170 json!({
171 "properties": { "scheme": { "const": scheme.as_str() } },
172 "required": ["scheme"],
173 })
174 };
175 add_rule(
176 schema,
177 json!({
178 "if": names_it,
179 "then": {
180 "properties": {
181 "threshold": { "maximum": max },
182 "shares": { "maximum": max },
183 }
184 },
185 }),
186 );
187 }
188}
189
190impl Default for SplitSecretParams {
191 fn default() -> Self {
192 Self {
193 scheme: None,
194 threshold: 2,
195 shares: 2,
196 }
197 }
198}