diem_crypto/
multi_ed25519.rs

1// Copyright (c) The Diem Core Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4// Copyright 2021 Conflux Foundation. All rights reserved.
5// Conflux is free software and distributed under GNU General Public License.
6// See http://www.gnu.org/licenses/
7
8//! This module provides an API for the accountable threshold multi-sig
9//! PureEdDSA signature scheme over the ed25519 twisted Edwards curve as defined in [RFC8032](https://tools.ietf.org/html/rfc8032).
10//!
11//! Signature verification also checks and rejects non-canonical signatures.
12
13use crate::{
14    ed25519::{
15        Ed25519PrivateKey, Ed25519PublicKey, Ed25519Signature,
16        ED25519_PRIVATE_KEY_LENGTH, ED25519_PUBLIC_KEY_LENGTH,
17        ED25519_SIGNATURE_LENGTH,
18    },
19    hash::{CryptoHash, CryptoHasher},
20    traits::*,
21};
22use anyhow::{anyhow, Result};
23use core::convert::TryFrom;
24use diem_crypto_derive::{
25    DeserializeKey, SerializeKey, SilentDebug, SilentDisplay,
26};
27use mirai_annotations::*;
28use rand::Rng;
29use serde::Serialize;
30use std::{convert::TryInto, fmt};
31
32const MAX_NUM_OF_KEYS: usize = 32;
33const BITMAP_NUM_OF_BYTES: usize = 4;
34
35/// Vector of private keys in the multi-key Ed25519 structure along with the
36/// threshold.
37#[derive(
38    DeserializeKey, Eq, PartialEq, SilentDisplay, SilentDebug, SerializeKey,
39)]
40pub struct MultiEd25519PrivateKey {
41    private_keys: Vec<Ed25519PrivateKey>,
42    threshold: u8,
43}
44
45#[cfg(feature = "assert-private-keys-not-cloneable")]
46static_assertions::assert_not_impl_any!(MultiEd25519PrivateKey: Clone);
47
48/// Vector of public keys in the multi-key Ed25519 structure along with the
49/// threshold.
50#[derive(Clone, DeserializeKey, Eq, PartialEq, SerializeKey)]
51pub struct MultiEd25519PublicKey {
52    public_keys: Vec<Ed25519PublicKey>,
53    threshold: u8,
54}
55
56#[cfg(mirai)]
57use crate::tags::ValidatedPublicKeyTag;
58#[cfg(not(mirai))]
59struct ValidatedPublicKeyTag {}
60
61/// Vector of the multi-key signatures along with a 32bit [u8; 4] bitmap
62/// required to map signatures with their corresponding public keys.
63///
64/// Note that bits are read from left to right. For instance, in the following
65/// bitmap [0b0001_0000, 0b0000_0000, 0b0000_0000, 0b0000_0001], the 3rd and
66/// 31st positions are set.
67#[derive(Clone, DeserializeKey, Eq, PartialEq, SerializeKey)]
68pub struct MultiEd25519Signature {
69    signatures: Vec<Ed25519Signature>,
70    bitmap: [u8; BITMAP_NUM_OF_BYTES],
71}
72
73impl MultiEd25519PrivateKey {
74    /// Construct a new MultiEd25519PrivateKey.
75    pub fn new(
76        private_keys: Vec<Ed25519PrivateKey>, threshold: u8,
77    ) -> std::result::Result<Self, CryptoMaterialError> {
78        let num_of_keys = private_keys.len();
79        if threshold == 0 || num_of_keys < threshold as usize {
80            Err(CryptoMaterialError::ValidationError)
81        } else if num_of_keys > MAX_NUM_OF_KEYS {
82            Err(CryptoMaterialError::WrongLengthError)
83        } else {
84            Ok(MultiEd25519PrivateKey {
85                private_keys,
86                threshold,
87            })
88        }
89    }
90
91    /// Serialize a MultiEd25519PrivateKey.
92    pub fn to_bytes(&self) -> Vec<u8> {
93        to_bytes(&self.private_keys, self.threshold)
94    }
95}
96
97impl MultiEd25519PublicKey {
98    /// Construct a new MultiEd25519PublicKey.
99    /// --- Rules ---
100    /// a) threshold cannot be zero.
101    /// b) public_keys.len() should be equal to or larger than threshold.
102    /// c) support up to MAX_NUM_OF_KEYS public keys.
103    pub fn new(
104        public_keys: Vec<Ed25519PublicKey>, threshold: u8,
105    ) -> std::result::Result<Self, CryptoMaterialError> {
106        let num_of_keys = public_keys.len();
107        if threshold == 0 || num_of_keys < threshold as usize {
108            Err(CryptoMaterialError::ValidationError)
109        } else if num_of_keys > MAX_NUM_OF_KEYS {
110            Err(CryptoMaterialError::WrongLengthError)
111        } else {
112            Ok(MultiEd25519PublicKey {
113                public_keys,
114                threshold,
115            })
116        }
117    }
118
119    /// Getter public_keys
120    pub fn public_keys(&self) -> &Vec<Ed25519PublicKey> { &self.public_keys }
121
122    /// Getter threshold
123    pub fn threshold(&self) -> &u8 { &self.threshold }
124
125    /// Serialize a MultiEd25519PublicKey.
126    pub fn to_bytes(&self) -> Vec<u8> {
127        to_bytes(&self.public_keys, self.threshold)
128    }
129}
130
131///////////////////////
132// PrivateKey Traits //
133///////////////////////
134
135/// Convenient method to create a MultiEd25519PrivateKey from a single
136/// Ed25519PrivateKey.
137impl From<&Ed25519PrivateKey> for MultiEd25519PrivateKey {
138    fn from(ed_private_key: &Ed25519PrivateKey) -> Self {
139        MultiEd25519PrivateKey {
140            private_keys: vec![Ed25519PrivateKey::try_from(
141                &ed_private_key.to_bytes()[..],
142            )
143            .unwrap()],
144            threshold: 1u8,
145        }
146    }
147}
148
149impl PrivateKey for MultiEd25519PrivateKey {
150    type PublicKeyMaterial = MultiEd25519PublicKey;
151}
152
153impl SigningKey for MultiEd25519PrivateKey {
154    type SignatureMaterial = MultiEd25519Signature;
155    type VerifyingKeyMaterial = MultiEd25519PublicKey;
156
157    fn sign<T: CryptoHash + Serialize>(
158        &self, message: &T,
159    ) -> MultiEd25519Signature {
160        let mut bitmap = [0u8; BITMAP_NUM_OF_BYTES];
161        let signatures: Vec<Ed25519Signature> = self
162            .private_keys
163            .iter()
164            .take(self.threshold as usize)
165            .enumerate()
166            .map(|(i, item)| {
167                bitmap_set_bit(&mut bitmap, i);
168                item.sign(message)
169            })
170            .collect();
171
172        MultiEd25519Signature { signatures, bitmap }
173    }
174
175    #[cfg(any(test, feature = "fuzzing"))]
176    fn sign_arbitrary_message(&self, message: &[u8]) -> MultiEd25519Signature {
177        let mut signatures: Vec<Ed25519Signature> =
178            Vec::with_capacity(self.threshold as usize);
179        let mut bitmap = [0u8; BITMAP_NUM_OF_BYTES];
180        signatures.extend(
181            self.private_keys
182                .iter()
183                .take(self.threshold as usize)
184                .enumerate()
185                .map(|(i, item)| {
186                    bitmap_set_bit(&mut bitmap, i);
187                    item.sign_arbitrary_message(message)
188                }),
189        );
190        MultiEd25519Signature { signatures, bitmap }
191    }
192}
193
194// Generating a random K out-of N key for testing.
195impl Uniform for MultiEd25519PrivateKey {
196    fn generate<R>(rng: &mut R) -> Self
197    where R: ::rand::RngCore + ::rand::CryptoRng {
198        let num_of_keys = rng.gen_range(1..=MAX_NUM_OF_KEYS);
199        let mut private_keys: Vec<Ed25519PrivateKey> =
200            Vec::with_capacity(num_of_keys);
201        for _ in 0..num_of_keys {
202            private_keys.push(
203                Ed25519PrivateKey::try_from(
204                    &ed25519_dalek::SecretKey::generate(rng).to_bytes()[..],
205                )
206                .unwrap(),
207            );
208        }
209        let threshold = rng.gen_range(1..=num_of_keys) as u8;
210        MultiEd25519PrivateKey {
211            private_keys,
212            threshold,
213        }
214    }
215}
216
217impl TryFrom<&[u8]> for MultiEd25519PrivateKey {
218    type Error = CryptoMaterialError;
219
220    /// Deserialize an Ed25519PrivateKey. This method will also check for key
221    /// and threshold validity.
222    fn try_from(
223        bytes: &[u8],
224    ) -> std::result::Result<MultiEd25519PrivateKey, CryptoMaterialError> {
225        if bytes.is_empty() {
226            return Err(CryptoMaterialError::WrongLengthError);
227        }
228        let threshold =
229            check_and_get_threshold(bytes, ED25519_PRIVATE_KEY_LENGTH)?;
230
231        let private_keys: Result<Vec<Ed25519PrivateKey>, _> = bytes
232            .chunks_exact(ED25519_PRIVATE_KEY_LENGTH)
233            .map(Ed25519PrivateKey::try_from)
234            .collect();
235
236        private_keys.map(|private_keys| MultiEd25519PrivateKey {
237            private_keys,
238            threshold,
239        })
240    }
241}
242
243impl Length for MultiEd25519PrivateKey {
244    fn length(&self) -> usize {
245        self.private_keys.len() * ED25519_PRIVATE_KEY_LENGTH + 1
246    }
247}
248
249impl ValidCryptoMaterial for MultiEd25519PrivateKey {
250    fn to_bytes(&self) -> Vec<u8> { self.to_bytes() }
251}
252
253impl Genesis for MultiEd25519PrivateKey {
254    fn genesis() -> Self {
255        let mut buf = [0u8; ED25519_PRIVATE_KEY_LENGTH];
256        buf[ED25519_PRIVATE_KEY_LENGTH - 1] = 1u8;
257        MultiEd25519PrivateKey {
258            private_keys: vec![
259                Ed25519PrivateKey::try_from(buf.as_ref()).unwrap()
260            ],
261            threshold: 1u8,
262        }
263    }
264}
265
266//////////////////////
267// PublicKey Traits //
268//////////////////////
269
270/// Convenient method to create a MultiEd25519PublicKey from a single
271/// Ed25519PublicKey.
272impl From<Ed25519PublicKey> for MultiEd25519PublicKey {
273    fn from(ed_public_key: Ed25519PublicKey) -> Self {
274        MultiEd25519PublicKey {
275            public_keys: vec![ed_public_key],
276            threshold: 1u8,
277        }
278    }
279}
280
281/// Implementing From<&PrivateKey<...>> allows to derive a public key in a more
282/// elegant fashion.
283impl From<&MultiEd25519PrivateKey> for MultiEd25519PublicKey {
284    fn from(private_key: &MultiEd25519PrivateKey) -> Self {
285        let public_keys = private_key
286            .private_keys
287            .iter()
288            .map(PrivateKey::public_key)
289            .collect();
290        MultiEd25519PublicKey {
291            public_keys,
292            threshold: private_key.threshold,
293        }
294    }
295}
296
297/// We deduce PublicKey from this.
298impl PublicKey for MultiEd25519PublicKey {
299    type PrivateKeyMaterial = MultiEd25519PrivateKey;
300}
301
302#[allow(clippy::derive_hash_xor_eq)]
303impl std::hash::Hash for MultiEd25519PublicKey {
304    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
305        let encoded_pubkey = self.to_bytes();
306        state.write(&encoded_pubkey);
307    }
308}
309
310impl TryFrom<&[u8]> for MultiEd25519PublicKey {
311    type Error = CryptoMaterialError;
312
313    /// Deserialize a MultiEd25519PublicKey. This method will also check for key
314    /// and threshold validity, and will only deserialize keys that are safe
315    /// against small subgroup attacks.
316    fn try_from(
317        bytes: &[u8],
318    ) -> std::result::Result<MultiEd25519PublicKey, CryptoMaterialError> {
319        if bytes.is_empty() {
320            return Err(CryptoMaterialError::WrongLengthError);
321        }
322        let threshold =
323            check_and_get_threshold(bytes, ED25519_PUBLIC_KEY_LENGTH)?;
324        let public_keys: Result<Vec<Ed25519PublicKey>, _> = bytes
325            .chunks_exact(ED25519_PUBLIC_KEY_LENGTH)
326            .map(Ed25519PublicKey::try_from)
327            .collect();
328        public_keys.map(|public_keys| {
329            let public_key = MultiEd25519PublicKey {
330                public_keys,
331                threshold,
332            };
333            add_tag!(&public_key, ValidatedPublicKeyTag);
334            public_key
335        })
336    }
337}
338
339/// We deduce VerifyingKey from pointing to the signature material
340/// we get the ability to do `pubkey.validate(msg, signature)`
341impl VerifyingKey for MultiEd25519PublicKey {
342    type SignatureMaterial = MultiEd25519Signature;
343    type SigningKeyMaterial = MultiEd25519PrivateKey;
344}
345
346impl fmt::Display for MultiEd25519PublicKey {
347    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
348        write!(f, "{}", hex::encode(&self.to_bytes()))
349    }
350}
351
352impl fmt::Debug for MultiEd25519PublicKey {
353    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354        write!(f, "MultiEd25519PublicKey({})", self)
355    }
356}
357
358impl Length for MultiEd25519PublicKey {
359    fn length(&self) -> usize {
360        self.public_keys.len() * ED25519_PUBLIC_KEY_LENGTH + 1
361    }
362}
363
364impl ValidCryptoMaterial for MultiEd25519PublicKey {
365    fn to_bytes(&self) -> Vec<u8> { self.to_bytes() }
366}
367
368impl MultiEd25519Signature {
369    /// This method will also sort signatures based on index.
370    pub fn new(
371        signatures: Vec<(Ed25519Signature, u8)>,
372    ) -> std::result::Result<Self, CryptoMaterialError> {
373        let num_of_sigs = signatures.len();
374        if num_of_sigs == 0 || num_of_sigs > MAX_NUM_OF_KEYS {
375            return Err(CryptoMaterialError::ValidationError);
376        }
377
378        let mut sorted_signatures = signatures;
379        sorted_signatures.sort_by(|a, b| a.1.cmp(&b.1));
380
381        let mut bitmap = [0u8; BITMAP_NUM_OF_BYTES];
382
383        // Check if all indexes are unique and < MAX_NUM_OF_KEYS
384        let (sigs, indexes): (Vec<_>, Vec<_>) =
385            sorted_signatures.iter().cloned().unzip();
386        for i in indexes {
387            // If an index is out of range.
388            if i < MAX_NUM_OF_KEYS as u8 {
389                // if an index has been set already (thus, there is a
390                // duplicate).
391                if bitmap_get_bit(bitmap, i as usize) {
392                    return Err(CryptoMaterialError::BitVecError(
393                        "Duplicate signature index".to_string(),
394                    ));
395                } else {
396                    bitmap_set_bit(&mut bitmap, i as usize);
397                }
398            } else {
399                return Err(CryptoMaterialError::BitVecError(
400                    "Signature index is out of range".to_string(),
401                ));
402            }
403        }
404        Ok(MultiEd25519Signature {
405            signatures: sigs,
406            bitmap,
407        })
408    }
409
410    /// Getter signatures.
411    pub fn signatures(&self) -> &Vec<Ed25519Signature> { &self.signatures }
412
413    /// Getter bitmap.
414    pub fn bitmap(&self) -> &[u8; BITMAP_NUM_OF_BYTES] { &self.bitmap }
415
416    /// Serialize a MultiEd25519Signature in the form of
417    /// sig0||sig1||..sigN||bitmap.
418    pub fn to_bytes(&self) -> Vec<u8> {
419        let mut bytes: Vec<u8> = self
420            .signatures
421            .iter()
422            .flat_map(|sig| sig.to_bytes().to_vec())
423            .collect();
424        bytes.extend(&self.bitmap[..]);
425        bytes
426    }
427}
428
429//////////////////////
430// Signature Traits //
431//////////////////////
432
433impl TryFrom<&[u8]> for MultiEd25519Signature {
434    type Error = CryptoMaterialError;
435
436    /// Deserialize a MultiEd25519Signature. This method will also check for
437    /// malleable signatures and bitmap validity.
438    fn try_from(
439        bytes: &[u8],
440    ) -> std::result::Result<MultiEd25519Signature, CryptoMaterialError> {
441        let length = bytes.len();
442        let bitmap_num_of_bytes = length % ED25519_SIGNATURE_LENGTH;
443        let num_of_sigs = length / ED25519_SIGNATURE_LENGTH;
444
445        if num_of_sigs == 0
446            || num_of_sigs > MAX_NUM_OF_KEYS
447            || bitmap_num_of_bytes != BITMAP_NUM_OF_BYTES
448        {
449            return Err(CryptoMaterialError::WrongLengthError);
450        }
451
452        let bitmap = match bytes[length - BITMAP_NUM_OF_BYTES..].try_into() {
453            Ok(bitmap) => bitmap,
454            Err(_) => return Err(CryptoMaterialError::DeserializationError),
455        };
456        if bitmap_count_ones(bitmap) != num_of_sigs as u32 {
457            return Err(CryptoMaterialError::DeserializationError);
458        }
459
460        let signatures: Result<Vec<Ed25519Signature>, _> = bytes
461            .chunks_exact(ED25519_SIGNATURE_LENGTH)
462            .map(Ed25519Signature::try_from)
463            .collect();
464        signatures
465            .map(|signatures| MultiEd25519Signature { signatures, bitmap })
466    }
467}
468
469impl Length for MultiEd25519Signature {
470    fn length(&self) -> usize {
471        self.signatures.len() * ED25519_SIGNATURE_LENGTH + BITMAP_NUM_OF_BYTES
472    }
473}
474
475#[allow(clippy::derive_hash_xor_eq)]
476impl std::hash::Hash for MultiEd25519Signature {
477    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
478        let encoded_signature = self.to_bytes();
479        state.write(&encoded_signature);
480    }
481}
482
483impl fmt::Display for MultiEd25519Signature {
484    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
485        write!(f, "{}", hex::encode(&self.to_bytes()[..]))
486    }
487}
488
489impl fmt::Debug for MultiEd25519Signature {
490    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
491        write!(f, "MultiEd25519Signature({})", self)
492    }
493}
494
495impl ValidCryptoMaterial for MultiEd25519Signature {
496    fn to_bytes(&self) -> Vec<u8> { self.to_bytes() }
497}
498
499impl Signature for MultiEd25519Signature {
500    type SigningKeyMaterial = MultiEd25519PrivateKey;
501    type VerifyingKeyMaterial = MultiEd25519PublicKey;
502
503    fn verify<T: CryptoHash + Serialize>(
504        &self, message: &T, public_key: &MultiEd25519PublicKey,
505    ) -> Result<()> {
506        // Public keys should be validated to be safe against small subgroup
507        // attacks, etc.
508        precondition!(has_tag!(public_key, ValidatedPublicKeyTag));
509        let mut bytes = <T as CryptoHash>::Hasher::seed().to_vec();
510        bcs::serialize_into(&mut bytes, &message)
511            .map_err(|_| CryptoMaterialError::SerializationError)?;
512        Self::verify_arbitrary_msg(self, &bytes, public_key)
513    }
514
515    /// Checks that `self` is valid for an arbitrary &[u8] `message` using
516    /// `public_key`. Outside of this crate, this particular function should
517    /// only be used for native signature verification in Move.
518    fn verify_arbitrary_msg(
519        &self, message: &[u8], public_key: &MultiEd25519PublicKey,
520    ) -> Result<()> {
521        // Public keys should be validated to be safe against small subgroup
522        // attacks, etc.
523        precondition!(has_tag!(public_key, ValidatedPublicKeyTag));
524        match bitmap_last_set_bit(self.bitmap) {
525            Some(last_bit) if last_bit as usize <= public_key.length() => (),
526            _ => {
527                return Err(anyhow!(
528                    "{}",
529                    CryptoMaterialError::BitVecError(
530                        "Signature index is out of range".to_string()
531                    )
532                ))
533            }
534        };
535        if bitmap_count_ones(self.bitmap) < public_key.threshold as u32 {
536            return Err(anyhow!(
537                "{}",
538                CryptoMaterialError::BitVecError(
539                    "Not enough signatures to meet the threshold".to_string()
540                )
541            ));
542        }
543        let mut bitmap_index = 0;
544        // TODO use deterministic batch verification when gets available.
545        for sig in &self.signatures {
546            while !bitmap_get_bit(self.bitmap, bitmap_index) {
547                bitmap_index += 1;
548            }
549            sig.verify_arbitrary_msg(
550                message,
551                &public_key.public_keys[bitmap_index as usize],
552            )?;
553            bitmap_index += 1;
554        }
555        Ok(())
556    }
557}
558
559impl From<Ed25519Signature> for MultiEd25519Signature {
560    fn from(ed_signature: Ed25519Signature) -> Self {
561        MultiEd25519Signature {
562            signatures: vec![ed_signature],
563            // "1000_0000 0000_0000 0000_0000 0000_0000"
564            bitmap: [0b1000_0000u8, 0u8, 0u8, 0u8],
565        }
566    }
567}
568
569//////////////////////
570// Helper functions //
571//////////////////////
572
573// Helper function required to MultiEd25519 keys to_bytes to add the threshold.
574fn to_bytes<T: ValidCryptoMaterial>(keys: &[T], threshold: u8) -> Vec<u8> {
575    let mut bytes: Vec<u8> = keys
576        .iter()
577        .flat_map(ValidCryptoMaterial::to_bytes)
578        .collect();
579    bytes.push(threshold);
580    bytes
581}
582
583// Helper method to get threshold from a serialized MultiEd25519 key payload.
584fn check_and_get_threshold(
585    bytes: &[u8], key_size: usize,
586) -> std::result::Result<u8, CryptoMaterialError> {
587    let payload_length = bytes.len();
588    if bytes.is_empty() {
589        return Err(CryptoMaterialError::WrongLengthError);
590    }
591    let threshold_num_of_bytes = payload_length % key_size;
592    let num_of_keys = payload_length / key_size;
593    let threshold_byte = bytes[bytes.len() - 1];
594
595    if num_of_keys == 0
596        || num_of_keys > MAX_NUM_OF_KEYS
597        || threshold_num_of_bytes != 1
598    {
599        Err(CryptoMaterialError::WrongLengthError)
600    } else if threshold_byte == 0 || threshold_byte > num_of_keys as u8 {
601        Err(CryptoMaterialError::ValidationError)
602    } else {
603        Ok(threshold_byte)
604    }
605}
606
607fn bitmap_set_bit(input: &mut [u8; BITMAP_NUM_OF_BYTES], index: usize) {
608    let bucket = index / 8;
609    // It's always invoked with index < 32, thus there is no need to check
610    // range.
611    let bucket_pos = index - (bucket * 8);
612    input[bucket] |= 128 >> bucket_pos as u8;
613}
614
615// Helper method to get the input's bit at index.
616fn bitmap_get_bit(input: [u8; BITMAP_NUM_OF_BYTES], index: usize) -> bool {
617    let bucket = index / 8;
618    // It's always invoked with index < 32, thus there is no need to check
619    // range.
620    let bucket_pos = index - (bucket * 8);
621    (input[bucket] & (128 >> bucket_pos as u8)) != 0
622}
623
624// Returns the number of set bits.
625fn bitmap_count_ones(input: [u8; BITMAP_NUM_OF_BYTES]) -> u32 {
626    input.iter().map(|a| a.count_ones()).sum()
627}
628
629// Find the last set bit.
630fn bitmap_last_set_bit(input: [u8; BITMAP_NUM_OF_BYTES]) -> Option<u8> {
631    input
632        .iter()
633        .rev()
634        .enumerate()
635        .find(|(_, byte)| byte != &&0u8)
636        .map(|(i, byte)| {
637            (8 * (BITMAP_NUM_OF_BYTES - i) - byte.trailing_zeros() as usize - 1)
638                as u8
639        })
640}
641
642#[test]
643fn bitmap_tests() {
644    let mut bitmap = [0b0100_0000u8, 0b1111_1111u8, 0u8, 0b1000_0000u8];
645    assert!(!bitmap_get_bit(bitmap, 0));
646    assert!(bitmap_get_bit(bitmap, 1));
647    for i in 8..16 {
648        assert!(bitmap_get_bit(bitmap, i));
649    }
650    for i in 16..24 {
651        assert!(!bitmap_get_bit(bitmap, i));
652    }
653    assert!(bitmap_get_bit(bitmap, 24));
654    assert!(!bitmap_get_bit(bitmap, 31));
655    assert_eq!(bitmap_last_set_bit(bitmap), Some(24));
656
657    bitmap_set_bit(&mut bitmap, 30);
658    assert!(bitmap_get_bit(bitmap, 30));
659    assert_eq!(bitmap_last_set_bit(bitmap), Some(30));
660}