1use alloc::string::{String, ToString};
2use core::fmt;
3use ur_registry::error::{URError, URResult};
4
5pub fn cyclic_encode(
6 message: &[u8],
7 max_fragment_length: usize,
8 ur_type: String,
9) -> URResult<UREncodeResult> {
10 let mut encoder = ur::Encoder::new(message, max_fragment_length, ur_type.clone())
11 .map_err(|e| URError::CborEncodeError(e.to_string()))?;
12 if encoder.fragment_count() > 1 {
13 Ok(UREncodeResult {
14 is_multi_part: true,
15 data: encoder
16 .next_part()
17 .map_err(|e| URError::UrEncodeError(e.to_string()))?,
18 encoder: Some(KeystoneUREncoder::new(encoder)),
19 })
20 } else {
21 let ur = ur::encode(message, ur_type);
22 Ok(UREncodeResult {
23 is_multi_part: false,
24 data: ur,
25 encoder: None,
26 })
27 }
28}
29
30pub fn probe_encode(
31 message: &[u8],
32 max_fragment_length: usize,
33 ur_type: String,
34) -> URResult<UREncodeResult> {
35 let mut encoder = ur::Encoder::new(message, max_fragment_length, ur_type.clone())
36 .map_err(|e| URError::CborEncodeError(e.to_string()))?;
37 if encoder.fragment_count() > 1 {
38 Ok(UREncodeResult {
39 is_multi_part: true,
40 data: encoder
41 .next_part()
42 .map_err(|e| URError::UrEncodeError(e.to_string()))?,
43 encoder: Some(KeystoneUREncoder::new(encoder)),
44 })
45 } else {
46 let ur = ur::encode(message, ur_type);
47 Ok(UREncodeResult {
48 is_multi_part: false,
49 data: ur,
50 encoder: None,
51 })
52 }
53}
54
55pub struct UREncodeResult {
56 pub is_multi_part: bool,
57 pub data: String,
58 pub encoder: Option<KeystoneUREncoder>,
59}
60
61pub struct KeystoneUREncoder {
62 encoder: ur::Encoder,
63}
64
65impl fmt::Debug for UREncodeResult {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 f.debug_tuple("")
68 .field(&self.is_multi_part)
69 .field(&self.data)
70 .finish()
71 }
72}
73
74impl KeystoneUREncoder {
75 pub fn new(encoder: ur::Encoder) -> Self {
76 KeystoneUREncoder { encoder }
77 }
78
79 pub fn next_cyclic_part(&mut self) -> URResult<String> {
80 self.encoder
81 .next_cyclic_part()
82 .map_err(|e| URError::CborEncodeError(e.to_string()))
83 }
84
85 pub fn next_part(&mut self) -> URResult<String> {
86 self.encoder
87 .next_part()
88 .map_err(|e| URError::CborEncodeError(e.to_string()))
89 }
90
91 pub fn current_index(&self) -> usize {
92 self.encoder.current_index()
93 }
94
95 pub fn fragment_count(&self) -> usize {
96 self.encoder.fragment_count()
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use crate::keystone_ur_decoder::{probe_decode, MultiURParseResult, URParseResult};
103 use crate::keystone_ur_encoder::{cyclic_encode, probe_encode};
104 use alloc::string::ToString;
105 use alloc::vec;
106 use alloc::vec::Vec;
107 use hex::FromHex;
108 use ur_registry::crypto_psbt::CryptoPSBT;
109 use ur_registry::extend::qr_hardware_call::QRHardwareCall;
110 use ur_registry::traits::{RegistryItem, UR};
111 use ur_registry::zcash::zcash_sign_batch::{
112 ZcashSignBatch, ZcashSignMessage, ZCASH_SIGN_BATCH_NETWORK_MAINNET,
113 ZCASH_SIGN_BATCH_VERSION, ZCASH_SIGN_MESSAGE_KIND_PCZT_V1,
114 };
115 use ur_registry::zcash::zcash_sign_result::{
116 ZcashSignMessageResult, ZcashSignResult, ZCASH_SIGN_RESULT_KIND_PCZT_V1,
117 ZCASH_SIGN_RESULT_VERSION, ZCASH_SIGN_STATUS_SIGNED,
118 };
119
120 #[test]
121 fn test_encode_decode_zcash_sign_batch_ur() {
122 let payload_digest =
123 Vec::from_hex("7a66e6be087afee0665161828bd11dc1e201fdb8c2d72786ee485e29897c8da4")
124 .unwrap();
125 let batch = ZcashSignBatch::new(
126 ZCASH_SIGN_BATCH_VERSION,
127 vec![0xaa, 0xbb],
128 ZCASH_SIGN_BATCH_NETWORK_MAINNET,
129 vec![ZcashSignMessage::new(
130 vec![0x01],
131 ZCASH_SIGN_MESSAGE_KIND_PCZT_V1,
132 b"pczt-request".to_vec(),
133 Some(payload_digest.clone()),
134 )],
135 Some(false),
136 );
137 let cbor: Vec<u8> = batch.try_into().unwrap();
138 let encoded =
139 probe_encode(&cbor, 400, ZcashSignBatch::get_registry_type().get_type()).unwrap();
140 let literal_ur = "ur:zcash-sign-batch/onadadaofwpkrkaxadaalyoxadfpadaoadaxgsjoiaknjydpjpihjskpihjkjyamhdcxkniyvarnayknzevtiygyhslfluttcasevoadzcrosatsdilnwyfdhydtldkelgoxbdwkeccarlis";
141
142 assert!(!encoded.is_multi_part);
143 assert_eq!(encoded.data, literal_ur);
144
145 let decoded: URParseResult<ZcashSignBatch> = probe_decode(literal_ur.to_string()).unwrap();
146 let decoded_batch = decoded.data.unwrap();
147
148 assert_eq!(decoded.ur_type.unwrap().get_type_str(), "zcash-sign-batch");
149 assert_eq!(decoded_batch.get_version(), ZCASH_SIGN_BATCH_VERSION);
150 assert_eq!(decoded_batch.get_request_id(), &vec![0xaa, 0xbb]);
151 assert_eq!(
152 decoded_batch.get_network(),
153 ZCASH_SIGN_BATCH_NETWORK_MAINNET
154 );
155 assert!(!decoded_batch.get_atomic());
156 assert_eq!(decoded_batch.get_messages().len(), 1);
157 assert_eq!(decoded_batch.get_messages()[0].get_id(), &vec![0x01]);
158 assert_eq!(
159 decoded_batch.get_messages()[0].get_kind(),
160 ZCASH_SIGN_MESSAGE_KIND_PCZT_V1
161 );
162 assert_eq!(
163 decoded_batch.get_messages()[0].get_payload(),
164 &b"pczt-request".to_vec()
165 );
166 assert_eq!(
167 decoded_batch.get_messages()[0].get_payload_digest(),
168 Some(&payload_digest)
169 );
170 }
171
172 #[test]
173 fn test_registry_ur_encoder_type_is_compatible() {
174 let crypto = CryptoPSBT::new(vec![0xaa, 0xbb, 0xcc]);
175 let mut encoder = super::KeystoneUREncoder::new(crypto.to_ur_encoder(400));
176
177 assert_eq!(encoder.fragment_count(), 1);
178
179 let part = encoder.next_part().unwrap();
180 assert!(part.starts_with("ur:crypto-psbt/"));
181 }
182
183 #[test]
184 fn test_encode_decode_zcash_sign_result_ur() {
185 let payload_digest =
186 Vec::from_hex("f2dbc955d1edad3014bc907efc15e93adb4412cdee847d261cd942998693e590")
187 .unwrap();
188 let result = ZcashSignResult::new(
189 ZCASH_SIGN_RESULT_VERSION,
190 vec![0xaa, 0xbb],
191 vec![ZcashSignMessageResult::signed(
192 vec![0x01],
193 ZCASH_SIGN_RESULT_KIND_PCZT_V1,
194 b"signed-pczt-result".to_vec(),
195 payload_digest.clone(),
196 )],
197 );
198 let cbor: Vec<u8> = result.try_into().unwrap();
199 let encoded =
200 probe_encode(&cbor, 400, ZcashSignResult::get_registry_type().get_type()).unwrap();
201 let literal_ur = "ur:zcash-sign-result/otadadaofwpkrkaxlyonadfpadaoaeaxadaagmjkiniojtihiedpjoiaknjydpjpihjkkpjzjyamhdcxwzuysogottwepmdybbrfmhkbztbzwlftuyfybgsnwylrkidscetafwnllnmuvwmhuorkvwgr";
202
203 assert!(!encoded.is_multi_part);
204 assert_eq!(encoded.data, literal_ur);
205
206 let decoded: URParseResult<ZcashSignResult> = probe_decode(literal_ur.to_string()).unwrap();
207 let decoded_result = decoded.data.unwrap();
208
209 assert_eq!(decoded.ur_type.unwrap().get_type_str(), "zcash-sign-result");
210 assert_eq!(decoded_result.get_version(), ZCASH_SIGN_RESULT_VERSION);
211 assert_eq!(decoded_result.get_request_id(), &vec![0xaa, 0xbb]);
212 assert_eq!(decoded_result.get_results().len(), 1);
213 assert_eq!(decoded_result.get_results()[0].get_id(), &vec![0x01]);
214 assert_eq!(
215 decoded_result.get_results()[0].get_status(),
216 ZCASH_SIGN_STATUS_SIGNED
217 );
218 assert_eq!(
219 decoded_result.get_results()[0].get_kind(),
220 ZCASH_SIGN_RESULT_KIND_PCZT_V1
221 );
222 assert_eq!(
223 decoded_result.get_results()[0].get_payload(),
224 &b"signed-pczt-result".to_vec()
225 );
226 assert_eq!(
227 decoded_result.get_results()[0].get_payload_digest(),
228 &payload_digest
229 );
230 }
231
232 #[test]
233 fn test_encode_decode_multipart_zcash_sign_batch_ur() {
234 let payload = vec![0x42; 1024];
235 let payload_digest =
236 Vec::from_hex("7a66e6be087afee0665161828bd11dc1e201fdb8c2d72786ee485e29897c8da4")
237 .unwrap();
238 let batch = ZcashSignBatch::new(
239 ZCASH_SIGN_BATCH_VERSION,
240 vec![0xaa, 0xbb],
241 ZCASH_SIGN_BATCH_NETWORK_MAINNET,
242 vec![ZcashSignMessage::new(
243 vec![0x01],
244 ZCASH_SIGN_MESSAGE_KIND_PCZT_V1,
245 payload.clone(),
246 Some(payload_digest.clone()),
247 )],
248 Some(true),
249 );
250 let cbor: Vec<u8> = batch.try_into().unwrap();
251 let encoded =
252 probe_encode(&cbor, 100, ZcashSignBatch::get_registry_type().get_type()).unwrap();
253
254 assert!(encoded.is_multi_part);
255 let first: URParseResult<ZcashSignBatch> = probe_decode(encoded.data).unwrap();
256 assert!(first.is_multi_part);
257 assert!(first.data.is_none());
258
259 let mut decoder = first.decoder.unwrap();
260 let mut encoder = encoded.encoder.unwrap();
261 let fragment_count = encoder.fragment_count();
262 let mut decoded_batch = None;
263 for _ in 1..fragment_count {
264 let part = encoder.next_part().unwrap();
265 let parsed: MultiURParseResult<ZcashSignBatch> = decoder.parse_ur(part).unwrap();
266 if parsed.is_complete {
267 decoded_batch = parsed.data;
268 break;
269 }
270 }
271 let decoded_batch = decoded_batch.unwrap();
272
273 assert_eq!(decoded_batch.get_version(), ZCASH_SIGN_BATCH_VERSION);
274 assert_eq!(decoded_batch.get_request_id(), &vec![0xaa, 0xbb]);
275 assert_eq!(
276 decoded_batch.get_network(),
277 ZCASH_SIGN_BATCH_NETWORK_MAINNET
278 );
279 assert!(decoded_batch.get_atomic());
280 assert_eq!(decoded_batch.get_messages().len(), 1);
281 assert_eq!(
282 decoded_batch.get_messages()[0].get_kind(),
283 ZCASH_SIGN_MESSAGE_KIND_PCZT_V1
284 );
285 assert_eq!(decoded_batch.get_messages()[0].get_payload(), &payload);
286 assert_eq!(
287 decoded_batch.get_messages()[0].get_payload_digest(),
288 Some(&payload_digest)
289 );
290 }
291
292 #[test]
293 fn test_encode_ada_hardware_call() {
294 let data = "a3010002d90515a10182d90516a101d90130a10186182cf500f500f5d90516a201d90130a1018a182cf51901f5f500f500f500f502010400";
295 let data = Vec::from_hex(data).unwrap();
296 let res = probe_encode(&data, 400, QRHardwareCall::get_registry_type().get_type()).unwrap();
298 assert_eq!(
299 "ur:qr-hardware-call/otadaeaotaahbzoyadlftaahcmoyadtaaddyoyadlncsdwykaeykaeyktaahcmoeadtaaddyoyadlecsdwykcfadykykaeykaeykaeykaoadaaaeyteyldre",
300 res.data
301 )
302 }
303 #[test]
305 fn test_encode_sol_hardware_call() {
306 let data = "a4010002d90515a10184d90516a301d90130a10186182cf5183cf500f502000463455448d90516a301d90130a10186182cf51901f5f500f502010463534f4cd90516a301d90130a10186182cf51901f5f501f502000463534f4cd90516a301d90130a1018a182cf51901f5f500f500f400f402010463534f4c036b4c6561702057616c6c65740401";
307 let data = Vec::from_hex(data).unwrap();
308 let res = probe_encode(&data, 400, QRHardwareCall::get_registry_type().get_type()).unwrap();
310 assert_eq!(
311 "ur:qr-hardware-call/oxadaeaotaahbzoyadlrtaahcmotadtaaddyoyadlncsdwykcsfnykaeykaoaeaaiafeghfdtaahcmotadtaaddyoyadlncsdwykcfadykykaeykaoadaaiagugwgstaahcmotadtaaddyoyadlncsdwykcfadykykadykaoaeaaiagugwgstaahcmotadtaaddyoyadlecsdwykcfadykykaeykaewkaewkaoadaaiagugwgsaxjegsihhsjocxhghsjzjzihjyaaadfnfxcmfy",
312 res.data
313 )
314 }
315 #[test]
316 fn test_encode_cosmos_hardware_call() {
317 let data = "a3010002d90515a10182d90516a101d90130a10186182cf500f500f5d90516a201d90130a1018a182cf51901f5f500f500f500f502010400";
318 let data = Vec::from_hex(data).unwrap();
319 let res = probe_encode(&data, 400, QRHardwareCall::get_registry_type().get_type()).unwrap();
321 assert_eq!(
322 "ur:qr-hardware-call/otadaeaotaahbzoyadlftaahcmoyadtaaddyoyadlncsdwykaeykaeyktaahcmoeadtaaddyoyadlecsdwykcfadykykaeykaeykaeykaoadaaaeyteyldre",
323 res.data
324 )
325 }
326
327 #[test]
328 fn test_encode() {
329 let crypto = CryptoPSBT::new(
330 Vec::from_hex("8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa")
331 .unwrap());
332 let result: Vec<u8> = crypto.try_into().unwrap();
333 let result =
334 probe_encode(&result, 400, CryptoPSBT::get_registry_type().get_type()).unwrap();
335 assert_eq!("ur:crypto-psbt/1-3/lpadaxcfaxiacyvwhdfhndhkadclhkaxhnlkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbnychpmiy",
336 result.data);
337 if result.is_multi_part {
338 let mut encoder = result.encoder.unwrap();
339 let next = encoder.next_part().unwrap();
340 assert_eq!("ur:crypto-psbt/2-3/lpaoaxcfaxiacyvwhdfhndhkadclaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaylbntahvo",
341 next);
342 let next = encoder.next_part().unwrap();
343 assert_eq!("ur:crypto-psbt/3-3/lpaxaxcfaxiacyvwhdfhndhkadclpklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypknseoskve",
344 next
345 );
346 let next = encoder.next_part().unwrap();
347 assert_eq!("ur:crypto-psbt/4-3/lpaaaxcfaxiacyvwhdfhndhkadclaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbayneieyksn",
348 next);
349 }
350 }
351
352 #[test]
353 fn test_cyclic_encode() {
354 let crypto = CryptoPSBT::new(
355 Vec::from_hex("8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa")
356 .unwrap());
357 let result: Vec<u8> = crypto.try_into().unwrap();
358 let result =
359 cyclic_encode(&result, 400, CryptoPSBT::get_registry_type().get_type()).unwrap();
360 assert_eq!("ur:crypto-psbt/1-3/lpadaxcfaxiacyvwhdfhndhkadclhkaxhnlkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbnychpmiy",
361 result.data);
362 if result.is_multi_part {
363 let mut encoder = result.encoder.unwrap();
364 let next = encoder.next_cyclic_part().unwrap();
365 assert_eq!("ur:crypto-psbt/2-3/lpaoaxcfaxiacyvwhdfhndhkadclaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaylbntahvo",
366 next);
367 let next = encoder.next_cyclic_part().unwrap();
368 assert_eq!("ur:crypto-psbt/3-3/lpaxaxcfaxiacyvwhdfhndhkadclpklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypknseoskve",
369 next
370 );
371 let next = encoder.next_cyclic_part().unwrap();
372 assert_eq!("ur:crypto-psbt/1-3/lpadaxcfaxiacyvwhdfhndhkadclhkaxhnlkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypklkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbnychpmiy",
373 next);
374 }
375 }
376}