From c2291dd64a1f1f1e9ce47fa11f70370a9f26f103 Mon Sep 17 00:00:00 2001 From: Elena Fuentes Bongenaar Date: Thu, 22 Aug 2024 15:17:40 -0600 Subject: [PATCH 1/9] Updated README & added examples. Moved original code into `lib` folder. --- .gitignore | 1 + README.md | 162 +++++++++++++++++++++++++++++++--- examples/example1/Nargo.toml | 8 ++ examples/example1/src/main.nr | 47 ++++++++++ examples/example2/Nargo.toml | 8 ++ examples/example2/Prover.toml | 1 + examples/example2/README.md | 24 +++++ examples/example2/src/main.nr | 12 +++ Nargo.toml => lib/Nargo.toml | 0 {src => lib/src}/lib.nr | 0 10 files changed, 250 insertions(+), 13 deletions(-) create mode 100644 .gitignore create mode 100644 examples/example1/Nargo.toml create mode 100644 examples/example1/src/main.nr create mode 100644 examples/example2/Nargo.toml create mode 100644 examples/example2/Prover.toml create mode 100644 examples/example2/README.md create mode 100644 examples/example2/src/main.nr rename Nargo.toml => lib/Nargo.toml (100%) rename {src => lib/src}/lib.nr (100%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1de5659 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target \ No newline at end of file diff --git a/README.md b/README.md index 022d27e..2f86c02 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,47 @@ # noir_base64 -A library to encode ASCII into Base64 and decode Base64 into ASCII +A library to encode ASCII into Base64 and decode Base64 into ASCII. -# Usage +## Dependencies -### `fn base64_encode` -Takees an input byte array of ASCII characters and produces an output byte array of base64-encoded characters. The 6-bit base64 characters are packed into a concatenated byte array (e.g. 4 bytes of ASCII produce 3 bytes of encoded Base64) +- Noir ≥v0.31.0 +- Barretenberg ≥v0.46.1 -### `fn base64_decode` -Takes an input byte array of packed base64 characters and produces an output byte array of ASCII characters (e.g. 3 input bytes of base64 produces 4 output bytes of ASCII) +Refer to [Noir's docs](https://noir-lang.org/docs/getting_started/installation/) and [Barretenberg's docs](https://github.com/AztecProtocol/aztec-packages/blob/master/barretenberg/cpp/src/barretenberg/bb/readme.md#installation) for installation steps. -### `fn base64_encode_elements` -Takes an input byte array of ASCII characters and produces an output byte array of base64-encoded characters. Data is not packed i.e. each output array element maps to a 6-bit base64 character +## Installation -### `fn base64_decode_elements` -Takes an input byte array of base64 characters and produces an output byte array of ASCII characters. Input data is not packed i.e. each input element maps to a 6-bit base64 character +In your _Nargo.toml_ file, add the version of this library you would like to install under dependency: + +``` +[dependencies] +noir_rsa = { tag = "v0.2.0", git = "https://github.com/noir-lang/noir_base64" } +``` +## Quickstart -### Example usage -(see tests in `lib.nr` for more examples) +The library offers 4 functions; `fn base64_encode`, `fn base64_decode`, `fn base64_encode_elements` & `fn base64_decode_elements`. Find descriptions per method below. +In this example we take input `"Noir"` represented in ASCII, and encode this into Base64. The result is either "packed" together or given as separate elements. (Refer to the methods descriptions below.) + +Define the input in ASCII (`"N"` = 78, `"o"`= 111, `"i"`= 105, `"r"`= 114): +```rust +let input: [u8; 4] = [78, 111, 105, 114]; ``` + +Encode either into a concatenated array or each Base64 element in a separate byte (Base64 values only take up 6 bits of space, see full explanation of the conversion + mapping table below): +```rust +// Packed +let result_packed: [u8; 3] = noir_base64::base64_encode(input); +assert(result_packed == [54, 136, 171]); + +// In separate elements +let result_elements: [u8; 4] = noir_base64::base64_encode_elements(input); +assert(result_elements == [13, 40, 34, 43]); +``` + +A larger example: + +```rust use dep::noir_base64; fn encode() { // Raw bh: GxMlgwLiypnVrE2C0Sf4yzhcWTkAhSZ5+WERhKhXtlU= @@ -49,7 +71,121 @@ fn encode() { } ``` -# Costs +See more examples in `lib.nr` and the `examples` folder. + +## Conversion explainer + +[Base64](https://datatracker.ietf.org/doc/html/rfc4648#section-4) is a 6-bit encoding system (`0` to `63`). + +[ASCII](https://www.ascii-code.com/) is a 7-bit character code ( `0` to `127`). + +Note that the character set of ASCII is larger than that of Base64. When encoding ASCII into Base64, the special characters that exist in ASCII but not in Base64 are mapped to `0`. + +For encoding and decoding the library uses lookup tables. The following table shows the mapping from ASCII <-> Base64. (See for the expanded version below.) + +| Character | Decimal in ASCII | Decimal in Base64 | +|:----------------|:-----------------:|:------------------:| +| `+` | 43 | 62 | +| `/` | 47 | 63 | +| `0-9` | 48,..,57 | 52,..,61 | +| `A-Z` | 65,..,90 | 0,..,25 | +| `a-z` | 97,..,122 | 26,..,51 | + +### Example + +For example for input "Noir" in ASCII, we have `"N"` = 78, `"o"`= 111, `"i"`= 105, `"r"`= 114: +```rust +let input_ascii: [u8; 4] = [78, 111, 105, 114]; +``` + +The output in Base64 will be: +- `N` -> 13 +- `o` -> 40 +- `i` -> 34 +- `r` -> 43 + +Base64 values are 6 bits and this library offers 2 way to output the result; `base64_encode` or `base64_encode_elements`. + +For `base64_encode_elements` each value is stored in a different byte, which in this case results in: `[13, 40, 34, 43]`. + +For `base64_encode` concatenate the values and then split them up into bytes. As follows: +1. Rewrite all values to binary: +``` +13 | 40 | 34 | 43 <- Decimal representation +001101 | 101000 | 100010 | 101011 <- Binary representation +``` +2. Glue together +``` +001101101000100010101011 +``` +3. Split up in chunks of 8 bits +``` +00110110 | 10001000 | 10101011 +``` +4. Convert to decimal: `[54, 136, 171]` + + + +## Methods + +### `fn base64_encode` +Takees an input byte array of ASCII characters and produces an output byte array of base64-encoded characters. The 6-bit base64 characters are packed into a concatenated byte array (e.g. 4 bytes of ASCII produce 3 bytes of encoded Base64) + +### `fn base64_decode` +Takes an input byte array of packed base64 characters and produces an output byte array of ASCII characters (e.g. 3 input bytes of base64 produces 4 output bytes of ASCII) + +### `fn base64_encode_elements` +Takes an input byte array of ASCII characters and produces an output byte array of base64-encoded characters. Data is not packed i.e. each output array element maps to a 6-bit base64 character + +### `fn base64_decode_elements` +Takes an input byte array of base64 characters and produces an output byte array of ASCII characters. Input data is not packed i.e. each input element maps to a 6-bit base64 character + +## Costs `base64_encode_elements` will encode an array of 44 ASCII bytes in ~470 gates, plus a ~256 gate cost to initialize an encoding lookup table (the initialization cost is incurred once regardless of the number of decodings) +## Base64 Encoding Table (Extended) + +| Character | Decimal in ASCII | Decimal in Base64 | +|:----------|:-----------------|:------------------| +| `+` | 43 | 62 | +| `/` | 47 | 63 | +| `0` | 48 | 52 | +| `1` | 49 | 53 | +| `2` | 50 | 54 | +| `3` | 51 | 55 | +| `4` | 52 | 56 | +| `5` | 53 | 57 | +| `6` | 54 | 58 | +| `7` | 55 | 59 | +| `8` | 56 | 60 | +| `9` | 57 | 61 | +| `A` | 65 | 0 | +| `B` | 66 | 1 | +| `C` | 67 | 2 | +| `D` | 68 | 3 | +| `E` | 69 | 4 | +| `F` | 70 | 5 | +| `G` | 71 | 6 | +| `H` | 72 | 7 | +| `I` | 73 | 8 | +| `J` | 74 | 9 | +| `K` | 75 | 10 | +| `L` | 76 | 11 | +| `M` | 77 | 12 | +| `N` | 78 | 13 | +| `O` | 79 | 14 | +| `P` | 80 | 15 | +| `Q` | 81 | 16 | +| `R` | 82 | 17 | +| `S` | 83 | 18 | +| `T` | 84 | 19 | +| `U` | 85 | 20 | +| `V` | 86 | 21 | +| `W` | 87 | 22 | +| `X` | 88 | 23 | +| `Y` | 89 | 24 | +| `Z` | 90 | 25 | +| `a` | 97 | 26 | +| `b` | 98 | 27 | +| `c` | 99 | 28 | diff --git a/examples/example1/Nargo.toml b/examples/example1/Nargo.toml new file mode 100644 index 0000000..581e46e --- /dev/null +++ b/examples/example1/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name = "example1" +type = "bin" +authors = [""] +compiler_version = ">=0.32.0" + +[dependencies] +noir_base64 = { path = "../../lib" } \ No newline at end of file diff --git a/examples/example1/src/main.nr b/examples/example1/src/main.nr new file mode 100644 index 0000000..4d5505d --- /dev/null +++ b/examples/example1/src/main.nr @@ -0,0 +1,47 @@ +use dep::noir_base64; + +fn main(){ +} + +#[test] +fn test_encode_elements_noir() { + // Convert "Noir" in ASCII to Base64 + + // "Noir" in ASCII equals [78, 111, 105, 114] + let input: [u8; 4] = [78, 111, 105, 114]; + + // Mapping to Base64 + // N -> 13 + // o -> 40 + // i -> 34 + // r -> 43 + let result: [u8; 4] = noir_base64::base64_encode_elements(input); + assert(result == [13, 40, 34, 43]); +} + +#[test] +fn test_encode_packed_noir() { + // Convert "Noir" in ASCII to Base64 (packed) + + // "Noir" in ASCII equals [78, 111, 105, 114] + let input: [u8; 4] = [78, 111, 105, 114]; + + // Mapping to Base64 + // N -> 13 + // o -> 40 + // i -> 34 + // r -> 43 + let result: [u8; 3] = noir_base64::base64_encode(input); + + // Base64 values are 6 bits. + // Instead of putting each of them in a separate byte, glue them together and then chop up into bytes: + + // 13 | 40 | 34 | 43 + // 001101 | 101000 | 100010 | 101011 + // 001101101000100010101011 <- glue together + // 00110110 | 10001000 | 10101011 <- chop up in bytes + // 54 | 136 | 171 <- decimal representation + + assert(result == [54, 136, 171]); +} + diff --git a/examples/example2/Nargo.toml b/examples/example2/Nargo.toml new file mode 100644 index 0000000..b60a9a7 --- /dev/null +++ b/examples/example2/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name = "example2" +type = "bin" +authors = [""] +compiler_version = ">=0.32.0" + +[dependencies] +noir_base64 = { path = "../../lib" } \ No newline at end of file diff --git a/examples/example2/Prover.toml b/examples/example2/Prover.toml new file mode 100644 index 0000000..bba047c --- /dev/null +++ b/examples/example2/Prover.toml @@ -0,0 +1 @@ +input = ["71", "120", "77", "108", "103", "119", "76", "105", "121", "112", "110", "86", "114", "69", "50", "67", "48", "83", "102", "52", "121", "122", "104", "99", "87", "84", "107", "65", "104", "83", "90", "53", "43", "87", "69", "82", "104", "75", "104", "88", "116", "108", "85", "61"] diff --git a/examples/example2/README.md b/examples/example2/README.md new file mode 100644 index 0000000..b2a0853 --- /dev/null +++ b/examples/example2/README.md @@ -0,0 +1,24 @@ +# Example 2 + +For this example the correct values have already been added to `Prover.toml`. Execute the circuit: +``` +nargo execute base64 +``` + +Prove it, for example with default backend Barretenberg: +``` +bb prove -b ./target/example2.json -w ./target/base64.gz -o ./target/proof +``` + +To verify, we need to export the verification key: + +```bash +bb write_vk -b ./target/example2.json -o ./target/vk +``` + +And verify: + +```bash +bb verify -k ./target/vk -p ./target/proof +``` +If verification passed, you see nothing. Otherwise there is an error. \ No newline at end of file diff --git a/examples/example2/src/main.nr b/examples/example2/src/main.nr new file mode 100644 index 0000000..7f3975f --- /dev/null +++ b/examples/example2/src/main.nr @@ -0,0 +1,12 @@ +use dep::noir_base64; + +fn main(input: [u8; 44]) { + let result: [u8; 32] = noir_base64::base64_encode(input); + let expected = [ + 27, 19, 37, 131, 2, 226, 202, 153, 213, 172, + 77, 130, 209, 39, 248, 203, 56, 92, 89, 57, + 0, 133, 38, 121, 249, 97, 17, 132, 168, 87, + 182, 85 + ]; + assert(result == expected); +} diff --git a/Nargo.toml b/lib/Nargo.toml similarity index 100% rename from Nargo.toml rename to lib/Nargo.toml diff --git a/src/lib.nr b/lib/src/lib.nr similarity index 100% rename from src/lib.nr rename to lib/src/lib.nr From 357865263740be8447ff8b937b428d94fa22acec Mon Sep 17 00:00:00 2001 From: Elena Fuentes Bongenaar Date: Thu, 22 Aug 2024 15:23:18 -0600 Subject: [PATCH 2/9] Updated README --- README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2f86c02..5d064ac 100644 --- a/README.md +++ b/README.md @@ -21,14 +21,15 @@ noir_rsa = { tag = "v0.2.0", git = "https://github.com/noir-lang/noir_base64" } The library offers 4 functions; `fn base64_encode`, `fn base64_decode`, `fn base64_encode_elements` & `fn base64_decode_elements`. Find descriptions per method below. -In this example we take input `"Noir"` represented in ASCII, and encode this into Base64. The result is either "packed" together or given as separate elements. (Refer to the methods descriptions below.) +In this example we take input `"Noir"` represented in ASCII, and encode this into Base64. The result is either "packed" together or given as separate elements. (Refer to the method descriptions below.) Define the input in ASCII (`"N"` = 78, `"o"`= 111, `"i"`= 105, `"r"`= 114): ```rust let input: [u8; 4] = [78, 111, 105, 114]; ``` -Encode either into a concatenated array or each Base64 element in a separate byte (Base64 values only take up 6 bits of space, see full explanation of the conversion + mapping table below): +Encode either into a concatenated array or each Base64 element in a separate byte; Base64 values only take up 6 bits of space, see full explanation of the conversion + mapping table below. + ```rust // Packed let result_packed: [u8; 3] = noir_base64::base64_encode(input); @@ -107,6 +108,10 @@ The output in Base64 will be: Base64 values are 6 bits and this library offers 2 way to output the result; `base64_encode` or `base64_encode_elements`. For `base64_encode_elements` each value is stored in a different byte, which in this case results in: `[13, 40, 34, 43]`. +```rust +let result_elements: [u8; 4] = noir_base64::base64_encode_elements(input); +assert(result_elements == [13, 40, 34, 43]); +``` For `base64_encode` concatenate the values and then split them up into bytes. As follows: 1. Rewrite all values to binary: @@ -124,7 +129,10 @@ For `base64_encode` concatenate the values and then split them up into bytes. As ``` 4. Convert to decimal: `[54, 136, 171]` - +```rust +let result_packed: [u8; 3] = noir_base64::base64_encode(input); +assert(result_packed == [54, 136, 171]); +``` ## Methods From f398ef679285cf56781cc51eb909cecc38f4b985 Mon Sep 17 00:00:00 2001 From: Elena Fuentes Bongenaar Date: Thu, 22 Aug 2024 15:26:24 -0600 Subject: [PATCH 3/9] Formatting --- examples/example1/src/main.nr | 7 +++---- examples/example2/src/main.nr | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/examples/example1/src/main.nr b/examples/example1/src/main.nr index 4d5505d..dd3ba52 100644 --- a/examples/example1/src/main.nr +++ b/examples/example1/src/main.nr @@ -1,7 +1,6 @@ use dep::noir_base64; -fn main(){ -} +fn main() {} #[test] fn test_encode_elements_noir() { @@ -9,7 +8,7 @@ fn test_encode_elements_noir() { // "Noir" in ASCII equals [78, 111, 105, 114] let input: [u8; 4] = [78, 111, 105, 114]; - + // Mapping to Base64 // N -> 13 // o -> 40 @@ -25,7 +24,7 @@ fn test_encode_packed_noir() { // "Noir" in ASCII equals [78, 111, 105, 114] let input: [u8; 4] = [78, 111, 105, 114]; - + // Mapping to Base64 // N -> 13 // o -> 40 diff --git a/examples/example2/src/main.nr b/examples/example2/src/main.nr index 7f3975f..dbcac98 100644 --- a/examples/example2/src/main.nr +++ b/examples/example2/src/main.nr @@ -1,12 +1,12 @@ use dep::noir_base64; fn main(input: [u8; 44]) { - let result: [u8; 32] = noir_base64::base64_encode(input); - let expected = [ + let result: [u8; 32] = noir_base64::base64_encode(input); + let expected = [ 27, 19, 37, 131, 2, 226, 202, 153, 213, 172, 77, 130, 209, 39, 248, 203, 56, 92, 89, 57, 0, 133, 38, 121, 249, 97, 17, 132, 168, 87, 182, 85 ]; - assert(result == expected); + assert(result == expected); } From b7a4f02904092324b9013bc3cc24d6627d0549dc Mon Sep 17 00:00:00 2001 From: Elena Fuentes Bongenaar Date: Mon, 26 Aug 2024 16:40:51 -0600 Subject: [PATCH 4/9] Fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5d064ac..7725ce9 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ In your _Nargo.toml_ file, add the version of this library you would like to ins ``` [dependencies] -noir_rsa = { tag = "v0.2.0", git = "https://github.com/noir-lang/noir_base64" } +noir_base64 = { tag = "v0.2.0", git = "https://github.com/noir-lang/noir_base64" } ``` ## Quickstart From 4e08ec5b286b59f294cb296f9c3906dc1b3e86f1 Mon Sep 17 00:00:00 2001 From: James Zaki Date: Fri, 6 Sep 2024 16:07:50 +0100 Subject: [PATCH 5/9] Add Nargo workspace for lib and examples --- Nargo.toml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Nargo.toml diff --git a/Nargo.toml b/Nargo.toml new file mode 100644 index 0000000..3ac3046 --- /dev/null +++ b/Nargo.toml @@ -0,0 +1,6 @@ +[workspace] +members = [ + "lib", + "examples/example1", + "examples/example2", +] From 2c0cf8fde3ad4a2e821355a384fc762da86fa2db Mon Sep 17 00:00:00 2001 From: James Zaki Date: Wed, 18 Sep 2024 14:15:21 +0100 Subject: [PATCH 6/9] Lib to root, update to 0.34.0 --- Nargo.toml | 13 +++++++------ examples/example1/Nargo.toml | 2 +- examples/example2/Nargo.toml | 2 +- lib/Nargo.toml | 7 ------- {lib/src => src}/lib.nr | 0 5 files changed, 9 insertions(+), 15 deletions(-) delete mode 100644 lib/Nargo.toml rename {lib/src => src}/lib.nr (100%) diff --git a/Nargo.toml b/Nargo.toml index 3ac3046..47b045e 100644 --- a/Nargo.toml +++ b/Nargo.toml @@ -1,6 +1,7 @@ -[workspace] -members = [ - "lib", - "examples/example1", - "examples/example2", -] +[package] +name = "noir_base64" +type = "lib" +authors = [""] +compiler_version = ">=0.34.0" + +[dependencies] \ No newline at end of file diff --git a/examples/example1/Nargo.toml b/examples/example1/Nargo.toml index 581e46e..50abac5 100644 --- a/examples/example1/Nargo.toml +++ b/examples/example1/Nargo.toml @@ -2,7 +2,7 @@ name = "example1" type = "bin" authors = [""] -compiler_version = ">=0.32.0" +compiler_version = ">=0.34.0" [dependencies] noir_base64 = { path = "../../lib" } \ No newline at end of file diff --git a/examples/example2/Nargo.toml b/examples/example2/Nargo.toml index b60a9a7..790a860 100644 --- a/examples/example2/Nargo.toml +++ b/examples/example2/Nargo.toml @@ -2,7 +2,7 @@ name = "example2" type = "bin" authors = [""] -compiler_version = ">=0.32.0" +compiler_version = ">=0.34.0" [dependencies] noir_base64 = { path = "../../lib" } \ No newline at end of file diff --git a/lib/Nargo.toml b/lib/Nargo.toml deleted file mode 100644 index 25c86a9..0000000 --- a/lib/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "noir_base64" -type = "lib" -authors = [""] -compiler_version = ">=0.31.0" - -[dependencies] \ No newline at end of file diff --git a/lib/src/lib.nr b/src/lib.nr similarity index 100% rename from lib/src/lib.nr rename to src/lib.nr From 0aefe4326bbfad14813218b81065a4c6bccd7d0c Mon Sep 17 00:00:00 2001 From: James Zaki Date: Wed, 18 Sep 2024 15:22:57 +0100 Subject: [PATCH 7/9] add example readme --- examples/README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 examples/README.md diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..d34304c --- /dev/null +++ b/examples/README.md @@ -0,0 +1,2 @@ +These examples will be moved to another repo so that they can be tested/updated. +`nargo` currently ascends the directory structure to the highest found Nargo.toml file. From bb8ea03425340d49ff259e39347661849a645261 Mon Sep 17 00:00:00 2001 From: James Zaki Date: Wed, 18 Sep 2024 15:57:09 +0100 Subject: [PATCH 8/9] Update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7725ce9..6e72e04 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ A library to encode ASCII into Base64 and decode Base64 into ASCII. ## Dependencies -- Noir ≥v0.31.0 -- Barretenberg ≥v0.46.1 +- Noir ≥v0.34.0 +- Compatible version of a proving backend, eg Barretenberg Refer to [Noir's docs](https://noir-lang.org/docs/getting_started/installation/) and [Barretenberg's docs](https://github.com/AztecProtocol/aztec-packages/blob/master/barretenberg/cpp/src/barretenberg/bb/readme.md#installation) for installation steps. From 2d72fe374e78e4ec42f482983da8c6aabf3923ec Mon Sep 17 00:00:00 2001 From: James Zaki Date: Thu, 19 Sep 2024 10:47:01 +0100 Subject: [PATCH 9/9] Update lib dep path in examples --- examples/example1/Nargo.toml | 2 +- examples/example2/Nargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/example1/Nargo.toml b/examples/example1/Nargo.toml index 50abac5..2f9acbc 100644 --- a/examples/example1/Nargo.toml +++ b/examples/example1/Nargo.toml @@ -5,4 +5,4 @@ authors = [""] compiler_version = ">=0.34.0" [dependencies] -noir_base64 = { path = "../../lib" } \ No newline at end of file +noir_base64 = { path = "../.." } \ No newline at end of file diff --git a/examples/example2/Nargo.toml b/examples/example2/Nargo.toml index 790a860..0debc41 100644 --- a/examples/example2/Nargo.toml +++ b/examples/example2/Nargo.toml @@ -5,4 +5,4 @@ authors = [""] compiler_version = ">=0.34.0" [dependencies] -noir_base64 = { path = "../../lib" } \ No newline at end of file +noir_base64 = { path = "../.." } \ No newline at end of file