diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..934b9d8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*/dist/**
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..082cd43
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "libsodium/libsodium"]
+ path = libsodium/libsodium
+ url = https://github.com/jedisct1/libsodium.git
+[submodule "cbor/tinycbor"]
+ path = cbor/tinycbor
+ url = https://github.com/intel/tinycbor.git
diff --git a/cbor/CMakeLists.txt b/cbor/CMakeLists.txt
new file mode 100644
index 0000000..f213c22
--- /dev/null
+++ b/cbor/CMakeLists.txt
@@ -0,0 +1,20 @@
+idf_component_register(SRCS "tinycbor/src/cborencoder_close_container_checked.c"
+ "tinycbor/src/cborencoder.c"
+ "tinycbor/src/cborerrorstrings.c"
+ "tinycbor/src/cborparser_dup_string.c"
+ "tinycbor/src/cborparser.c"
+ "tinycbor/src/cborpretty_stdio.c"
+ "tinycbor/src/cborpretty.c"
+ "tinycbor/src/cbortojson.c"
+ "tinycbor/src/cborvalidation.c"
+ "tinycbor/src/open_memstream.c"
+ INCLUDE_DIRS "port/include"
+ PRIV_INCLUDE_DIRS "tinycbor/src")
+
+# for open_memstream.c
+set_source_files_properties(tinycbor/src/open_memstream.c PROPERTIES COMPILE_DEFINITIONS "__linux__")
+
+# workaround for the fact that we are passing -ffreestanding to Clang
+if(CMAKE_C_COMPILER_ID MATCHES "Clang")
+ target_compile_options(${COMPONENT_LIB} PRIVATE "-U __STDC_HOSTED__")
+endif()
diff --git a/cbor/LICENSE b/cbor/LICENSE
new file mode 120000
index 0000000..7dfaefc
--- /dev/null
+++ b/cbor/LICENSE
@@ -0,0 +1 @@
+tinycbor/LICENSE
\ No newline at end of file
diff --git a/cbor/README.md b/cbor/README.md
new file mode 120000
index 0000000..f7f75f4
--- /dev/null
+++ b/cbor/README.md
@@ -0,0 +1 @@
+tinycbor/README
\ No newline at end of file
diff --git a/cbor/idf_component.yml b/cbor/idf_component.yml
new file mode 100644
index 0000000..ff92d94
--- /dev/null
+++ b/cbor/idf_component.yml
@@ -0,0 +1,5 @@
+version: "0.5.4"
+description: "CBOR: Concise Binary Object Representation Library"
+url: https://github.com/espressif/idf-extra-components/tree/master/cbor
+dependencies:
+ idf: ">=4.3"
\ No newline at end of file
diff --git a/cbor/port/include/cbor.h b/cbor/port/include/cbor.h
new file mode 100644
index 0000000..c8e6ccf
--- /dev/null
+++ b/cbor/port/include/cbor.h
@@ -0,0 +1,2 @@
+#include "../../tinycbor/src/cbor.h"
+#include "../../tinycbor/src/cborjson.h"
diff --git a/cbor/tinycbor b/cbor/tinycbor
new file mode 160000
index 0000000..7c349db
--- /dev/null
+++ b/cbor/tinycbor
@@ -0,0 +1 @@
+Subproject commit 7c349dbb6b8d76db39383b226d3ebdf59b8ab37d
diff --git a/jsmn/CMakeLists.txt b/jsmn/CMakeLists.txt
new file mode 100644
index 0000000..d05badb
--- /dev/null
+++ b/jsmn/CMakeLists.txt
@@ -0,0 +1,10 @@
+idf_component_register(SRCS "src/jsmn.c"
+ INCLUDE_DIRS "include")
+
+if(CONFIG_JSMN_PARENT_LINKS)
+ target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DJSMN_PARENT_LINKS")
+endif()
+
+if(CONFIG_JSMN_STRICT)
+ target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DJSMN_STRICT")
+endif()
diff --git a/jsmn/Kconfig b/jsmn/Kconfig
new file mode 100644
index 0000000..114fbe4
--- /dev/null
+++ b/jsmn/Kconfig
@@ -0,0 +1,16 @@
+menu "jsmn"
+
+
+ config JSMN_PARENT_LINKS
+ bool "Enable parent links"
+ default n
+ help
+ You can access to parent node of parsed json
+
+ config JSMN_STRICT
+ bool "Enable strict mode"
+ default n
+ help
+ In strict mode primitives are: numbers and booleans
+
+endmenu
diff --git a/jsmn/LICENSE b/jsmn/LICENSE
new file mode 100644
index 0000000..e50f5ae
--- /dev/null
+++ b/jsmn/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2010 Serge A. Zaitsev
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/jsmn/README.md b/jsmn/README.md
new file mode 100644
index 0000000..5bde6fb
--- /dev/null
+++ b/jsmn/README.md
@@ -0,0 +1,168 @@
+JSMN
+====
+
+[![Build Status](https://travis-ci.org/zserge/jsmn.svg?branch=master)](https://travis-ci.org/zserge/jsmn)
+
+jsmn (pronounced like 'jasmine') is a minimalistic JSON parser in C. It can be
+easily integrated into resource-limited or embedded projects.
+
+You can find more information about JSON format at [json.org][1]
+
+Library sources are available at https://github.com/zserge/jsmn
+
+The web page with some information about jsmn can be found at
+[http://zserge.com/jsmn.html][2]
+
+Philosophy
+----------
+
+Most JSON parsers offer you a bunch of functions to load JSON data, parse it
+and extract any value by its name. jsmn proves that checking the correctness of
+every JSON packet or allocating temporary objects to store parsed JSON fields
+often is an overkill.
+
+JSON format itself is extremely simple, so why should we complicate it?
+
+jsmn is designed to be **robust** (it should work fine even with erroneous
+data), **fast** (it should parse data on the fly), **portable** (no superfluous
+dependencies or non-standard C extensions). And of course, **simplicity** is a
+key feature - simple code style, simple algorithm, simple integration into
+other projects.
+
+Features
+--------
+
+* compatible with C89
+* no dependencies (even libc!)
+* highly portable (tested on x86/amd64, ARM, AVR)
+* about 200 lines of code
+* extremely small code footprint
+* API contains only 2 functions
+* no dynamic memory allocation
+* incremental single-pass parsing
+* library code is covered with unit-tests
+
+Design
+------
+
+The rudimentary jsmn object is a **token**. Let's consider a JSON string:
+
+ '{ "name" : "Jack", "age" : 27 }'
+
+It holds the following tokens:
+
+* Object: `{ "name" : "Jack", "age" : 27}` (the whole object)
+* Strings: `"name"`, `"Jack"`, `"age"` (keys and some values)
+* Number: `27`
+
+In jsmn, tokens do not hold any data, but point to token boundaries in JSON
+string instead. In the example above jsmn will create tokens like: Object
+[0..31], String [3..7], String [12..16], String [20..23], Number [27..29].
+
+Every jsmn token has a type, which indicates the type of corresponding JSON
+token. jsmn supports the following token types:
+
+* Object - a container of key-value pairs, e.g.:
+ `{ "foo":"bar", "x":0.3 }`
+* Array - a sequence of values, e.g.:
+ `[ 1, 2, 3 ]`
+* String - a quoted sequence of chars, e.g.: `"foo"`
+* Primitive - a number, a boolean (`true`, `false`) or `null`
+
+Besides start/end positions, jsmn tokens for complex types (like arrays
+or objects) also contain a number of child items, so you can easily follow
+object hierarchy.
+
+This approach provides enough information for parsing any JSON data and makes
+it possible to use zero-copy techniques.
+
+Install
+-------
+
+To clone the repository you should have Git installed. Just run:
+
+ $ git clone https://github.com/zserge/jsmn
+
+Repository layout is simple: jsmn.c and jsmn.h are library files, tests are in
+the jsmn\_test.c, you will also find README, LICENSE and Makefile files inside.
+
+To build the library, run `make`. It is also recommended to run `make test`.
+Let me know, if some tests fail.
+
+If build was successful, you should get a `libjsmn.a` library.
+The header file you should include is called `"jsmn.h"`.
+
+API
+---
+
+Token types are described by `jsmntype_t`:
+
+ typedef enum {
+ JSMN_UNDEFINED = 0,
+ JSMN_OBJECT = 1,
+ JSMN_ARRAY = 2,
+ JSMN_STRING = 3,
+ JSMN_PRIMITIVE = 4
+ } jsmntype_t;
+
+**Note:** Unlike JSON data types, primitive tokens are not divided into
+numbers, booleans and null, because one can easily tell the type using the
+first character:
+
+* 't', 'f'
- boolean
+* 'n'
- null
+* '-', '0'..'9'
- number
+
+Token is an object of `jsmntok_t` type:
+
+ typedef struct {
+ jsmntype_t type; // Token type
+ int start; // Token start position
+ int end; // Token end position
+ int size; // Number of child (nested) tokens
+ } jsmntok_t;
+
+**Note:** string tokens point to the first character after
+the opening quote and the previous symbol before final quote. This was made
+to simplify string extraction from JSON data.
+
+All job is done by `jsmn_parser` object. You can initialize a new parser using:
+
+ jsmn_parser parser;
+ jsmntok_t tokens[10];
+
+ jsmn_init(&parser);
+
+ // js - pointer to JSON string
+ // tokens - an array of tokens available
+ // 10 - number of tokens available
+ jsmn_parse(&parser, js, strlen(js), tokens, 10);
+
+This will create a parser, and then it tries to parse up to 10 JSON tokens from
+the `js` string.
+
+A non-negative return value of `jsmn_parse` is the number of tokens actually
+used by the parser.
+Passing NULL instead of the tokens array would not store parsing results, but
+instead the function will return the value of tokens needed to parse the given
+string. This can be useful if you don't know yet how many tokens to allocate.
+
+If something goes wrong, you will get an error. Error will be one of these:
+
+* `JSMN_ERROR_INVAL` - bad token, JSON string is corrupted
+* `JSMN_ERROR_NOMEM` - not enough tokens, JSON string is too large
+* `JSMN_ERROR_PART` - JSON string is too short, expecting more JSON data
+
+If you get `JSMN_ERROR_NOMEM`, you can re-allocate more tokens and call
+`jsmn_parse` once more. If you read json data from the stream, you can
+periodically call `jsmn_parse` and check if return value is `JSMN_ERROR_PART`.
+You will get this error until you reach the end of JSON data.
+
+Other info
+----------
+
+This software is distributed under [MIT license](http://www.opensource.org/licenses/mit-license.php),
+ so feel free to integrate it in your commercial products.
+
+[1]: http://www.json.org/
+[2]: http://zserge.com/jsmn.html
\ No newline at end of file
diff --git a/jsmn/idf_component.yml b/jsmn/idf_component.yml
new file mode 100644
index 0000000..180edbd
--- /dev/null
+++ b/jsmn/idf_component.yml
@@ -0,0 +1,5 @@
+version: "1.0.0"
+description: "JSMN: minimalistic JSON parser in C"
+url: https://github.com/espressif/idf-extra-components/tree/master/jsmn
+dependencies:
+ idf: ">=4.3"
diff --git a/jsmn/include/jsmn.h b/jsmn/include/jsmn.h
new file mode 100644
index 0000000..1df808e
--- /dev/null
+++ b/jsmn/include/jsmn.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2010 Serge A. Zaitsev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @file jsmn.h
+ * @brief Definition of the JSMN (Jasmine) JSON parser.
+ *
+ * For more information on JSMN:
+ * @see http://zserge.com/jsmn.html
+ */
+
+#ifndef __JSMN_H_
+#define __JSMN_H_
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * JSON type identifier. Basic types are:
+ * o Object
+ * o Array
+ * o String
+ * o Other primitive: number, boolean (true/false) or null
+ */
+typedef enum {
+ JSMN_UNDEFINED = 0,
+ JSMN_OBJECT = 1,
+ JSMN_ARRAY = 2,
+ JSMN_STRING = 3,
+ JSMN_PRIMITIVE = 4
+} jsmntype_t;
+
+enum jsmnerr {
+ /* Not enough tokens were provided */
+ JSMN_ERROR_NOMEM = -1,
+ /* Invalid character inside JSON string */
+ JSMN_ERROR_INVAL = -2,
+ /* The string is not a full JSON packet, more bytes expected */
+ JSMN_ERROR_PART = -3
+};
+
+/**
+ * JSON token description.
+ * @param type type (object, array, string etc.)
+ * @param start start position in JSON data string
+ * @param end end position in JSON data string
+ */
+typedef struct {
+ jsmntype_t type;
+ int start;
+ int end;
+ int size;
+#ifdef JSMN_PARENT_LINKS
+ int parent;
+#endif
+} jsmntok_t;
+
+/**
+ * JSON parser. Contains an array of token blocks available. Also stores
+ * the string being parsed now and current position in that string
+ */
+typedef struct {
+ unsigned int pos; /* offset in the JSON string */
+ unsigned int toknext; /* next token to allocate */
+ int toksuper; /* superior token node, e.g parent object or array */
+} jsmn_parser;
+
+/**
+ * Create JSON parser over an array of tokens
+ */
+void jsmn_init(jsmn_parser *parser);
+
+/**
+ * Run JSON parser. It parses a JSON data string into and array of tokens, each describing
+ * a single JSON object.
+ */
+int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
+ jsmntok_t *tokens, unsigned int num_tokens);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __JSMN_H_ */
diff --git a/jsmn/src/jsmn.c b/jsmn/src/jsmn.c
new file mode 100644
index 0000000..2769b1d
--- /dev/null
+++ b/jsmn/src/jsmn.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2010 Serge A. Zaitsev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @file jsmn.c
+ * @brief Implementation of the JSMN (Jasmine) JSON parser.
+ *
+ * For more information on JSMN:
+ * @see http://zserge.com/jsmn.html
+ */
+
+#include "jsmn.h"
+
+/**
+ * Allocates a fresh unused token from the token pull.
+ */
+static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
+ jsmntok_t *tokens, size_t num_tokens) {
+ jsmntok_t *tok;
+ if (parser->toknext >= num_tokens) {
+ return NULL;
+ }
+ tok = &tokens[parser->toknext++];
+ tok->start = tok->end = -1;
+ tok->size = 0;
+#ifdef JSMN_PARENT_LINKS
+ tok->parent = -1;
+#endif
+ return tok;
+}
+
+/**
+ * Fills token type and boundaries.
+ */
+static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
+ int start, int end) {
+ token->type = type;
+ token->start = start;
+ token->end = end;
+ token->size = 0;
+}
+
+/**
+ * Fills next available token with JSON primitive.
+ */
+static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
+ size_t len, jsmntok_t *tokens, size_t num_tokens) {
+ jsmntok_t *token;
+ int start;
+
+ start = parser->pos;
+
+ for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+ switch (js[parser->pos]) {
+#ifndef JSMN_STRICT
+ /* In strict mode primitive must be followed by "," or "}" or "]" */
+ case ':':
+#endif
+ case '\t' : case '\r' : case '\n' : case ' ' :
+ case ',' : case ']' : case '}' :
+ goto found;
+ }
+ if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ }
+#ifdef JSMN_STRICT
+ /* In strict mode primitive must be followed by a comma/object/array */
+ parser->pos = start;
+ return JSMN_ERROR_PART;
+#endif
+
+found:
+ if (tokens == NULL) {
+ parser->pos--;
+ return 0;
+ }
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
+ if (token == NULL) {
+ parser->pos = start;
+ return JSMN_ERROR_NOMEM;
+ }
+ jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+ token->parent = parser->toksuper;
+#endif
+ parser->pos--;
+ return 0;
+}
+
+/**
+ * Fills next token with JSON string.
+ */
+static int jsmn_parse_string(jsmn_parser *parser, const char *js,
+ size_t len, jsmntok_t *tokens, size_t num_tokens) {
+ jsmntok_t *token;
+
+ int start = parser->pos;
+
+ parser->pos++;
+
+ /* Skip starting quote */
+ for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+ char c = js[parser->pos];
+
+ /* Quote: end of string */
+ if (c == '\"') {
+ if (tokens == NULL) {
+ return 0;
+ }
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
+ if (token == NULL) {
+ parser->pos = start;
+ return JSMN_ERROR_NOMEM;
+ }
+ jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+ token->parent = parser->toksuper;
+#endif
+ return 0;
+ }
+
+ /* Backslash: Quoted symbol expected */
+ if (c == '\\' && parser->pos + 1 < len) {
+ int i;
+ parser->pos++;
+ switch (js[parser->pos]) {
+ /* Allowed escaped symbols */
+ case '\"': case '/' : case '\\' : case 'b' :
+ case 'f' : case 'r' : case 'n' : case 't' :
+ break;
+ /* Allows escaped symbol \uXXXX */
+ case 'u':
+ parser->pos++;
+ for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
+ /* If it isn't a hex character we have an error */
+ if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
+ (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
+ (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ parser->pos++;
+ }
+ parser->pos--;
+ break;
+ /* Unexpected symbol */
+ default:
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ }
+ }
+ parser->pos = start;
+ return JSMN_ERROR_PART;
+}
+
+/**
+ * Parse JSON string and fill tokens.
+ */
+int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
+ jsmntok_t *tokens, unsigned int num_tokens) {
+ int r;
+ int i;
+ jsmntok_t *token;
+ int count = parser->toknext;
+
+ for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+ char c;
+ jsmntype_t type;
+
+ c = js[parser->pos];
+ switch (c) {
+ case '{': case '[':
+ count++;
+ if (tokens == NULL) {
+ break;
+ }
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
+ if (token == NULL)
+ return JSMN_ERROR_NOMEM;
+ if (parser->toksuper != -1) {
+ tokens[parser->toksuper].size++;
+#ifdef JSMN_PARENT_LINKS
+ token->parent = parser->toksuper;
+#endif
+ }
+ token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
+ token->start = parser->pos;
+ parser->toksuper = parser->toknext - 1;
+ break;
+ case '}': case ']':
+ if (tokens == NULL)
+ break;
+ type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
+#ifdef JSMN_PARENT_LINKS
+ if (parser->toknext < 1) {
+ return JSMN_ERROR_INVAL;
+ }
+ token = &tokens[parser->toknext - 1];
+ for (;;) {
+ if (token->start != -1 && token->end == -1) {
+ if (token->type != type) {
+ return JSMN_ERROR_INVAL;
+ }
+ token->end = parser->pos + 1;
+ parser->toksuper = token->parent;
+ break;
+ }
+ if (token->parent == -1) {
+ break;
+ }
+ token = &tokens[token->parent];
+ }
+#else
+ for (i = parser->toknext - 1; i >= 0; i--) {
+ token = &tokens[i];
+ if (token->start != -1 && token->end == -1) {
+ if (token->type != type) {
+ return JSMN_ERROR_INVAL;
+ }
+ parser->toksuper = -1;
+ token->end = parser->pos + 1;
+ break;
+ }
+ }
+ /* Error if unmatched closing bracket */
+ if (i == -1) return JSMN_ERROR_INVAL;
+ for (; i >= 0; i--) {
+ token = &tokens[i];
+ if (token->start != -1 && token->end == -1) {
+ parser->toksuper = i;
+ break;
+ }
+ }
+#endif
+ break;
+ case '\"':
+ r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
+ if (r < 0) return r;
+ count++;
+ if (parser->toksuper != -1 && tokens != NULL)
+ tokens[parser->toksuper].size++;
+ break;
+ case '\t' : case '\r' : case '\n' : case ' ':
+ break;
+ case ':':
+ parser->toksuper = parser->toknext - 1;
+ break;
+ case ',':
+ if (tokens != NULL && parser->toksuper != -1 &&
+ tokens[parser->toksuper].type != JSMN_ARRAY &&
+ tokens[parser->toksuper].type != JSMN_OBJECT) {
+#ifdef JSMN_PARENT_LINKS
+ parser->toksuper = tokens[parser->toksuper].parent;
+#else
+ for (i = parser->toknext - 1; i >= 0; i--) {
+ if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
+ if (tokens[i].start != -1 && tokens[i].end == -1) {
+ parser->toksuper = i;
+ break;
+ }
+ }
+ }
+#endif
+ }
+ break;
+#ifdef JSMN_STRICT
+ /* In strict mode primitives are: numbers and booleans */
+ case '-': case '0': case '1' : case '2': case '3' : case '4':
+ case '5': case '6': case '7' : case '8': case '9':
+ case 't': case 'f': case 'n' :
+ /* And they must not be keys of the object */
+ if (tokens != NULL && parser->toksuper != -1) {
+ jsmntok_t *t = &tokens[parser->toksuper];
+ if (t->type == JSMN_OBJECT ||
+ (t->type == JSMN_STRING && t->size != 0)) {
+ return JSMN_ERROR_INVAL;
+ }
+ }
+#else
+ /* In non-strict mode every unquoted value is a primitive */
+ default:
+#endif
+ r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
+ if (r < 0) return r;
+ count++;
+ if (parser->toksuper != -1 && tokens != NULL)
+ tokens[parser->toksuper].size++;
+ break;
+
+#ifdef JSMN_STRICT
+ /* Unexpected char in strict mode */
+ default:
+ return JSMN_ERROR_INVAL;
+#endif
+ }
+ }
+
+ if (tokens != NULL) {
+ for (i = parser->toknext - 1; i >= 0; i--) {
+ /* Unmatched opened object or array */
+ if (tokens[i].start != -1 && tokens[i].end == -1) {
+ return JSMN_ERROR_PART;
+ }
+ }
+ }
+
+ return count;
+}
+
+/**
+ * Creates a new parser based over a given buffer with an array of tokens
+ * available.
+ */
+void jsmn_init(jsmn_parser *parser) {
+ parser->pos = 0;
+ parser->toknext = 0;
+ parser->toksuper = -1;
+}
diff --git a/libsodium/CMakeLists.txt b/libsodium/CMakeLists.txt
new file mode 100644
index 0000000..ac3e87f
--- /dev/null
+++ b/libsodium/CMakeLists.txt
@@ -0,0 +1,178 @@
+set(SRC libsodium/src/libsodium)
+# Derived from libsodium/src/libsodium/Makefile.am
+# (ignoring the !MINIMAL set)
+set(srcs
+ "${SRC}/crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c"
+ "${SRC}/crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c"
+ "${SRC}/crypto_auth/crypto_auth.c"
+ "${SRC}/crypto_auth/hmacsha256/auth_hmacsha256.c"
+ "${SRC}/crypto_auth/hmacsha512/auth_hmacsha512.c"
+ "${SRC}/crypto_auth/hmacsha512256/auth_hmacsha512256.c"
+ "${SRC}/crypto_box/crypto_box.c"
+ "${SRC}/crypto_box/crypto_box_easy.c"
+ "${SRC}/crypto_box/crypto_box_seal.c"
+ "${SRC}/crypto_box/curve25519xchacha20poly1305/box_curve25519xchacha20poly1305.c"
+ "${SRC}/crypto_box/curve25519xchacha20poly1305/box_seal_curve25519xchacha20poly1305.c"
+ "${SRC}/crypto_box/curve25519xsalsa20poly1305/box_curve25519xsalsa20poly1305.c"
+ "${SRC}/crypto_core/ed25519/core_ed25519.c"
+ "${SRC}/crypto_core/ed25519/core_ristretto255.c"
+ "${SRC}/crypto_core/ed25519/ref10/ed25519_ref10.c"
+ "${SRC}/crypto_core/hchacha20/core_hchacha20.c"
+ "${SRC}/crypto_core/hsalsa20/core_hsalsa20.c"
+ "${SRC}/crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c"
+ "${SRC}/crypto_core/salsa/ref/core_salsa_ref.c"
+ "${SRC}/crypto_generichash/blake2b/generichash_blake2.c"
+ "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-avx2.c"
+ "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-ref.c"
+ "${SRC}/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.c"
+ "${SRC}/crypto_generichash/blake2b/ref/blake2b-ref.c"
+ "${SRC}/crypto_generichash/blake2b/ref/generichash_blake2b.c"
+ "${SRC}/crypto_generichash/crypto_generichash.c"
+ "${SRC}/crypto_hash/crypto_hash.c"
+ "${SRC}/crypto_hash/sha256/cp/hash_sha256_cp.c"
+ "${SRC}/crypto_hash/sha256/hash_sha256.c"
+ "${SRC}/crypto_hash/sha512/cp/hash_sha512_cp.c"
+ "${SRC}/crypto_hash/sha512/hash_sha512.c"
+ "${SRC}/crypto_kdf/blake2b/kdf_blake2b.c"
+ "${SRC}/crypto_kdf/crypto_kdf.c"
+ "${SRC}/crypto_kx/crypto_kx.c"
+ "${SRC}/crypto_onetimeauth/crypto_onetimeauth.c"
+ "${SRC}/crypto_onetimeauth/poly1305/donna/poly1305_donna.c"
+ "${SRC}/crypto_onetimeauth/poly1305/onetimeauth_poly1305.c"
+ "${SRC}/crypto_pwhash/argon2/argon2-core.c"
+ "${SRC}/crypto_pwhash/argon2/argon2-encoding.c"
+ "${SRC}/crypto_pwhash/argon2/argon2-fill-block-avx2.c"
+ "${SRC}/crypto_pwhash/argon2/argon2-fill-block-avx512f.c"
+ "${SRC}/crypto_pwhash/argon2/argon2-fill-block-ref.c"
+ "${SRC}/crypto_pwhash/argon2/argon2-fill-block-ssse3.c"
+ "${SRC}/crypto_pwhash/argon2/argon2.c"
+ "${SRC}/crypto_pwhash/argon2/blake2b-long.c"
+ "${SRC}/crypto_pwhash/argon2/pwhash_argon2i.c"
+ "${SRC}/crypto_pwhash/argon2/pwhash_argon2id.c"
+ "${SRC}/crypto_pwhash/crypto_pwhash.c"
+ "${SRC}/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c"
+ "${SRC}/crypto_pwhash/scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c"
+ "${SRC}/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.c"
+ "${SRC}/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c"
+ "${SRC}/crypto_pwhash/scryptsalsa208sha256/scrypt_platform.c"
+ "${SRC}/crypto_scalarmult/crypto_scalarmult.c"
+ "${SRC}/crypto_scalarmult/curve25519/ref10/x25519_ref10.c"
+ "${SRC}/crypto_scalarmult/curve25519/sandy2x/consts.S"
+ "${SRC}/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.c"
+ "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_invert.c"
+ "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_mul.S"
+ "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_nsquare.S"
+ "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe51_pack.S"
+ "${SRC}/crypto_scalarmult/curve25519/sandy2x/fe_frombytes_sandy2x.c"
+ "${SRC}/crypto_scalarmult/curve25519/sandy2x/ladder.S"
+ "${SRC}/crypto_scalarmult/curve25519/sandy2x/sandy2x.S"
+ "${SRC}/crypto_scalarmult/curve25519/scalarmult_curve25519.c"
+ "${SRC}/crypto_scalarmult/ed25519/ref10/scalarmult_ed25519_ref10.c"
+ "${SRC}/crypto_scalarmult/ristretto255/ref10/scalarmult_ristretto255_ref10.c"
+ "${SRC}/crypto_secretbox/crypto_secretbox.c"
+ "${SRC}/crypto_secretbox/crypto_secretbox_easy.c"
+ "${SRC}/crypto_secretbox/xchacha20poly1305/secretbox_xchacha20poly1305.c"
+ "${SRC}/crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305.c"
+ "${SRC}/crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c"
+ "${SRC}/crypto_shorthash/crypto_shorthash.c"
+ "${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c"
+ "${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphashx24_ref.c"
+ "${SRC}/crypto_shorthash/siphash24/shorthash_siphash24.c"
+ "${SRC}/crypto_shorthash/siphash24/shorthash_siphashx24.c"
+ "${SRC}/crypto_sign/crypto_sign.c"
+ "${SRC}/crypto_sign/ed25519/ref10/keypair.c"
+ "${SRC}/crypto_sign/ed25519/ref10/obsolete.c"
+ "${SRC}/crypto_sign/ed25519/ref10/open.c"
+ "${SRC}/crypto_sign/ed25519/ref10/sign.c"
+ "${SRC}/crypto_sign/ed25519/sign_ed25519.c"
+ "${SRC}/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.c"
+ "${SRC}/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.c"
+ "${SRC}/crypto_stream/chacha20/ref/chacha20_ref.c"
+ "${SRC}/crypto_stream/chacha20/stream_chacha20.c"
+ "${SRC}/crypto_stream/crypto_stream.c"
+ "${SRC}/crypto_stream/salsa20/ref/salsa20_ref.c"
+ "${SRC}/crypto_stream/salsa20/stream_salsa20.c"
+ "${SRC}/crypto_stream/salsa20/xmm6/salsa20_xmm6-asm.S"
+ "${SRC}/crypto_stream/salsa20/xmm6/salsa20_xmm6.c"
+ "${SRC}/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.c"
+ "${SRC}/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.c"
+ "${SRC}/crypto_stream/salsa2012/ref/stream_salsa2012_ref.c"
+ "${SRC}/crypto_stream/salsa2012/stream_salsa2012.c"
+ "${SRC}/crypto_stream/salsa208/ref/stream_salsa208_ref.c"
+ "${SRC}/crypto_stream/salsa208/stream_salsa208.c"
+ "${SRC}/crypto_stream/xchacha20/stream_xchacha20.c"
+ "${SRC}/crypto_stream/xsalsa20/stream_xsalsa20.c"
+ "${SRC}/crypto_verify/sodium/verify.c"
+ "${SRC}/randombytes/randombytes.c"
+ "${SRC}/sodium/codecs.c"
+ "${SRC}/sodium/core.c"
+ "${SRC}/sodium/runtime.c"
+ "${SRC}/sodium/utils.c"
+ "${SRC}/sodium/version.c"
+ "port/randombytes_esp32.c")
+
+if(CONFIG_LIBSODIUM_USE_MBEDTLS_SHA)
+ list(APPEND srcs
+ "port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c"
+ "port/crypto_hash_mbedtls/crypto_hash_sha512_mbedtls.c")
+else()
+ list(APPEND srcs
+ "${SRC}/crypto_hash/sha256/cp/hash_sha256_cp.c"
+ "${SRC}/crypto_hash/sha512/cp/hash_sha512_cp.c")
+endif()
+
+set(include_dirs ${SRC}/include port_include)
+set(priv_include_dirs ${SRC}/include/sodium port_include/sodium port)
+idf_component_register(SRCS "${srcs}"
+ INCLUDE_DIRS "${include_dirs}"
+ PRIV_INCLUDE_DIRS "${priv_include_dirs}"
+ REQUIRES mbedtls)
+
+target_compile_definitions(${COMPONENT_LIB} PRIVATE
+ CONFIGURED
+ NATIVE_LITTLE_ENDIAN
+ HAVE_WEAK_SYMBOLS
+ __STDC_LIMIT_MACROS
+ __STDC_CONSTANT_MACROS
+ )
+
+# patch around warnings in third-party files
+set_source_files_properties(
+ ${SRC}/crypto_pwhash/argon2/pwhash_argon2i.c
+ ${SRC}/crypto_pwhash/argon2/pwhash_argon2id.c
+ ${SRC}/crypto_pwhash/argon2/argon2-core.c
+ ${SRC}/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c
+ PROPERTIES COMPILE_FLAGS
+ -Wno-type-limits
+ )
+set_source_files_properties(
+ ${SRC}/sodium/utils.c
+ PROPERTIES COMPILE_FLAGS
+ -Wno-unused-variable
+ )
+set_source_files_properties(
+ ${SRC}/crypto_pwhash/argon2/argon2-fill-block-ref.c
+ PROPERTIES COMPILE_FLAGS
+ -Wno-unknown-pragmas
+ )
+
+# Temporary suppress "fallthrough" warnings until they are fixed in libsodium repo
+set_source_files_properties(
+ ${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphashx24_ref.c
+ ${SRC}/crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c
+ PROPERTIES COMPILE_FLAGS
+ -Wno-implicit-fallthrough
+ )
+
+set_source_files_properties(
+ ${SRC}/randombytes/randombytes.c
+ PROPERTIES COMPILE_FLAGS
+ -DRANDOMBYTES_DEFAULT_IMPLEMENTATION
+)
+
+target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-function)
+
+if(CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE)
+ # some libsodium variables are only used for asserts
+ target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-but-set-variable)
+endif()
diff --git a/libsodium/Kconfig b/libsodium/Kconfig
new file mode 100644
index 0000000..4d500f2
--- /dev/null
+++ b/libsodium/Kconfig
@@ -0,0 +1,15 @@
+menu "libsodium"
+
+ config LIBSODIUM_USE_MBEDTLS_SHA
+ bool "Use mbedTLS SHA256 & SHA512 implementations"
+ default y
+ depends on !MBEDTLS_HARDWARE_SHA
+ help
+ If this option is enabled, libsodium will use thin wrappers
+ around mbedTLS for SHA256 & SHA512 operations.
+
+ This saves some code size if mbedTLS is also used. However it
+ is incompatible with hardware SHA acceleration (due to the
+ way libsodium's API manages SHA state).
+
+endmenu # libsodium
diff --git a/libsodium/LICENSE b/libsodium/LICENSE
new file mode 120000
index 0000000..40c3df3
--- /dev/null
+++ b/libsodium/LICENSE
@@ -0,0 +1 @@
+libsodium/LICENSE
\ No newline at end of file
diff --git a/libsodium/README.md b/libsodium/README.md
new file mode 120000
index 0000000..69dfaf5
--- /dev/null
+++ b/libsodium/README.md
@@ -0,0 +1 @@
+libsodium/README.markdown
\ No newline at end of file
diff --git a/libsodium/idf_component.yml b/libsodium/idf_component.yml
new file mode 100644
index 0000000..3c15bb9
--- /dev/null
+++ b/libsodium/idf_component.yml
@@ -0,0 +1,6 @@
+
+version: "1.0.18"
+description: libsodium port to ESP32
+url: https://github.com/espressif/idf-extra-components/tree/master/libsodium
+dependencies:
+ idf: ">=4.2"
\ No newline at end of file
diff --git a/libsodium/libsodium b/libsodium/libsodium
new file mode 160000
index 0000000..4f5e89f
--- /dev/null
+++ b/libsodium/libsodium
@@ -0,0 +1 @@
+Subproject commit 4f5e89fa84ce1d178a6765b8b46f2b6f91216677
diff --git a/libsodium/port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c b/libsodium/port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c
new file mode 100644
index 0000000..13b6a39
--- /dev/null
+++ b/libsodium/port/crypto_hash_mbedtls/crypto_hash_sha256_mbedtls.c
@@ -0,0 +1,93 @@
+/*
+ * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "crypto_hash_sha256.h"
+#include "mbedtls/sha256.h"
+#include
+
+#ifdef MBEDTLS_SHA256_ALT
+/* Wrapper only works if the libsodium context structure can be mapped
+ directly to the mbedTLS context structure.
+
+ See extended comments in crypto_hash_sha512_mbedtls.c
+*/
+#error "This wrapper only support standard software mbedTLS SHA"
+#endif
+
+/* Sanity check that all the context fields have identical sizes
+ (this should be more or less given from the SHA256 algorithm)
+
+ Note that the meaning of the fields is *not* all the same. In libsodium, SHA256 'count' is a 64-bit *bit* count. In
+ mbedTLS, 'total' is a 2x32-bit *byte* count (count[0] == MSB).
+
+ For this implementation, we don't convert so the libsodium state structure actually holds a binary copy of the
+ mbedTLS totals. This doesn't matter inside libsodium's documented API, but would matter if any callers try to use
+ the state's bit count.
+*/
+_Static_assert(sizeof(((crypto_hash_sha256_state *)0)->state) == sizeof(((mbedtls_sha256_context *)0)->state), "state mismatch");
+_Static_assert(sizeof(((crypto_hash_sha256_state *)0)->count) == sizeof(((mbedtls_sha256_context *)0)->total), "count mismatch");
+_Static_assert(sizeof(((crypto_hash_sha256_state *)0)->buf) == sizeof(((mbedtls_sha256_context *)0)->buffer), "buf mismatch");
+
+/* Inline functions to convert between mbedTLS & libsodium
+ context structures
+*/
+
+static void sha256_mbedtls_to_libsodium(crypto_hash_sha256_state *ls_state, const mbedtls_sha256_context *mb_ctx)
+{
+ memcpy(&ls_state->count, mb_ctx->total, sizeof(ls_state->count));
+ memcpy(ls_state->state, mb_ctx->state, sizeof(ls_state->state));
+ memcpy(ls_state->buf, mb_ctx->buffer, sizeof(ls_state->buf));
+}
+
+static void sha256_libsodium_to_mbedtls(mbedtls_sha256_context *mb_ctx, crypto_hash_sha256_state *ls_state)
+{
+ memcpy(mb_ctx->total, &ls_state->count, sizeof(mb_ctx->total));
+ memcpy(mb_ctx->state, ls_state->state, sizeof(mb_ctx->state));
+ memcpy(mb_ctx->buffer, ls_state->buf, sizeof(mb_ctx->buffer));
+ mb_ctx->is224 = 0;
+}
+
+int
+crypto_hash_sha256_init(crypto_hash_sha256_state *state)
+{
+ mbedtls_sha256_context ctx;
+ mbedtls_sha256_init(&ctx);
+ int ret = mbedtls_sha256_starts_ret(&ctx, 0);
+ if (ret != 0) {
+ return ret;
+ }
+ sha256_mbedtls_to_libsodium(state, &ctx);
+ return 0;
+}
+
+int
+crypto_hash_sha256_update(crypto_hash_sha256_state *state,
+ const unsigned char *in, unsigned long long inlen)
+{
+ mbedtls_sha256_context ctx;
+ sha256_libsodium_to_mbedtls(&ctx, state);
+ int ret = mbedtls_sha256_update_ret(&ctx, in, inlen);
+ if (ret != 0) {
+ return ret;
+ }
+ sha256_mbedtls_to_libsodium(state, &ctx);
+ return 0;
+}
+
+int
+crypto_hash_sha256_final(crypto_hash_sha256_state *state, unsigned char *out)
+{
+ mbedtls_sha256_context ctx;
+ sha256_libsodium_to_mbedtls(&ctx, state);
+ return mbedtls_sha256_finish_ret(&ctx, out);
+}
+
+int
+crypto_hash_sha256(unsigned char *out, const unsigned char *in,
+ unsigned long long inlen)
+{
+ return mbedtls_sha256_ret(in, inlen, out, 0);
+}
diff --git a/libsodium/port/crypto_hash_mbedtls/crypto_hash_sha512_mbedtls.c b/libsodium/port/crypto_hash_mbedtls/crypto_hash_sha512_mbedtls.c
new file mode 100644
index 0000000..d0d7a66
--- /dev/null
+++ b/libsodium/port/crypto_hash_mbedtls/crypto_hash_sha512_mbedtls.c
@@ -0,0 +1,97 @@
+/*
+ * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "crypto_hash_sha512.h"
+#include "mbedtls/sha512.h"
+#include
+
+#ifdef MBEDTLS_SHA512_ALT
+/* Wrapper only works if the libsodium context structure can be mapped
+ directly to the mbedTLS context structure.
+
+ For ESP32 hardware SHA, the problems are fitting all the data in
+ the libsodium state structure, and also that libsodium doesn't
+ have mbedtls_sha512_free() or mbedtls_sha512_clone() so we can't
+ manage the hardware state in a clean way.
+*/
+#error "This wrapper only support standard software mbedTLS SHA"
+#endif
+
+/* Sanity check that all the context fields have identical sizes
+ (this should be more or less given from the SHA512 algorithm)
+
+ Note that the meaning of the fields is *not* all the same. In libsodium,
+ SHA512 'count' is a 2xuin64_t *bit* count where count[0] == MSB. In mbedTLS,
+ SHA512 'total' is a 2xuint64_t *byte* count where count[0] == LSB.
+
+ For this implementation, we don't convert so the libsodium state structure actually holds a binary copy of the
+ mbedTLS totals. This doesn't matter inside libsodium's documented API, but would matter if any callers try to use
+ the state's bit count.
+*/
+_Static_assert(sizeof(((crypto_hash_sha512_state *)0)->state) == sizeof(((mbedtls_sha512_context *)0)->state), "state mismatch");
+_Static_assert(sizeof(((crypto_hash_sha512_state *)0)->count) == sizeof(((mbedtls_sha512_context *)0)->total), "count mismatch");
+_Static_assert(sizeof(((crypto_hash_sha512_state *)0)->buf) == sizeof(((mbedtls_sha512_context *)0)->buffer), "buf mismatch");
+
+/* Inline functions to convert between mbedTLS & libsodium
+ context structures
+*/
+
+static void sha512_mbedtls_to_libsodium(crypto_hash_sha512_state *ls_state, const mbedtls_sha512_context *mb_ctx)
+{
+ memcpy(ls_state->count, mb_ctx->total, sizeof(ls_state->count));
+ memcpy(ls_state->state, mb_ctx->state, sizeof(ls_state->state));
+ memcpy(ls_state->buf, mb_ctx->buffer, sizeof(ls_state->buf));
+}
+
+static void sha512_libsodium_to_mbedtls(mbedtls_sha512_context *mb_ctx, crypto_hash_sha512_state *ls_state)
+{
+ memcpy(mb_ctx->total, ls_state->count, sizeof(mb_ctx->total));
+ memcpy(mb_ctx->state, ls_state->state, sizeof(mb_ctx->state));
+ memcpy(mb_ctx->buffer, ls_state->buf, sizeof(mb_ctx->buffer));
+ mb_ctx->is384 = 0;
+}
+
+int
+crypto_hash_sha512_init(crypto_hash_sha512_state *state)
+{
+ mbedtls_sha512_context ctx;
+ mbedtls_sha512_init(&ctx);
+ int ret = mbedtls_sha512_starts_ret(&ctx, 0);
+ if (ret != 0) {
+ return ret;
+ }
+ sha512_mbedtls_to_libsodium(state, &ctx);
+ return 0;
+}
+
+int
+crypto_hash_sha512_update(crypto_hash_sha512_state *state,
+ const unsigned char *in, unsigned long long inlen)
+{
+ mbedtls_sha512_context ctx;
+ sha512_libsodium_to_mbedtls(&ctx, state);
+ int ret = mbedtls_sha512_update_ret(&ctx, in, inlen);
+ if (ret != 0) {
+ return ret;
+ }
+ sha512_mbedtls_to_libsodium(state, &ctx);
+ return 0;
+}
+
+int
+crypto_hash_sha512_final(crypto_hash_sha512_state *state, unsigned char *out)
+{
+ mbedtls_sha512_context ctx;
+ sha512_libsodium_to_mbedtls(&ctx, state);
+ return mbedtls_sha512_finish_ret(&ctx, out);
+}
+
+int
+crypto_hash_sha512(unsigned char *out, const unsigned char *in,
+ unsigned long long inlen)
+{
+ return mbedtls_sha512_ret(in, inlen, out, 0);
+}
diff --git a/libsodium/port/randombytes_esp32.c b/libsodium/port/randombytes_esp32.c
new file mode 100644
index 0000000..4d98538
--- /dev/null
+++ b/libsodium/port/randombytes_esp32.c
@@ -0,0 +1,28 @@
+/*
+ * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "randombytes_internal.h"
+#include "esp_system.h"
+
+static const char *randombytes_esp32xx_implementation_name(void)
+{
+ return CONFIG_IDF_TARGET;
+}
+
+/*
+ Plug the ESP32 hardware RNG into libsodium's custom RNG support, as per
+ https://download.libsodium.org/doc/advanced/custom_rng.html
+
+ Note that this RNG is selected by default (see randombytes_default.h), so there
+ is no need to call randombytes_set_implementation().
+*/
+const struct randombytes_implementation randombytes_esp32_implementation = {
+ .implementation_name = randombytes_esp32xx_implementation_name,
+ .random = esp_random,
+ .stir = NULL,
+ .uniform = NULL,
+ .buf = esp_fill_random,
+ .close = NULL,
+};
diff --git a/libsodium/port/randombytes_internal.h b/libsodium/port/randombytes_internal.h
new file mode 100644
index 0000000..35da42d
--- /dev/null
+++ b/libsodium/port/randombytes_internal.h
@@ -0,0 +1,20 @@
+/*
+ * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#pragma once
+
+# include "export.h"
+# include "randombytes.h"
+
+SODIUM_EXPORT
+extern const struct randombytes_implementation randombytes_esp32_implementation;
+
+/* Defining RANDOMBYTES_DEFAULT_IMPLEMENTATION here allows us to compile with the ESP32 hardware
+ implementation as the default. No need to call randombytes_set_implementation().
+
+ Doing it in the header like this is easier than passing it via a -D argument to gcc.
+*/
+#undef RANDOMBYTES_DEFAULT_IMPLEMENTATION
+#define RANDOMBYTES_DEFAULT_IMPLEMENTATION &randombytes_esp32_implementation
diff --git a/libsodium/port_include/sodium/version.h b/libsodium/port_include/sodium/version.h
new file mode 100644
index 0000000..6ca9192
--- /dev/null
+++ b/libsodium/port_include/sodium/version.h
@@ -0,0 +1,40 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef sodium_version_H
+#define sodium_version_H
+
+#include
+
+/* IMPORTANT: As we don't use autotools, these version are not automatically
+ updated if we change submodules. They need to be changed manually.
+*/
+
+#define SODIUM_VERSION_STRING "1.0.18-idf"
+
+/* Note: these are not the same as the overall version, see
+ configure.ac for the relevant macros */
+#define SODIUM_LIBRARY_VERSION_MAJOR 10
+#define SODIUM_LIBRARY_VERSION_MINOR 3
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SODIUM_EXPORT
+const char *sodium_version_string(void);
+
+SODIUM_EXPORT
+int sodium_library_version_major(void);
+
+SODIUM_EXPORT
+int sodium_library_version_minor(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libsodium/test/CMakeLists.txt b/libsodium/test/CMakeLists.txt
new file mode 100644
index 0000000..41de273
--- /dev/null
+++ b/libsodium/test/CMakeLists.txt
@@ -0,0 +1,36 @@
+if(TESTS_ALL EQUAL 1)
+ message("not linking libsodium tests, use '-T libsodium' to test it")
+else()
+ get_filename_component(LS_TESTDIR "${CMAKE_CURRENT_LIST_DIR}/../libsodium/test/default" ABSOLUTE)
+
+ set(TEST_CASES "chacha20;aead_chacha20poly1305;box;box2;ed25519_convert;sign;hash")
+
+ foreach(test_case ${TEST_CASES})
+ file(GLOB test_case_file "${LS_TESTDIR}/${test_case}.c")
+ list(APPEND TEST_CASES_FILES ${test_case_file})
+ endforeach()
+
+ idf_component_register(SRCS "${TEST_CASES_FILES}" "test_sodium.c"
+ PRIV_INCLUDE_DIRS "." "${LS_TESTDIR}/../quirks"
+ PRIV_REQUIRES cmock libsodium)
+
+ # The libsodium test suite is designed to be run each test case as an executable on a desktop computer and uses
+ # filesytem to write & then compare contents of each file.
+ #
+ # For now, use their "BROWSER_TEST" mode with these hacks so that
+ # multiple test cases can be combined into one ELF file.
+ #
+ # Run each test case from test_sodium.c as CASENAME_xmain().
+ foreach(test_case_file ${TEST_CASES_FILES})
+ get_filename_component(test_case ${test_case_file} NAME_WE)
+ set_source_files_properties(${test_case_file}
+ PROPERTIES COMPILE_FLAGS
+ # This would generate 'warning "main" redefined' warnings at runtime, which are
+ # silenced here. Only other solution involves patching libsodium's cmptest.h.
+ "-Dxmain=${test_case}_xmain -Dmain=${test_case}_main -Wp,-w")
+ endforeach()
+
+ # this seems odd, but it prevents the libsodium test harness from
+ # trying to write to a file!
+ add_definitions(-DBROWSER_TESTS)
+endif()
diff --git a/libsodium/test/test_sodium.c b/libsodium/test/test_sodium.c
new file mode 100644
index 0000000..22455dc
--- /dev/null
+++ b/libsodium/test/test_sodium.c
@@ -0,0 +1,124 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "unity.h"
+#include "sodium/crypto_hash_sha256.h"
+#include "sodium/crypto_hash_sha512.h"
+
+/* Note: a lot of these libsodium test programs assert() things, but they're not complete unit tests - most expect
+ output to be compared to the matching .exp file.
+
+ We don't do this automatically yet, maybe once we have more options for
+ internal filesystem storage.
+*/
+
+extern int aead_chacha20poly1305_xmain(void);
+
+TEST_CASE("aead_chacha20poly1305 test vectors", "[libsodium]")
+{
+ printf("Running aead_chacha20poly1305\n");
+ TEST_ASSERT_EQUAL(0, aead_chacha20poly1305_xmain());
+}
+
+extern int chacha20_xmain(void);
+
+TEST_CASE("chacha20 test vectors", "[libsodium]")
+{
+ printf("Running chacha20\n");
+ TEST_ASSERT_EQUAL(0, chacha20_xmain());
+}
+
+extern int box_xmain(void);
+extern int box2_xmain(void);
+
+TEST_CASE("box tests", "[libsodium]")
+{
+ printf("Running box\n");
+ TEST_ASSERT_EQUAL(0, box_xmain());
+
+ printf("Running box2\n");
+ TEST_ASSERT_EQUAL(0, box2_xmain());
+}
+
+extern int ed25519_convert_xmain(void);
+
+TEST_CASE("ed25519_convert tests", "[libsodium][timeout=60]")
+{
+ printf("Running ed25519_convert\n");
+ TEST_ASSERT_EQUAL(0, ed25519_convert_xmain() );
+}
+
+extern int sign_xmain(void);
+
+TEST_CASE("sign tests", "[libsodium]")
+{
+ printf("Running sign\n");
+ TEST_ASSERT_EQUAL(0, sign_xmain() );
+}
+
+extern int hash_xmain(void);
+
+TEST_CASE("hash tests", "[libsodium]")
+{
+ printf("Running hash\n");
+ TEST_ASSERT_EQUAL(0, hash_xmain() );
+}
+
+TEST_CASE("sha256 sanity check", "[libsodium]")
+{
+ const uint8_t expected[] = { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41,
+ 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03,
+ 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff,
+ 0x61, 0xf2, 0x00, 0x15, 0xad, };
+ uint8_t calculated[32];
+ crypto_hash_sha256_state state;
+
+ const uint8_t *in = (const uint8_t *)"abc";
+ const size_t inlen = 3;
+
+ // One-liner version
+ crypto_hash_sha256(calculated, in, inlen);
+ TEST_ASSERT_EQUAL(sizeof(calculated), sizeof(expected));
+ TEST_ASSERT_EQUAL(sizeof(calculated), crypto_hash_sha256_bytes());
+ TEST_ASSERT_EQUAL_MEMORY(expected, calculated, crypto_hash_sha256_bytes());
+
+ // Multi-line version
+ crypto_hash_sha256_init(&state);
+ crypto_hash_sha256_update(&state, in, inlen - 1); // split into two updates
+ crypto_hash_sha256_update(&state, in + (inlen -1), 1);
+ crypto_hash_sha256_final(&state, calculated);
+ TEST_ASSERT_EQUAL_MEMORY(expected, calculated, crypto_hash_sha256_bytes());
+}
+
+TEST_CASE("sha512 sanity check", "[libsodium]")
+{
+ const uint8_t expected[] = { 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc,
+ 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6,
+ 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, 0x0a, 0x9e, 0xee,
+ 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a,
+ 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3,
+ 0xfe, 0xeb, 0xbd, 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c,
+ 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4,
+ 0x9f };
+
+ uint8_t calculated[64];
+ crypto_hash_sha512_state state;
+
+ const uint8_t *in = (const uint8_t *)"abc";
+ const size_t inlen = 3;
+
+ // One-liner version
+ crypto_hash_sha512(calculated, in, inlen);
+ TEST_ASSERT_EQUAL(sizeof(calculated), sizeof(expected));
+ TEST_ASSERT_EQUAL(sizeof(calculated), crypto_hash_sha512_bytes());
+ TEST_ASSERT_EQUAL_MEMORY(expected, calculated, crypto_hash_sha512_bytes());
+
+ // Multi-line version
+ crypto_hash_sha512_init(&state);
+ crypto_hash_sha512_update(&state, in, inlen - 1); // split into two updates
+ crypto_hash_sha512_update(&state, in + (inlen -1), 1);
+ crypto_hash_sha512_final(&state, calculated);
+ TEST_ASSERT_EQUAL_MEMORY(expected, calculated, crypto_hash_sha512_bytes());
+}
diff --git a/pid_ctrl/idf_component.yml b/pid_ctrl/idf_component.yml
index 01a186b..9c21bb1 100644
--- a/pid_ctrl/idf_component.yml
+++ b/pid_ctrl/idf_component.yml
@@ -1,4 +1,5 @@
version: "0.1.0"
description: Proportional-integral-derivative controller
+url: https://github.com/espressif/idf-extra-components/tree/master/pid_ctrl
dependencies:
idf: ">=4.3"
diff --git a/qrcode/idf_component.yml b/qrcode/idf_component.yml
index 55d12d1..7f41493 100644
--- a/qrcode/idf_component.yml
+++ b/qrcode/idf_component.yml
@@ -1,4 +1,5 @@
version: "0.1.0"
description: QR Code generator
+url: https://github.com/espressif/idf-extra-components/tree/master/qr_code
dependencies:
idf: ">=4.3"