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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
use crate::{
    PrivateKey,
    PrivateKeyGenerator,
    PublicKey,
    RecoverableSignature,
    Signature,
};

use iota_crypto_preview::Sponge;
use iota_ternary_preview::{
    TritBuf,
    Trits,
};

use std::marker::PhantomData;

#[derive(Default)]
pub struct MssPrivateKeyGeneratorBuilder<S, G> {
    depth: Option<u8>,
    generator: Option<G>,
    _sponge: PhantomData<S>,
}

pub struct MssPrivateKeyGenerator<S, G> {
    depth: u8,
    generator: G,
    _sponge: PhantomData<S>,
}

pub struct MssPrivateKey<S, K> {
    depth: u8,
    index: u64,
    keys: Vec<K>,
    tree: TritBuf,
    _sponge: PhantomData<S>,
}

pub struct MssPublicKey<S, K> {
    state: TritBuf,
    depth: u8,
    _sponge: PhantomData<S>,
    _key: PhantomData<K>,
}

pub struct MssSignature<S> {
    state: TritBuf,
    index: u64,
    _sponge: PhantomData<S>,
}

// TODO: documentation
#[derive(Debug, PartialEq)]
pub enum MssError {
    InvalidDepth(u8),
    MissingDepth,
    MissingGenerator,
    FailedUnderlyingPrivateKeyGeneration,
    FailedUnderlyingPublicKeyGeneration,
    FailedUnderlyingSignatureGeneration,
    FailedUnderlyingPublicKeyRecovery,
    FailedSpongeOperation,
}

impl<S, G> MssPrivateKeyGeneratorBuilder<S, G>
where
    S: Sponge + Default,
    G: PrivateKeyGenerator,
{
    pub fn depth(mut self, depth: u8) -> Self {
        self.depth = Some(depth);
        self
    }

    pub fn generator(mut self, generator: G) -> Self {
        self.generator = Some(generator);
        self
    }

    pub fn build(self) -> Result<MssPrivateKeyGenerator<S, G>, MssError> {
        let depth = match self.depth {
            Some(depth) => match depth {
                0..=20 => depth,
                _ => Err(MssError::InvalidDepth(depth))?,
            },
            None => Err(MssError::MissingDepth)?,
        };
        let generator = self.generator.ok_or(MssError::MissingGenerator)?;

        Ok(MssPrivateKeyGenerator {
            depth: depth,
            generator: generator,
            _sponge: PhantomData,
        })
    }
}

impl<S, G> PrivateKeyGenerator for MssPrivateKeyGenerator<S, G>
where
    S: Sponge + Default,
    G: PrivateKeyGenerator,
    <<<G as PrivateKeyGenerator>::PrivateKey as PrivateKey>::PublicKey as PublicKey>::Signature: RecoverableSignature,
{
    type Seed = G::Seed;
    type PrivateKey = MssPrivateKey<S, G::PrivateKey>;
    type Error = MssError;

    fn generate(&self, seed: &Self::Seed, _: u64) -> Result<Self::PrivateKey, Self::Error> {
        let mut sponge = S::default();
        let mut keys = Vec::new();
        let mut tree = TritBuf::zeros(((1 << self.depth) - 1) * 243);

        // TODO: subseed collision ?
        // TODO: reserve ?

        for key_index in 0..(1 << (self.depth - 1)) {
            let ots_private_key = self
                .generator
                .generate(seed, key_index)
                .map_err(|_| Self::Error::FailedUnderlyingPrivateKeyGeneration)?;
            let ots_public_key = ots_private_key
                .generate_public_key()
                .map_err(|_| Self::Error::FailedUnderlyingPublicKeyGeneration)?;
            let tree_index = ((1 << (self.depth - 1)) + key_index - 1) as usize;

            keys.push(ots_private_key);
            tree[tree_index * 243..(tree_index + 1) * 243].copy_from(ots_public_key.trits());
        }

        for depth in (0..self.depth - 1).rev() {
            for i in 0..(1 << depth) {
                let index = (1 << depth) + i - 1;
                let left_index = index * 2 + 1;
                let right_index = left_index + 1;

                sponge
                    .absorb(&tree[left_index * 243..(left_index + 1) * 243])
                    .map_err(|_| Self::Error::FailedSpongeOperation)?;
                sponge
                    .absorb(&tree[right_index * 243..(right_index + 1) * 243])
                    .map_err(|_| Self::Error::FailedSpongeOperation)?;
                sponge
                    .squeeze_into(&mut tree[index * 243..(index + 1) * 243])
                    .map_err(|_| Self::Error::FailedSpongeOperation)?;
                sponge.reset();
            }
        }

        Ok(MssPrivateKey {
            depth: self.depth,
            index: 0,
            keys: keys,
            tree: tree,
            _sponge: PhantomData,
        })
    }
}

impl<S, K> PrivateKey for MssPrivateKey<S, K>
where
    S: Sponge + Default,
    K: PrivateKey,
    <<K as PrivateKey>::PublicKey as PublicKey>::Signature: RecoverableSignature,
{
    type PublicKey = MssPublicKey<S, K::PublicKey>;
    type Signature = MssSignature<S>;
    type Error = MssError;

    fn generate_public_key(&self) -> Result<Self::PublicKey, Self::Error> {
        // TODO return or generate ?
        Ok(Self::PublicKey::from_buf(self.tree[0..243].to_buf()).depth(self.depth))
    }

    fn sign(&mut self, message: &[i8]) -> Result<Self::Signature, Self::Error> {
        let ots_private_key = &mut self.keys[self.index as usize];
        let ots_signature = ots_private_key
            .sign(message)
            .map_err(|_| Self::Error::FailedUnderlyingSignatureGeneration)?;
        // let mut state = vec![0; ots_signature.size() + 6561];
        let mut state: TritBuf = TritBuf::zeros(ots_signature.size() + 6561);
        let mut tree_index = ((1 << (self.depth - 1)) + self.index - 1) as usize;
        let mut sibling_index;
        let mut i = 0;

        // TODO PAD TO 6561
        state[0..ots_signature.size()].copy_from(ots_signature.trits());

        while tree_index != 0 {
            if tree_index % 2 != 0 {
                sibling_index = tree_index + 1;
                tree_index = tree_index / 2;
            } else {
                sibling_index = tree_index - 1;
                tree_index = (tree_index - 1) / 2;
            }

            state[ots_signature.size() + i * 243..ots_signature.size() + (i + 1) * 243]
                .copy_from(&self.tree[sibling_index * 243..(sibling_index + 1) * 243]);
            i = i + 1;
        }

        self.index = self.index + 1;

        Ok(Self::Signature::from_buf(state).index(self.index - 1))
    }
}

impl<S, K> MssPublicKey<S, K>
where
    S: Sponge + Default,
    K: PublicKey,
{
    pub fn depth(mut self, depth: u8) -> Self {
        self.depth = depth;
        self
    }
}

impl<S, K> PublicKey for MssPublicKey<S, K>
where
    S: Sponge + Default,
    K: PublicKey,
    <K as PublicKey>::Signature: RecoverableSignature,
{
    type Signature = MssSignature<S>;
    type Error = MssError;

    fn verify(&self, message: &[i8], signature: &Self::Signature) -> Result<bool, Self::Error> {
        let mut sponge = S::default();
        let ots_signature =
            K::Signature::from_buf(signature.state[0..((signature.state.len() / 6561) - 1) * 6561].to_buf());
        let siblings: TritBuf = signature.state.chunks(6561).last().unwrap().to_buf();
        let ots_public_key = ots_signature
            .recover_public_key(message)
            .map_err(|_| Self::Error::FailedUnderlyingPublicKeyRecovery)?;
        let mut hash: TritBuf = TritBuf::zeros(243);

        hash.copy_from(ots_public_key.trits());

        let mut j = 1;
        for (i, sibling) in siblings.chunks(243).enumerate() {
            if self.depth - 1 == i as u8 {
                break;
            }

            if signature.index & j != 0 {
                sponge.absorb(sibling).map_err(|_| Self::Error::FailedSpongeOperation)?;
                sponge.absorb(&hash).map_err(|_| Self::Error::FailedSpongeOperation)?;
            } else {
                sponge.absorb(&hash).map_err(|_| Self::Error::FailedSpongeOperation)?;
                sponge
                    .absorb(&sibling)
                    .map_err(|_| Self::Error::FailedSpongeOperation)?;
            }
            sponge
                .squeeze_into(&mut hash)
                .map_err(|_| Self::Error::FailedSpongeOperation)?;
            sponge.reset();

            j <<= 1;
        }

        Ok(hash == self.state)
    }

    fn from_buf(state: TritBuf) -> Self {
        Self {
            state,
            // TODO OPTION
            depth: 0,
            _sponge: PhantomData,
            _key: PhantomData,
        }
    }

    fn as_bytes(&self) -> &[i8] {
        &self.state.as_i8_slice()
    }

    fn trits(&self) -> &Trits {
        &self.state
    }
}

impl<S: Sponge + Default> MssSignature<S> {
    pub fn index(mut self, index: u64) -> Self {
        self.index = index;
        self
    }
}

// TODO default impl ?
impl<S: Sponge + Default> Signature for MssSignature<S> {
    fn size(&self) -> usize {
        self.state.len()
    }

    fn from_buf(state: TritBuf) -> Self {
        Self {
            state,
            // TODO OPTION
            index: 0,
            _sponge: PhantomData,
        }
    }

    fn as_bytes(&self) -> &[i8] {
        self.state.as_i8_slice()
    }

    fn trits(&self) -> &Trits {
        &self.state
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    use crate::{
        seed::Seed,
        wots::{
            WotsPrivateKeyGenerator,
            WotsPrivateKeyGeneratorBuilder,
            WotsPublicKey,
            WotsSecurityLevel,
        },
    };

    use iota_crypto_preview::{
        CurlP27,
        CurlP81,
        Kerl,
    };
    use iota_ternary_preview::{
        T1B1Buf,
        TryteBuf,
    };

    #[test]
    fn mss_generator_missing_depth_test() {
        let wots_private_key_generator = WotsPrivateKeyGeneratorBuilder::<Kerl>::default()
            .security_level(WotsSecurityLevel::Low)
            .build()
            .unwrap();
        match MssPrivateKeyGeneratorBuilder::<Kerl, WotsPrivateKeyGenerator<Kerl>>::default()
            .generator(wots_private_key_generator)
            .build()
        {
            Ok(_) => unreachable!(),
            Err(err) => assert_eq!(err, MssError::MissingDepth),
        }
    }

    #[test]
    fn mss_generator_invalid_depth_test() {
        let wots_private_key_generator = WotsPrivateKeyGeneratorBuilder::<Kerl>::default()
            .security_level(WotsSecurityLevel::Low)
            .build()
            .unwrap();
        match MssPrivateKeyGeneratorBuilder::<Kerl, WotsPrivateKeyGenerator<Kerl>>::default()
            .generator(wots_private_key_generator)
            .depth(21)
            .build()
        {
            Err(MssError::InvalidDepth(depth)) => assert_eq!(depth, 21),
            _ => unreachable!(),
        }
    }

    #[test]
    fn mss_generator_missing_generator_test() {
        match MssPrivateKeyGeneratorBuilder::<Kerl, WotsPrivateKeyGenerator<Kerl>>::default()
            .depth(5)
            .build()
        {
            Ok(_) => unreachable!(),
            Err(err) => assert_eq!(err, MssError::MissingGenerator),
        }
    }

    fn mss_wots_generic_signature_verify<S>(public_key: &str, message: &str, signature: &str, depth: u8, index: u64)
    where
        S: Sponge + Default,
    {
        let public_key_trits = TryteBuf::try_from_str(public_key)
            .unwrap()
            .as_trits()
            .encode::<T1B1Buf>();
        let message_trits = TryteBuf::try_from_str(message).unwrap().as_trits().encode::<T1B1Buf>();
        let signature_trits = TryteBuf::try_from_str(signature)
            .unwrap()
            .as_trits()
            .encode::<T1B1Buf>();

        let public_key = MssPublicKey::<S, WotsPublicKey<S>>::from_buf(public_key_trits).depth(depth);
        let signature = MssSignature::<S>::from_buf(signature_trits).index(index);
        let valid = public_key.verify(message_trits.as_i8_slice(), &signature).unwrap();

        assert!(valid);
    }

    #[test]
    fn mss_wots_kerl_sec_1_signature_verify_test() {
        const PUBLIC_KEY: &str = "ECRGOIGKMFCNJPILB9GRUN9WIFOXY9GPKLSJV9UUQINIOHWKYJRZEQ9IHTS9HMFCMQBGRNODBIWTPILGC";
        const MESSAGE: &str = "KEWPSJHHGOICFXVGNUNRUDSKDUKNWGADKUFOFYVTZVGBVLWGIQBOICNNZIMWAXMV9RRMWSYGIABIBZUZ9";
        const SIGNATURE: &str = "DJ9WGAKRZOMH9KVRCHGCDCREXZVDKY9FXAXVSLELYADXHQCQQSMQYAEEBTEIWTQDUZIOFSFLBQQA9RUPXZ9THOGJIBPKN9XLYMNYMWHWRKJMDTGM9BNFDZQH9IVIOGSOMNUBDAGUMWECIQX9YVLNIXPXYTAACLZRIYPFVDVVDGQXCROYORAPAWIOQGHRVWNBXKAAGBGGYOORIUDBMYYZXTCUHDYFDZOHOERAOP9VCNKEULPU9ZCVKOMSYNCOPXTKTTFLWHQKEVNIAKLPKJ9YHBZDBQZDSAJYGVVSKMQZ9OJNBDUDJTGAE9OLPACMMX9WLVC9TWJRRGNLQJPJMEPBAFBNYJ9CWMTLTWIHISDMKRMUUHSPLIXMWYIMBAUOFTKMQSSBZOXTKKBADHUJFCQVYJJCAUGAEJJPJWWFWCZNHRFZZLMQLDVRQAVNHJBOXGZCWQZCLKDIDXSAHYOCSOUIHMIRTM9PHPTTGWUCJWNYPSIGTRQSUWQMFCXAKNJZZUCMGQUDJWZJRSLTHPIPVLMKZRTDJBGHQOSUXAENIGPKRBSZPAPFAGNPBXXHZR9SEWVCRSGUXIJLKSAJVCJDBJXJY9M9LVLWJAMHHNGAIVZ9DFGOFGPHLVDSDEGPNJZWVNGHKWEUFQRCMEGNLJMAFJKIAZBRPUDZTFLGRLADIBRNNIGWAKCCZD9KCFRX9ENNXGR9MBCDFJWUCZUMPOFW9GWF9GRBDVHWOLSXVWDIVKBOARUPCZSLVD9UNSKLDLJGLPHZR9KFSSGLRCHMESLBYUDIJTGPARIZFQROWSRZOZAJW9TPYIA9YHECNANSTMNLBUWJZVLTYAILPGJLCUNGXQNGBRXCBFCONWEIDXD9OQIWNCJZDFXOAVOVOUMGTOYB9ATJLKPVRHWPHGZSBPMEUWNDZGVMZYVAFQT9YGBGXDBDCTLTHBJEYDOZPLAAZCMFKHAQ9CAXVGZUTJYDMPL9DIMAUATSIOSHWJWAVPWIQIMXOLAYEIUGDISTOCIGGPA9WNVOSDDXVPOMFZKNKMSNIMXKCTGPNCRO9NQFYXVRTPSXHRRDGHMKNLFEPKAXDZLOCSFCVMIBEIQMJTBHWUHXNH9WGSKVCRBDRXRWAURDMNSKFLGMPXQEBXKKENSUKRZMQZUMNHJYWEZXIRPEPSKPC9JRGNYWAJFPN9AZKGYZCHVBCHHPTLXOURSVUHCM9QDACGWBDVTMNZKNVTOJSINYRDYNRPCMEBDUMUXFRCPYRHXOHDFGJFXOETGT9TOJVNWBEYXSK9PVVYZAS9WOSWJAH9UFXFFNWKWEUKXZM9BJDRXFFTQYRIVKWVFKCMSRDVNWVDPXWT9KOEBIDUKBE9MNKENKVABUSUDMIKZLCSBS9ZDTZNXRKCMIQTDEHYKEBPJUIGFZNCTSGOCQAVZIBFXKCREXDLWRBUDXWPHPYEDFLMSUBODJPSUIHCAHGLQZZHRQCMHRCSTKWCRRJHEVYXKGKIXRXSFREXRKQHHOIETURROFUTKYIDSQFAKZYWJKZESEYXIPKXCJLIPFCORSVH9WKFHJLUAQ9NSTRYBIFZIWZXMV9ZCCPTELAFRAMRFCOQHNOTLAXVTKLHEILANKBOTOQDACLYWXXKVFDIODLYNUIXQXPRFZTELIBDJUXJFPIQ9FRTGEXHOLOIVKCVTGLGHQNTONFRLAHDLHVSWDKBNH9ILD9IKJPNCBNAOASMFZVLUSOMPAHNIXRAKQDNTUZSCVNUOORADATIBHLHXTAADAUTPFTQEIRGWHMNBGSWPGMHAXNEUWVPETBYQKKTLBKVCEDYUSZ9KYMWMRYKDYWMFKJYEGHUSGDIVZWFFFQXAHSJYTRIAVQNXG9WXRIZFCZPWMOXZQRFAFMVRUCDSACJ9FRATCGNOPJRSGGTOCJIZIQNYOFKZWHBCRKLERIECSBLQND9ATPIFCSNPONGMI9LMRMKDHIFEGYRWPHBYHLS9ZXVE9JLJNIMCTGVTTCWQOYPREFLBJUAVBOE9JKHTWHKZPKCMPAGPFIVRWIBEXNPTEKCNDZOIOHLVWEGWSEKRSW9DUIXDKPQLQNZWGFMMCTGYKZWYHNRLQRDTIDFZRBVOQFCRMURK9CZS9IZPUSCIEPPCCTFKBS9FYXSPIKTNWXYENQDUNXLJWVBJBSQTUHIGDFRWEJEXPZYZTJAPZR99TTEXIIPGTIFRSLZKAKAAPACWEKAIAWVQRODDVMHOGGMSXEDAACFPSTWKARTNLZCBDISLZSJPAGCRZEDQBWIMQIUASDWYTZRZMYGZDEQLWCIJY9ULUIYQWWIFKEBZAIINGPMWCEFYWXQAPCYNOTL9HMYDNQMUEJJVDAQ9HRHZMI9NRJWLFM9SQIOFYXDBGCCBEWDQWUHIGFZKHJNRWMFSEFAWPM9AYNEQVUDKPPLK9WPLDFQBHLWWWGRTL9QCFMMMFKIEAORYLUEHFZMMSVVUHVNEJVTWKNUVOLSFEIFSZIDGOKPUXJADTAKWCYZZVQE9LWEDDRRKEFDHUUUPVTZHGBTBAAY9EQYGTNUFETRJBPPUP9HBJHXTPEUWDFDACXRQCAKGLBIK9GPGCVHUMRW9CCKMKJIAZEAWP9GMVRWQFTGDRGHZHPRSJTBRRPJQHMIDFJKSKKVVZWASKJG9FVWUGARVWXRBUFBSWNHPPXAKKX9MBGZUBRYCXWVSWWAEMTFGMMLYMGXSAWWQNJCGAXDVSKZTHW9NFKJHAQTKAOWHXBTLIUDLCQX9GPW999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999";
        const DEPTH: u8 = 8;
        const INDEX: u64 = 0;

        mss_wots_generic_signature_verify::<Kerl>(PUBLIC_KEY, MESSAGE, SIGNATURE, DEPTH, INDEX);
    }

    #[test]
    fn mss_wots_kerl_sec_3_signature_verify_test() {
        const PUBLIC_KEY: &str = "IDSWNWLGPFLAQADAEYUINRS9MBEMCYARHXHVSBOZDOBHPIPNVYUFFTQLNYGDZKKTEBHYOQXVQVHXBGXH9";
        const MESSAGE: &str = "NNZLXQKRAQBEUKNGVTKAHIIJUGSNNNNCASGGPNBJHKGTH9EGEAJZPKYL9WTNVYHFKDSQYERI9AYUFHYB9";
        const SIGNATURE: &str = "PGCWBHJEXWRBTMSIWGIDRXWNFTYGTTXPEAHWEFXKXGH9VA9JARHWUHUYEOOYENBHKNF9WLIFOH9HGQJVDOMSJ9XWTOVUDVDJBDCSKOYHM9QQFEHHMGUMXNBTWVBDCBBCAGEAKCWMHUUGBIXURKNMUSQTWQVRYGQAS9SJFAXLWXALFRWJUFNS9LDMOVUFVPHBZPDLYD9DKSWDY9TUOCCQQM9JXMTJRLRWEUBAQLJCOYJTASG9QBXKKGDTRWHQGATGSWDEEZUU9EJQACNU9CHIUIQRGLWGHFF9ABGE9SGYFRANEOZJLRHCYRWI9IT9FGYMKYGYMYDWRUOFMDGIR9EYNMIHWDBAJRBBYBBRL9YAWDGWUVGWLMKKVJQAAFVOTYMQNBAGZZFLVP9HHENEFZC9DPLOABBV9FKJCYJ9OH9BTBNEQTJSJICBWHUQVHSOISVIIRCUUEVJLJNLZUGBQUDXTUNS9HQYXHNAQWTQIWYYERXQKFZBEJGRDJJLZUNNTZDDEIYZBFWFF9ENLLS9TNPFXJARPBMYFOAQEP9GYBRNAAFOPBRSTOKPCUZQLQAMNWHVKZHVPHDLDRORAUTLQKZNPTIAERPPMDD99WTVZGGJWCLVOWXIJHEKAKINBSQQEBFIWTFIZINBGEOI9IRNCVY9QBQECCDCTOTAOEUCLJCM9MSNXJMHHNFGIBLT9KDMASEGKFPOAQQ9ZFXUSRCNZTGPOXHDWTGUAL9JYLMOOKLWCTNC9UKMEFSBZSV9DXBYTOHNMUEAJTHJNVBMCYIEDOICPHROXUVMA9UREPMUCPBPJDELBJEBZYOR9D9TKLEQ9G9GXRXPSDBDZXTTUAKJSAIRCFTCTQFRLUDQBPRXIYCDAXCUOZIGZKCZRWXSLLZLAJTCDCEUIPYASTQOLMSEYEIMVBEGKOBAPYJZMHPGSXPFUGYLWGZZPBVCBKZBBCSPGEGBZAJQUCHSMSNW9HFEDYHOJAUJBJSKYFSMTWTTF9HGERJZIYMMLYBRVLJLCQFMXNXUPILZSERKSNMVTLMSKJZRIAVN9IRIBNBYLU9MW9EVPBEESKHOWTETUTZRHKM9BKWRFLZGIREKNC9KSKHBPRLCHCIEXPZEXILOYXBOPFLMWHSCN9JWUGZPWCWFSBNFFOKBQKPIJSUXNN9UZQQDKKEWZQDRXPDYQJHPBZJTOLQEFDWCKFPQELRFWTVBZVVZTAXDRQIGJVFNBM9TZCKRE9WDFTFVPV9RYIIUDIOIPYUG9UZCSVTJCLLSAFQJKPZGTTQLQYIAYGWJUMARKHSXKGCOXKKBBVUSPZZETMAGQBPAH9WUXLUJQGZKQUYUWMPCFCHMNGNQL9XNMFVEKMIPVTBXLBNKGDFVLLHNAREIC9HLZHNZYMBJHWAGESNDANOLPXHE9CVDQPVJBQHLTZLOEBSHZPMTAMLDTTNVYJWGOXCSGUEFIMLY9CNCLJSAUDLMRRFXSESMPMXDZRVTHZGLKJCHUYHNBNGBUOPISW9TAGGJY9FUQVLX9BRDJGRQ9BHCMLCZPJZFLCFBPDCIHAGJNNT9OKHSRBHPPNPNFFKYBUTXKUOTHH9ASBNDCYTUQOJWMYUDFDGBRPRSKKHQIOERZPWZWWZQLSORYDOU9QV9UW9NZFVBGUCFBNGGJSPYDVPXO9ZBDR9WYJIYDRNKIJQTJCJOOAEQT9OTADGBDAZACMTWKWFDMSS9BGLSNKZVFTKDQDNSGBACUVFCQBJXMVNPIY9RUR9IUWTDUJFQWTJTWUQYNSSZB9QWGDPXJWNUSKWUYBVIC9BSMNHQVKXSOUSJUBZDOUOMEXAX9KDEWZSWRJZNQDBCXQZFEZJMCMPMOA9ZVCHLQDUCMFDNIFCHOSIJIPCKTFOPVUTZCTZWAWBIGMQRRQGCNQYMAYZXDPXBFAKVDEPMJUXPMRLEMXUMFNSMGHZ9MSEWKYPWOUPSIOZTEJYUFLRVHXCMCTQX9IVNKMTQYQCHW9VSSSXJBOJPBGBIDIIKNRUQBDZUSOMOSWRZCGBLZZWNJQFRUWPBPXHMPVGOEZATZSDRLULE9ECFUMNPWELRL9AAJCONHTXMXSSIXNQBCNNLGREGDPRDWBNOVCOJVTKDPVRAYLXMFMZHABVZXZAIKUJGHYGYQWTBIDFHLBCLRASI9MTFFFHLJOYSIOSGPFKPUDYAXVRVXGDERBTZIAEG9UFXMWDGOCMXZSOHSCAPPYKWUJQLXJCIKJOP9NJJXRLCDEBUWMAKTNLVSJEZNTDVRPXWWKEZXIKBWEQRIR9RDIKXNPTIKNQWWOMIAECGNCYWY9LDSZQBVAOIJFWBYFYKXPLWPNWGDVMOVTNYMH9ZLYUBXPCOWOHJEHBTWEX9XNBWKOTGKWYCTIIKTZSUJPPXNXZOS9USOUIPOAZFWZRMQKKOWSSRMMTIVYQHRIODKXAKPH9FSJNQ9ZUEJNUMHPOPINIUZGNAIDBWEDSGPDPXRWLNKCMJCGYQBDWIGULQKYKLPHQQDDHBWNRVEBXJDSBGWSXEJFBYVVNOIOOQOTKLJYVDVRQUZCVKFBPROB9VVSHLAEKEEJLQHHNZDQLNAKEHBVPDSKGNHXTZNA9WUXBTK99SZXZYRHHHGRZIRLRQEVQSGPVHIOPKP9T9AGGJBTFASXWMKAOFUUZYMRHBUXRBZAO9SGMACE9CXLXCQADLITOI9AWXSUXUPAYFVNIMUZAGCJLZGCKX9IFJQKSNAAG9YBZRJBGJFWBSYCYV99GOSLLMSAXJNQWMCCQWBARLWDDRXUYBUIKHTAOGWWXLTZKOCBYIGBKVFCHDAPQIBBMJFPCQMQCWZYAMGWRBTMBJNDCXP9ADBXSUBAROQYODUWKDSXFMPKANYEJYESWNCHVDKCDBCQXXCRRENIIABYT9WUMDWRVRPSLLS99HYAACBKEWJQXXEWMHXFAEPVQD9KTDZFIWTGBLEBWAYAHVRNLGKPHXFNFLSFWRIKX99OTIUQVFYA9YPJAJJEYGXFSINSXDGNPUKPERLCCSCPHU9WKCGNWMCQRXBTWRRXACOVLKPWSHOXKLRIRWBDMEEUJOOALMYZLIWPHSCWXHV9RNHTFAUSPRHZMR9OAJWFWQENFOFCPMVJEPBQAS9LJWDUP9WKFDWOZRREWX9TSNCCDCHNMVBYGCIF9VVVBWRKDRGJNQQLIP9CABUZRISLUJIZTWIEXGDLMBVIFVEUWSDGTRVLGOPTEUOWUY99G9OEKUFIORYCXXQMTSL9MCVUQJWMVTSVSEMXREZHBIETUVNNUACCVFUECTCKWMUUCLXOEY9LQFAYGUKWGFZWXTTVCXVYJYCRCCARSKWMIGBZONSJIAACSNZUFBVBASXEXHXIJEQTEANIDZSREFIUOEVRSKUGFHMNV9ZQDUFBZAXNHZLZTH9YSVRWNEXAZVXPYIPRSNRHNZUJPALZQHUO9QLAS9RX9QBIXMAGIRNM9GUUYOGUBQOXXLKQEZPZMHKNCITFOYBEUKAXHJLRRMMVF9SLJZDGQAM9UXQ9VMVLIHFUVSNLBVVMDLYULLELHMTFTWCNUEXXQFDIJSNWUDWYLWAXEUSVOJFCCCYZFLQNFFRTPOTVVUALPYZCTUSEQOKVHCTZETMDMFSNSNGDTUCEGJYYZTXGRMUZJTWCULIZWUIBOVJAISLCGJ9MFOJIDZROGYYXHEXAIIWOAVEJWXVVQEKZXVIT99LBOIKGZWNX9OPTPLSOQPEAOIRKYIMLXHYLPVPXG9AKFIOFBFEBLASXYENQ9WXIMKILNNJOAJHWODVRBGNCBGWT9BHZZYDPJXQQHSO9CNDSPNZZEIPVIMNAPVCSXTTFGJSRVDYTMIQAKFPUEZAT9AKAQDBMP9FKXLQZUDDSMKVK9ZKVWDAPAINQYCYHOFGOUCFRBLUYB9HGVWJPKQXLXF9JKQJLNMROEGCPFGXUSAIJNQ9YLVCCPUDJNJPNWLMYVDQPQXBTDEWMQVZYWDVKBTVEF9VOKDVHVZDZRWFK9WTMYU9ATRQJSKFDWXNPRDHQAYNGWXYFDKSIHFNA9UGGMVNCDMTZPEFBJAHGHMMDHEQLA9IGVDUGBQHJQORJ9ZWNEUJPVWVFDXKWDWLUHEVE9PYVYSMYPSYU9ZSMACZUAXCSAEJNVHOJGBRFYARSFZMYESXLNQOAB9HOH9VGQJTSAURKCMPYUFWZGEPHP9PUVFNHSCCHVVTGWYHLLVKIZCROMYQIYOCAHPONKRPEGJPKWTNQ9LIKTSHMKPESEZEPJETUUO99JDHXAUJIFEZCJLDGDTKZNLNEUSFYBWXHJILLHILNRXZKYAJDYYPNIJHIYXZ9RJKAGYLEVKVQDAIOCHGEKPQPCZOLSDXNFVFBDVCKKN9ZXJDSXGC9MMLCZGOBGDACJAHCOKJBDSTGANCAKNEVVTKARLTCPFRSGPPFPDIEDMCUEEFOGWUUXXQEPULAIFOEINWPDCMFXOJXCLQITCCMAUUDLGXDJDLVMOFEADOWJDVIXBBSINQMLGXGILLMHWIVHDBDTIHWOEETQZPJOSSWNWJYYGEDGMSNNJUDYTOATBYCACKRICFQALDFLDZGKFKCCLWZIKGWOGMEVKOITUUDCZCBQEDXWYGV9XARB9CKWNLCKVOZBWZAKAMAWNMLVGYDFQOARCUN9CA9YAKIZDBSFZXZRZJABWZLZGGNAXVOHZMXXMTCQZWIMSYYGS9QA9KLXYHLUFEGIFUVLAHKOINTMFMJZFUUWZKRT9GZZGSAWWCFUZUYNJXPWPKKYYZVUBCWSMWZFJEFZHDTLVACXIYPPFYWCFUDHZGTSOJPKNOADZPQPMYCJGSZRKANUOZRGKD9UAFAKUSDDPPPJORELCGTNZZQDBKZYWUBKM9GKGIBOJANBZFQMZKNVMLNZPQFFFVXYYUBHXQPBQZHCCZIP9Y99PIHURWQTJIJMA9L9UQIOMCWJLVCFTRQ9DNOWJKBEAANBCMLXX9DFYVDLVIYWAYPISVVYSMHYHHQMOVHMHLWPDWWMFYBUHNVSDU9BP9CSZVCLU9MEBETEJRNEQ9XPNGRPCMQSRNBZA9HUWBRCLEJEJZYVVFWGY9QMGCLYRVC9YBBKVDQNZDBTJGS9YZOH9XLNQFKPVWHEFPWOWOEPMRVBATFBOZAWIYVTPJMBCCBVSLBZTCXWQNGWLPCYXWHHHVUAAMABPWGIXMPIRPCWMKRPY9VYEGAHSIKDJT9GEXSPKFGUZWJBKRIGQSYUFFIRXWXFENFFHDHYROGHPVFHUXMMQETAHWJGJSVUUV9Z9CPWUTRDE9OYZAJXGXEJONLEUNSACYMXQBIBGELXFULFBU9AISG9IQSPASNHU9OWHILBVGYJAMEYMZOKMNFDBPMMORLENRVUOVZEBETIASNTBOHXUWAPAVJCZZGJUYAPTPREPLJOEW9OTD9DMALQOGUDZAKOYHEFALMNKGCKWECEQMSGDA9VPVHFEMYEVVHC9HVXQKQJABAYEGLFJVDWNCSOOPURHMYPGSWKSDFMCGTSZRYVQAKMATIRRGVIYHHTXATCXQHEJWOJMEVDXV9QCRGTGYQYDWCEJMRGSCHZOTERVNBDNCKZWUDZPXOOWDUXZ9GYQKNVUNZKUGOMPWDWGTTXGJIQ9XUOGKCEWMDKFYXIBUSAUGYJYJYUVEMAIKEXPLEBKMUEBECVIGYXJUQLISTYSXLQ9RNIHWVDWLXCXCYCUK9TAGBBFXCIYLOPRKZCKTDSMQVCUXU9WQCQ9GKPCN9PKUQYUAJDIAJKNTDWJH9PPGYGN9PVRKRMUBZZCW9SVGPLRRZDRADYMWGXWMWAFWLVGKVRI9WQGZIUHOXQJUCIBXQBB9VZNXDKT9ONCYCFZMTNHPJMJPUJZDWSPQLRAZNGV9QTKNYBZDSUQIPLVSQZHEOLUPFPRAXRHJSXADGQDBEVNPMVEC9TCYAGZSZASMGJLRZYWOKLUZULZZXTCBLZUQND9VPFJJHEDLOTRINEBFMPWSGDHKEOQACITVNPNTXKKQWCZLC9PYUHGSQEATWZRGZPELGOWUYVIHDYQPGJXAL9O9XNODA9GLDBYXXVPURQTQSWXZRWYRHOIQUUCRBZYTKSGSOMAXHRZSTUP9HRIMHNIBQJFCUBIWHIXHUWXATPHSVIFXMWJKKOBFMICGJGFJKLDPCVLFGHILHLIKFSDOPYFHEWVPGQISJQHKV9HBLKWX9JGDSUZWBUTPOHAINLBFNMUTEQ9NFFBKFSCZELK9XIXFTDZFQIYVIEULYEOEWMQWHZJZQR9SDBIOCXEPHXMCWCQSFCSDWY9QTJRDJDRFVJUCPBMRHIADTC9KZNDNUVDYSKQEDUX9BLFFNPNS9OCQHCHNMDYBRTOJNWAGWKLSTEAQHYCYEEYPKRUFPTWEWXMOQE9UKZYXHBFBHOHNDRYVTW9JKBIUZFF9OOFKFHPVCFYAEDUYSRMKKDCEOGNIJQYCYKVVUHUZRWMJFHVGTYFVFNXOIRXXZHBGMFQJEBUPSBKLAY9QTJZNIWMHYIQLVWF9TQMM9ZEDDKCCPEKDMJCJCKGDICZKINBYZGBCEUXAFMGWZTF9TUMVAEELCKMBESECIMAAVDRJWJBYEWDVB9HPVWNYUPUMOEFJETRHKD9N9KOAZRBFOQCXXMUBFPAVWZEEJ9FPOTLMLEMZ9EEJWKYMHDVXYFTKLRRCHWDWSCJTODJWIHWMFUTKGFLPDTFEYGCFAATPX9MTX9YCFWXWRMLZBNAAFOZMYUQZ9JYUXFQUXI9XKYVCTL9BIKJJPSVILKNDOHZWQQBG9QINKZPVG9EDU9WFVUZZQXZTCWWLHWIFQW9ECOJVGNYZFPXQAMKTVPEMAVLBQKUCBCQVFQFBDKATSOZGOQZJUKMOYZYHKECFQCR9NFEYCLFKFUMTSFZVYZYBFZQC9SAYIXTIPQJSKHTFEZ9NKPOYGRSOXROPRPGEJH9JPTLSI9VWQODQQZMAABCN9NNDUNO9WGWBSHLOXMTFWNTAFXAAMXBS9IHOPEPBRIBGDLKFCTEPSQWOZVKWJKZNGSTVYVJYKPCBUSIOY9FRPXCVBPCFMSKYDDXKYJJWMXMXDPZNAUNCKRCWDIHWGZUMUPMRBZKHSXEZSWWLXXVLLQBSVJFQWNSJZIA999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999";
        const DEPTH: u8 = 8;
        const INDEX: u64 = 4;

        mss_wots_generic_signature_verify::<Kerl>(PUBLIC_KEY, MESSAGE, SIGNATURE, DEPTH, INDEX);
    }

    #[test]
    fn mss_wots_curl27_sec_1_signature_verify_test() {
        const PUBLIC_KEY: &str = "ECFTA9SVHYH9MRRKJHQCBXNQKDBNGCWWDUAVILCOF9LMJNDPZLLTRYPKNHPVLXJYGGAXGOBYHZHGLNXKE";
        const MESSAGE: &str = "MMMMBNKRJWVAYO9ZCXYAODVATBOZPAQVLUH9FBCMQQOKTHKXOLIASYMMMMVRNNIQQAPVCUTMUVZAMYJA9";
        const SIGNATURE: &str = "XERUGTJZGCCJDUFSKVTNSZAENGJ9XBGRVVPVDVVWZMLQERHXNTSE9UPP99AIHZRUATYJUAVLEGAXVFVDRSFLQGSLWSNKKPBVSYXEMNAU9W9NLKYVSN9OLXS9URJFCR9GHINRIHDEOJNUDHADUWDFCAIESB9LJHOHFGWYYX9DDNPSQEXKGLJLKGALKTEZWOLIKJLWVTYVLUHYNON9UYKBXDKUTYJMQWHEZTNYNGXO9OMBLAPBDUCVWWVVAOQKNVLMZFMEFAX9MRZHEAFOPVBQEFHFEHXILKPJWVHZJUGGPQVHWYCRGJXMQOSNEHOZBKCCAHMRGZKBDDFSHJRNFSLXHVO9RQWJCPOBV9JUFZHAEQAEBIAQWNZNXHRIFKCVKOJSYTSACRIWJKLVIPYHGS9CGXFPTBBOCIV99O9GXZJAENKGLAOMKFBTXJRZOTWSMITMMI9GQFJQNYRHWDO9KUHHKDCRA9Z9MUBMLLPBOFSIGLAQAMHSSJTZSPTYJKPRJDVZLWGHFNRXSKOLVJLCOSLMBAVDMIUJCHOOAKJMHNRPHCFYTRPGIPIMNAYTAAKOJKFSXUMOYEZPWMXUGFJIOJVXQMGIXYKLOQWOCIOLIZTTOKVXVDRQAMBJVOQBDQHAAKDJKFRHXAFMPGXNLBKQIZUCTBBAZCKGCGOPXJHQSKGRZWTFTGALKESETAQKSXZWWKGFMGPTQFWHCXPJUN9MBTAVSAQSLNKVZHUKDDCEKLIEZJTOMBSPWIFUBTYCKOPKITSOEXENX9OHACHEH9WXBYMVSTYSAHEDWGTMGF9YKNFNJZUKJPYFEQ9HKIWNELFBBIHNGPUQQTCNAMZBZTRVDMQYJHV9LMRZZVVVKNTCJMDEEGQFXHRDHB9DMJDXEQWXLPPWJRIBYYXTAZNZSHL9RLFASMDLNVCZDEFIRDMEMAXQZMTPRWRWCZERT9EWUNBI9QRCHICMJEWVBHHRVDGSZCATFSHP9WFBQFMNPDDH9KYDVXIBVTOEMVTHZLDNASLKFDNQRXUNADCYOZOHBDQQPCHRHSNCAEANGSJVFUYLEJWCBF9OHM9GFRGKAO9VCJLDGXRCPECEOIKZPPFMDZCXDPCMNTHVELWLMIVAVZCZUGLFAZTLUYZKOIRPCPORDI9TCZZJU9XKZTCFVUGGFSCPKTKUGF9FJWBGQFJZQUT9FALIOJVEULADRINQHUQWNPWXSDHTPISNMHVHVSRZSTOIJUGOZBVPAGPBJVRLSABLMAH9OXG9CCTMRX9AYNUKBWZVNCINUYNZNJPUCJGQCQJHMHZOYFDWQEWRRYMOLUCBCHQMCVTPWZASBYQZUFUUKCYNVXNVHHAVVYBQPKHHKQWIJBRKZDZZFUDU9GJXUCKLXVVNEONUQSXNA9XUVCHOLIPHWQ9KBVIIGAXRHJBMTLGHQQSMMACAJSMHKZXECJPG9ELQIHTPUXDGAFYQTZACZMNUMDPSNSYUOKIUAOXNSJDTTZVAWJUQZITPTWSETMWXKEGDOKXVFUPSGUDMZZKRFPFWIPDFAJFFELZOXMZVJRGDFJAKCXQYPKVPNCENWJZVDOKNKJPXNGOP9KBP9RJEWTNCOABFJEOKONQSCCQRR9XCSXKTDJXVYJAVNUODHOXBZEUDFFTVCWHUPYV9RJZNVBAWCAL9XSGSMNFNADOAGFVEOXIAFRVEEFQKWEVTUVJHYINOSCHDWFSHJDATPUKJNBVFGKUQNUJLTHVNGVMXZWF9OCYKVJPKLME9EIWCIUBDBNHQJUMVXQJDJJDPJWHMVN9UCYKALOUSXZPZOGKVTGVAODHUTYVLEECAGNBRHBTQVOIMRGEHD9YJZITIEGRTDOA9FURPNRBDQAEPMLLUIHULV9AE99EADNBUYLDUKIBAIZHKFYJKGDQRKYTDZKOPCXG9WWBYOBZZBAHBOZVKXLPDZJRHBCSTCHMKSHGGYAXEVC9LWMZQISIJXAWOUVOULIHLAVTATZTZX9CRWJDYSGRPQVEBSDFVL9OAJLAHEISSYAKXKRTTSNHZPP9MDRCCPAIHWUYTKKJN9MZNGDJBDKJDEXYORFFJHXKK9MNGHPLYETLYGYBCJTFDPZGZTGICNEY9PFLWGIIGJ9CUOFAEXLHJNLHCTUYINWOHXAYJT9BTPDTFXIYEXBOWILI9AIDSQUVINLQMLEGLIGDYLWSRVCSRDCI9JTVKFYZXXVUPRXXCSPOLCHXQOBDCTBAGSGVVHANITAKBBMSWMWJ9TTTNF9HGMYXQEEDLDKXTDCFYXYLJJALBRJ9WMBYDBFGBHBUWYVDAHES9VSKVW9OXMOXMKNHAQPGRLFQRRGXRTTFPLYRZIYCDDJAHGTOLCUGHEHODTMKWUUAL9VFCISRXUKUTSZBPKPJEFSODZIBATZRPVFPGHDVXKOMIGTWTNYQKENYQKJFDCCRALOPQKCNZGQPRXQCAEYPZYZFSQMOCSLRTNTQWRYVFGPWMYKSUMKMMXCHPWRMF9QWKQJYYPKGJUJMBIAOQRII9PWKXUQOLNPCNKBCRDYM9FCGQ9BCMLIRHLIUANSYXBLZTLWGVIGJLWDWEQVLATWF9VJSQAKYEAZ9AAJMYEMXPXZDRXOOFRG9GGKARKNZZRTNOKZUBLPYNLPPLZMQPKACCHYNSQOBFXUYVWDGINAMIEODYZ9JTZQNRWCLGKCUBEGTKRIMESUPGYXQMIT9WWKQRVJNBOMXDOHBIOCNHWAICO9PQADCIEWLMFVZK9LXXMFWLWZ999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999";
        const DEPTH: u8 = 8;
        const INDEX: u64 = 4;

        mss_wots_generic_signature_verify::<CurlP27>(PUBLIC_KEY, MESSAGE, SIGNATURE, DEPTH, INDEX);
    }

    #[test]
    fn mss_wots_curl27_sec_3_signature_verify_test() {
        const PUBLIC_KEY: &str = "ROLHKXFNMSN9WWAWLWYKWXJUQ9BREXTKOMCZFT99JOLWNWBPUYSCZPLSOSOPICLKXXSDRAYEYRNTTKTNI";
        const MESSAGE: &str = "NKWSPOYLCE9NMZEWZBRLMZISBYBMMMKCOAUU9PQRHZYZPFVXPQHILAUQLHYKRPMTTIXGMSCTJWFVNMQX9";
        const SIGNATURE: &str = "JYIDCZPR9QNEUDENZCQQLBQNWPMQ9O9VOTTZNO9RWIDRQRUWZNURKZWLMHZRXUEYHUFCKUUCVMWMGBTEIAMPXQYYTB9S9YRHBEDWJRVPYCMFWTLUP9NWGSYQDYJAJMOGXERUYSGKFDKTFRWSRPGXUOAEPOFN9FURIJADBRKEZWQNDNJALFAQAZL9QJVGDK9KNIFHVLQI9ARIC9ZBRARPHFDGZGNU9SHCFWWCYUPXQRQADWBYMHNEZXXNDJYY9QTPXATBKHXBNHUNWCPARKWIJ9OLWVHJVU9SLVVUGECSZH9VDSCZJRJEIZVTSUVRLMJPKLQSJW9XUTAAXXCQ9FZVHKKFBXFDHUXUCAUGKIOWL9ZFQCPQT9WRWKWRPXRYXCJCNOKGRNBWBVYXISEIW9FLZBAVQ9SQNIXWZEVBEJSFD9LEGOYJMMGKWC9AESFF9HXETEHTXT9TULC9LIATTEVRVWRFKCUNJOOOAOMBZOMUYDUHVFWSPOTJACZAFCPGSZXRHPUCCNHEHHIFJMOCV9CXEPDT9G9DPWEH9LIDZKAYBXKFLTJQSUMBBJV9HHQQCX9TADOIVW9TBYGXSPDIATJEUBJK9OXBMIJWIMOC9OFUNIBEYSTGZCMNWZDKCPALIGEUAIQLSDEDUOXKJJWXXGEC9DTXWYRQPPGOUGYTSBXVOXUJIILLNLLSVRSJCFNUKEBINRLBFBOXUWPXYETMIWSGXXZMOJJMHLHHDQXZETJSPUBBQMDEVRQAUTLNLTNFEUURRGVUDJFESHKRJMKACUPPIYGQCZQVWZUOAYAAIOZVPRCYUFTMMIEUCCJZRQJDCWLUQIJYYSGTGJEESLME9DTTFJL9XHYDDSLBIEXYYQZ9BMSZMLIN9ANJXWOT9LHMCID9LIFKJZSAQOCWPBDCHI9BYF9SGKZFXZDXIPGDMEUDDRIRQUSYDVEYEEEWBAHJZKNZXVTTPGYVQWFSRBWZEVGYFWEQJONFGBWTLKKVPZ9CNHEYDKPK9YW9JBRXMMYQVHMHRUPPQQGZQRPLKPXRGSX9LQMETBEWAZKSVLKJFYTBZXVLDCKS9TZTZJFZQJPTB9RZJYJGACMFDPCOBSDMXEPFJDJXGEMLZKRLXMOQUYQACLMSUALGDGEFTRIYZBNYWKGKWTVXQXCXVDYRBZHMANNYATAPQKXEALVFEGS9MJZCTXOUCBNHKRWJNTKFMPFOI9LGEI9YEYAFYA9GRCTCBUP9ABJUABWZQKV9WETMQACUQKYSRXJWNUYZKDZQISRQPZOEUQFYYOTPWMZGYFQPTIW9ZEGKSBQYUUNBTFM9PGRKBPPV99TEXQAREHRUCWJ9ETABXDTBJDHPCCLEFSHKHMZPENXNQVHMHJAZVIAWR99UMFYGNBFMKIDVBMSBXANIXMEIPOUHPWBBXDMCETESPCB9AOQNGZVGKJHSSJFIRHJEKWLSCNYTIQXXZCGSYECRIGITGYIRRZRE9YGUTTSQARCCZBKBDJVZQLQDOVESVCXRSFXAAJAZPNURMOEUGMCRWBXNIFKKSOCPUMWP9UICRSZKZJNRUAV9VEJMOLLP9TECFBPINGTUZBZ9ARZIJTIQ9MTQOPNUNVIUHIXSDCFOJEWYJUAYJSKEVDQYXGH9IDMZDDHOBQ9NYUTPDRDPSTEIHXST9MPEQUGGMHTHECPLSH9CPPZHRDWPHVZGHCYFT9ESHTTPGRUBELXKOZHTG9LKLTPFGZAAGQKPEEOPZFKOWMPMAUSGBDYOZCHHFZZENDFVSFSKNCT9RQZXIIKTBP9MKRJYYMUDIPGVPFOXVFRKMBNRRTKO9STAAXVBHHQAWUGGYBUSSRKVMLLVBNLJOW99MJOUPZFXOPAMJFQLBURBWYIZLICWCNKJBCLQAAOSEGKCHJTYXMAFSRECUR9RKJW99NNHMOHWAEOJKTQCOENF9ROEYBSEAYFYNVEWEL9DTTAATCKVHEBMFMZPXWILAIEFNXRIWCSJRLYGZXFLVASNGSGKMQZFQJYDJUBOETECNGUQQXJXZYLMQCYKWXGIZTOPCIPYCVHAII9PTJLWAHHXORFQATHMTYLRTFFIS9WMNSLNET99QSCPLKXOGYMLEHRQQGFDRLHBRPKTUJGLKYENBIJGCTOSBYQ9GRYXB9OULPJHYTBIJPUL9YJNQVOGFZQZGIVKUYGOCVZDIDUIFKHDFXGMESJHRPNKSKJNJZLJNXUEKJGQZXWSYBGPEHPSFB9BXFHMMSLUPAHD9KAEMASLVNBOQ9NANOKHQBLFHIUIKKVBROGBYVABWEGRBYOPYPOJXYEKMEFGYBEPUTKBJWALHRIZILHATXXENUPQNQDOCBGFKEXNAYBHOQXF9WZUUPADXGRIRHLTZZBDFOGH9ADOY9QSMWOUARWMPJJEJZZNXAGGKWYBNQNZBFJFDIJKJTHBPRHI9UUGDVBPNTDXVIDGAEFBADUQRHVLEGZOTWBQIDVUVZYOOHXNTVOUUEMG9YTTSAXSINFPBIONVZSEFZNHZCXNZADLXXHNBTSEPHUA9IPUXESBXDLFLJWKJBXOX9HKQIOFKFQYJIMTQYJSBBHGVGTMTSQUTOPYVGSJPDIRRPIXLYASBAJWJIDTTTJYOXVSHASCFOTBCZYCTCCYAZB9TDLHFL9BJB9TGBEQRVJXVWSNNVJGYQXUJLCB9ZVRWCUVNFMNZZ9SBAVGENHMKJO9MGNKYRQTPFCETOLPDCPTWGMZJHKRKI9QWMBTQMLHI9FVHSYWGZQUIDA9C9NDAKGKXBIRZGMSSZAFPEOKDPNNUQIDDOBMSF9HHARDEGAHSDHFGSECSVTIGKKUJRCNGQNIYWMMULPNHZNJX9MWDIESXPTCGAAZQPKUPSLZGCFBXRUYSDYTQDJXPYBZVAWCXJTOVA9EJZG9XN9RAXAW9PBVTGMYJUOWLHMZNUXCJP9URUGJJYHKKFVZNNKPSXNSYIS9STBETRFKUM9QABQHFPFKTQLONWINQEYEJKWQASOBWBRCZRV9VDQJKMOTYLPYRBZANWFERYMPBOTDFWHFZJKFMOPVWABJWZDAFTIZNCZO99UBGHGFTXHZSMDVCXIX9UBPTYQYPEIHFXBONHHZHLYRCNVAEVTCZIHZVZZCCDMCPUFZEZVBWH9HSBFJATDLAGVOCGLBIVWJSRCLQQWTWNQSXHKRIQLLG9BCRSHNTSYRYWJJXVZDOHFSBXTOSFTNKSVEVPOTDYFYGHVAMUITVDSXDAARRFYETDRW9NW9CTOFNOFURWWTFDWNKVHRODCCPRFGIFPZBBFSZZHDAEZ9BOFTVFMUASHFRCVFHSDKQKILHUUMUK9ZZIHZTREQGXLLPHDNUOGOVNUEGYDHQYNQ9XWHCRJ9IWXJUKQYPDSHWCAVVWZNYSVGBPIGFFMT9PGHKXYCAZVCUOQVFWPOXES9SHNZSEBQAHHZRJHMBGJ9EJAMZKFQEIFTSTCOFBWEVMXGGJZYNFOAAFFVRXIMFCBRNFHIXMDKLRJIOJGXQABDVXKKICKXMNDWIQOPGFYSRNVWWKMZTC9CQCCPAJIMAWQYTSS9SAFOWNLAOSXGR9WI9PYHBKGTTQFBSSZEW9FHTMBGFIWFCEBH9ZPU9YARCLGLIDDKPIHHUDOSE9YINTJHWAZOWACAJHXXV9ZWDKQRHXDKFCLGBT9TNIKYKNGEIJEKRRI9SHKL9TFVTOHMKRVVWSZIJWFLDLJHKDWPQVOEDZU9DF9JXNFVNUBI9JUBTTAKKR9WAF9AGTPVFDPSOCPXVSYJMHGGWLUBQQTJVJGPAFBWVYQTEBTENKJARVSJ9VCYVCLSHIRVOQVHDRLR9FSOWJ9FAKCULBQYXARKPGVPXFCCDTZEYPMI9OZUBNNDPLLKQW9COFNAKLUTJQBCWAPYICQAVGYAQOYRSWVHKDJQVPGFZWGDFMTPUIOTKDB9FSJSXPFYYNWRICNKUROBQHLYLPJIQBJFGHIUVQYKDMQNHHRXNVWXE9TZKRFNNVHCKZNVICCSSMGSQZTPVTCWRASVCNMIH9S9VGUPAHMSB9ZPUOVAFDPIHIRHMXKFDHJXUGDFP9IGGL9CRNNMVAL99HXZB9KIVUYMKAUSLNPBMMX9VEBGAKXFTURHKGYR9LQRAPGJZQAJKAAQTFEYXDFNLZKJKHCDPEOKNIRXKZIMPSTGKWWVYREWXUEAPPHLSVGSJTCBZWCCMXRSAKWBQTDDSWUKKQBSKANV9R9BAXEPMNRH9MLSQLZWPTUMD9SDTWPIXEGLYDWFJILKJFZE9EHXSFWWDUWWMCIOPXMFSPHBCYOTUWPDLQOFU9EUT9FXSCQJBFKZIJMKYYQGVVGGBPCJHKPLBYSCZJDEUKK9YIXESUEVJTUB9UGFMXTUVIUUKAMTRJXHUSIIBVAYPY9RBQAKFADROQYRJVSTWZMVPQ99EFXFIBRBGSOMPQFSO9PNEXNOTJEOI9F9VQJF9QHZUTLJJDBSEMBKVUPBEVLDIGBQIKYIPDBARIMCEYTW9LVW9PQMVIRRCIPOE9TMCCVPUO9MIAHHBVZEBHRUASOSSCKFJIKLLNGRTYGLYCMU9FPLPOUCHQEYYUPQXCMZWHXCYLFAVPWHXFYYKQVLSCHESVDUBSRHPPOOOVRSVQFCMBUYIAFNBERKQVXWLBKHDKYNWXLAAOCSKBIHHXZ9XRCJZELNCEXFWUKSHZLRXJAHFBXNEJOTSYPSTVHECBWKHDTRENPCDGPAHIQJMQKJPDNGUUPYPQRHJORGYRMAAKPVYZBP9CUBIJQQRQPSPCCVRJZCUJZQNQCKNPAWIXZHMWTCWDGPLAHRUNVS9QVOLYXEDZRMNDSCRLISGHI9SNCAGPICRAIBQNDILYQIAZO9RBKBYIDOAGKFOEJNUSEUECREDOYPH9EZIQVFKGVJPOHGLXCFUKJWDCKEQAZIKKKIHAUSFNNHOFZLMVSFDJPZYNTWLHLFBTASMFQGTODHYPKGUKRAHAZNRILYEBSYEFEUJWOYIAACENBHGJFACRWDZXOTOOBYFOZS9YSPSRMYZMKBMYSBMWCHJV9LXQQEASTNPVC9USWEQBWHDGXNNYMCMUIHWANCPSRLWPXNHDOLMTMXBLRWXWK9ASDQNGFAJJPNFMTPQERZF9FY9ENZSKDQXXSBABCNK9FSMTEFLXHHXIWSKEXY9EU9QYZOHXGHAYDVDZJH9YWAXXBSUURBBIXYSIEAOAGBVP9F9NJBPN9AJAYONVNRIWOUHAZDGZ9NKXHOIWBTQLXRRQCHG9DQNZYXPXKPPOHMNMWTVEETFLKIMKUDOKMKCW99T9OTNTXBYYHUKUQUYJPRCPDMWIRHYMTXHQWVDHUBXYXKAFU9ZDODFXAZCTVJPTZALFKIEEX9KFNQXORIVYSNQDXEDTQ9LCCSWGSVGJADOZWVXYPVYGV9MSKWWHQFSWSQNOUWVWIKAVDOCTVNTXNGRAO9TLMPRUR9FFZWTAGANOTKNG9OPINIYDNAOPYNLGQMDUSGYEZZWAEYE99ZWVDJHBYSOOXFYFCGISWCTMFUOG9OJVDXEDIOOEF9HVZWQVWANYKNJIYARMDHNDWTZMNFOFGUVVETUBPIDRRZCGYDEKVJQVUHWJSQLBN9VMWONIBABYFLHDNYSNJMLEZKBAVRXYWAYQIWXBTSMUINPOLKNAWNDEWPTAQFYRCLABXL9GLSJBNBWXYDLYOLYVNV9UAFLDHNAELXBYQXERGHAYDRDHAYEUXXTXHQYTOIHDLRROCFJCR9CVWJPLXKAEFPPHWWQPKNZWSWI9WWYGWKUKXMPLZSWDJGRRGANQF9YVNFGIYRCIDHSIU9TUGNHRRTCXVQFNVMUM9GRJFQKDPKCTVQRBIYVIVFBPLVBNIBTKBMGRDDPEYQNNWYFBZEHWCLNZMKZUXQTGOXRPNWYHCWSCHUUNYCTRWBZXVJECIMWTAUAJFTC99AUNEZIRJEPYADMYNW9HFQHGX9QYMGRCLUTQLIHOGAYWRVJVOJZERUPFTOOXQCFEEIXHFBVDITQCPMCVXDNWHIBESNGDBUJHZALMVOOTH9YLFMEZQTPUQBVD9JPKUVBDDMNLRZOFTNLNWKEMRRYCHCXGRSPWMRISRUHOTOJPUCXJZZMZRSBDNVDNWZQLAZWTVJPFUARURHHGOZPBOICYQHY9EIBSZFZSEVDUGKETNVLTKYCGGHNYQYBF9OWDHMOVT9FPYWCVSMBDRTGTBVGPRMVFVWLAZISLEJWLHZWDGYWRZBEHBMNOELYKIMGHGBISMKNLLISNOA9RMFBLXDKNEVVSARAZUDYPVMGOKMPWOIKDHWCFTOMEGPPCALOE9NC9DEFVMUOFFQQJDIPAXOESW9LOYANYLHTVYQBAOCJYDWJKAMPTVRRXAJPPMFFMYNXHBBLLQ9IMMRSCSQXPAGR9BSRZXGZJYVNCWPADSHXITMPBBVMDUEYIMKPJOWBFIUZJYWHFCKRPEU9FZIYNSRZJP9ECGKSYLV9LEFPPEFA9VYBV9TZUXXVUYMGDBTCDHIUTWMCB9NGJBPXGTPNIOHLWNTQIKINRKCOAWYDIQLPYPQDSSSLQDIDMKZDRFHZZACOPWAQJLQXSCAJXNAUPPNLH9XYYUFRNXZS9XKXWUVVYVB9YRSGOLHFGPBKVYMVHCNKPBEAGWWUE9ROVFYHXAUZAOPLNNQQTQXNBXWJMJVQZEQWSZAQYUQHKQGJTSHLXBR9PUVQUWSG9GUMVVXDKZOZEJTAEJHMTOOWUWTO9NUOKL9MIJDSW9HZMLWEJYJTKHRDVBPWUTKJI9GBQZUQRMNDMFTDHJJKPGZVMNYAKXGHQIQPLPSMJOGIIMVHXMYNPTFYKEFWYHBIEASGBYUD9GFIBUIJBKNJCOAGNDDKHGMNWFBRDXUVIZBBENU9QQAZU9SRLVADEWUIHKKOCERSDEGVFKDXYAQDKGLVKVNWXJ9PVIUD9RYYATRM9AAKSPVMDGBNIAMZPWXALNDBHWUBNQWVMIAJIFCAEOSETTEAZ9GBCXP9EPSKBQMZPDPQXOKVRBIWJTMRLWJAJJFPICRQFKGXYYIERERVKRDYTLUNLQNJYHFEDRRQJHYSGLANFGBVAZJLKOYJMJHPJACMMMCQNPZJEHGRYLXSTADGKLVXKSD999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999";
        const DEPTH: u8 = 8;
        const INDEX: u64 = 4;

        mss_wots_generic_signature_verify::<CurlP27>(PUBLIC_KEY, MESSAGE, SIGNATURE, DEPTH, INDEX);
    }

    fn mss_wots_generic_roundtrip_test<S, G>(generator: G)
    where
        S: Sponge + Default,
        G: PrivateKeyGenerator + Default,
        <<<G as PrivateKeyGenerator>::PrivateKey as PrivateKey>::PublicKey as PublicKey>::Signature:
            RecoverableSignature,
        <<G as PrivateKeyGenerator>::Seed as Seed>::Error: std::fmt::Debug,
    {
        const SEED: &str = "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN";
        const MESSAGE: &str = "CHXHLHQLOPYP9NSUXTMWWABIBSBLUFXFRNWOZXJPVJPBCIDI99YBSCFYILCHPXHTSEYSYWIGQFERCRVDD";
        const DEPTH: u8 = 4;

        let seed_trits = TryteBuf::try_from_str(SEED).unwrap().as_trits().encode::<T1B1Buf>();
        let seed = G::Seed::from_buf(seed_trits).unwrap();
        let message_trits = TryteBuf::try_from_str(MESSAGE).unwrap().as_trits().encode::<T1B1Buf>();

        // todo try with not recover
        let mss_private_key_generator = MssPrivateKeyGeneratorBuilder::<S, G>::default()
            .depth(DEPTH)
            .generator(generator)
            .build()
            .unwrap();
        let mut mss_private_key = mss_private_key_generator.generate(&seed, 0).unwrap();
        let mss_public_key = mss_private_key.generate_public_key().unwrap();

        for _ in 0..(1 << DEPTH - 1) {
            let mss_signature = mss_private_key.sign(message_trits.as_i8_slice()).unwrap();
            let valid = mss_public_key
                .verify(message_trits.as_i8_slice(), &mss_signature)
                .unwrap();

            assert!(valid);
            //  TODO invalid test
        }
    }

    #[test]
    fn mss_kerl_wots_kerl_roundtrip_test() {
        for s in [
            WotsSecurityLevel::Low,
            WotsSecurityLevel::Medium,
            WotsSecurityLevel::High,
        ]
        .to_vec()
        .into_iter()
        {
            let wots_private_key_generator = WotsPrivateKeyGeneratorBuilder::<Kerl>::default()
                .security_level(s)
                .build()
                .unwrap();
            mss_wots_generic_roundtrip_test::<Kerl, WotsPrivateKeyGenerator<Kerl>>(wots_private_key_generator);
        }
    }

    #[test]
    fn mss_kerl_wots_curl27_roundtrip_test() {
        for s in [
            WotsSecurityLevel::Low,
            WotsSecurityLevel::Medium,
            WotsSecurityLevel::High,
        ]
        .to_vec()
        .into_iter()
        {
            let wots_private_key_generator = WotsPrivateKeyGeneratorBuilder::<CurlP27>::default()
                .security_level(s)
                .build()
                .unwrap();
            mss_wots_generic_roundtrip_test::<Kerl, WotsPrivateKeyGenerator<CurlP27>>(wots_private_key_generator);
        }
    }

    #[test]
    fn mss_kerl_wots_curl81_roundtrip_test() {
        for s in [
            WotsSecurityLevel::Low,
            WotsSecurityLevel::Medium,
            WotsSecurityLevel::High,
        ]
        .to_vec()
        .into_iter()
        {
            let wots_private_key_generator = WotsPrivateKeyGeneratorBuilder::<CurlP81>::default()
                .security_level(s)
                .build()
                .unwrap();
            mss_wots_generic_roundtrip_test::<Kerl, WotsPrivateKeyGenerator<CurlP81>>(wots_private_key_generator);
        }
    }

    #[test]
    fn mss_curl27_wots_kerl_roundtrip_test() {
        for s in [
            WotsSecurityLevel::Low,
            WotsSecurityLevel::Medium,
            WotsSecurityLevel::High,
        ]
        .to_vec()
        .into_iter()
        {
            let wots_private_key_generator = WotsPrivateKeyGeneratorBuilder::<Kerl>::default()
                .security_level(s)
                .build()
                .unwrap();
            mss_wots_generic_roundtrip_test::<CurlP27, WotsPrivateKeyGenerator<Kerl>>(wots_private_key_generator);
        }
    }

    #[test]
    fn mss_curl27_wots_curl27_roundtrip_test() {
        for s in [
            WotsSecurityLevel::Low,
            WotsSecurityLevel::Medium,
            WotsSecurityLevel::High,
        ]
        .to_vec()
        .into_iter()
        {
            let wots_private_key_generator = WotsPrivateKeyGeneratorBuilder::<CurlP27>::default()
                .security_level(s)
                .build()
                .unwrap();
            mss_wots_generic_roundtrip_test::<CurlP27, WotsPrivateKeyGenerator<CurlP27>>(wots_private_key_generator);
        }
    }

    #[test]
    fn mss_curl27_wots_curl81_roundtrip_test() {
        for s in [
            WotsSecurityLevel::Low,
            WotsSecurityLevel::Medium,
            WotsSecurityLevel::High,
        ]
        .to_vec()
        .into_iter()
        {
            let wots_private_key_generator = WotsPrivateKeyGeneratorBuilder::<CurlP81>::default()
                .security_level(s)
                .build()
                .unwrap();
            mss_wots_generic_roundtrip_test::<CurlP27, WotsPrivateKeyGenerator<CurlP81>>(wots_private_key_generator);
        }
    }

    #[test]
    fn mss_curl81_wots_kerl_roundtrip_test() {
        for s in [
            WotsSecurityLevel::Low,
            WotsSecurityLevel::Medium,
            WotsSecurityLevel::High,
        ]
        .to_vec()
        .into_iter()
        {
            let wots_private_key_generator = WotsPrivateKeyGeneratorBuilder::<Kerl>::default()
                .security_level(s)
                .build()
                .unwrap();
            mss_wots_generic_roundtrip_test::<CurlP81, WotsPrivateKeyGenerator<Kerl>>(wots_private_key_generator);
        }
    }

    #[test]
    fn mss_curl81_wots_curl27_roundtrip_test() {
        for s in [
            WotsSecurityLevel::Low,
            WotsSecurityLevel::Medium,
            WotsSecurityLevel::High,
        ]
        .to_vec()
        .into_iter()
        {
            let wots_private_key_generator = WotsPrivateKeyGeneratorBuilder::<CurlP27>::default()
                .security_level(s)
                .build()
                .unwrap();
            mss_wots_generic_roundtrip_test::<CurlP81, WotsPrivateKeyGenerator<CurlP27>>(wots_private_key_generator);
        }
    }

    #[test]
    fn mss_curl81_wots_curl81_roundtrip_test() {
        for s in [
            WotsSecurityLevel::Low,
            WotsSecurityLevel::Medium,
            WotsSecurityLevel::High,
        ]
        .to_vec()
        .into_iter()
        {
            let wots_private_key_generator = WotsPrivateKeyGeneratorBuilder::<CurlP81>::default()
                .security_level(s)
                .build()
                .unwrap();
            mss_wots_generic_roundtrip_test::<CurlP81, WotsPrivateKeyGenerator<CurlP81>>(wots_private_key_generator);
        }
    }
}