aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2017-02-06 04:20:56 +0100
committerJ08nY2017-02-06 04:20:56 +0100
commit96bf13d11b595aabf514c706adcf57aefc660a1f (patch)
tree995e149e650bc4981bb8ca05862a028be03a7827
parent763fc80153c5e9287f1b0f0609b11fb4f50c90ab (diff)
downloadecgen-96bf13d11b595aabf514c706adcf57aefc660a1f.tar.gz
ecgen-96bf13d11b595aabf514c706adcf57aefc660a1f.tar.zst
ecgen-96bf13d11b595aabf514c706adcf57aefc660a1f.zip
-rw-r--r--.gitignore6
-rw-r--r--CMakeLists.txt11
-rw-r--r--README.md10
-rw-r--r--lib/parson/Makefile29
-rw-r--r--lib/parson/parson.c1972
-rw-r--r--lib/parson/parson.h234
-rw-r--r--src/Makefile19
-rw-r--r--src/cli.c76
-rw-r--r--src/cli.h13
-rw-r--r--src/curve.c219
-rw-r--r--src/curve.h109
-rw-r--r--src/ecgen.c93
-rw-r--r--src/field.c29
-rw-r--r--src/field.h21
-rw-r--r--src/gp.c199
-rw-r--r--src/gp.h14
-rw-r--r--src/gp/gp.gp4
-rw-r--r--src/gp/utils.gp33
-rw-r--r--src/input.c129
-rw-r--r--src/input.h17
-rw-r--r--src/output.c44
-rw-r--r--src/output.h42
-rw-r--r--src/point.c13
-rw-r--r--src/point.h17
-rw-r--r--src/poly.h4
-rw-r--r--src/random.c34
-rw-r--r--src/random.h14
27 files changed, 2925 insertions, 480 deletions
diff --git a/.gitignore b/.gitignore
index 68700a8..78494d8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,6 @@
### Custom
-*.curves
-ecgen
data/
-
+src/ecgen
### C template
# Prerequisites
@@ -81,7 +79,7 @@ dkms.conf
.idea/mongoSettings.xml
## CMake
-cmake-build-debug/
+build/
## File-based project format:
*.iws
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b0c5410..5e53579 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,10 @@
cmake_minimum_required(VERSION 2.8.11)
project(ecgen)
-SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall")
+set(CMAKE_LIBRARY_PATH ${CMAKE_SOURCE_DIR}/lib)
+
+SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -Wall")
+SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -Wall")
add_custom_command(
OUTPUT gp.c gp.h
@@ -14,10 +17,12 @@ add_custom_command(
add_custom_target(gp2c ALL DEPENDS gp.c gp.h)
include_directories(src)
+include_directories(lib)
file(GLOB SOURCES "src/*.c")
add_executable(ecgen ${SOURCES})
-add_dependencies(ecgen gp2c)
-target_link_libraries(ecgen pari) \ No newline at end of file
+target_link_libraries(ecgen pari)
+find_library(parson parson/libparson.a)
+target_link_libraries(ecgen ${parson}) \ No newline at end of file
diff --git a/README.md b/README.md
index 560b3cc..e02298f 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ ecgen --fp/--f2m -r BITS
- `-o/--output FILE` writes output to `FILE`.
- `-i/--input FILE` reads input from `FILE`.
- `-a/--append` appends to output file(doesn't overwrite it).
- - `-d/--datadir DIR` specifies the PARI/GP datadir containing the `seadata` and `elldata` packages.
+ - `-d/--datadir DIR` specifies the PARI/GP datadir containing the `seadata` package.
### Build
```
@@ -24,8 +24,14 @@ make
```
### Requirements
+ - PARI/GP
+ - parson
+
ecgen uses the [PARI/GP](http://pari.math.u-bordeaux.fr/) library for elliptic
-curve arithmetic and it's SEA point counting algorithm implementation.
+curve arithmetic and it's SEA point counting algorithm implementation. It also requires the
+additional [seadata](http://pari.math.u-bordeaux.fr/packages.html) package (seadata and seadata-big recommended for large curves).
+
+[parson](https://github.com/kgabis/parson) is used to output curve parameters in JSON format.
### License
```
diff --git a/lib/parson/Makefile b/lib/parson/Makefile
new file mode 100644
index 0000000..e46da31
--- /dev/null
+++ b/lib/parson/Makefile
@@ -0,0 +1,29 @@
+CC=gcc
+CCFLAGS=-Wall
+LDFLAGS=
+
+SOURCES=$(wildcard *.c)
+OBJECTS=$(SOURCES:.c=.o)
+
+TARGET=parson
+A=libparson.a
+
+all: $(TARGET)
+
+$(TARGET): $(OBJECTS)
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+$(A): $(OBJECTS)
+ ar rcs $(A) $(OBJECTS)
+
+%.o: %.c %.h
+ $(CC) $(CCFLAGS) -c $<
+
+%.o: %.c
+ $(CC) $(CCFLAGS) -c $<
+
+
+clean:
+ rm -f *.o *.a $(TARGET)
+
+.PHONY: clean \ No newline at end of file
diff --git a/lib/parson/parson.c b/lib/parson/parson.c
new file mode 100644
index 0000000..b914ae8
--- /dev/null
+++ b/lib/parson/parson.c
@@ -0,0 +1,1972 @@
+/*
+ Parson ( http://kgabis.github.com/parson/ )
+ Copyright (c) 2012 - 2016 Krzysztof Gabis
+
+ 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.
+*/
+#ifdef _MSC_VER
+#ifndef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+#endif /* _CRT_SECURE_NO_WARNINGS */
+#endif /* _MSC_VER */
+
+#include "parson.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <errno.h>
+
+#define STARTING_CAPACITY 15
+#define ARRAY_MAX_CAPACITY 122880 /* 15*(2^13) */
+#define OBJECT_MAX_CAPACITY 960 /* 15*(2^6) */
+#define MAX_NESTING 19
+#define DOUBLE_SERIALIZATION_FORMAT "%f"
+
+#define SIZEOF_TOKEN(a) (sizeof(a) - 1)
+#define SKIP_CHAR(str) ((*str)++)
+#define SKIP_WHITESPACES(str) while (isspace(**str)) { SKIP_CHAR(str); }
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#undef malloc
+#undef free
+
+static JSON_Malloc_Function parson_malloc = malloc;
+static JSON_Free_Function parson_free = free;
+
+#define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */
+
+/* Type definitions */
+typedef union json_value_value {
+ char *string;
+ double number;
+ JSON_Object *object;
+ JSON_Array *array;
+ int boolean;
+ int null;
+} JSON_Value_Value;
+
+struct json_value_t {
+ JSON_Value *parent;
+ JSON_Value_Type type;
+ JSON_Value_Value value;
+};
+
+struct json_object_t {
+ JSON_Value *wrapping_value;
+ char **names;
+ JSON_Value **values;
+ size_t count;
+ size_t capacity;
+};
+
+struct json_array_t {
+ JSON_Value *wrapping_value;
+ JSON_Value **items;
+ size_t count;
+ size_t capacity;
+};
+
+/* Various */
+static char * read_file(const char *filename);
+static void remove_comments(char *string, const char *start_token, const char *end_token);
+static char * parson_strndup(const char *string, size_t n);
+static char * parson_strdup(const char *string);
+static int is_utf16_hex(const unsigned char *string);
+static int num_bytes_in_utf8_sequence(unsigned char c);
+static int verify_utf8_sequence(const unsigned char *string, int *len);
+static int is_valid_utf8(const char *string, size_t string_len);
+static int is_decimal(const char *string, size_t length);
+
+/* JSON Object */
+static JSON_Object * json_object_init(JSON_Value *wrapping_value);
+static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value);
+static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity);
+static JSON_Value * json_object_nget_value(const JSON_Object *object, const char *name, size_t n);
+static void json_object_free(JSON_Object *object);
+
+/* JSON Array */
+static JSON_Array * json_array_init(JSON_Value *wrapping_value);
+static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value);
+static JSON_Status json_array_resize(JSON_Array *array, size_t new_capacity);
+static void json_array_free(JSON_Array *array);
+
+/* JSON Value */
+static JSON_Value * json_value_init_string_no_copy(char *string);
+
+/* Parser */
+static JSON_Status skip_quotes(const char **string);
+static int parse_utf_16(const char **unprocessed, char **processed);
+static char * process_string(const char *input, size_t len);
+static char * get_quoted_string(const char **string);
+static JSON_Value * parse_object_value(const char **string, size_t nesting);
+static JSON_Value * parse_array_value(const char **string, size_t nesting);
+static JSON_Value * parse_string_value(const char **string);
+static JSON_Value * parse_boolean_value(const char **string);
+static JSON_Value * parse_number_value(const char **string);
+static JSON_Value * parse_null_value(const char **string);
+static JSON_Value * parse_value(const char **string, size_t nesting);
+
+/* Serialization */
+static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, int is_pretty, char *num_buf);
+static int json_serialize_string(const char *string, char *buf);
+static int append_indent(char *buf, int level);
+static int append_string(char *buf, const char *string);
+
+/* Various */
+static char * parson_strndup(const char *string, size_t n) {
+ char *output_string = (char*)parson_malloc(n + 1);
+ if (!output_string) {
+ return NULL;
+ }
+ output_string[n] = '\0';
+ strncpy(output_string, string, n);
+ return output_string;
+}
+
+static char * parson_strdup(const char *string) {
+ return parson_strndup(string, strlen(string));
+}
+
+static int is_utf16_hex(const unsigned char *s) {
+ return isxdigit(s[0]) && isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]);
+}
+
+static int num_bytes_in_utf8_sequence(unsigned char c) {
+ if (c == 0xC0 || c == 0xC1 || c > 0xF4 || IS_CONT(c)) {
+ return 0;
+ } else if ((c & 0x80) == 0) { /* 0xxxxxxx */
+ return 1;
+ } else if ((c & 0xE0) == 0xC0) { /* 110xxxxx */
+ return 2;
+ } else if ((c & 0xF0) == 0xE0) { /* 1110xxxx */
+ return 3;
+ } else if ((c & 0xF8) == 0xF0) { /* 11110xxx */
+ return 4;
+ }
+ return 0; /* won't happen */
+}
+
+static int verify_utf8_sequence(const unsigned char *string, int *len) {
+ unsigned int cp = 0;
+ *len = num_bytes_in_utf8_sequence(string[0]);
+
+ if (*len == 1) {
+ cp = string[0];
+ } else if (*len == 2 && IS_CONT(string[1])) {
+ cp = string[0] & 0x1F;
+ cp = (cp << 6) | (string[1] & 0x3F);
+ } else if (*len == 3 && IS_CONT(string[1]) && IS_CONT(string[2])) {
+ cp = ((unsigned char)string[0]) & 0xF;
+ cp = (cp << 6) | (string[1] & 0x3F);
+ cp = (cp << 6) | (string[2] & 0x3F);
+ } else if (*len == 4 && IS_CONT(string[1]) && IS_CONT(string[2]) && IS_CONT(string[3])) {
+ cp = string[0] & 0x7;
+ cp = (cp << 6) | (string[1] & 0x3F);
+ cp = (cp << 6) | (string[2] & 0x3F);
+ cp = (cp << 6) | (string[3] & 0x3F);
+ } else {
+ return 0;
+ }
+
+ /* overlong encodings */
+ if ((cp < 0x80 && *len > 1) ||
+ (cp < 0x800 && *len > 2) ||
+ (cp < 0x10000 && *len > 3)) {
+ return 0;
+ }
+
+ /* invalid unicode */
+ if (cp > 0x10FFFF) {
+ return 0;
+ }
+
+ /* surrogate halves */
+ if (cp >= 0xD800 && cp <= 0xDFFF) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int is_valid_utf8(const char *string, size_t string_len) {
+ int len = 0;
+ const char *string_end = string + string_len;
+ while (string < string_end) {
+ if (!verify_utf8_sequence((const unsigned char*)string, &len)) {
+ return 0;
+ }
+ string += len;
+ }
+ return 1;
+}
+
+static int is_decimal(const char *string, size_t length) {
+ if (length > 1 && string[0] == '0' && string[1] != '.') {
+ return 0;
+ }
+ if (length > 2 && !strncmp(string, "-0", 2) && string[2] != '.') {
+ return 0;
+ }
+ while (length--) {
+ if (strchr("xX", string[length])) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static char * read_file(const char * filename) {
+ FILE *fp = fopen(filename, "r");
+ size_t file_size;
+ long pos;
+ char *file_contents;
+ if (!fp) {
+ return NULL;
+ }
+ fseek(fp, 0L, SEEK_END);
+ pos = ftell(fp);
+ if (pos < 0) {
+ fclose(fp);
+ return NULL;
+ }
+ file_size = pos;
+ rewind(fp);
+ file_contents = (char*)parson_malloc(sizeof(char) * (file_size + 1));
+ if (!file_contents) {
+ fclose(fp);
+ return NULL;
+ }
+ if (fread(file_contents, file_size, 1, fp) < 1) {
+ if (ferror(fp)) {
+ fclose(fp);
+ parson_free(file_contents);
+ return NULL;
+ }
+ }
+ fclose(fp);
+ file_contents[file_size] = '\0';
+ return file_contents;
+}
+
+static void remove_comments(char *string, const char *start_token, const char *end_token) {
+ int in_string = 0, escaped = 0;
+ size_t i;
+ char *ptr = NULL, current_char;
+ size_t start_token_len = strlen(start_token);
+ size_t end_token_len = strlen(end_token);
+ if (start_token_len == 0 || end_token_len == 0) {
+ return;
+ }
+ while ((current_char = *string) != '\0') {
+ if (current_char == '\\' && !escaped) {
+ escaped = 1;
+ string++;
+ continue;
+ } else if (current_char == '\"' && !escaped) {
+ in_string = !in_string;
+ } else if (!in_string && strncmp(string, start_token, start_token_len) == 0) {
+ for(i = 0; i < start_token_len; i++) {
+ string[i] = ' ';
+ }
+ string = string + start_token_len;
+ ptr = strstr(string, end_token);
+ if (!ptr) {
+ return;
+ }
+ for (i = 0; i < (ptr - string) + end_token_len; i++) {
+ string[i] = ' ';
+ }
+ string = ptr + end_token_len - 1;
+ }
+ escaped = 0;
+ string++;
+ }
+}
+
+/* JSON Object */
+static JSON_Object * json_object_init(JSON_Value *wrapping_value) {
+ JSON_Object *new_obj = (JSON_Object*)parson_malloc(sizeof(JSON_Object));
+ if (new_obj == NULL) {
+ return NULL;
+ }
+ new_obj->wrapping_value = wrapping_value;
+ new_obj->names = (char**)NULL;
+ new_obj->values = (JSON_Value**)NULL;
+ new_obj->capacity = 0;
+ new_obj->count = 0;
+ return new_obj;
+}
+
+static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value) {
+ size_t index = 0;
+ if (object == NULL || name == NULL || value == NULL) {
+ return JSONFailure;
+ }
+ if (json_object_get_value(object, name) != NULL) {
+ return JSONFailure;
+ }
+ if (object->count >= object->capacity) {
+ size_t new_capacity = MAX(object->capacity * 2, STARTING_CAPACITY);
+ if (new_capacity > OBJECT_MAX_CAPACITY) {
+ return JSONFailure;
+ }
+ if (json_object_resize(object, new_capacity) == JSONFailure) {
+ return JSONFailure;
+ }
+ }
+ index = object->count;
+ object->names[index] = parson_strdup(name);
+ if (object->names[index] == NULL) {
+ return JSONFailure;
+ }
+ value->parent = json_object_get_wrapping_value(object);
+ object->values[index] = value;
+ object->count++;
+ return JSONSuccess;
+}
+
+static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity) {
+ char **temp_names = NULL;
+ JSON_Value **temp_values = NULL;
+
+ if ((object->names == NULL && object->values != NULL) ||
+ (object->names != NULL && object->values == NULL) ||
+ new_capacity == 0) {
+ return JSONFailure; /* Shouldn't happen */
+ }
+ temp_names = (char**)parson_malloc(new_capacity * sizeof(char*));
+ if (temp_names == NULL) {
+ return JSONFailure;
+ }
+ temp_values = (JSON_Value**)parson_malloc(new_capacity * sizeof(JSON_Value*));
+ if (temp_values == NULL) {
+ parson_free(temp_names);
+ return JSONFailure;
+ }
+ if (object->names != NULL && object->values != NULL && object->count > 0) {
+ memcpy(temp_names, object->names, object->count * sizeof(char*));
+ memcpy(temp_values, object->values, object->count * sizeof(JSON_Value*));
+ }
+ parson_free(object->names);
+ parson_free(object->values);
+ object->names = temp_names;
+ object->values = temp_values;
+ object->capacity = new_capacity;
+ return JSONSuccess;
+}
+
+static JSON_Value * json_object_nget_value(const JSON_Object *object, const char *name, size_t n) {
+ size_t i, name_length;
+ for (i = 0; i < json_object_get_count(object); i++) {
+ name_length = strlen(object->names[i]);
+ if (name_length != n) {
+ continue;
+ }
+ if (strncmp(object->names[i], name, n) == 0) {
+ return object->values[i];
+ }
+ }
+ return NULL;
+}
+
+static void json_object_free(JSON_Object *object) {
+ while(object->count--) {
+ parson_free(object->names[object->count]);
+ json_value_free(object->values[object->count]);
+ }
+ parson_free(object->names);
+ parson_free(object->values);
+ parson_free(object);
+}
+
+/* JSON Array */
+static JSON_Array * json_array_init(JSON_Value *wrapping_value) {
+ JSON_Array *new_array = (JSON_Array*)parson_malloc(sizeof(JSON_Array));
+ if (new_array == NULL) {
+ return NULL;
+ }
+ new_array->wrapping_value = wrapping_value;
+ new_array->items = (JSON_Value**)NULL;
+ new_array->capacity = 0;
+ new_array->count = 0;
+ return new_array;
+}
+
+static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value) {
+ if (array->count >= array->capacity) {
+ size_t new_capacity = MAX(array->capacity * 2, STARTING_CAPACITY);
+ if (new_capacity > ARRAY_MAX_CAPACITY) {
+ return JSONFailure;
+ }
+ if (json_array_resize(array, new_capacity) == JSONFailure) {
+ return JSONFailure;
+ }
+ }
+ value->parent = json_array_get_wrapping_value(array);
+ array->items[array->count] = value;
+ array->count++;
+ return JSONSuccess;
+}
+
+static JSON_Status json_array_resize(JSON_Array *array, size_t new_capacity) {
+ JSON_Value **new_items = NULL;
+ if (new_capacity == 0) {
+ return JSONFailure;
+ }
+ new_items = (JSON_Value**)parson_malloc(new_capacity * sizeof(JSON_Value*));
+ if (new_items == NULL) {
+ return JSONFailure;
+ }
+ if (array->items != NULL && array->count > 0) {
+ memcpy(new_items, array->items, array->count * sizeof(JSON_Value*));
+ }
+ parson_free(array->items);
+ array->items = new_items;
+ array->capacity = new_capacity;
+ return JSONSuccess;
+}
+
+static void json_array_free(JSON_Array *array) {
+ while (array->count--) {
+ json_value_free(array->items[array->count]);
+ }
+ parson_free(array->items);
+ parson_free(array);
+}
+
+/* JSON Value */
+static JSON_Value * json_value_init_string_no_copy(char *string) {
+ JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+ if (!new_value) {
+ return NULL;
+ }
+ new_value->parent = NULL;
+ new_value->type = JSONString;
+ new_value->value.string = string;
+ return new_value;
+}
+
+/* Parser */
+static JSON_Status skip_quotes(const char **string) {
+ if (**string != '\"') {
+ return JSONFailure;
+ }
+ SKIP_CHAR(string);
+ while (**string != '\"') {
+ if (**string == '\0') {
+ return JSONFailure;
+ } else if (**string == '\\') {
+ SKIP_CHAR(string);
+ if (**string == '\0') {
+ return JSONFailure;
+ }
+ }
+ SKIP_CHAR(string);
+ }
+ SKIP_CHAR(string);
+ return JSONSuccess;
+}
+
+static int parse_utf_16(const char **unprocessed, char **processed) {
+ unsigned int cp, lead, trail;
+ char *processed_ptr = *processed;
+ const char *unprocessed_ptr = *unprocessed;
+ unprocessed_ptr++; /* skips u */
+ if (!is_utf16_hex((const unsigned char*)unprocessed_ptr) || sscanf(unprocessed_ptr, "%4x", &cp) == EOF) {
+ return JSONFailure;
+ }
+ if (cp < 0x80) {
+ *processed_ptr = cp; /* 0xxxxxxx */
+ } else if (cp < 0x800) {
+ *processed_ptr++ = ((cp >> 6) & 0x1F) | 0xC0; /* 110xxxxx */
+ *processed_ptr = ((cp ) & 0x3F) | 0x80; /* 10xxxxxx */
+ } else if (cp < 0xD800 || cp > 0xDFFF) {
+ *processed_ptr++ = ((cp >> 12) & 0x0F) | 0xE0; /* 1110xxxx */
+ *processed_ptr++ = ((cp >> 6) & 0x3F) | 0x80; /* 10xxxxxx */
+ *processed_ptr = ((cp ) & 0x3F) | 0x80; /* 10xxxxxx */
+ } else if (cp >= 0xD800 && cp <= 0xDBFF) { /* lead surrogate (0xD800..0xDBFF) */
+ lead = cp;
+ unprocessed_ptr += 4; /* should always be within the buffer, otherwise previous sscanf would fail */
+ if (*unprocessed_ptr++ != '\\' || *unprocessed_ptr++ != 'u' || /* starts with \u? */
+ !is_utf16_hex((const unsigned char*)unprocessed_ptr) ||
+ sscanf(unprocessed_ptr, "%4x", &trail) == EOF ||
+ trail < 0xDC00 || trail > 0xDFFF) { /* valid trail surrogate? (0xDC00..0xDFFF) */
+ return JSONFailure;
+ }
+ cp = ((((lead-0xD800)&0x3FF)<<10)|((trail-0xDC00)&0x3FF))+0x010000;
+ *processed_ptr++ = (((cp >> 18) & 0x07) | 0xF0); /* 11110xxx */
+ *processed_ptr++ = (((cp >> 12) & 0x3F) | 0x80); /* 10xxxxxx */
+ *processed_ptr++ = (((cp >> 6) & 0x3F) | 0x80); /* 10xxxxxx */
+ *processed_ptr = (((cp ) & 0x3F) | 0x80); /* 10xxxxxx */
+ } else { /* trail surrogate before lead surrogate */
+ return JSONFailure;
+ }
+ unprocessed_ptr += 3;
+ *processed = processed_ptr;
+ *unprocessed = unprocessed_ptr;
+ return JSONSuccess;
+}
+
+
+/* Copies and processes passed string up to supplied length.
+Example: "\u006Corem ipsum" -> lorem ipsum */
+static char* process_string(const char *input, size_t len) {
+ const char *input_ptr = input;
+ size_t initial_size = (len + 1) * sizeof(char);
+ size_t final_size = 0;
+ char *output = (char*)parson_malloc(initial_size);
+ char *output_ptr = output;
+ char *resized_output = NULL;
+ while ((*input_ptr != '\0') && (size_t)(input_ptr - input) < len) {
+ if (*input_ptr == '\\') {
+ input_ptr++;
+ switch (*input_ptr) {
+ case '\"': *output_ptr = '\"'; break;
+ case '\\': *output_ptr = '\\'; break;
+ case '/': *output_ptr = '/'; break;
+ case 'b': *output_ptr = '\b'; break;
+ case 'f': *output_ptr = '\f'; break;
+ case 'n': *output_ptr = '\n'; break;
+ case 'r': *output_ptr = '\r'; break;
+ case 't': *output_ptr = '\t'; break;
+ case 'u':
+ if (parse_utf_16(&input_ptr, &output_ptr) == JSONFailure) {
+ goto error;
+ }
+ break;
+ default:
+ goto error;
+ }
+ } else if ((unsigned char)*input_ptr < 0x20) {
+ goto error; /* 0x00-0x19 are invalid characters for json string (http://www.ietf.org/rfc/rfc4627.txt) */
+ } else {
+ *output_ptr = *input_ptr;
+ }
+ output_ptr++;
+ input_ptr++;
+ }
+ *output_ptr = '\0';
+ /* resize to new length */
+ final_size = (size_t)(output_ptr-output) + 1;
+ /* todo: don't resize if final_size == initial_size */
+ resized_output = (char*)parson_malloc(final_size);
+ if (resized_output == NULL) {
+ goto error;
+ }
+ memcpy(resized_output, output, final_size);
+ parson_free(output);
+ return resized_output;
+error:
+ parson_free(output);
+ return NULL;
+}
+
+/* Return processed contents of a string between quotes and
+ skips passed argument to a matching quote. */
+static char * get_quoted_string(const char **string) {
+ const char *string_start = *string;
+ size_t string_len = 0;
+ JSON_Status status = skip_quotes(string);
+ if (status != JSONSuccess) {
+ return NULL;
+ }
+ string_len = *string - string_start - 2; /* length without quotes */
+ return process_string(string_start + 1, string_len);
+}
+
+static JSON_Value * parse_value(const char **string, size_t nesting) {
+ if (nesting > MAX_NESTING) {
+ return NULL;
+ }
+ SKIP_WHITESPACES(string);
+ switch (**string) {
+ case '{':
+ return parse_object_value(string, nesting + 1);
+ case '[':
+ return parse_array_value(string, nesting + 1);
+ case '\"':
+ return parse_string_value(string);
+ case 'f': case 't':
+ return parse_boolean_value(string);
+ case '-':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ return parse_number_value(string);
+ case 'n':
+ return parse_null_value(string);
+ default:
+ return NULL;
+ }
+}
+
+static JSON_Value * parse_object_value(const char **string, size_t nesting) {
+ JSON_Value *output_value = json_value_init_object(), *new_value = NULL;
+ JSON_Object *output_object = json_value_get_object(output_value);
+ char *new_key = NULL;
+ if (output_value == NULL || **string != '{') {
+ return NULL;
+ }
+ SKIP_CHAR(string);
+ SKIP_WHITESPACES(string);
+ if (**string == '}') { /* empty object */
+ SKIP_CHAR(string);
+ return output_value;
+ }
+ while (**string != '\0') {
+ new_key = get_quoted_string(string);
+ SKIP_WHITESPACES(string);
+ if (new_key == NULL || **string != ':') {
+ json_value_free(output_value);
+ return NULL;
+ }
+ SKIP_CHAR(string);
+ new_value = parse_value(string, nesting);
+ if (new_value == NULL) {
+ parson_free(new_key);
+ json_value_free(output_value);
+ return NULL;
+ }
+ if(json_object_add(output_object, new_key, new_value) == JSONFailure) {
+ parson_free(new_key);
+ parson_free(new_value);
+ json_value_free(output_value);
+ return NULL;
+ }
+ parson_free(new_key);
+ SKIP_WHITESPACES(string);
+ if (**string != ',') {
+ break;
+ }
+ SKIP_CHAR(string);
+ SKIP_WHITESPACES(string);
+ }
+ SKIP_WHITESPACES(string);
+ if (**string != '}' || /* Trim object after parsing is over */
+ json_object_resize(output_object, json_object_get_count(output_object)) == JSONFailure) {
+ json_value_free(output_value);
+ return NULL;
+ }
+ SKIP_CHAR(string);
+ return output_value;
+}
+
+static JSON_Value * parse_array_value(const char **string, size_t nesting) {
+ JSON_Value *output_value = json_value_init_array(), *new_array_value = NULL;
+ JSON_Array *output_array = json_value_get_array(output_value);
+ if (!output_value || **string != '[') {
+ return NULL;
+ }
+ SKIP_CHAR(string);
+ SKIP_WHITESPACES(string);
+ if (**string == ']') { /* empty array */
+ SKIP_CHAR(string);
+ return output_value;
+ }
+ while (**string != '\0') {
+ new_array_value = parse_value(string, nesting);
+ if (!new_array_value) {
+ json_value_free(output_value);
+ return NULL;
+ }
+ if (json_array_add(output_array, new_array_value) == JSONFailure) {
+ parson_free(new_array_value);
+ json_value_free(output_value);
+ return NULL;
+ }
+ SKIP_WHITESPACES(string);
+ if (**string != ',') {
+ break;
+ }
+ SKIP_CHAR(string);
+ SKIP_WHITESPACES(string);
+ }
+ SKIP_WHITESPACES(string);
+ if (**string != ']' || /* Trim array after parsing is over */
+ json_array_resize(output_array, json_array_get_count(output_array)) == JSONFailure) {
+ json_value_free(output_value);
+ return NULL;
+ }
+ SKIP_CHAR(string);
+ return output_value;
+}
+
+static JSON_Value * parse_string_value(const char **string) {
+ JSON_Value *value = NULL;
+ char *new_string = get_quoted_string(string);
+ if (new_string == NULL) {
+ return NULL;
+ }
+ value = json_value_init_string_no_copy(new_string);
+ if (value == NULL) {
+ parson_free(new_string);
+ return NULL;
+ }
+ return value;
+}
+
+static JSON_Value * parse_boolean_value(const char **string) {
+ size_t true_token_size = SIZEOF_TOKEN("true");
+ size_t false_token_size = SIZEOF_TOKEN("false");
+ if (strncmp("true", *string, true_token_size) == 0) {
+ *string += true_token_size;
+ return json_value_init_boolean(1);
+ } else if (strncmp("false", *string, false_token_size) == 0) {
+ *string += false_token_size;
+ return json_value_init_boolean(0);
+ }
+ return NULL;
+}
+
+static JSON_Value * parse_number_value(const char **string) {
+ char *end;
+ double number = 0;
+ errno = 0;
+ number = strtod(*string, &end);
+ if (errno || !is_decimal(*string, end - *string)) {
+ return NULL;
+ }
+ *string = end;
+ return json_value_init_number(number);
+}
+
+static JSON_Value * parse_null_value(const char **string) {
+ size_t token_size = SIZEOF_TOKEN("null");
+ if (strncmp("null", *string, token_size) == 0) {
+ *string += token_size;
+ return json_value_init_null();
+ }
+ return NULL;
+}
+
+/* Serialization */
+#define APPEND_STRING(str) do { written = append_string(buf, (str));\
+ if (written < 0) { return -1; }\
+ if (buf != NULL) { buf += written; }\
+ written_total += written; } while(0)
+
+#define APPEND_INDENT(level) do { written = append_indent(buf, (level));\
+ if (written < 0) { return -1; }\
+ if (buf != NULL) { buf += written; }\
+ written_total += written; } while(0)
+
+static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, int is_pretty, char *num_buf)
+{
+ const char *key = NULL, *string = NULL;
+ JSON_Value *temp_value = NULL;
+ JSON_Array *array = NULL;
+ JSON_Object *object = NULL;
+ size_t i = 0, count = 0;
+ double num = 0.0;
+ int written = -1, written_total = 0;
+
+ switch (json_value_get_type(value)) {
+ case JSONArray:
+ array = json_value_get_array(value);
+ count = json_array_get_count(array);
+ APPEND_STRING("[");
+ if (count > 0 && is_pretty) {
+ APPEND_STRING("\n");
+ }
+ for (i = 0; i < count; i++) {
+ if (is_pretty) {
+ APPEND_INDENT(level+1);
+ }
+ temp_value = json_array_get_value(array, i);
+ written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty, num_buf);
+ if (written < 0) {
+ return -1;
+ }
+ if (buf != NULL) {
+ buf += written;
+ }
+ written_total += written;
+ if (i < (count - 1)) {
+ APPEND_STRING(",");
+ }
+ if (is_pretty) {
+ APPEND_STRING("\n");
+ }
+ }
+ if (count > 0 && is_pretty) {
+ APPEND_INDENT(level);
+ }
+ APPEND_STRING("]");
+ return written_total;
+ case JSONObject:
+ object = json_value_get_object(value);
+ count = json_object_get_count(object);
+ APPEND_STRING("{");
+ if (count > 0 && is_pretty) {
+ APPEND_STRING("\n");
+ }
+ for (i = 0; i < count; i++) {
+ key = json_object_get_name(object, i);
+ if (key == NULL) {
+ return -1;
+ }
+ if (is_pretty) {
+ APPEND_INDENT(level+1);
+ }
+ written = json_serialize_string(key, buf);
+ if (written < 0) {
+ return -1;
+ }
+ if (buf != NULL) {
+ buf += written;
+ }
+ written_total += written;
+ APPEND_STRING(":");
+ if (is_pretty) {
+ APPEND_STRING(" ");
+ }
+ temp_value = json_object_get_value(object, key);
+ written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty, num_buf);
+ if (written < 0) {
+ return -1;
+ }
+ if (buf != NULL) {
+ buf += written;
+ }
+ written_total += written;
+ if (i < (count - 1)) {
+ APPEND_STRING(",");
+ }
+ if (is_pretty) {
+ APPEND_STRING("\n");
+ }
+ }
+ if (count > 0 && is_pretty) {
+ APPEND_INDENT(level);
+ }
+ APPEND_STRING("}");
+ return written_total;
+ case JSONString:
+ string = json_value_get_string(value);
+ if (string == NULL) {
+ return -1;
+ }
+ written = json_serialize_string(string, buf);
+ if (written < 0) {
+ return -1;
+ }
+ if (buf != NULL) {
+ buf += written;
+ }
+ written_total += written;
+ return written_total;
+ case JSONBoolean:
+ if (json_value_get_boolean(value)) {
+ APPEND_STRING("true");
+ } else {
+ APPEND_STRING("false");
+ }
+ return written_total;
+ case JSONNumber:
+ num = json_value_get_number(value);
+ if (buf != NULL) {
+ num_buf = buf;
+ }
+ if (num == ((double)(int)num)) { /* check if num is integer */
+ written = sprintf(num_buf, "%d", (int)num);
+ } else if (num == ((double)(unsigned int)num)) {
+ written = sprintf(num_buf, "%u", (unsigned int)num);
+ } else {
+ written = sprintf(num_buf, DOUBLE_SERIALIZATION_FORMAT, num);
+ }
+ if (written < 0) {
+ return -1;
+ }
+ if (buf != NULL) {
+ buf += written;
+ }
+ written_total += written;
+ return written_total;
+ case JSONNull:
+ APPEND_STRING("null");
+ return written_total;
+ case JSONError:
+ return -1;
+ default:
+ return -1;
+ }
+}
+
+static int json_serialize_string(const char *string, char *buf) {
+ size_t i = 0, len = strlen(string);
+ char c = '\0';
+ int written = -1, written_total = 0;
+ APPEND_STRING("\"");
+ for (i = 0; i < len; i++) {
+ c = string[i];
+ switch (c) {
+ case '\"': APPEND_STRING("\\\""); break;
+ case '\\': APPEND_STRING("\\\\"); break;
+ case '/': APPEND_STRING("\\/"); break; /* to make json embeddable in xml\/html */
+ case '\b': APPEND_STRING("\\b"); break;
+ case '\f': APPEND_STRING("\\f"); break;
+ case '\n': APPEND_STRING("\\n"); break;
+ case '\r': APPEND_STRING("\\r"); break;
+ case '\t': APPEND_STRING("\\t"); break;
+ case '\x00': APPEND_STRING("\\u0000"); break;
+ case '\x01': APPEND_STRING("\\u0001"); break;
+ case '\x02': APPEND_STRING("\\u0002"); break;
+ case '\x03': APPEND_STRING("\\u0003"); break;
+ case '\x04': APPEND_STRING("\\u0004"); break;
+ case '\x05': APPEND_STRING("\\u0005"); break;
+ case '\x06': APPEND_STRING("\\u0006"); break;
+ case '\x07': APPEND_STRING("\\u0007"); break;
+ /* '\x08' duplicate: '\b' */
+ /* '\x09' duplicate: '\t' */
+ /* '\x0a' duplicate: '\n' */
+ case '\x0b': APPEND_STRING("\\u000b"); break;
+ /* '\x0c' duplicate: '\f' */
+ /* '\x0d' duplicate: '\r' */
+ case '\x0e': APPEND_STRING("\\u000e"); break;
+ case '\x0f': APPEND_STRING("\\u000f"); break;
+ case '\x10': APPEND_STRING("\\u0010"); break;
+ case '\x11': APPEND_STRING("\\u0011"); break;
+ case '\x12': APPEND_STRING("\\u0012"); break;
+ case '\x13': APPEND_STRING("\\u0013"); break;
+ case '\x14': APPEND_STRING("\\u0014"); break;
+ case '\x15': APPEND_STRING("\\u0015"); break;
+ case '\x16': APPEND_STRING("\\u0016"); break;
+ case '\x17': APPEND_STRING("\\u0017"); break;
+ case '\x18': APPEND_STRING("\\u0018"); break;
+ case '\x19': APPEND_STRING("\\u0019"); break;
+ case '\x1a': APPEND_STRING("\\u001a"); break;
+ case '\x1b': APPEND_STRING("\\u001b"); break;
+ case '\x1c': APPEND_STRING("\\u001c"); break;
+ case '\x1d': APPEND_STRING("\\u001d"); break;
+ case '\x1e': APPEND_STRING("\\u001e"); break;
+ case '\x1f': APPEND_STRING("\\u001f"); break;
+ default:
+ if (buf != NULL) {
+ buf[0] = c;
+ buf += 1;
+ }
+ written_total += 1;
+ break;
+ }
+ }
+ APPEND_STRING("\"");
+ return written_total;
+}
+
+static int append_indent(char *buf, int level) {
+ int i;
+ int written = -1, written_total = 0;
+ for (i = 0; i < level; i++) {
+ APPEND_STRING(" ");
+ }
+ return written_total;
+}
+
+static int append_string(char *buf, const char *string) {
+ if (buf == NULL) {
+ return (int)strlen(string);
+ }
+ return sprintf(buf, "%s", string);
+}
+
+#undef APPEND_STRING
+#undef APPEND_INDENT
+
+/* Parser API */
+JSON_Value * json_parse_file(const char *filename) {
+ char *file_contents = read_file(filename);
+ JSON_Value *output_value = NULL;
+ if (file_contents == NULL) {
+ return NULL;
+ }
+ output_value = json_parse_string(file_contents);
+ parson_free(file_contents);
+ return output_value;
+}
+
+JSON_Value * json_parse_file_with_comments(const char *filename) {
+ char *file_contents = read_file(filename);
+ JSON_Value *output_value = NULL;
+ if (file_contents == NULL) {
+ return NULL;
+ }
+ output_value = json_parse_string_with_comments(file_contents);
+ parson_free(file_contents);
+ return output_value;
+}
+
+JSON_Value * json_parse_string(const char *string) {
+ if (string == NULL) {
+ return NULL;
+ }
+ if (string[0] == '\xEF' && string[1] == '\xBB' && string[2] == '\xBF') {
+ string = string + 3; /* Support for UTF-8 BOM */
+ }
+ return parse_value((const char**)&string, 0);
+}
+
+JSON_Value * json_parse_string_with_comments(const char *string) {
+ JSON_Value *result = NULL;
+ char *string_mutable_copy = NULL, *string_mutable_copy_ptr = NULL;
+ string_mutable_copy = parson_strdup(string);
+ if (string_mutable_copy == NULL) {
+ return NULL;
+ }
+ remove_comments(string_mutable_copy, "/*", "*/");
+ remove_comments(string_mutable_copy, "//", "\n");
+ string_mutable_copy_ptr = string_mutable_copy;
+ result = parse_value((const char**)&string_mutable_copy_ptr, 0);
+ parson_free(string_mutable_copy);
+ return result;
+}
+
+/* JSON Object API */
+
+JSON_Value * json_object_get_value(const JSON_Object *object, const char *name) {
+ if (object == NULL || name == NULL) {
+ return NULL;
+ }
+ return json_object_nget_value(object, name, strlen(name));
+}
+
+const char * json_object_get_string(const JSON_Object *object, const char *name) {
+ return json_value_get_string(json_object_get_value(object, name));
+}
+
+double json_object_get_number(const JSON_Object *object, const char *name) {
+ return json_value_get_number(json_object_get_value(object, name));
+}
+
+JSON_Object * json_object_get_object(const JSON_Object *object, const char *name) {
+ return json_value_get_object(json_object_get_value(object, name));
+}
+
+JSON_Array * json_object_get_array(const JSON_Object *object, const char *name) {
+ return json_value_get_array(json_object_get_value(object, name));
+}
+
+int json_object_get_boolean(const JSON_Object *object, const char *name) {
+ return json_value_get_boolean(json_object_get_value(object, name));
+}
+
+JSON_Value * json_object_dotget_value(const JSON_Object *object, const char *name) {
+ const char *dot_position = strchr(name, '.');
+ if (!dot_position) {
+ return json_object_get_value(object, name);
+ }
+ object = json_value_get_object(json_object_nget_value(object, name, dot_position - name));
+ return json_object_dotget_value(object, dot_position + 1);
+}
+
+const char * json_object_dotget_string(const JSON_Object *object, const char *name) {
+ return json_value_get_string(json_object_dotget_value(object, name));
+}
+
+double json_object_dotget_number(const JSON_Object *object, const char *name) {
+ return json_value_get_number(json_object_dotget_value(object, name));
+}
+
+JSON_Object * json_object_dotget_object(const JSON_Object *object, const char *name) {
+ return json_value_get_object(json_object_dotget_value(object, name));
+}
+
+JSON_Array * json_object_dotget_array(const JSON_Object *object, const char *name) {
+ return json_value_get_array(json_object_dotget_value(object, name));
+}
+
+int json_object_dotget_boolean(const JSON_Object *object, const char *name) {
+ return json_value_get_boolean(json_object_dotget_value(object, name));
+}
+
+size_t json_object_get_count(const JSON_Object *object) {
+ return object ? object->count : 0;
+}
+
+const char * json_object_get_name(const JSON_Object *object, size_t index) {
+ if (object == NULL || index >= json_object_get_count(object)) {
+ return NULL;
+ }
+ return object->names[index];
+}
+
+JSON_Value * json_object_get_value_at(const JSON_Object *object, size_t index) {
+ if (object == NULL || index >= json_object_get_count(object)) {
+ return NULL;
+ }
+ return object->values[index];
+}
+
+JSON_Value *json_object_get_wrapping_value(const JSON_Object *object) {
+ return object->wrapping_value;
+}
+
+int json_object_has_value (const JSON_Object *object, const char *name) {
+ return json_object_get_value(object, name) != NULL;
+}
+
+int json_object_has_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type) {
+ JSON_Value *val = json_object_get_value(object, name);
+ return val != NULL && json_value_get_type(val) == type;
+}
+
+int json_object_dothas_value (const JSON_Object *object, const char *name) {
+ return json_object_dotget_value(object, name) != NULL;
+}
+
+int json_object_dothas_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type) {
+ JSON_Value *val = json_object_dotget_value(object, name);
+ return val != NULL && json_value_get_type(val) == type;
+}
+
+/* JSON Array API */
+JSON_Value * json_array_get_value(const JSON_Array *array, size_t index) {
+ if (array == NULL || index >= json_array_get_count(array)) {
+ return NULL;
+ }
+ return array->items[index];
+}
+
+const char * json_array_get_string(const JSON_Array *array, size_t index) {
+ return json_value_get_string(json_array_get_value(array, index));
+}
+
+double json_array_get_number(const JSON_Array *array, size_t index) {
+ return json_value_get_number(json_array_get_value(array, index));
+}
+
+JSON_Object * json_array_get_object(const JSON_Array *array, size_t index) {
+ return json_value_get_object(json_array_get_value(array, index));
+}
+
+JSON_Array * json_array_get_array(const JSON_Array *array, size_t index) {
+ return json_value_get_array(json_array_get_value(array, index));
+}
+
+int json_array_get_boolean(const JSON_Array *array, size_t index) {
+ return json_value_get_boolean(json_array_get_value(array, index));
+}
+
+size_t json_array_get_count(const JSON_Array *array) {
+ return array ? array->count : 0;
+}
+
+JSON_Value * json_array_get_wrapping_value(const JSON_Array *array) {
+ return array->wrapping_value;
+}
+
+/* JSON Value API */
+JSON_Value_Type json_value_get_type(const JSON_Value *value) {
+ return value ? value->type : JSONError;
+}
+
+JSON_Object * json_value_get_object(const JSON_Value *value) {
+ return json_value_get_type(value) == JSONObject ? value->value.object : NULL;
+}
+
+JSON_Array * json_value_get_array(const JSON_Value *value) {
+ return json_value_get_type(value) == JSONArray ? value->value.array : NULL;
+}
+
+const char * json_value_get_string(const JSON_Value *value) {
+ return json_value_get_type(value) == JSONString ? value->value.string : NULL;
+}
+
+double json_value_get_number(const JSON_Value *value) {
+ return json_value_get_type(value) == JSONNumber ? value->value.number : 0;
+}
+
+int json_value_get_boolean(const JSON_Value *value) {
+ return json_value_get_type(value) == JSONBoolean ? value->value.boolean : -1;
+}
+
+JSON_Value * json_value_get_parent (const JSON_Value *value) {
+ return value ? value->parent : NULL;
+}
+
+void json_value_free(JSON_Value *value) {
+ switch (json_value_get_type(value)) {
+ case JSONObject:
+ json_object_free(value->value.object);
+ break;
+ case JSONString:
+ parson_free(value->value.string);
+ break;
+ case JSONArray:
+ json_array_free(value->value.array);
+ break;
+ default:
+ break;
+ }
+ parson_free(value);
+}
+
+JSON_Value * json_value_init_object(void) {
+ JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+ if (!new_value) {
+ return NULL;
+ }
+ new_value->parent = NULL;
+ new_value->type = JSONObject;
+ new_value->value.object = json_object_init(new_value);
+ if (!new_value->value.object) {
+ parson_free(new_value);
+ return NULL;
+ }
+ return new_value;
+}
+
+JSON_Value * json_value_init_array(void) {
+ JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+ if (!new_value) {
+ return NULL;
+ }
+ new_value->parent = NULL;
+ new_value->type = JSONArray;
+ new_value->value.array = json_array_init(new_value);
+ if (!new_value->value.array) {
+ parson_free(new_value);
+ return NULL;
+ }
+ return new_value;
+}
+
+JSON_Value * json_value_init_string(const char *string) {
+ char *copy = NULL;
+ JSON_Value *value;
+ size_t string_len = 0;
+ if (string == NULL) {
+ return NULL;
+ }
+ string_len = strlen(string);
+ if (!is_valid_utf8(string, string_len)) {
+ return NULL;
+ }
+ copy = parson_strndup(string, string_len);
+ if (copy == NULL) {
+ return NULL;
+ }
+ value = json_value_init_string_no_copy(copy);
+ if (value == NULL) {
+ parson_free(copy);
+ }
+ return value;
+}
+
+JSON_Value * json_value_init_number(double number) {
+ JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+ if (!new_value) {
+ return NULL;
+ }
+ new_value->parent = NULL;
+ new_value->type = JSONNumber;
+ new_value->value.number = number;
+ return new_value;
+}
+
+JSON_Value * json_value_init_boolean(int boolean) {
+ JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+ if (!new_value) {
+ return NULL;
+ }
+ new_value->parent = NULL;
+ new_value->type = JSONBoolean;
+ new_value->value.boolean = boolean ? 1 : 0;
+ return new_value;
+}
+
+JSON_Value * json_value_init_null(void) {
+ JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
+ if (!new_value) {
+ return NULL;
+ }
+ new_value->parent = NULL;
+ new_value->type = JSONNull;
+ return new_value;
+}
+
+JSON_Value * json_value_deep_copy(const JSON_Value *value) {
+ size_t i = 0;
+ JSON_Value *return_value = NULL, *temp_value_copy = NULL, *temp_value = NULL;
+ const char *temp_string = NULL, *temp_key = NULL;
+ char *temp_string_copy = NULL;
+ JSON_Array *temp_array = NULL, *temp_array_copy = NULL;
+ JSON_Object *temp_object = NULL, *temp_object_copy = NULL;
+
+ switch (json_value_get_type(value)) {
+ case JSONArray:
+ temp_array = json_value_get_array(value);
+ return_value = json_value_init_array();
+ if (return_value == NULL) {
+ return NULL;
+ }
+ temp_array_copy = json_value_get_array(return_value);
+ for (i = 0; i < json_array_get_count(temp_array); i++) {
+ temp_value = json_array_get_value(temp_array, i);
+ temp_value_copy = json_value_deep_copy(temp_value);
+ if (temp_value_copy == NULL) {
+ json_value_free(return_value);
+ return NULL;
+ }
+ if (json_array_add(temp_array_copy, temp_value_copy) == JSONFailure) {
+ json_value_free(return_value);
+ json_value_free(temp_value_copy);
+ return NULL;
+ }
+ }
+ return return_value;
+ case JSONObject:
+ temp_object = json_value_get_object(value);
+ return_value = json_value_init_object();
+ if (return_value == NULL) {
+ return NULL;
+ }
+ temp_object_copy = json_value_get_object(return_value);
+ for (i = 0; i < json_object_get_count(temp_object); i++) {
+ temp_key = json_object_get_name(temp_object, i);
+ temp_value = json_object_get_value(temp_object, temp_key);
+ temp_value_copy = json_value_deep_copy(temp_value);
+ if (temp_value_copy == NULL) {
+ json_value_free(return_value);
+ return NULL;
+ }
+ if (json_object_add(temp_object_copy, temp_key, temp_value_copy) == JSONFailure) {
+ json_value_free(return_value);
+ json_value_free(temp_value_copy);
+ return NULL;
+ }
+ }
+ return return_value;
+ case JSONBoolean:
+ return json_value_init_boolean(json_value_get_boolean(value));
+ case JSONNumber:
+ return json_value_init_number(json_value_get_number(value));
+ case JSONString:
+ temp_string = json_value_get_string(value);
+ if (temp_string == NULL) {
+ return NULL;
+ }
+ temp_string_copy = parson_strdup(temp_string);
+ if (temp_string_copy == NULL) {
+ return NULL;
+ }
+ return_value = json_value_init_string_no_copy(temp_string_copy);
+ if (return_value == NULL) {
+ parson_free(temp_string_copy);
+ }
+ return return_value;
+ case JSONNull:
+ return json_value_init_null();
+ case JSONError:
+ return NULL;
+ default:
+ return NULL;
+ }
+}
+
+size_t json_serialization_size(const JSON_Value *value) {
+ char num_buf[1100]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */
+ int res = json_serialize_to_buffer_r(value, NULL, 0, 0, num_buf);
+ return res < 0 ? 0 : (size_t)(res + 1);
+}
+
+JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes) {
+ int written = -1;
+ size_t needed_size_in_bytes = json_serialization_size(value);
+ if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) {
+ return JSONFailure;
+ }
+ written = json_serialize_to_buffer_r(value, buf, 0, 0, NULL);
+ if (written < 0) {
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename) {
+ JSON_Status return_code = JSONSuccess;
+ FILE *fp = NULL;
+ char *serialized_string = json_serialize_to_string(value);
+ if (serialized_string == NULL) {
+ return JSONFailure;
+ }
+ fp = fopen (filename, "w");
+ if (fp == NULL) {
+ json_free_serialized_string(serialized_string);
+ return JSONFailure;
+ }
+ if (fputs(serialized_string, fp) == EOF) {
+ return_code = JSONFailure;
+ }
+ if (fclose(fp) == EOF) {
+ return_code = JSONFailure;
+ }
+ json_free_serialized_string(serialized_string);
+ return return_code;
+}
+
+char * json_serialize_to_string(const JSON_Value *value) {
+ JSON_Status serialization_result = JSONFailure;
+ size_t buf_size_bytes = json_serialization_size(value);
+ char *buf = NULL;
+ if (buf_size_bytes == 0) {
+ return NULL;
+ }
+ buf = (char*)parson_malloc(buf_size_bytes);
+ if (buf == NULL) {
+ return NULL;
+ }
+ serialization_result = json_serialize_to_buffer(value, buf, buf_size_bytes);
+ if (serialization_result == JSONFailure) {
+ json_free_serialized_string(buf);
+ return NULL;
+ }
+ return buf;
+}
+
+size_t json_serialization_size_pretty(const JSON_Value *value) {
+ char num_buf[1100]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */
+ int res = json_serialize_to_buffer_r(value, NULL, 0, 1, num_buf);
+ return res < 0 ? 0 : (size_t)(res + 1);
+}
+
+JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes) {
+ int written = -1;
+ size_t needed_size_in_bytes = json_serialization_size_pretty(value);
+ if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) {
+ return JSONFailure;
+ }
+ written = json_serialize_to_buffer_r(value, buf, 0, 1, NULL);
+ if (written < 0) {
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename) {
+ JSON_Status return_code = JSONSuccess;
+ FILE *fp = NULL;
+ char *serialized_string = json_serialize_to_string_pretty(value);
+ if (serialized_string == NULL) {
+ return JSONFailure;
+ }
+ fp = fopen (filename, "w");
+ if (fp == NULL) {
+ json_free_serialized_string(serialized_string);
+ return JSONFailure;
+ }
+ if (fputs(serialized_string, fp) == EOF) {
+ return_code = JSONFailure;
+ }
+ if (fclose(fp) == EOF) {
+ return_code = JSONFailure;
+ }
+ json_free_serialized_string(serialized_string);
+ return return_code;
+}
+
+char * json_serialize_to_string_pretty(const JSON_Value *value) {
+ JSON_Status serialization_result = JSONFailure;
+ size_t buf_size_bytes = json_serialization_size_pretty(value);
+ char *buf = NULL;
+ if (buf_size_bytes == 0) {
+ return NULL;
+ }
+ buf = (char*)parson_malloc(buf_size_bytes);
+ if (buf == NULL) {
+ return NULL;
+ }
+ serialization_result = json_serialize_to_buffer_pretty(value, buf, buf_size_bytes);
+ if (serialization_result == JSONFailure) {
+ json_free_serialized_string(buf);
+ return NULL;
+ }
+ return buf;
+}
+
+void json_free_serialized_string(char *string) {
+ parson_free(string);
+}
+
+JSON_Status json_array_remove(JSON_Array *array, size_t ix) {
+ JSON_Value *temp_value = NULL;
+ size_t last_element_ix = 0;
+ if (array == NULL || ix >= json_array_get_count(array)) {
+ return JSONFailure;
+ }
+ last_element_ix = json_array_get_count(array) - 1;
+ json_value_free(json_array_get_value(array, ix));
+ if (ix != last_element_ix) { /* Replace value with one from the end of array */
+ temp_value = json_array_get_value(array, last_element_ix);
+ if (temp_value == NULL) {
+ return JSONFailure;
+ }
+ array->items[ix] = temp_value;
+ }
+ array->count -= 1;
+ return JSONSuccess;
+}
+
+JSON_Status json_array_replace_value(JSON_Array *array, size_t ix, JSON_Value *value) {
+ if (array == NULL || value == NULL || value->parent != NULL || ix >= json_array_get_count(array)) {
+ return JSONFailure;
+ }
+ json_value_free(json_array_get_value(array, ix));
+ value->parent = json_array_get_wrapping_value(array);
+ array->items[ix] = value;
+ return JSONSuccess;
+}
+
+JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string) {
+ JSON_Value *value = json_value_init_string(string);
+ if (value == NULL) {
+ return JSONFailure;
+ }
+ if (json_array_replace_value(array, i, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number) {
+ JSON_Value *value = json_value_init_number(number);
+ if (value == NULL) {
+ return JSONFailure;
+ }
+ if (json_array_replace_value(array, i, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean) {
+ JSON_Value *value = json_value_init_boolean(boolean);
+ if (value == NULL) {
+ return JSONFailure;
+ }
+ if (json_array_replace_value(array, i, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_array_replace_null(JSON_Array *array, size_t i) {
+ JSON_Value *value = json_value_init_null();
+ if (value == NULL) {
+ return JSONFailure;
+ }
+ if (json_array_replace_value(array, i, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_array_clear(JSON_Array *array) {
+ size_t i = 0;
+ if (array == NULL) {
+ return JSONFailure;
+ }
+ for (i = 0; i < json_array_get_count(array); i++) {
+ json_value_free(json_array_get_value(array, i));
+ }
+ array->count = 0;
+ return JSONSuccess;
+}
+
+JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value) {
+ if (array == NULL || value == NULL || value->parent != NULL) {
+ return JSONFailure;
+ }
+ return json_array_add(array, value);
+}
+
+JSON_Status json_array_append_string(JSON_Array *array, const char *string) {
+ JSON_Value *value = json_value_init_string(string);
+ if (value == NULL) {
+ return JSONFailure;
+ }
+ if (json_array_append_value(array, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_array_append_number(JSON_Array *array, double number) {
+ JSON_Value *value = json_value_init_number(number);
+ if (value == NULL) {
+ return JSONFailure;
+ }
+ if (json_array_append_value(array, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_array_append_boolean(JSON_Array *array, int boolean) {
+ JSON_Value *value = json_value_init_boolean(boolean);
+ if (value == NULL) {
+ return JSONFailure;
+ }
+ if (json_array_append_value(array, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_array_append_null(JSON_Array *array) {
+ JSON_Value *value = json_value_init_null();
+ if (value == NULL) {
+ return JSONFailure;
+ }
+ if (json_array_append_value(array, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value) {
+ size_t i = 0;
+ JSON_Value *old_value;
+ if (object == NULL || name == NULL || value == NULL || value->parent != NULL) {
+ return JSONFailure;
+ }
+ old_value = json_object_get_value(object, name);
+ if (old_value != NULL) { /* free and overwrite old value */
+ json_value_free(old_value);
+ for (i = 0; i < json_object_get_count(object); i++) {
+ if (strcmp(object->names[i], name) == 0) {
+ value->parent = json_object_get_wrapping_value(object);
+ object->values[i] = value;
+ return JSONSuccess;
+ }
+ }
+ }
+ /* add new key value pair */
+ return json_object_add(object, name, value);
+}
+
+JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string) {
+ return json_object_set_value(object, name, json_value_init_string(string));
+}
+
+JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number) {
+ return json_object_set_value(object, name, json_value_init_number(number));
+}
+
+JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean) {
+ return json_object_set_value(object, name, json_value_init_boolean(boolean));
+}
+
+JSON_Status json_object_set_null(JSON_Object *object, const char *name) {
+ return json_object_set_value(object, name, json_value_init_null());
+}
+
+JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value) {
+ const char *dot_pos = NULL;
+ char *current_name = NULL;
+ JSON_Object *temp_obj = NULL;
+ JSON_Value *new_value = NULL;
+ if (value == NULL || name == NULL || value == NULL) {
+ return JSONFailure;
+ }
+ dot_pos = strchr(name, '.');
+ if (dot_pos == NULL) {
+ return json_object_set_value(object, name, value);
+ } else {
+ current_name = parson_strndup(name, dot_pos - name);
+ temp_obj = json_object_get_object(object, current_name);
+ if (temp_obj == NULL) {
+ new_value = json_value_init_object();
+ if (new_value == NULL) {
+ parson_free(current_name);
+ return JSONFailure;
+ }
+ if (json_object_add(object, current_name, new_value) == JSONFailure) {
+ json_value_free(new_value);
+ parson_free(current_name);
+ return JSONFailure;
+ }
+ temp_obj = json_object_get_object(object, current_name);
+ }
+ parson_free(current_name);
+ return json_object_dotset_value(temp_obj, dot_pos + 1, value);
+ }
+}
+
+JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string) {
+ JSON_Value *value = json_value_init_string(string);
+ if (value == NULL) {
+ return JSONFailure;
+ }
+ if (json_object_dotset_value(object, name, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number) {
+ JSON_Value *value = json_value_init_number(number);
+ if (value == NULL) {
+ return JSONFailure;
+ }
+ if (json_object_dotset_value(object, name, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean) {
+ JSON_Value *value = json_value_init_boolean(boolean);
+ if (value == NULL) {
+ return JSONFailure;
+ }
+ if (json_object_dotset_value(object, name, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_object_dotset_null(JSON_Object *object, const char *name) {
+ JSON_Value *value = json_value_init_null();
+ if (value == NULL) {
+ return JSONFailure;
+ }
+ if (json_object_dotset_value(object, name, value) == JSONFailure) {
+ json_value_free(value);
+ return JSONFailure;
+ }
+ return JSONSuccess;
+}
+
+JSON_Status json_object_remove(JSON_Object *object, const char *name) {
+ size_t i = 0, last_item_index = 0;
+ if (object == NULL || json_object_get_value(object, name) == NULL) {
+ return JSONFailure;
+ }
+ last_item_index = json_object_get_count(object) - 1;
+ for (i = 0; i < json_object_get_count(object); i++) {
+ if (strcmp(object->names[i], name) == 0) {
+ parson_free(object->names[i]);
+ json_value_free(object->values[i]);
+ if (i != last_item_index) { /* Replace key value pair with one from the end */
+ object->names[i] = object->names[last_item_index];
+ object->values[i] = object->values[last_item_index];
+ }
+ object->count -= 1;
+ return JSONSuccess;
+ }
+ }
+ return JSONFailure; /* No execution path should end here */
+}
+
+JSON_Status json_object_dotremove(JSON_Object *object, const char *name) {
+ const char *dot_pos = strchr(name, '.');
+ char *current_name = NULL;
+ JSON_Object *temp_obj = NULL;
+ if (dot_pos == NULL) {
+ return json_object_remove(object, name);
+ } else {
+ current_name = parson_strndup(name, dot_pos - name);
+ temp_obj = json_object_get_object(object, current_name);
+ if (temp_obj == NULL) {
+ parson_free(current_name);
+ return JSONFailure;
+ }
+ parson_free(current_name);
+ return json_object_dotremove(temp_obj, dot_pos + 1);
+ }
+}
+
+JSON_Status json_object_clear(JSON_Object *object) {
+ size_t i = 0;
+ if (object == NULL) {
+ return JSONFailure;
+ }
+ for (i = 0; i < json_object_get_count(object); i++) {
+ parson_free(object->names[i]);
+ json_value_free(object->values[i]);
+ }
+ object->count = 0;
+ return JSONSuccess;
+}
+
+JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value) {
+ JSON_Value *temp_schema_value = NULL, *temp_value = NULL;
+ JSON_Array *schema_array = NULL, *value_array = NULL;
+ JSON_Object *schema_object = NULL, *value_object = NULL;
+ JSON_Value_Type schema_type = JSONError, value_type = JSONError;
+ const char *key = NULL;
+ size_t i = 0, count = 0;
+ if (schema == NULL || value == NULL) {
+ return JSONFailure;
+ }
+ schema_type = json_value_get_type(schema);
+ value_type = json_value_get_type(value);
+ if (schema_type != value_type && schema_type != JSONNull) { /* null represents all values */
+ return JSONFailure;
+ }
+ switch (schema_type) {
+ case JSONArray:
+ schema_array = json_value_get_array(schema);
+ value_array = json_value_get_array(value);
+ count = json_array_get_count(schema_array);
+ if (count == 0) {
+ return JSONSuccess; /* Empty array allows all types */
+ }
+ /* Get first value from array, rest is ignored */
+ temp_schema_value = json_array_get_value(schema_array, 0);
+ for (i = 0; i < json_array_get_count(value_array); i++) {
+ temp_value = json_array_get_value(value_array, i);
+ if (json_validate(temp_schema_value, temp_value) == JSONFailure) {
+ return JSONFailure;
+ }
+ }
+ return JSONSuccess;
+ case JSONObject:
+ schema_object = json_value_get_object(schema);
+ value_object = json_value_get_object(value);
+ count = json_object_get_count(schema_object);
+ if (count == 0) {
+ return JSONSuccess; /* Empty object allows all objects */
+ } else if (json_object_get_count(value_object) < count) {
+ return JSONFailure; /* Tested object mustn't have less name-value pairs than schema */
+ }
+ for (i = 0; i < count; i++) {
+ key = json_object_get_name(schema_object, i);
+ temp_schema_value = json_object_get_value(schema_object, key);
+ temp_value = json_object_get_value(value_object, key);
+ if (temp_value == NULL) {
+ return JSONFailure;
+ }
+ if (json_validate(temp_schema_value, temp_value) == JSONFailure) {
+ return JSONFailure;
+ }
+ }
+ return JSONSuccess;
+ case JSONString: case JSONNumber: case JSONBoolean: case JSONNull:
+ return JSONSuccess; /* equality already tested before switch */
+ case JSONError: default:
+ return JSONFailure;
+ }
+}
+
+JSON_Status json_value_equals(const JSON_Value *a, const JSON_Value *b) {
+ JSON_Object *a_object = NULL, *b_object = NULL;
+ JSON_Array *a_array = NULL, *b_array = NULL;
+ const char *a_string = NULL, *b_string = NULL;
+ const char *key = NULL;
+ size_t a_count = 0, b_count = 0, i = 0;
+ JSON_Value_Type a_type, b_type;
+ a_type = json_value_get_type(a);
+ b_type = json_value_get_type(b);
+ if (a_type != b_type) {
+ return 0;
+ }
+ switch (a_type) {
+ case JSONArray:
+ a_array = json_value_get_array(a);
+ b_array = json_value_get_array(b);
+ a_count = json_array_get_count(a_array);
+ b_count = json_array_get_count(b_array);
+ if (a_count != b_count) {
+ return 0;
+ }
+ for (i = 0; i < a_count; i++) {
+ if (!json_value_equals(json_array_get_value(a_array, i),
+ json_array_get_value(b_array, i))) {
+ return 0;
+ }
+ }
+ return 1;
+ case JSONObject:
+ a_object = json_value_get_object(a);
+ b_object = json_value_get_object(b);
+ a_count = json_object_get_count(a_object);
+ b_count = json_object_get_count(b_object);
+ if (a_count != b_count) {
+ return 0;
+ }
+ for (i = 0; i < a_count; i++) {
+ key = json_object_get_name(a_object, i);
+ if (!json_value_equals(json_object_get_value(a_object, key),
+ json_object_get_value(b_object, key))) {
+ return 0;
+ }
+ }
+ return 1;
+ case JSONString:
+ a_string = json_value_get_string(a);
+ b_string = json_value_get_string(b);
+ if (a_string == NULL || b_string == NULL) {
+ return 0; /* shouldn't happen */
+ }
+ return strcmp(a_string, b_string) == 0;
+ case JSONBoolean:
+ return json_value_get_boolean(a) == json_value_get_boolean(b);
+ case JSONNumber:
+ return fabs(json_value_get_number(a) - json_value_get_number(b)) < 0.000001; /* EPSILON */
+ case JSONError:
+ return 1;
+ case JSONNull:
+ return 1;
+ default:
+ return 1;
+ }
+}
+
+JSON_Value_Type json_type(const JSON_Value *value) {
+ return json_value_get_type(value);
+}
+
+JSON_Object * json_object (const JSON_Value *value) {
+ return json_value_get_object(value);
+}
+
+JSON_Array * json_array (const JSON_Value *value) {
+ return json_value_get_array(value);
+}
+
+const char * json_string (const JSON_Value *value) {
+ return json_value_get_string(value);
+}
+
+double json_number (const JSON_Value *value) {
+ return json_value_get_number(value);
+}
+
+int json_boolean(const JSON_Value *value) {
+ return json_value_get_boolean(value);
+}
+
+void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun) {
+ parson_malloc = malloc_fun;
+ parson_free = free_fun;
+}
diff --git a/lib/parson/parson.h b/lib/parson/parson.h
new file mode 100644
index 0000000..e4cd21e
--- /dev/null
+++ b/lib/parson/parson.h
@@ -0,0 +1,234 @@
+/*
+ Parson ( http://kgabis.github.com/parson/ )
+ Copyright (c) 2012 - 2016 Krzysztof Gabis
+
+ 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.
+*/
+
+#ifndef parson_parson_h
+#define parson_parson_h
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stddef.h> /* size_t */
+
+/* Types and enums */
+typedef struct json_object_t JSON_Object;
+typedef struct json_array_t JSON_Array;
+typedef struct json_value_t JSON_Value;
+
+enum json_value_type {
+ JSONError = -1,
+ JSONNull = 1,
+ JSONString = 2,
+ JSONNumber = 3,
+ JSONObject = 4,
+ JSONArray = 5,
+ JSONBoolean = 6
+};
+typedef int JSON_Value_Type;
+
+enum json_result_t {
+ JSONSuccess = 0,
+ JSONFailure = -1
+};
+typedef int JSON_Status;
+
+typedef void * (*JSON_Malloc_Function)(size_t);
+typedef void (*JSON_Free_Function)(void *);
+
+/* Call only once, before calling any other function from parson API. If not called, malloc and free
+ from stdlib will be used for all allocations */
+void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun);
+
+/* Parses first JSON value in a file, returns NULL in case of error */
+JSON_Value * json_parse_file(const char *filename);
+
+/* Parses first JSON value in a file and ignores comments (/ * * / and //),
+ returns NULL in case of error */
+JSON_Value * json_parse_file_with_comments(const char *filename);
+
+/* Parses first JSON value in a string, returns NULL in case of error */
+JSON_Value * json_parse_string(const char *string);
+
+/* Parses first JSON value in a string and ignores comments (/ * * / and //),
+ returns NULL in case of error */
+JSON_Value * json_parse_string_with_comments(const char *string);
+
+/* Serialization */
+size_t json_serialization_size(const JSON_Value *value); /* returns 0 on fail */
+JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes);
+JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename);
+char * json_serialize_to_string(const JSON_Value *value);
+
+/* Pretty serialization */
+size_t json_serialization_size_pretty(const JSON_Value *value); /* returns 0 on fail */
+JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes);
+JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename);
+char * json_serialize_to_string_pretty(const JSON_Value *value);
+
+void json_free_serialized_string(char *string); /* frees string from json_serialize_to_string and json_serialize_to_string_pretty */
+
+/* Comparing */
+int json_value_equals(const JSON_Value *a, const JSON_Value *b);
+
+/* Validation
+ This is *NOT* JSON Schema. It validates json by checking if object have identically
+ named fields with matching types.
+ For example schema {"name":"", "age":0} will validate
+ {"name":"Joe", "age":25} and {"name":"Joe", "age":25, "gender":"m"},
+ but not {"name":"Joe"} or {"name":"Joe", "age":"Cucumber"}.
+ In case of arrays, only first value in schema is checked against all values in tested array.
+ Empty objects ({}) validate all objects, empty arrays ([]) validate all arrays,
+ null validates values of every type.
+ */
+JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value);
+
+/*
+ * JSON Object
+ */
+JSON_Value * json_object_get_value (const JSON_Object *object, const char *name);
+const char * json_object_get_string (const JSON_Object *object, const char *name);
+JSON_Object * json_object_get_object (const JSON_Object *object, const char *name);
+JSON_Array * json_object_get_array (const JSON_Object *object, const char *name);
+double json_object_get_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
+int json_object_get_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
+
+/* dotget functions enable addressing values with dot notation in nested objects,
+ just like in structs or c++/java/c# objects (e.g. objectA.objectB.value).
+ Because valid names in JSON can contain dots, some values may be inaccessible
+ this way. */
+JSON_Value * json_object_dotget_value (const JSON_Object *object, const char *name);
+const char * json_object_dotget_string (const JSON_Object *object, const char *name);
+JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name);
+JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name);
+double json_object_dotget_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
+int json_object_dotget_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
+
+/* Functions to get available names */
+size_t json_object_get_count (const JSON_Object *object);
+const char * json_object_get_name (const JSON_Object *object, size_t index);
+JSON_Value * json_object_get_value_at(const JSON_Object *object, size_t index);
+JSON_Value * json_object_get_wrapping_value(const JSON_Object *object);
+
+/* Functions to check if object has a value with a specific name. Returned value is 1 if object has
+ * a value and 0 if it doesn't. dothas functions behave exactly like dotget functions. */
+int json_object_has_value (const JSON_Object *object, const char *name);
+int json_object_has_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type);
+
+int json_object_dothas_value (const JSON_Object *object, const char *name);
+int json_object_dothas_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type);
+
+/* Creates new name-value pair or frees and replaces old value with a new one.
+ * json_object_set_value does not copy passed value so it shouldn't be freed afterwards. */
+JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value);
+JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string);
+JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number);
+JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean);
+JSON_Status json_object_set_null(JSON_Object *object, const char *name);
+
+/* Works like dotget functions, but creates whole hierarchy if necessary.
+ * json_object_dotset_value does not copy passed value so it shouldn't be freed afterwards. */
+JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value);
+JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string);
+JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number);
+JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean);
+JSON_Status json_object_dotset_null(JSON_Object *object, const char *name);
+
+/* Frees and removes name-value pair */
+JSON_Status json_object_remove(JSON_Object *object, const char *name);
+
+/* Works like dotget function, but removes name-value pair only on exact match. */
+JSON_Status json_object_dotremove(JSON_Object *object, const char *key);
+
+/* Removes all name-value pairs in object */
+JSON_Status json_object_clear(JSON_Object *object);
+
+/*
+ *JSON Array
+ */
+JSON_Value * json_array_get_value (const JSON_Array *array, size_t index);
+const char * json_array_get_string (const JSON_Array *array, size_t index);
+JSON_Object * json_array_get_object (const JSON_Array *array, size_t index);
+JSON_Array * json_array_get_array (const JSON_Array *array, size_t index);
+double json_array_get_number (const JSON_Array *array, size_t index); /* returns 0 on fail */
+int json_array_get_boolean(const JSON_Array *array, size_t index); /* returns -1 on fail */
+size_t json_array_get_count (const JSON_Array *array);
+JSON_Value * json_array_get_wrapping_value(const JSON_Array *array);
+
+/* Frees and removes value at given index, does nothing and returns JSONFailure if index doesn't exist.
+ * Order of values in array may change during execution. */
+JSON_Status json_array_remove(JSON_Array *array, size_t i);
+
+/* Frees and removes from array value at given index and replaces it with given one.
+ * Does nothing and returns JSONFailure if index doesn't exist.
+ * json_array_replace_value does not copy passed value so it shouldn't be freed afterwards. */
+JSON_Status json_array_replace_value(JSON_Array *array, size_t i, JSON_Value *value);
+JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string);
+JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number);
+JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean);
+JSON_Status json_array_replace_null(JSON_Array *array, size_t i);
+
+/* Frees and removes all values from array */
+JSON_Status json_array_clear(JSON_Array *array);
+
+/* Appends new value at the end of array.
+ * json_array_append_value does not copy passed value so it shouldn't be freed afterwards. */
+JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value);
+JSON_Status json_array_append_string(JSON_Array *array, const char *string);
+JSON_Status json_array_append_number(JSON_Array *array, double number);
+JSON_Status json_array_append_boolean(JSON_Array *array, int boolean);
+JSON_Status json_array_append_null(JSON_Array *array);
+
+/*
+ *JSON Value
+ */
+JSON_Value * json_value_init_object (void);
+JSON_Value * json_value_init_array (void);
+JSON_Value * json_value_init_string (const char *string); /* copies passed string */
+JSON_Value * json_value_init_number (double number);
+JSON_Value * json_value_init_boolean(int boolean);
+JSON_Value * json_value_init_null (void);
+JSON_Value * json_value_deep_copy (const JSON_Value *value);
+void json_value_free (JSON_Value *value);
+
+JSON_Value_Type json_value_get_type (const JSON_Value *value);
+JSON_Object * json_value_get_object (const JSON_Value *value);
+JSON_Array * json_value_get_array (const JSON_Value *value);
+const char * json_value_get_string (const JSON_Value *value);
+double json_value_get_number (const JSON_Value *value);
+int json_value_get_boolean(const JSON_Value *value);
+JSON_Value * json_value_get_parent (const JSON_Value *value);
+
+/* Same as above, but shorter */
+JSON_Value_Type json_type (const JSON_Value *value);
+JSON_Object * json_object (const JSON_Value *value);
+JSON_Array * json_array (const JSON_Value *value);
+const char * json_string (const JSON_Value *value);
+double json_number (const JSON_Value *value);
+int json_boolean(const JSON_Value *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/Makefile b/src/Makefile
index 6e4726a..3a4b559 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -9,22 +9,22 @@ CC=gcc
GP2C=gp2c
CFLAGS=-O3 -Wall
-LDFLAGS=
+LDFLAGS=-L../lib
GP_CFLAGS=-O3 -Wall -fomit-frame-pointer -fno-strict-aliasing -fPIC
GPFLAGS=-g -i4
-INCLUDES=-I.
-LIBS=-lpari
+INCLUDES=-I. -I../lib
+LIBS=-lpari -lparson
####
-GP = gp
+GP =
GPC = $(addsuffix .c, $(GP))
GPO = $(addsuffix .o, $(GP))
GPH = $(addsuffix .h, $(GP))
-SRC = cli input
+SRC = cli input output poly field curve random
OBJ = $(addsuffix .o, $(SRC))
HDR = $(addsuffix .h, $(SRC))
@@ -48,8 +48,6 @@ $(GPO): $(GPC) $(GPH)
####
-.PHONY: all gp2c clean-all clean clean-gp help
-
clean-all: clean clean-gp
clean:
@@ -70,3 +68,10 @@ help:
@echo " - clean : cleans up after a build"
@echo " - clean-gp : cleans up after gp2c generation"
@echo " - clean-all : cleans all"
+ @echo " - format : run clang-format on source files"
+
+format:
+ clang-format -i *.c
+ clang-format -i *.h
+
+.PHONY: all gp2c clean-all clean clean-gp help format \ No newline at end of file
diff --git a/src/cli.c b/src/cli.c
index cdc2af4..728bb6e 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -4,87 +4,97 @@
*/
#include "cli.h"
-char doc[] = "ecgen, tool for generating Elliptic curve domain parameters.\v(C) 2017 Eastern Seaboard Phishing Authority";
+char doc[] =
+ "ecgen, tool for generating Elliptic curve domain parameters.\v(C) 2017 "
+ "Eastern Seaboard Phishing Authority";
char args_doc[] = "bits";
enum opt_keys {
OPT_DATADIR = 'd',
- OPT_APPEND = 'a',
OPT_PRIME = 'p',
+ OPT_RANDOM = 'r',
+ OPT_SEED = 's',
OPT_OUTPUT = 'o',
OPT_INPUT = 'i',
- OPT_RANDOM = 'r',
+ OPT_APPEND = 'a',
OPT_FP = 1,
OPT_F2M = 2,
};
+// clang-format off
struct argp_option options[] = {
// Field specification
- {"fp", OPT_FP, 0, 0, "Prime field."},
- {"f2m", OPT_F2M, 0, 0, "Binary field."},
+ {"fp", OPT_FP, 0, 0, "Prime field."},
+ {"f2m", OPT_F2M, 0, 0, "Binary field."},
// Curve specification
- {"random", OPT_RANDOM, 0, 0, "Generate a random curve."},
- {"prime", OPT_PRIME, 0, 0, "Generate a curve with prime order."},
+ {"random", OPT_RANDOM, 0, 0, "Generate a random curve."},
+ {"prime", OPT_PRIME, 0, 0, "Generate a curve with prime order."},
+ {"seed", OPT_SEED, "SEED", OPTION_ARG_OPTIONAL, "Generate a curve from SEED(ANSI X9.62 verifiable procedure)."},
// Other
- {"data-dir", OPT_DATADIR, "DIR", 0,
- "PARI/GP data directory (containing seadata and elldata)."},
- {"input", OPT_INPUT, "FILE", 0, "Input from file."},
- {"output", OPT_OUTPUT, "FILE", 0, "Output into file. Overwrites any existing file!"},
- {"append", OPT_APPEND, 0, 0, "Append to output file(don't overwrite)."},
+ {"data-dir", OPT_DATADIR, "DIR", 0, "PARI/GP data directory (containing seadata and elldata)."},
+ {"input", OPT_INPUT, "FILE", 0, "Input from file."},
+ {"output", OPT_OUTPUT, "FILE", 0, "Output into file. Overwrites any existing file!"},
+ {"append", OPT_APPEND, 0, 0, "Append to output file(don't overwrite)."},
{0}};
+// clang-format on
error_t parse_opt(int key, char *arg, struct argp_state *state) {
- struct arguments *args = state->input;
+ struct config_t *cfg = state->input;
switch (key) {
case OPT_DATADIR:
- args->datadir = arg;
+ cfg->datadir = arg;
break;
case OPT_INPUT:
- args->input = arg;
+ cfg->input = arg;
break;
case OPT_OUTPUT:
- args->output = arg;
+ cfg->output = arg;
break;
case OPT_APPEND:
- args->append = true;
+ cfg->append = true;
break;
case OPT_RANDOM:
- args->random = true;
+ cfg->random = true;
break;
case OPT_PRIME:
- args->prime = true;
+ cfg->prime = true;
+ break;
+ case OPT_SEED:
+ cfg->from_seed = true;
+ cfg->seed = arg;
break;
case OPT_FP:
- if (args->binary_field) {
+ if (cfg->binary_field) {
argp_failure(
- state, 1, 0,
- "Either specify prime field or binary field, not both.");
+ state, 1, 0,
+ "Either specify prime field or binary field, not both.");
}
- args->field = FIELD_PRIME;
- args->prime_field = true;
+ cfg->field = FIELD_PRIME;
+ cfg->prime_field = true;
break;
case OPT_F2M:
- if (args->prime_field) {
+ if (cfg->prime_field) {
argp_failure(
- state, 1, 0,
- "Either specify binary field or prime field, not both.");
+ state, 1, 0,
+ "Either specify binary field or prime field, not both.");
}
- args->field = FIELD_BINARY;
- args->binary_field = true;
+ cfg->field = FIELD_BINARY;
+ cfg->binary_field = true;
break;
case ARGP_KEY_ARG:
if (state->arg_num >= 1) {
argp_usage(state);
}
- args->bits = strtol(arg, NULL, 10);
+ cfg->bits = strtol(arg, NULL, 10);
break;
case ARGP_KEY_END:
- if (!args->prime_field && !args->binary_field) {
+ // validate all option states here.
+ if (!cfg->prime_field && !cfg->binary_field) {
argp_failure(
- state, 1, 0,
- "Specify field type, prime or binary, with --fp / --f2m.");
+ state, 1, 0,
+ "Specify field type, prime or binary, with --fp / --f2m.");
}
break;
case ARGP_KEY_NO_ARGS:
diff --git a/src/cli.h b/src/cli.h
index e9b832b..0f0c625 100644
--- a/src/cli.h
+++ b/src/cli.h
@@ -13,23 +13,22 @@ extern char doc[];
extern char args_doc[];
extern struct argp_option options[];
-typedef enum {
- FIELD_PRIME,
- FIELD_BINARY
-} field_t;
+enum field_e { FIELD_PRIME, FIELD_BINARY } ;
-struct arguments {
- field_t field;
+typedef struct config_t {
+ enum field_e field;
bool binary_field;
bool prime_field;
bool random;
bool prime;
+ bool from_seed;
+ char *seed;
char *datadir;
char *output;
char *input;
bool append;
long bits;
-};
+} config_t;
error_t parse_opt(int key, char *arg, struct argp_state *state);
diff --git a/src/curve.c b/src/curve.c
index 0d15ccf..7c3ae9d 100644
--- a/src/curve.c
+++ b/src/curve.c
@@ -4,32 +4,207 @@
*/
#include "curve.h"
-GEN curve_random(GEN field) {
+curve_t *new_curve() {
+ curve_t *curve = malloc(sizeof(curve_t));
+ if (!curve) {
+ perror("Couldn't malloc.");
+ exit(1);
+ }
+ memset(curve, 0, sizeof(curve_t));
+ return curve;
+}
+
+void free_curve(curve_t **curve) {
+ if (*curve) {
+ free((*curve)->points);
+ free(*curve);
+ *curve = NULL;
+ }
+}
+
+curve_t *curve_random(GEN field) {
+ curve_t *result = new_curve();
+ pari_sp ltop = avma;
+
+ GEN curve, a, b;
+ a = genrand(field);
+ b = genrand(field);
+
+ GEN v = gen_0;
+ switch (typ(field)) {
+ case t_INT:
+ v = gtovec0(gen_0, 2);
+ gel(v, 1) = a;
+ gel(v, 2) = b;
+ break;
+ case t_FFELT:
+ v = gtovec0(gen_0, 5);
+ gel(v, 1) = gen_1;
+ gel(v, 4) = a;
+ gel(v, 5) = b;
+ break;
+ default:
+ pari_err_TYPE("curve_random", field);
+ }
+ curve = ellinit(v, field, -1);
+
+ result->field = field;
+ gerepileall(ltop, 3, &a, &b, &curve);
+ result->a = a;
+ result->b = b;
+ result->curve = curve;
+ return result;
+}
+
+curve_t *curve_randomf(enum field_e t, long bits) {
+ GEN field = field_random(t, bits);
+ return curve_random(field);
+}
+
+curve_t *curve_nonzero(GEN field) {
+ pari_sp ltop = avma;
+
+ curve_t *result = NULL;
+ do {
+ if (result) {
+ avma = ltop;
+ free_curve(&result);
+ }
+ result = curve_random(field);
+ } while (gequal0(ell_get_disc(result->curve)));
+
+ return result;
+}
+
+curve_t *curve_nonzerof(enum field_e t, long bits) {
+ pari_sp ltop = avma;
+
+ curve_t *result = NULL;
+ do {
+ if (result) {
+ avma = ltop;
+ free_curve(&result);
+ }
+ result = curve_randomf(t, bits);
+ } while(gequal0(ell_get_disc(result->curve)));
+
+ return result;
+}
+
+curve_t *curve_prime(GEN field) {
+ pari_sp ltop = avma;
+
+ curve_t *result = NULL;
+ do {
+ if (result) {
+ avma = ltop;
+ free_curve(&result);
+ }
+ result = curve_nonzero(field);
+ result->order = ellsea(result->curve, 1);
+ } while (gequal0(result->order) || !isprime(result->order));
+
+ return result;
+}
+
+curve_t *curve_primef(enum field_e t, long bits) {
pari_sp ltop = avma;
- GEN curve;
+ curve_t *result = NULL;
do {
- GEN a = genrand(field);
- GEN b = genrand(field);
+ if (result) {
+ avma = ltop;
+ free_curve(&result);
+ }
+ result = curve_nonzerof(t, bits);
+ result->order = ellsea(result->curve, 1);
+ } while (gequal0(result->order) || !isprime(result->order));
+
+ return result;
+}
+
+GEN curve_invalid(GEN field, GEN a, GEN b) {
+ return gen_m1;
+}
+
+curve_t *curve_seed_Fp(GEN field, GEN seed) {
+ return NULL;
+}
+
+curve_t *curve_seed_F2m(GEN field, GEN seed) {
+ return NULL;
+}
- GEN v = gen_0;
- switch (typ(field)) {
- case t_INT:
- v = gtovec0(gen_0, 2);
- gel(v, 1) = a;
- gel(v, 2) = b;
- break;
- case t_FFELT:
- v = gtovec0(gen_0, 5);
- gel(v, 1) = gen_1;
- gel(v, 4) = a;
- gel(v, 5) = b;
- break;
- default:
- pari_err_TYPE("curve_random", field);
+curve_t *curve_seed(GEN field, GEN seed) {
+ switch (typ(field)) {
+ case t_INT:
+ return curve_seed_Fp(field, seed);
+ case t_FFELT:
+ return curve_seed_F2m(field, seed);
+ default:
+ pari_err_TYPE("curve_seed", field);
+ return NULL; /* NOT REACHED */
+ }
+}
+
+curve_t *curve_seedr(GEN field) {
+ pari_sp ltop = avma;
+
+ GEN seed;
+ curve_t *result = NULL;
+ do {
+ if (result) {
+ avma = ltop;
+ free_curve(&result);
}
- curve = ellinit(v, field, -1);
- } while (gequal0(ell_get_disc(curve)));
+ seed = random_int(160);
+ result = curve_seed(field, seed);
+ } while(gequal0(ell_get_disc(result->curve)));
+
+ return result;
+}
+
+curve_t *curve_seedf(GEN seed, enum field_e t, long bits) {
+ pari_sp ltop = avma;
+
+ GEN field;
+ curve_t *result = NULL;
+ do {
+ if (result) {
+ avma = ltop;
+ free_curve(&result);
+ }
+ field = field_random(t, bits);
+ result = curve_seed(field, seed);
+ } while(gequal0(ell_get_disc(result->curve)));
+
+ return result;
+}
+
+curve_t *curve_seedrf(enum field_e t, long bits) {
+ pari_sp ltop = avma;
+
+ GEN seed, field;
+ curve_t *result = NULL;
+ do {
+ if (result) {
+ avma = ltop;
+ free_curve(&result);
+ }
+ seed = random_int(160);
+ field = field_random(t, bits);
+ result = curve_seed(field, seed);
+ } while(gequal0(ell_get_disc(result->curve)));
+
+ return result;
+}
+
+GEN curve_params(curve_t *curve) {
+ pari_sp ltop = avma;
+
+ GEN field = field_params(curve->field);
+ GEN a = gtovec(field_elementi(curve->a));
+ GEN b = gtovec(field_elementi(curve->b));
- return gerepilecopy(ltop, curve);
+ return gerepilecopy(ltop, gconcat(gconcat(field, a), b));
}
diff --git a/src/curve.h b/src/curve.h
index 106bf5e..5002f45 100644
--- a/src/curve.h
+++ b/src/curve.h
@@ -5,8 +5,111 @@
#ifndef ECGEN_CURVE_H
#define ECGEN_CURVE_H
-#include "gp.h"
+#include <pari/pari.h>
+#include "field.h"
+#include "point.h"
-GEN curve_random(GEN field);
+typedef struct curve_t {
+ GEN seed;
+ GEN field;
+ GEN a;
+ GEN b;
+ GEN curve;
+ GEN order;
+ point_t **points;
+ size_t npoints;
+} curve_t;
-#endif //ECGEN_CURVE_H
+/**
+ *
+ * @param field
+ * @return
+ */
+curve_t *curve_random(GEN field);
+
+/**
+ *
+ * @param t
+ * @param bits
+ * @return
+ */
+curve_t *curve_randomf(enum field_e t, long bits);
+
+/**
+ *
+ * @param field
+ * @return
+ */
+curve_t *curve_nonzero(GEN field);
+
+/**
+ *
+ * @param t
+ * @param bits
+ * @return
+ */
+curve_t *curve_nonzerof(enum field_e t, long bits);
+
+/**
+ *
+ * @param field
+ * @return
+ */
+curve_t *curve_prime(GEN field);
+
+/**
+ *
+ * @param t
+ * @param bits
+ * @return
+ */
+curve_t *curve_primef(enum field_e t, long bits);
+
+/**
+ * ANSI X9.62 Verifiable random curve over field with seed.
+ *
+ * @param field
+ * @param seed
+ * @return
+ */
+curve_t *curve_seed(GEN field, GEN seed);
+
+/**
+ *
+ * @param field
+ * @return
+ */
+curve_t *curve_seedr(GEN field);
+
+/**
+ *
+ * @param seed
+ * @param t
+ * @param bits
+ * @return
+ */
+curve_t *curve_seedf(GEN seed, enum field_e t, long bits);
+
+/**
+ *
+ * @param t
+ * @param bits
+ * @return
+ */
+curve_t *curve_seedrf(enum field_e t, long bits);
+
+/**
+ *
+ * @param curve
+ * @return
+ */
+GEN curve_params(curve_t *curve);
+
+/**
+ *
+ * @param curve
+ */
+void free_curve(curve_t **curve);
+
+
+#endif // ECGEN_CURVE_H
diff --git a/src/ecgen.c b/src/ecgen.c
index 4459805..320cd0b 100644
--- a/src/ecgen.c
+++ b/src/ecgen.c
@@ -14,7 +14,8 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
/**
* @author J08nY <johny@neuromancer.sk>
@@ -24,27 +25,27 @@
#include <time.h>
#include "cli.h"
-#include "field.h"
#include "curve.h"
#include "output.h"
+#include "input.h"
-const char *argp_program_version = "ecgen 0.2\n"
- "Copyright (C) 2017 J08nY\n"
- "License GPLv2: GNU GPL version 2 (or later) <http://gnu.org/licenses/gpl.html>\n"
- "This is free software: you are free to change and redistribute it.\n"
- "There is NO WARRANTY, to the extent permitted by law.";
+const char *argp_program_version =
+ "ecgen 0.2\n"
+ "Copyright (C) 2017 J08nY\n"
+ "License GPLv2: GNU GPL version 2 (or later) "
+ "<http://gnu.org/licenses/gpl.html>\n"
+ "This is free software: you are free to change and redistribute it.\n"
+ "There is NO WARRANTY, to the extent permitted by law.";
const char *argp_program_bug_address = "<johny@neuromancer.sk>";
static struct argp argp = {options, parse_opt, args_doc, doc};
-static struct arguments args;
+static struct config_t cfg;
static FILE *in;
static FILE *out;
bool init() {
// Init PARI, 1GB stack, 1M primes
pari_init(1000000000, 1000000);
- init_gp();
-
// Init PARI PRNG
pari_ulong seed = 0;
@@ -58,9 +59,9 @@ bool init() {
if (seed == 0) {
struct timespec t;
if (!clock_gettime(CLOCK_REALTIME, &t)) {
- seed = (pari_ulong) t.tv_nsec;
+ seed = (pari_ulong)t.tv_nsec;
} else {
- seed = (pari_ulong) time(NULL);
+ seed = (pari_ulong)time(NULL);
}
}
@@ -68,32 +69,16 @@ bool init() {
setrand(utoi(seed));
avma = ltop;
- //set datadir if specified
- if (args.datadir) {
- default0("datadir", args.datadir);
+ // set datadir if specified
+ if (cfg.datadir) {
+ default0("datadir", cfg.datadir);
}
- //open outfile
- out = stdout;
- if (args.output) {
- out = fopen(args.output, args.append ? "a" : "w");
- if (!out) {
- //fallback to stdout and output err
- out = stdout;
- perror("Failed to open output file.");
- }
- }
+ // open outfile
+ out = output_open(cfg.output, cfg.append);
- //open infile
- in = stdin;
- if (args.input) {
- in = fopen(args.input, "r");
- if (!in) {
- //fallback to stdin or quit?
- in = stdin;
- perror("Failed to open input file.");
- }
- }
+ // open infile
+ in = input_open(cfg.input);
return true;
}
@@ -101,47 +86,33 @@ bool init() {
int quit(int status) {
pari_close();
- if (out != NULL && out != stdout) {
- fclose(out);
- }
-
- if (in != NULL && in != stdout) {
- fclose(in);
- }
+ output_close(out);
+ input_close(in);
return status;
}
int main(int argc, char *argv[]) {
// Parse cli args
- memset(&args, 0, sizeof(args));
- argp_parse(&argp, argc, argv, 0, 0, &args);
-
+ memset(&cfg, 0, sizeof(cfg));
+ argp_parse(&argp, argc, argv, 0, 0, &cfg);
if (!init()) {
return quit(1);
}
- if (args.random) {
- GEN field = gen_0;
- switch (args.field) {
- case FIELD_PRIME:
- field = field_primer(args.bits);
- break;
- case FIELD_BINARY:
- field = field_binaryr(args.bits);
- break;
+ if (cfg.random) {
+ curve_t *curve;
+ if (cfg.prime) {
+ curve = curve_primef(cfg.field, cfg.bits);
+ } else {
+ curve = curve_nonzerof(cfg.field, cfg.bits);
}
- GEN curve = curve_random(field);
- GEN ord = ellcard(curve, NULL);
- GEN f = field_params(field);
- GEN a = gtovec(field_elementi(ell_get_a4(curve)));
- GEN b = gtovec(field_elementi(ell_get_a6(curve)));
+ output_csv(out, "%Px", ',', curve_params(curve));
- GEN o = gconcat(gconcat(gconcat(f, a), b), gtovec(ord));
+ free_curve(&curve);
- output_csv(out, ',', 'x', o);
} else {
fprintf(stderr, "Currently unsupported.");
}
diff --git a/src/field.c b/src/field.c
index 016f095..c2cfdf8 100644
--- a/src/field.c
+++ b/src/field.c
@@ -4,36 +4,42 @@
*/
#include "field.h"
-
-GEN field_primer(long bits) {
- return random_prime(bits);
-}
-
+GEN field_primer(long bits) { return random_prime(bits); }
GEN field_binaryr(long bits) {
if (poly_exists(bits)) {
return poly_find_gen(bits);
} else {
- fprintf(stderr, "Unable to find a suitable binary field. Use an explicit one.");
+ fprintf(stderr,
+ "Unable to find a suitable binary field. Use an explicit one.");
exit(1);
}
}
+GEN field_random(enum field_e t, long bits) {
+ switch(t) {
+ case FIELD_PRIME:
+ return field_primer(bits);
+ case FIELD_BINARY:
+ return field_binaryr(bits);
+ default:
+ return gen_0; /* NOT REACHABLE */
+ }
+}
+
GEN field_params(GEN field) {
pari_sp ltop = avma;
- long l2;
if (typ(field) == t_INT) {
GEN p3 = cgetg(2, t_VEC);
gel(p3, 1) = gcopy(field);
- p3 = gerepilecopy(ltop, p3);
- return p3;
+ return gerepilecopy(ltop, p3);
}
GEN out = gtovec0(gen_0, 3);
long j = 1;
- l2 = glength(member_mod(field)) - 2;
+ long l2 = glength(member_mod(field)) - 2;
{
pari_sp btop = avma;
for (GEN i = gen_1; gcmpgs(i, l2) <= 0; i = gaddgs(i, 1)) {
@@ -45,8 +51,7 @@ GEN field_params(GEN field) {
if (gc_needed(btop, 1)) gerepileall(btop, 4, &out, &c, &i);
}
}
- out = gerepilecopy(ltop, out);
- return out;
+ return gerepilecopy(ltop, out);
}
GEN field_elementi(GEN element) {
diff --git a/src/field.h b/src/field.h
index 55d6bf9..e09ea62 100644
--- a/src/field.h
+++ b/src/field.h
@@ -6,7 +6,8 @@
#define ECGEN_FIELD_H
#include "poly.h"
-#include "gp.h"
+#include "random.h"
+#include "cli.h"
/**
*
@@ -23,9 +24,18 @@ GEN field_primer(long bits);
GEN field_binaryr(long bits);
/**
+ *
+ * @param t
+ * @param bits
+ * @return
+ */
+GEN field_random(enum field_e t, long bits);
+
+/**
* Extract a field representation from a field.
* - char(field) == 2:
- * returns the vector of powers of middle coefficients of the reduction polynomial.
+ * returns the vector of powers of middle coefficients of the reduction
+ * polynomial.
* - char(field) != 2:
* returns the field characteristic(p).-
*
@@ -34,6 +44,11 @@ GEN field_binaryr(long bits);
*/
GEN field_params(GEN field);
+/**
+ *
+ * @param element
+ * @return
+ */
GEN field_elementi(GEN element);
-#endif //ECGEN_FIELD_H
+#endif // ECGEN_FIELD_H
diff --git a/src/gp.c b/src/gp.c
index d15e117..59cb11a 100644
--- a/src/gp.c
+++ b/src/gp.c
@@ -6,202 +6,3 @@ void init_gp(void) /* void */
avma = ltop;
return;
}
-
-/*
-* ecgen, tool for generating Elliptic curve domain parameters
-* Copyright (C) 2017 J08nY
-*/
-
-/*
-* ecgen, tool for generating Elliptic curve domain parameters
-* Copyright (C) 2017 J08nY
-*/
-
-GEN random_primer(GEN range) /* int */
-{
- pari_sp ltop = avma;
- GEN p = gen_0; /* int */
- if (!is_matvec_t(typ(range))) pari_err_TYPE("random_primer", range);
- {
- pari_sp btop = avma;
- do {
- p = randomprime(range);
- if (gc_needed(btop, 1)) p = gerepilecopy(btop, p);
- } while (!isprime(p));
- }
- p = gerepilecopy(ltop, p);
- return p;
-}
-
-/**
-* Calculates a random prime of bit size bits.
-*
-* @param bits bit size of the requested prime
-* @return random prime between 2^(bits - 1) and 2^bits
-*/
-GEN random_prime(long bits) /* int */
-{
- pari_sp ltop = avma;
- GEN p1 = gen_0; /* vec */
- GEN p2 = gen_0; /* int */
- p1 = cgetg(3, t_VEC);
- gel(p1, 1) = powis(gen_2, bits - 1);
- gel(p1, 2) = powis(gen_2, bits);
- p2 = random_primer(p1);
- p2 = gerepilecopy(ltop, p2);
- return p2;
-}
-
-GEN random_intr(GEN range) {
- pari_sp ltop = avma;
- GEN p1 = gen_0;
- if (!is_matvec_t(typ(range))) pari_err_TYPE("random_intr", range);
- p1 = genrand(range);
- p1 = gerepilecopy(ltop, p1);
- return p1;
-}
-
-/**
-* Generates a random integer with bit size bits.
-*
-* @param bits bit size of the requested integer
-* @return random int between 2^(bits - 1) and 2^bits
-*/
-GEN random_int(long bits) {
- pari_sp ltop = avma;
- GEN p1 = gen_0; /* vec */
- GEN p2 = gen_0;
- p1 = cgetg(3, t_VEC);
- gel(p1, 1) = powis(gen_2, bits - 1);
- gel(p1, 2) = powis(gen_2, bits);
- p2 = random_intr(p1);
- p2 = gerepilecopy(ltop, p2);
- return p2;
-}
-
-/**
-* Converts a list to a vector.
-*
-* @param l list to convert
-* @return a vector of the lists values
-*/
-GEN list_to_vec(GEN l) /* vec */
-{
- pari_sp ltop = avma;
- GEN v = gen_0; /* vec */
- GEN n = gen_0; /* int */
- GEN p1 = gen_0; /* vec */
- n = stoi(glength(l));
- {
- long l2;
- p1 = cgetg(itos(n) + 1, t_VEC);
- for (l2 = 1; cmpsi(l2, n) <= 0; ++l2) gel(p1, l2) = gen_0;
- }
- v = p1;
- {
- pari_sp btop = avma;
- GEN i = gen_0;
- for (i = gen_1; gcmp(i, n) <= 0; i = gaddgs(i, 1)) {
- gel(v, gtos(i)) = gcopy(gel(list_data(l), gtos(i)));
- if (gc_needed(btop, 1)) gerepileall(btop, 2, &v, &i);
- }
- }
- v = gerepilecopy(ltop, v);
- return v;
-}
-
-/*
-* ecgen, tool for generating Elliptic curve domain parameters
-* Copyright (C) 2017 J08nY
-*/
-
-/**
-* Computes primes upto some upper bound.
-*
-* @param bound an upper bound on primes
-* @return a vector of primes up to bound^2
-*/
-GEN prime_upto(GEN bound) /* vec */
-{
- pari_sp ltop = avma;
- GEN p = gen_0; /* list */
- GEN product = gen_0, last = gen_0; /* int */
- GEN result = gen_0; /* vec */
- if (typ(bound) != t_INT) pari_err_TYPE("prime_upto", bound);
- p = mklist();
- bound = sqri(bound);
- listput0(p, gen_2, 0);
- product = gen_2;
- last = gen_2;
- {
- pari_sp btop = avma;
- while (cmpii(product, bound) < 0) {
- last = nextprime(addis(last, 1));
- listput0(p, last, 0);
- product = mulii(product, last);
- if (gc_needed(btop, 1)) gerepileall(btop, 3, &p, &product, &last);
- }
- }
- result = list_to_vec(p);
- listkill(p);
- result = gerepilecopy(ltop, result);
- return result;
-}
-
-/**
-*
-*/
-GEN invalid(GEN coeffs, GEN field, GEN primes, GEN bits, long prec) /* vec */
-{
- pari_sp ltop = avma;
- GEN bs = gen_0, cs = gen_0, eq = gen_0; /* vec */
- GEN e = gen_0; /* ell */
- GEN b = gen_0, n = gen_0, c = gen_0, o = gen_0; /* int */
- GEN p1 = gen_0; /* vec */
- if (!is_matvec_t(typ(coeffs))) pari_err_TYPE("invalid", coeffs);
- if (typ(field) != t_POL) pari_err_TYPE("invalid", field);
- if (!is_matvec_t(typ(primes))) pari_err_TYPE("invalid", primes);
- if (typ(bits) != t_INT) pari_err_TYPE("invalid", bits);
- n = stoi(lg(primes) - 1);
- {
- long l2;
- p1 = cgetg(itos(n) + 1, t_VEC);
- for (l2 = 1; cmpsi(l2, n) <= 0; ++l2) gel(p1, l2) = gen_0;
- }
- bs = p1;
- eq = gcopy(coeffs);
- c = gen_0;
- {
- pari_sp btop = avma;
- while (cmpii(c, n) < 0) {
- b = random_int(itos(bits));
- gel(eq, 4) = icopy(b);
- /* Times field? */
-
- pari_CATCH(CATCH_ALL) {
- GEN E = pari_err_last(); /* error */
- continue;
- }
- pari_TRY { e = ellinit(eq, field, prec); }
- pari_ENDCATCH o = ellsea(e, 0);
- {
- pari_sp btop = avma;
- GEN i = gen_0;
- for (i = gen_1; gcmp(i, n) <= 0; i = gaddgs(i, 1)) {
- if (gequal0(gmod(o, gel(primes, gtos(i)))) &&
- gequal0(gel(bs, gtos(i)))) {
- gel(bs, gtos(i)) = icopy(b);
- gel(cs, gtos(i)) = gcopy(e);
- c = addis(c, 1);
- }
- if (gc_needed(btop, 1))
- gerepileall(btop, 4, &bs, &cs, &c, &i);
- }
- }
- if (gc_needed(btop, 1))
- gerepileall(btop, 7, &bs, &cs, &eq, &e, &b, &c, &o);
- }
- }
- cs = gerepilecopy(ltop, cs);
- return cs;
-}
diff --git a/src/gp.h b/src/gp.h
index c81c4c1..f066dec 100644
--- a/src/gp.h
+++ b/src/gp.h
@@ -8,21 +8,7 @@
#include <pari/pari.h>
/*
GP;install("init_gp","v","init_gp","./gp/gp.gp.so");
-GP;install("random_primer","G","random_primer","./gp/gp.gp.so");
-GP;install("random_prime","L","random_prime","./gp/gp.gp.so");
-GP;install("random_intr","G","random_intr","./gp/gp.gp.so");
-GP;install("random_int","L","random_int","./gp/gp.gp.so");
-GP;install("list_to_vec","G","list_to_vec","./gp/gp.gp.so");
-GP;install("prime_upto","G","prime_upto","./gp/gp.gp.so");
-GP;install("invalid","GGGGp","invalid","./gp/gp.gp.so");
*/
void init_gp(void);
-GEN random_primer(GEN range);
-GEN random_prime(long bits);
-GEN random_intr(GEN range);
-GEN random_int(long bits);
-GEN list_to_vec(GEN l);
-GEN prime_upto(GEN bound);
-GEN invalid(GEN coeffs, GEN field, GEN primes, GEN bits, long prec);
/*End of prototype*/
#endif //GP_H
diff --git a/src/gp/gp.gp b/src/gp/gp.gp
index 0124958..9bae867 100644
--- a/src/gp/gp.gp
+++ b/src/gp/gp.gp
@@ -3,5 +3,7 @@
* Copyright (C) 2017 J08nY
*/
+/*
\r gp/utils
-\r gp/invalid \ No newline at end of file
+\r gp/invalid
+*/ \ No newline at end of file
diff --git a/src/gp/utils.gp b/src/gp/utils.gp
index 932a44a..0f29394 100644
--- a/src/gp/utils.gp
+++ b/src/gp/utils.gp
@@ -2,39 +2,6 @@
* ecgen, tool for generating Elliptic curve domain parameters
* Copyright (C) 2017 J08nY
*/
-
- random_primer(range:vec) = {
- local(p:int);
- until(isprime(p),
- p = randomprime(range):int;
- );
- return(p);
- }
-
-/**
- * Calculates a random prime of bit size bits.
- *
- * @param bits bit size of the requested prime
- * @return random prime between 2^(bits - 1) and 2^bits
- */
-random_prime(bits:small) = {
- return(random_primer([2^(bits-1), 2^bits]));
-}
-
-random_intr(range:vec) = {
- return(random(range));
-}
-
-/**
- * Generates a random integer with bit size bits.
- *
- * @param bits bit size of the requested integer
- * @return random int between 2^(bits - 1) and 2^bits
- */
-random_int(bits:small) = {
- return(random_intr([2^(bits-1), 2^bits]));
-}
-
/**
* Converts a list to a vector.
*
diff --git a/src/input.c b/src/input.c
index 441fd47..e49eae6 100644
--- a/src/input.c
+++ b/src/input.c
@@ -7,67 +7,68 @@
/*
*
*char *prime_prompts[] = {"p:", "a:", "b:"};
- param_t prime_params[] = {PARAM_PRIME, PARAM_INT, PARAM_INT};
+ param_t prime_params[] = {PARAM_PRIME, PARAM_INT, PARAM_INT};
- char *binary_prompts[] = {"e1:", "e2:", "e3:", "a:", "b:"};
- param_t binary_params[] = {PARAM_SHORT, PARAM_SHORT, PARAM_SHORT, PARAM_INT, PARAM_INT};
+ char *binary_prompts[] = {"e1:", "e2:", "e3:", "a:", "b:"};
+ param_t binary_params[] = {PARAM_SHORT, PARAM_SHORT, PARAM_SHORT, PARAM_INT,
+ PARAM_INT};
- char **prompts;
- param_t *params;
- size_t length;
- if (args.prime_field) {
- prompts = prime_prompts;
- params = prime_params;
- length = 3;
- } else {
- prompts = binary_prompts;
- params = binary_params;
- length = 5;
- }
- GEN field;
- GEN domain[length];
+ char **prompts;
+ param_t *params;
+ size_t length;
+ if (cfg.prime_field) {
+ prompts = prime_prompts;
+ params = prime_params;
+ length = 3;
+ } else {
+ prompts = binary_prompts;
+ params = binary_params;
+ length = 5;
+ }
+ GEN field;
+ GEN domain[length];
- if (args.random) {
- //random domain, might not define a curve... check disc
- if (args.prime_field) {
- field = ifield_prime(args.bits);
- } else {
- field = ifield_binary(args.bits);
- }
- } else {
- for (size_t i = 0; i < length; ++i) {
- domain[i] = fread_param(params[i], in, prompts[i], args.bits, in == stdin ? '\n' : ',');
- if (equalii(domain[i], gen_m1)) {
- fprintf(stderr, "Whoops?");
- return quit(1);
- }
- }
- if (args.prime_field) {
- field = field_prime(domain[0]);
- } else {
- field = field_binary(args.bits, domain[0], domain[1], domain[2]);
- }
- }
- pari_fprintf(out, "%Ps", field_params(field));
+ if (cfg.random) {
+ //random domain, might not define a curve... check disc
+ if (cfg.prime_field) {
+ field = ifield_prime(cfg.bits);
+ } else {
+ field = ifield_binary(cfg.bits);
+ }
+ } else {
+ for (size_t i = 0; i < length; ++i) {
+ domain[i] = fread_param(params[i], in, prompts[i], cfg.bits, in ==
+ stdin ? '\n' : ',');
+ if (equalii(domain[i], gen_m1)) {
+ fprintf(stderr, "Whoops?");
+ return quit(1);
+ }
+ }
+ if (cfg.prime_field) {
+ field = field_prime(domain[0]);
+ } else {
+ field = field_binary(cfg.bits, domain[0], domain[1], domain[2]);
+ }
+ }
+ pari_fprintf(out, "%Ps", field_params(field));
- if (args.prime_field) {
- GEN field = prime_field(p);
- GEN curve = prime_weierstrass(a, b, field, 0);
- } else if (args.binary_field) {
- GEN e[3];
- for (size_t i = 0; i < 3; ++i) {
- char prompt[] = {'e', (char) ('1' + i), ':', 0};
- e[i] = read_short(prompt, '\n');
- }
- GEN a = read_int("a:", args.bits, '\n');
+ if (cfg.prime_field) {
+ GEN field = prime_field(p);
+ GEN curve = prime_weierstrass(a, b, field, 0);
+ } else if (cfg.binary_field) {
+ GEN e[3];
+ for (size_t i = 0; i < 3; ++i) {
+ char prompt[] = {'e', (char) ('1' + i), ':', 0};
+ e[i] = read_short(prompt, '\n');
+ }
+ GEN a = read_int("a:", cfg.bits, '\n');
- GEN field = binary_field(args.bits, e[0], e[1], e[2]);
- }
+ GEN field = binary_field(cfg.bits, e[0], e[1], e[2]);
+ }
*/
-
GEN fread_i(FILE *stream, const char *prompt, long bits, int delim,
- GEN (*rand_func)(long)) {
+ GEN (*rand_func)(long)) {
printf("%s ", prompt);
char *line = NULL;
size_t n = 0;
@@ -117,7 +118,8 @@ GEN fread_short(FILE *stream, const char *prompt, int delim) {
return fread_i(stream, prompt, 16, delim, NULL);
}
-GEN fread_param(param_t param, FILE *stream, const char *prompt, long bits, int delim) {
+GEN fread_param(param_t param, FILE *stream, const char *prompt, long bits,
+ int delim) {
switch (param) {
case PARAM_PRIME:
return fread_prime(stream, prompt, bits, delim);
@@ -133,3 +135,22 @@ GEN read_param(param_t param, const char *prompt, long bits, int delim) {
return fread_param(param, stdin, prompt, bits, delim);
}
+FILE *input_open(const char *input) {
+ if (input) {
+ FILE *in = fopen(input, "r");
+ if (!in) {
+ // fallback to stdin or quit?
+ in = stdin;
+ perror("Failed to open input file.");
+ }
+ return in;
+ } else {
+ return stdin;
+ }
+}
+
+void input_close(FILE *in) {
+ if (in != NULL && in != stdout) {
+ fclose(in);
+ }
+}
diff --git a/src/input.h b/src/input.h
index b0ab421..ead8baa 100644
--- a/src/input.h
+++ b/src/input.h
@@ -5,13 +5,9 @@
#ifndef ECGEN_INPUT_H
#define ECGEN_INPUT_H
-#include "gp.h"
+#include "random.h"
-typedef enum PARAM {
- PARAM_PRIME,
- PARAM_INT,
- PARAM_SHORT
-} param_t;
+typedef enum PARAM { PARAM_PRIME, PARAM_INT, PARAM_SHORT } param_t;
/**
*
@@ -42,10 +38,13 @@ GEN fread_int(FILE *stream, const char *prompt, long bits, int delim);
*/
GEN fread_short(FILE *stream, const char *prompt, int delim);
-
-GEN fread_param(param_t param, FILE *stream, const char *prompt, long bits, int delim);
+GEN fread_param(param_t param, FILE *stream, const char *prompt, long bits,
+ int delim);
GEN read_param(param_t param, const char *prompt, long bits, int delim);
+FILE *input_open(const char *input);
+
+void input_close(FILE *in);
-#endif //ECGEN_INPUT_H
+#endif // ECGEN_INPUT_H
diff --git a/src/output.c b/src/output.c
index 26f4f89..adeda58 100644
--- a/src/output.c
+++ b/src/output.c
@@ -2,22 +2,21 @@
* ecgen, tool for generating Elliptic curve domain parameters
* Copyright (C) 2017 J08nY
*/
-#include "output.h"
-void output_csv(FILE *out, char delim, char format, GEN vector) {
- char fmt[] = {'%', 'P', format, 0};
+#include "output.h"
+char *output_scsv(const char *format, char delim, GEN vector) {
long len = lg(vector) - 1;
char *params[len];
size_t lengths[len];
size_t total = 0;
for (long i = 0; i < len; ++i) {
- params[i] = pari_sprintf(fmt, gel(vector, i + 1));
+ params[i] = pari_sprintf(format, gel(vector, i + 1));
lengths[i] = strlen(params[i]);
total += lengths[i];
}
- char *result = malloc(total + len);
+ char *result = (char *)malloc(total + len);
if (!result) {
perror("Couldn't malloc.");
exit(1);
@@ -34,9 +33,38 @@ void output_csv(FILE *out, char delim, char format, GEN vector) {
offset++;
}
}
- result[offset] = 0;
+ memset(result + offset, 0, 1);
+
+ return result;
+}
+
+void output_csv(FILE *out, const char *format, char delim, GEN vector) {
+ char *string = output_scsv(format, delim, vector);
+ fprintf(out, "%s", string);
+ free(string);
+}
- fprintf(out, "%s", result);
- free(result);
+char *output_sjson(GEN vector) {
}
+void output_json(FILE *out, GEN vector) {}
+
+FILE *output_open(const char *output, bool append) {
+ if (output) {
+ FILE *out = fopen(output, append ? "a" : "w");
+ if (!out) {
+ // fallback to stdout and output err
+ out = stdout;
+ perror("Failed to open output file.");
+ }
+ return out;
+ } else {
+ return stdout;
+ }
+}
+
+void output_close(FILE *out) {
+ if (out != NULL && out != stdout) {
+ fclose(out);
+ }
+} \ No newline at end of file
diff --git a/src/output.h b/src/output.h
index f3632a1..f45aa50 100644
--- a/src/output.h
+++ b/src/output.h
@@ -5,8 +5,44 @@
#ifndef ECGEN_OUTPUT_H
#define ECGEN_OUTPUT_H
-#include "gp.h"
+#include <stdbool.h>
+#include <parson/parson.h>
+#include <pari/pari.h>
-void output_csv(FILE *out, char delim, char format, GEN vector);
+/**
+ *
+ * @param delim
+ * @param format
+ * @param vector
+ * @return
+ */
+char *output_scsv(const char *format, char delim, GEN vector);
+
+/**
+ *
+ * @param out
+ * @param delim
+ * @param format
+ * @param vector
+ */
+void output_csv(FILE *out, const char *format, char delim, GEN vector);
+
+/**
+ *
+ * @param vector
+ * @return
+ */
+char *output_sjson(GEN vector);
+
+/**
+ *
+ * @param out
+ * @param vector
+ */
+void output_json(FILE *out, GEN vector);
+
+FILE *output_open(const char *output, bool append);
+
+void output_close(FILE *out);
-#endif //ECGEN_OUTPUT_H
+#endif // ECGEN_OUTPUT_H
diff --git a/src/point.c b/src/point.c
new file mode 100644
index 0000000..8fa1007
--- /dev/null
+++ b/src/point.c
@@ -0,0 +1,13 @@
+/*
+ * ecgen, tool for generating Elliptic curve domain parameters
+ * Copyright (C) 2017 J08nY
+ */
+#include "point.h"
+
+
+point_t *gerepile_point(pari_sp ltop, point_t *point) {
+ if (point) {
+ gerepileall(ltop, 2, &point->point, &point->order);
+ }
+ return point;
+} \ No newline at end of file
diff --git a/src/point.h b/src/point.h
new file mode 100644
index 0000000..710c3ce
--- /dev/null
+++ b/src/point.h
@@ -0,0 +1,17 @@
+/*
+ * ecgen, tool for generating Elliptic curve domain parameters
+ * Copyright (C) 2017 J08nY
+ */
+#ifndef ECGEN_POINT_H
+#define ECGEN_POINT_H
+
+#include <pari/pari.h>
+
+typedef struct point_t {
+ GEN point;
+ GEN order;
+} point_t;
+
+point_t *gerepile_point(pari_sp ltop, point_t *point);
+
+#endif //ECGEN_POINT_H
diff --git a/src/poly.h b/src/poly.h
index 2bb5c96..a0c1904 100644
--- a/src/poly.h
+++ b/src/poly.h
@@ -6,7 +6,7 @@
#define ECGEN_POLY_H
#include <stdbool.h>
-#include "gp.h"
+#include <pari/pari.h>
typedef struct polynomial {
int m;
@@ -45,4 +45,4 @@ GEN poly_find_gen(long m);
*/
GEN poly_gen(polynomial_t *polynomial);
-#endif //ECGEN_POLY_H
+#endif // ECGEN_POLY_H
diff --git a/src/random.c b/src/random.c
new file mode 100644
index 0000000..eaa1a7c
--- /dev/null
+++ b/src/random.c
@@ -0,0 +1,34 @@
+/*
+ * ecgen, tool for generating Elliptic curve domain parameters
+ * Copyright (C) 2017 J08nY
+ */
+#include "random.h"
+
+GEN random_prime(long bits) {
+ pari_sp ltop = avma;
+
+ GEN range = gtovec0(gen_0, 2);
+ gel(range, 1) = powis(gen_2, bits - 1);
+ gel(range, 2) = powis(gen_2, bits);
+
+ GEN p;
+ {
+ pari_sp btop = avma;
+ do {
+ p = randomprime(range);
+ if (gc_needed(btop, 1)) p = gerepilecopy(btop, p);
+ } while (!isprime(p));
+ }
+
+ return gerepilecopy(ltop, p);
+}
+
+GEN random_int(long bits) {
+ pari_sp ltop = avma;
+
+ GEN range = gtovec0(gen_0, 2);
+ gel(range, 1) = powis(gen_2, bits - 1);
+ gel(range, 2) = powis(gen_2, bits);
+
+ return gerepilecopy(ltop, genrand(range));
+} \ No newline at end of file
diff --git a/src/random.h b/src/random.h
new file mode 100644
index 0000000..9faa946
--- /dev/null
+++ b/src/random.h
@@ -0,0 +1,14 @@
+/*
+ * ecgen, tool for generating Elliptic curve domain parameters
+ * Copyright (C) 2017 J08nY
+ */
+#ifndef ECGEN_RANDOM_H
+#define ECGEN_RANDOM_H
+
+#include <pari/pari.h>
+
+GEN random_prime(long bits);
+
+GEN random_int(long bits);
+
+#endif // ECGEN_RANDOM_H