base64/
encode.rs

1use byteorder::{BigEndian, ByteOrder};
2
3use ::{chunked_encoder, Config, STANDARD};
4
5///Encode arbitrary octets as base64.
6///Returns a String.
7///Convenience for `encode_config(input, base64::STANDARD);`.
8///
9///# Example
10///
11///```rust
12///extern crate base64;
13///
14///fn main() {
15///    let b64 = base64::encode(b"hello world");
16///    println!("{}", b64);
17///}
18///```
19pub fn encode<T: ?Sized + AsRef<[u8]>>(input: &T) -> String {
20    encode_config(input, STANDARD)
21}
22
23///Encode arbitrary octets as base64.
24///Returns a String.
25///
26///# Example
27///
28///```rust
29///extern crate base64;
30///
31///fn main() {
32///    let b64 = base64::encode_config(b"hello world~", base64::STANDARD);
33///    println!("{}", b64);
34///
35///    let b64_url = base64::encode_config(b"hello internet~", base64::URL_SAFE);
36///    println!("{}", b64_url);
37///}
38///```
39pub fn encode_config<T: ?Sized + AsRef<[u8]>>(input: &T, config: Config) -> String {
40    let mut buf = match encoded_size(input.as_ref().len(), config) {
41        Some(n) => vec![0; n],
42        None => panic!("integer overflow when calculating buffer size"),
43    };
44
45    let encoded_len = encode_config_slice(input.as_ref(), config, &mut buf[..]);
46    debug_assert_eq!(encoded_len, buf.len());
47
48    String::from_utf8(buf).expect("Invalid UTF8")
49}
50
51///Encode arbitrary octets as base64.
52///Writes into the supplied output buffer, which will grow the buffer if needed.
53///
54///# Example
55///
56///```rust
57///extern crate base64;
58///
59///fn main() {
60///    let mut buf = String::new();
61///    base64::encode_config_buf(b"hello world~", base64::STANDARD, &mut buf);
62///    println!("{}", buf);
63///
64///    buf.clear();
65///    base64::encode_config_buf(b"hello internet~", base64::URL_SAFE, &mut buf);
66///    println!("{}", buf);
67///}
68///```
69pub fn encode_config_buf<T: ?Sized + AsRef<[u8]>>(input: &T, config: Config, buf: &mut String) {
70    let input_bytes = input.as_ref();
71
72    {
73        let mut sink = chunked_encoder::StringSink::new(buf);
74        let encoder = chunked_encoder::ChunkedEncoder::new(config);
75
76        encoder
77            .encode(input_bytes, &mut sink)
78            .expect("Writing to a String shouldn't fail")
79    }
80}
81
82/// Encode arbitrary octets as base64.
83/// Writes into the supplied output buffer.
84///
85/// This is useful if you wish to avoid allocation entirely (e.g. encoding into a stack-resident
86/// or statically-allocated buffer).
87///
88/// # Panics
89///
90/// If `output` is too small to hold the encoded version of `input`, a panic will result.
91///
92/// # Example
93///
94/// ```rust
95/// extern crate base64;
96///
97/// fn main() {
98///     let s = b"hello internet!";
99///     let mut buf = Vec::new();
100///     // make sure we'll have a slice big enough for base64 + padding
101///     buf.resize(s.len() * 4 / 3 + 4, 0);
102///
103///     let bytes_written = base64::encode_config_slice(s,
104///                             base64::STANDARD, &mut buf);
105///
106///     // shorten our vec down to just what was written
107///     buf.resize(bytes_written, 0);
108///
109///     assert_eq!(s, base64::decode(&buf).unwrap().as_slice());
110/// }
111/// ```
112pub fn encode_config_slice<T: ?Sized + AsRef<[u8]>>(
113    input: &T,
114    config: Config,
115    output: &mut [u8],
116) -> usize {
117    let input_bytes = input.as_ref();
118
119    let encoded_size = encoded_size(input_bytes.len(), config)
120        .expect("usize overflow when calculating buffer size");
121
122    let mut b64_output = &mut output[0..encoded_size];
123
124    encode_with_padding(&input_bytes, config, encoded_size, &mut b64_output);
125
126    encoded_size
127}
128
129/// B64-encode and pad (if configured).
130///
131/// This helper exists to avoid recalculating encoded_size, which is relatively expensive on short
132/// inputs.
133///
134/// `encoded_size` is the encoded size calculated for `input`.
135///
136/// `output` must be of size `encoded_size`.
137///
138/// All bytes in `output` will be written to since it is exactly the size of the output.
139fn encode_with_padding(input: &[u8], config: Config, encoded_size: usize, output: &mut [u8]) {
140    debug_assert_eq!(encoded_size, output.len());
141
142    let b64_bytes_written = encode_to_slice(input, output, config.char_set.encode_table());
143
144    let padding_bytes = if config.pad {
145        add_padding(input.len(), &mut output[b64_bytes_written..])
146    } else {
147        0
148    };
149
150    let encoded_bytes = b64_bytes_written
151        .checked_add(padding_bytes)
152        .expect("usize overflow when calculating b64 length");
153
154    debug_assert_eq!(encoded_size, encoded_bytes);
155}
156
157/// Encode input bytes to utf8 base64 bytes. Does not pad.
158/// `output` must be long enough to hold the encoded `input` without padding.
159/// Returns the number of bytes written.
160#[inline]
161pub fn encode_to_slice(input: &[u8], output: &mut [u8], encode_table: &[u8; 64]) -> usize {
162    let mut input_index: usize = 0;
163
164    const BLOCKS_PER_FAST_LOOP: usize = 4;
165    const LOW_SIX_BITS: u64 = 0x3F;
166
167    // we read 8 bytes at a time (u64) but only actually consume 6 of those bytes. Thus, we need
168    // 2 trailing bytes to be available to read..
169    let last_fast_index = input.len().saturating_sub(BLOCKS_PER_FAST_LOOP * 6 + 2);
170    let mut output_index = 0;
171
172    if last_fast_index > 0 {
173        while input_index <= last_fast_index {
174            // Major performance wins from letting the optimizer do the bounds check once, mostly
175            // on the output side
176            let input_chunk = &input[input_index..(input_index + (BLOCKS_PER_FAST_LOOP * 6 + 2))];
177            let output_chunk = &mut output[output_index..(output_index + BLOCKS_PER_FAST_LOOP * 8)];
178
179            // Hand-unrolling for 32 vs 16 or 8 bytes produces yields performance about equivalent
180            // to unsafe pointer code on a Xeon E5-1650v3. 64 byte unrolling was slightly better for
181            // large inputs but significantly worse for 50-byte input, unsurprisingly. I suspect
182            // that it's a not uncommon use case to encode smallish chunks of data (e.g. a 64-byte
183            // SHA-512 digest), so it would be nice if that fit in the unrolled loop at least once.
184            // Plus, single-digit percentage performance differences might well be quite different
185            // on different hardware.
186
187            let input_u64 = BigEndian::read_u64(&input_chunk[0..]);
188
189            output_chunk[0] = encode_table[((input_u64 >> 58) & LOW_SIX_BITS) as usize];
190            output_chunk[1] = encode_table[((input_u64 >> 52) & LOW_SIX_BITS) as usize];
191            output_chunk[2] = encode_table[((input_u64 >> 46) & LOW_SIX_BITS) as usize];
192            output_chunk[3] = encode_table[((input_u64 >> 40) & LOW_SIX_BITS) as usize];
193            output_chunk[4] = encode_table[((input_u64 >> 34) & LOW_SIX_BITS) as usize];
194            output_chunk[5] = encode_table[((input_u64 >> 28) & LOW_SIX_BITS) as usize];
195            output_chunk[6] = encode_table[((input_u64 >> 22) & LOW_SIX_BITS) as usize];
196            output_chunk[7] = encode_table[((input_u64 >> 16) & LOW_SIX_BITS) as usize];
197
198            let input_u64 = BigEndian::read_u64(&input_chunk[6..]);
199
200            output_chunk[8] = encode_table[((input_u64 >> 58) & LOW_SIX_BITS) as usize];
201            output_chunk[9] = encode_table[((input_u64 >> 52) & LOW_SIX_BITS) as usize];
202            output_chunk[10] = encode_table[((input_u64 >> 46) & LOW_SIX_BITS) as usize];
203            output_chunk[11] = encode_table[((input_u64 >> 40) & LOW_SIX_BITS) as usize];
204            output_chunk[12] = encode_table[((input_u64 >> 34) & LOW_SIX_BITS) as usize];
205            output_chunk[13] = encode_table[((input_u64 >> 28) & LOW_SIX_BITS) as usize];
206            output_chunk[14] = encode_table[((input_u64 >> 22) & LOW_SIX_BITS) as usize];
207            output_chunk[15] = encode_table[((input_u64 >> 16) & LOW_SIX_BITS) as usize];
208
209            let input_u64 = BigEndian::read_u64(&input_chunk[12..]);
210
211            output_chunk[16] = encode_table[((input_u64 >> 58) & LOW_SIX_BITS) as usize];
212            output_chunk[17] = encode_table[((input_u64 >> 52) & LOW_SIX_BITS) as usize];
213            output_chunk[18] = encode_table[((input_u64 >> 46) & LOW_SIX_BITS) as usize];
214            output_chunk[19] = encode_table[((input_u64 >> 40) & LOW_SIX_BITS) as usize];
215            output_chunk[20] = encode_table[((input_u64 >> 34) & LOW_SIX_BITS) as usize];
216            output_chunk[21] = encode_table[((input_u64 >> 28) & LOW_SIX_BITS) as usize];
217            output_chunk[22] = encode_table[((input_u64 >> 22) & LOW_SIX_BITS) as usize];
218            output_chunk[23] = encode_table[((input_u64 >> 16) & LOW_SIX_BITS) as usize];
219
220            let input_u64 = BigEndian::read_u64(&input_chunk[18..]);
221
222            output_chunk[24] = encode_table[((input_u64 >> 58) & LOW_SIX_BITS) as usize];
223            output_chunk[25] = encode_table[((input_u64 >> 52) & LOW_SIX_BITS) as usize];
224            output_chunk[26] = encode_table[((input_u64 >> 46) & LOW_SIX_BITS) as usize];
225            output_chunk[27] = encode_table[((input_u64 >> 40) & LOW_SIX_BITS) as usize];
226            output_chunk[28] = encode_table[((input_u64 >> 34) & LOW_SIX_BITS) as usize];
227            output_chunk[29] = encode_table[((input_u64 >> 28) & LOW_SIX_BITS) as usize];
228            output_chunk[30] = encode_table[((input_u64 >> 22) & LOW_SIX_BITS) as usize];
229            output_chunk[31] = encode_table[((input_u64 >> 16) & LOW_SIX_BITS) as usize];
230
231            output_index += BLOCKS_PER_FAST_LOOP * 8;
232            input_index += BLOCKS_PER_FAST_LOOP * 6;
233        }
234    }
235
236    // Encode what's left after the fast loop.
237
238    const LOW_SIX_BITS_U8: u8 = 0x3F;
239
240    let rem = input.len() % 3;
241    let start_of_rem = input.len() - rem;
242
243    // start at the first index not handled by fast loop, which may be 0.
244
245    while input_index < start_of_rem {
246        let input_chunk = &input[input_index..(input_index + 3)];
247        let output_chunk = &mut output[output_index..(output_index + 4)];
248
249        output_chunk[0] = encode_table[(input_chunk[0] >> 2) as usize];
250        output_chunk[1] =
251            encode_table[((input_chunk[0] << 4 | input_chunk[1] >> 4) & LOW_SIX_BITS_U8) as usize];
252        output_chunk[2] =
253            encode_table[((input_chunk[1] << 2 | input_chunk[2] >> 6) & LOW_SIX_BITS_U8) as usize];
254        output_chunk[3] = encode_table[(input_chunk[2] & LOW_SIX_BITS_U8) as usize];
255
256        input_index += 3;
257        output_index += 4;
258    }
259
260    if rem == 2 {
261        output[output_index] = encode_table[(input[start_of_rem] >> 2) as usize];
262        output[output_index + 1] = encode_table[((input[start_of_rem] << 4
263            | input[start_of_rem + 1] >> 4)
264            & LOW_SIX_BITS_U8) as usize];
265        output[output_index + 2] =
266            encode_table[((input[start_of_rem + 1] << 2) & LOW_SIX_BITS_U8) as usize];
267        output_index += 3;
268    } else if rem == 1 {
269        output[output_index] = encode_table[(input[start_of_rem] >> 2) as usize];
270        output[output_index + 1] =
271            encode_table[((input[start_of_rem] << 4) & LOW_SIX_BITS_U8) as usize];
272        output_index += 2;
273    }
274
275    output_index
276}
277
278/// calculate the base64 encoded string size, including padding if appropriate
279pub fn encoded_size(bytes_len: usize, config: Config) -> Option<usize> {
280    let rem = bytes_len % 3;
281
282    let complete_input_chunks = bytes_len / 3;
283    let complete_chunk_output = complete_input_chunks.checked_mul(4);
284
285    if rem > 0 {
286        if config.pad {
287            complete_chunk_output.and_then(|c| c.checked_add(4))
288        } else {
289            let encoded_rem = match rem {
290                1 => 2,
291                2 => 3,
292                _ => unreachable!("Impossible remainder"),
293            };
294            complete_chunk_output.and_then(|c| c.checked_add(encoded_rem))
295        }
296    } else {
297        complete_chunk_output
298    }
299}
300
301/// Write padding characters.
302/// `output` is the slice where padding should be written, of length at least 2.
303///
304/// Returns the number of padding bytes written.
305pub fn add_padding(input_len: usize, output: &mut [u8]) -> usize {
306    let rem = input_len % 3;
307    let mut bytes_written = 0;
308    for _ in 0..((3 - rem) % 3) {
309        output[bytes_written] = b'=';
310        bytes_written += 1;
311    }
312
313    bytes_written
314}
315
316#[cfg(test)]
317mod tests {
318    use super::*;
319
320    use std;
321    use std::str;
322
323    use rand::{FromEntropy, Rng};
324    use rand::distributions::{Distribution, Uniform};
325
326    use ::{Config, STANDARD, URL_SAFE_NO_PAD};
327    use decode::decode_config_buf;
328    use tests::{assert_encode_sanity, random_config};
329
330    #[test]
331    fn encoded_size_correct_standard() {
332        assert_encoded_length(0, 0, STANDARD);
333
334        assert_encoded_length(1, 4, STANDARD);
335        assert_encoded_length(2, 4, STANDARD);
336        assert_encoded_length(3, 4, STANDARD);
337
338        assert_encoded_length(4, 8, STANDARD);
339        assert_encoded_length(5, 8, STANDARD);
340        assert_encoded_length(6, 8, STANDARD);
341
342        assert_encoded_length(7, 12, STANDARD);
343        assert_encoded_length(8, 12, STANDARD);
344        assert_encoded_length(9, 12, STANDARD);
345
346        assert_encoded_length(54, 72, STANDARD);
347
348        assert_encoded_length(55, 76, STANDARD);
349        assert_encoded_length(56, 76, STANDARD);
350        assert_encoded_length(57, 76, STANDARD);
351
352        assert_encoded_length(58, 80, STANDARD);
353    }
354
355    #[test]
356    fn encoded_size_correct_no_pad() {
357        assert_encoded_length(0, 0, URL_SAFE_NO_PAD);
358
359        assert_encoded_length(1, 2, URL_SAFE_NO_PAD);
360        assert_encoded_length(2, 3, URL_SAFE_NO_PAD);
361        assert_encoded_length(3, 4, URL_SAFE_NO_PAD);
362
363        assert_encoded_length(4, 6, URL_SAFE_NO_PAD);
364        assert_encoded_length(5, 7, URL_SAFE_NO_PAD);
365        assert_encoded_length(6, 8, URL_SAFE_NO_PAD);
366
367        assert_encoded_length(7, 10, URL_SAFE_NO_PAD);
368        assert_encoded_length(8, 11, URL_SAFE_NO_PAD);
369        assert_encoded_length(9, 12, URL_SAFE_NO_PAD);
370
371        assert_encoded_length(54, 72, URL_SAFE_NO_PAD);
372
373        assert_encoded_length(55, 74, URL_SAFE_NO_PAD);
374        assert_encoded_length(56, 75, URL_SAFE_NO_PAD);
375        assert_encoded_length(57, 76, URL_SAFE_NO_PAD);
376
377        assert_encoded_length(58, 78, URL_SAFE_NO_PAD);
378    }
379
380    #[test]
381    fn encoded_size_overflow() {
382        assert_eq!(None, encoded_size(std::usize::MAX, STANDARD));
383    }
384
385    #[test]
386    fn encode_config_buf_into_nonempty_buffer_doesnt_clobber_prefix() {
387        let mut orig_data = Vec::new();
388        let mut prefix = String::new();
389        let mut encoded_data_no_prefix = String::new();
390        let mut encoded_data_with_prefix = String::new();
391        let mut decoded = Vec::new();
392
393        let prefix_len_range = Uniform::new(0, 1000);
394        let input_len_range = Uniform::new(0, 1000);
395
396        let mut rng = rand::rngs::SmallRng::from_entropy();
397
398        for _ in 0..10_000 {
399            orig_data.clear();
400            prefix.clear();
401            encoded_data_no_prefix.clear();
402            encoded_data_with_prefix.clear();
403            decoded.clear();
404
405            let input_len = input_len_range.sample(&mut rng);
406
407            for _ in 0..input_len {
408                orig_data.push(rng.gen());
409            }
410
411            let prefix_len = prefix_len_range.sample(&mut rng);
412            for _ in 0..prefix_len {
413                // getting convenient random single-byte printable chars that aren't base64 is
414                // annoying
415                prefix.push('#');
416            }
417            encoded_data_with_prefix.push_str(&prefix);
418
419            let config = random_config(&mut rng);
420            encode_config_buf(&orig_data, config, &mut encoded_data_no_prefix);
421            encode_config_buf(&orig_data, config, &mut encoded_data_with_prefix);
422
423            assert_eq!(
424                encoded_data_no_prefix.len() + prefix_len,
425                encoded_data_with_prefix.len()
426            );
427            assert_encode_sanity(&encoded_data_no_prefix, config, input_len);
428            assert_encode_sanity(&encoded_data_with_prefix[prefix_len..], config, input_len);
429
430            // append plain encode onto prefix
431            prefix.push_str(&mut encoded_data_no_prefix);
432
433            assert_eq!(prefix, encoded_data_with_prefix);
434
435            decode_config_buf(&encoded_data_no_prefix, config, &mut decoded).unwrap();
436            assert_eq!(orig_data, decoded);
437        }
438    }
439
440    #[test]
441    fn encode_config_slice_into_nonempty_buffer_doesnt_clobber_suffix() {
442        let mut orig_data = Vec::new();
443        let mut encoded_data = Vec::new();
444        let mut encoded_data_original_state = Vec::new();
445        let mut decoded = Vec::new();
446
447        let input_len_range = Uniform::new(0, 1000);
448
449        let mut rng = rand::rngs::SmallRng::from_entropy();
450
451        for _ in 0..10_000 {
452            orig_data.clear();
453            encoded_data.clear();
454            encoded_data_original_state.clear();
455            decoded.clear();
456
457            let input_len = input_len_range.sample(&mut rng);
458
459            for _ in 0..input_len {
460                orig_data.push(rng.gen());
461            }
462
463            // plenty of existing garbage in the encoded buffer
464            for _ in 0..10 * input_len {
465                encoded_data.push(rng.gen());
466            }
467
468            encoded_data_original_state.extend_from_slice(&encoded_data);
469
470            let config = random_config(&mut rng);
471
472            let encoded_size = encoded_size(input_len, config).unwrap();
473
474            assert_eq!(
475                encoded_size,
476                encode_config_slice(&orig_data, config, &mut encoded_data)
477            );
478
479            assert_encode_sanity(
480                std::str::from_utf8(&encoded_data[0..encoded_size]).unwrap(),
481                config,
482                input_len,
483            );
484
485            assert_eq!(
486                &encoded_data[encoded_size..],
487                &encoded_data_original_state[encoded_size..]
488            );
489
490            decode_config_buf(&encoded_data[0..encoded_size], config, &mut decoded).unwrap();
491            assert_eq!(orig_data, decoded);
492        }
493    }
494
495    #[test]
496    fn encode_config_slice_fits_into_precisely_sized_slice() {
497        let mut orig_data = Vec::new();
498        let mut encoded_data = Vec::new();
499        let mut decoded = Vec::new();
500
501        let input_len_range = Uniform::new(0, 1000);
502
503        let mut rng = rand::rngs::SmallRng::from_entropy();
504
505        for _ in 0..10_000 {
506            orig_data.clear();
507            encoded_data.clear();
508            decoded.clear();
509
510            let input_len = input_len_range.sample(&mut rng);
511
512            for _ in 0..input_len {
513                orig_data.push(rng.gen());
514            }
515
516            let config = random_config(&mut rng);
517
518            let encoded_size = encoded_size(input_len, config).unwrap();
519
520            encoded_data.resize(encoded_size, 0);
521
522            assert_eq!(
523                encoded_size,
524                encode_config_slice(&orig_data, config, &mut encoded_data)
525            );
526
527            assert_encode_sanity(
528                std::str::from_utf8(&encoded_data[0..encoded_size]).unwrap(),
529                config,
530                input_len,
531            );
532
533            decode_config_buf(&encoded_data[0..encoded_size], config, &mut decoded).unwrap();
534            assert_eq!(orig_data, decoded);
535        }
536    }
537
538    #[test]
539    fn encode_to_slice_random_valid_utf8() {
540        let mut input = Vec::new();
541        let mut output = Vec::new();
542
543        let input_len_range = Uniform::new(0, 1000);
544
545        let mut rng = rand::rngs::SmallRng::from_entropy();
546
547        for _ in 0..10_000 {
548            input.clear();
549            output.clear();
550
551            let input_len = input_len_range.sample(&mut rng);
552
553            for _ in 0..input_len {
554                input.push(rng.gen());
555            }
556
557            let config = random_config(&mut rng);
558
559            // fill up the output buffer with garbage
560            let encoded_size = encoded_size(input_len, config).unwrap();
561            for _ in 0..encoded_size {
562                output.push(rng.gen());
563            }
564
565            let orig_output_buf = output.to_vec();
566
567            let bytes_written =
568                encode_to_slice(&input, &mut output, config.char_set.encode_table());
569
570            // make sure the part beyond bytes_written is the same garbage it was before
571            assert_eq!(orig_output_buf[bytes_written..], output[bytes_written..]);
572
573            // make sure the encoded bytes are UTF-8
574            let _ = str::from_utf8(&output[0..bytes_written]).unwrap();
575        }
576    }
577
578    #[test]
579    fn encode_with_padding_random_valid_utf8() {
580        let mut input = Vec::new();
581        let mut output = Vec::new();
582
583        let input_len_range = Uniform::new(0, 1000);
584
585        let mut rng = rand::rngs::SmallRng::from_entropy();
586
587        for _ in 0..10_000 {
588            input.clear();
589            output.clear();
590
591            let input_len = input_len_range.sample(&mut rng);
592
593            for _ in 0..input_len {
594                input.push(rng.gen());
595            }
596
597            let config = random_config(&mut rng);
598
599            // fill up the output buffer with garbage
600            let encoded_size = encoded_size(input_len, config).unwrap();
601            for _ in 0..encoded_size + 1000 {
602                output.push(rng.gen());
603            }
604
605            let orig_output_buf = output.to_vec();
606
607            encode_with_padding(&input, config, encoded_size, &mut output[0..encoded_size]);
608
609            // make sure the part beyond b64 is the same garbage it was before
610            assert_eq!(orig_output_buf[encoded_size..], output[encoded_size..]);
611
612            // make sure the encoded bytes are UTF-8
613            let _ = str::from_utf8(&output[0..encoded_size]).unwrap();
614        }
615    }
616
617    #[test]
618    fn add_padding_random_valid_utf8() {
619        let mut output = Vec::new();
620
621        let mut rng = rand::rngs::SmallRng::from_entropy();
622
623        // cover our bases for length % 3
624        for input_len in 0..10 {
625            output.clear();
626
627            // fill output with random
628            for _ in 0..10 {
629                output.push(rng.gen());
630            }
631
632            let orig_output_buf = output.to_vec();
633
634            let bytes_written = add_padding(input_len, &mut output);
635
636            // make sure the part beyond bytes_written is the same garbage it was before
637            assert_eq!(orig_output_buf[bytes_written..], output[bytes_written..]);
638
639            // make sure the encoded bytes are UTF-8
640            let _ = str::from_utf8(&output[0..bytes_written]).unwrap();
641        }
642    }
643
644    fn assert_encoded_length(input_len: usize, encoded_len: usize, config: Config) {
645        assert_eq!(encoded_len, encoded_size(input_len, config).unwrap());
646
647        let mut bytes: Vec<u8> = Vec::new();
648        let mut rng = rand::rngs::SmallRng::from_entropy();
649
650        for _ in 0..input_len {
651            bytes.push(rng.gen());
652        }
653
654        let encoded = encode_config(&bytes, config);
655        assert_encode_sanity(&encoded, config, input_len);
656
657        assert_eq!(encoded_len, encoded.len());
658    }
659
660}