Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Migrate to devdocs #25

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 91 additions & 9 deletions src/decoder.nr
Original file line number Diff line number Diff line change
@@ -1,19 +1,48 @@
use super::defaults::BASE64_PADDING_CHAR;

/// Standard Base64 Alphabet (base64) with padding.
pub global STANDARD: Base64DecodeBE = Base64DecodeBE::new(true);

/// Standard Base64 Alphabet (base64) without padding.
pub global STANDARD_NO_PAD: Base64DecodeBE = Base64DecodeBE::new(false);

/// URL and Filename Safe Alphabet without padding.
pub global URL_SAFE: Base64DecodeBE = Base64DecodeBE::base64url(false);

/// URL and Filename Safe Alphabet with padding.
pub global URL_SAFE_WITH_PAD: Base64DecodeBE = Base64DecodeBE::base64url(true);

/// Invalid value for the lookup table.
global INVALID_VALUE: u8 = 255;

/// Base64 decoder for big-endian byte arrays.
///
/// > Note: If the lookup table is not defined in a struct, access costs are expensive and ROM
/// tables aren't being used.
struct Base64DecodeBE {
// for some reason, if the lookup table is not defined in a struct, access costs are expensive and ROM tables aren't being used :/
/// The base64 lookup table.
table: [u8; 256],
/// Whether the input has padding.
pad: bool,
}

impl Base64DecodeBE {
/// Creates a new decoder that uses the standard Base64 Alphabet (base64) specified in RFC 4648
/// https://datatracker.ietf.org/doc/html/rfc4648#section-4
/// (https://datatracker.ietf.org/doc/html/rfc4648#section-4).
///
/// ## Value Parameters
///
/// - `pad`: Whether the input has padding.
///
/// ## Returns
///
/// The Base64 decoder instance.
///
/// ## Usage
///
/// ```nr
/// let decoder = Base64DecodeBE::new(true);
/// ```
fn new(pad: bool) -> Self {
Base64DecodeBE {
table: [
Expand Down Expand Up @@ -280,8 +309,22 @@ impl Base64DecodeBE {
}
}

// Creates a new decoder that uses the URL and Filename Safe Alphabet specified in RFC 4648
// https://datatracker.ietf.org/doc/html/rfc4648#section-5
/// Creates a new decoder that uses the URL and Filename Safe Alphabet specified in RFC 4648
/// (https://datatracker.ietf.org/doc/html/rfc4648#section-5).
///
/// ## Value Parameters
///
/// - `pad`: Whether the input has padding.
///
/// ## Returns
///
/// The Base64 decoder instance.
///
/// ## Usage
///
/// ```nr
/// let decoder = Base64DecodeBE::base64url(true);
/// ```
fn base64url(pad: bool) -> Self {
Base64DecodeBE {
table: [
Expand Down Expand Up @@ -548,15 +591,54 @@ impl Base64DecodeBE {
}
}

/// Gets the lookup table value at a given index.
///
/// ## Value Parameters
///
/// - `idx`: The index to get the value for.
///
/// ## Returns
///
/// The value from the lookup table.
///
/// ## Usage
///
/// ```nr
/// let value = Base64DecodeBE::new(true).get(65);
/// ```
fn get(self, idx: Field) -> u8 {
self.table[idx]
}

/**
* @brief Take an array of ASCII values and convert into *packed* byte array of base64 values
* Each Base64 value is 6 bits. This method will produce a byte array where data is concatenated so that there are no sparse bits
* (e.g. encoding 4 ASCII values produces 24 bits of Base64 data = 3 bytes of output data)
**/
/// Converts an array of ASCII values into a packed byte array of base64 values.
///
/// > Note: Each Base64 value is 6 bits. This method will produce a byte array where data is
/// > concatenated so that there are no sparse bits (e.g. encoding 4 ASCII values produces 24
/// > bits of Base64 data = 3 bytes of output data).
///
/// ## Type Parameters
///
/// - `InputElements`: The number of input elements.
/// - `OutputBytes`: The number of output bytes.
///
/// ## Value Parameters
///
/// - `self`: The Base64 decoder instance.
/// - `input`: The input array.
///
/// ## Constraints
///
/// - input and output lengths are correct, including padding.
///
/// ## Returns
///
/// The packed byte array of base64 values.
///
/// ## Usage
///
/// ```nr
/// let result = Decoder::new(false).decode::<4, 3>([65, 66, 67, 68]);
/// ```
pub fn decode<let InputElements: u32, let OutputBytes: u32>(
self,
input: [u8; InputElements],
Expand Down
120 changes: 107 additions & 13 deletions src/encoder.nr
Original file line number Diff line number Diff line change
@@ -1,24 +1,50 @@
use super::defaults::BASE64_PADDING_CHAR;

/// Standard base64 encoder with padding.
pub global STANDARD: Base64EncodeBE = Base64EncodeBE::new(true);

/// Standard base64 encoder without padding.
pub global STANDARD_NO_PAD: Base64EncodeBE = Base64EncodeBE::new(false);

/// URL and Filename Safe base64 encoder without padding.
pub global URL_SAFE: Base64EncodeBE = Base64EncodeBE::base64url(false);

/// URL and Filename Safe base64 encoder with padding.
pub global URL_SAFE_WITH_PAD: Base64EncodeBE = Base64EncodeBE::base64url(true);

/// Base 64 encoder for big-endian byte arrays.
///
/// > Note: If the lookup table is not defined in a struct, access costs are expensive and ROM
/// > tables aren't being used.
struct Base64EncodeBE {
// for some reason, if the lookup table is not defined in a struct, access costs are expensive and ROM tables aren't being used :/
/// The base64 lookup table.
table: [u8; 64],
/// Whether to pad the output with '=' characters.
pad: bool,
}

impl Base64EncodeBE {
/// Creates a new encoder that uses the standard Base64 Alphabet (base64) specified in RFC 4648
/// (https://datatracker.ietf.org/doc/html/rfc4648#section-4)
/// (https://datatracker.ietf.org/doc/html/rfc4648#section-4).
///
/// The alphabet values are standard UTF-8 (and ASCII) byte encodings so the index in the table
/// is the 6-bit Base64 value, and the value at that index is the UTF-8 encoding of that value.
///
/// ## Value Parameters
///
/// - `pad`: Whether to pad the output with '=' characters.
///
/// ## Returns
///
/// The Base64 encoder instance.
///
/// ## Usage
///
/// ```nr
/// let encoder = Base64EncodeBE::new(true);
/// ```
fn new(pad: bool) -> Self {
Base64EncodeBE {
// The alphabet values here are standard UTF-8 (and ASCII) byte encodings, so the index
// in the table is the 6-bit Base64 value, and the value at that index is the UTF-8
// encoding of that value.
table: [
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, // 0-25 (A-Z)
Expand All @@ -32,8 +58,22 @@ impl Base64EncodeBE {
}
}

// Creates a new encoder that uses the URL and Filename Safe Alphabet specified in RFC 4648
// https://datatracker.ietf.org/doc/html/rfc4648#section-5
/// Creates a new encoder that uses the URL and Filename Safe Alphabet specified in RFC 4648
/// (https://datatracker.ietf.org/doc/html/rfc4648#section-5).
///
/// ## Value Parameters
///
/// - `pad`: Whether to pad the output with '=' characters.
///
/// ## Returns
///
/// The Base64 encoder instance.
///
/// ## Usage
///
/// ```nr
/// let encoder = Base64EncodeBE::base64url(true);
/// ```
fn base64url(pad: bool) -> Self {
Base64EncodeBE {
table: [
Expand All @@ -50,13 +90,45 @@ impl Base64EncodeBE {
}
}

/// Gets the lookup table value at a given index.
///
/// ## Value Parameters
///
/// - `idx`: The index in the lookup table.
///
/// ## Returns
///
/// The byte value from the lookup table.
///
/// ## Usage
///
/// ```nr
/// let encoder = Base64EncodeBE::new(true);
/// ```
fn get(self, idx: Field) -> u8 {
self.table[idx]
}

/**
* @brief Take an array of ASCII values and convert into base64 values
**/
/// Converts an array of ASCII values into base64 values.
///
/// ## Type Parameters
///
/// - `InputElements`: The number of elements in the input array.
///
/// ## Value Parameters
///
/// - `self`: The Base64 encoder instance.
/// - `input`: The input array of ASCII values.
///
/// ## Returns
///
/// The array of base64 values.
///
/// ## Usage
///
/// ```nr
/// let encoded = Base64EncodeBE::new(true).encode_elements("asdf".as_bytes());
/// ```
fn encode_elements<let InputElements: u32>(
self,
input: [u8; InputElements],
Expand All @@ -69,9 +141,31 @@ impl Base64EncodeBE {
result
}

/**
* @brief Take an array of packed base64 encoded bytes and convert into ASCII
**/
/// Converts an array of packed base64 values into ASCII values.
///
/// ## Type Parameters
///
/// - `InputElements`: The number of elements in the input array.
/// - `OutputElements`: The number of elements in the output array.
///
/// ## Value Parameters
///
/// - `self`: The Base64 encoder instance.
/// - `input`: The input array of packed base64 values.
///
/// ## Constraints
///
/// - input and output lengths are correct, including padding.
///
/// ## Returns
///
/// The array of ASCII values.
///
/// ## Usage
///
/// ```nr
/// let decoded = Base64EncodeBE::new(true).encode("asdf".as_bytes());
/// ```
pub fn encode<let InputBytes: u32, let OutputElements: u32>(
self,
input: [u8; InputBytes],
Expand Down
33 changes: 16 additions & 17 deletions src/lib.nr
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
// Encodings use the alphabets and padding rules specified in RFC 4648
// (https://datatracker.ietf.org/doc/html/rfc4648:
//
// A 65-character subset of US-ASCII is used, enabling 6 bits to be
// represented per printable character. (The extra 65th character, "=",
// is used to signify a special processing function.)
//
// The encoding process represents 24-bit groups of input bits as output
// strings of 4 encoded characters. Proceeding from left to right, a
// 24-bit input group is formed by concatenating 3 8-bit input groups.
// These 24 bits are then treated as 4 concatenated 6-bit groups, each
// of which is translated into a single character in the base 64
// alphabet.
//
// Each 6-bit group is used as an index into an array of 64 printable
// characters. The character referenced by the index is placed in the
// output string.
//! Base64 Encoder and Decoder
//!
//! Encodings use the alphabets and padding rules specified in RFC-4648
//! (https://datatracker.ietf.org/doc/html/rfc4648):
//!
//! A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable
//! character. (The extra 65th character, "=", is used to signify a special processing function.)
//!
//! The encoding process represents 24-bit groups of input bits as output strings of 4 encoded
//! characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3
//! 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which
//! is translated into a single character in the base 64 alphabet.
//!
//! Each 6-bit group is used as an index into an array of 64 printable characters. The character
//! referenced by the index is placed in the output string.

mod encoder;
pub use encoder::{
STANDARD as BASE64_ENCODER, STANDARD_NO_PAD as BASE64_NO_PAD_ENCODER,
Expand Down