diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..669754923b366865fe2a5a864b9cec3de15818d4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+*.o
+*.exe
+bin/*
+.vscode/*
+.idea/*
+build/*
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f006d22e00219d067cce78178cad68b1bcf2b66e
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 3.5)
+project(ql_csdk C)
+
+set(CMAKE_C_STANDARD 11)
+
+include_directories(include)
+include_directories(include/base)
+include_directories(include/proto)
+include_directories(include/types)
+include_directories(test)
+
+add_executable(ql_csdk
+ demo/main.c
+ include/base/ecc.h
+ include/base/hash.h
+ include/base/json.h
+ include/base/keccak256.h
+ include/base/log.h
+ include/base/x509.h
+ include/base/md5.h
+ include/proto/account.h
+ include/proto/largefile.h
+ include/types/ql_error_type.h
+ include/types/ql_type.h
+ src/base/ecc.c
+ src/base/hash.c
+ src/base/json.c
+ src/base/keccak256.c
+ src/base/log.c
+ src/base/md5.c
+ src/base/x509.c
+ src/proto/account.c
+ src/proto/largefile.c
+)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..29f81d812f3e768fa89638d1f72920dbfd1413a8
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..bfdf9812ef79f93d10126b57b208de13954bc54b
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,86 @@
+CC = gcc
+CFLAGS = -g -O -Wall
+CFLAGS += -fprofile-arcs -ftest-coverage
+
+TOP_PATH = $(shell pwd)
+HEAD_PATH = $(TOP_PATH)/include
+SRC_PATH = $(TOP_PATH)/src
+OUT_PATH = $(TOP_PATH)/bin
+TEST_PATH = $(TOP_PATH)/test
+DEMO_PATH = $(TOP_PATH)/demo
+
+TARGET_TEST = $(OUT_PATH)/AllTest
+TARGET_MAIN = $(OUT_PATH)/main
+OBJS = $(OUT_PATH)/log.o $(OUT_PATH)/keccak256.o $(OUT_PATH)/ecc.o $(OUT_PATH)/hash.o $(OUT_PATH)/account.o $(OUT_PATH)/largefile.o $(OUT_PATH)/x509.o $(OUT_PATH)/json.o $(OUT_PATH)/md5.o
+OBJS_TEST = $(OBJS) $(OUT_PATH)/all_test.o $(OUT_PATH)/CuTest.o $(OUT_PATH)/x509_test.o $(OUT_PATH)/account_test.o $(OUT_PATH)/keccak256_test.o $(OUT_PATH)/ecc_test.o
+OBJS_MAIN = $(OBJS) $(OUT_PATH)/main.o
+
+CFLAGS += -I$(HEAD_PATH)/types/
+CFLAGS += -I$(HEAD_PATH)/base/
+CFLAGS += -I$(HEAD_PATH)/proto/
+
+$(TARGET_MAIN): $(OBJS_MAIN)
+ $(CC) $(CFLAGS) $^ -o $@
+
+$(TARGET_TEST): $(OBJS_TEST)
+ $(CC) $(CFLAGS) $^ -o $@
+
+# ------- demo -------
+$(OUT_PATH)/main.o: $(DEMO_PATH)/main.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+# ------- test-------
+$(OUT_PATH)/all_test.o: $(TEST_PATH)/all_test.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+$(OUT_PATH)/CuTest.o: $(TEST_PATH)/CuTest.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+$(OUT_PATH)/x509_test.o: $(TEST_PATH)/x509_test.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+$(OUT_PATH)/account_test.o: $(TEST_PATH)/account_test.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+$(OUT_PATH)/keccak256_test.o: $(TEST_PATH)/keccak256_test.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+$(OUT_PATH)/ecc_test.o: $(TEST_PATH)/ecc_test.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+# ------- base -------
+$(OUT_PATH)/log.o: $(SRC_PATH)/base/log.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+$(OUT_PATH)/keccak256.o: $(SRC_PATH)/base/keccak256.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+$(OUT_PATH)/ecc.o: $(SRC_PATH)/base/ecc.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+$(OUT_PATH)/hash.o: $(SRC_PATH)/base/hash.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+$(OUT_PATH)/x509.o: $(SRC_PATH)/base/x509.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+$(OUT_PATH)/json.o: $(SRC_PATH)/base/json.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+$(OUT_PATH)/md5.o: $(SRC_PATH)/base/md5.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+# ------- proto -------
+$(OUT_PATH)/account.o: $(SRC_PATH)/proto/account.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+$(OUT_PATH)/largefile.o: $(SRC_PATH)/proto/largefile.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+all: prepare $(TARGET_MAIN) $(TARGET_TEST)
+
+
+prepare:
+ mkdir -p $(OUT_PATH)
+
+clean:
+ rm -rf $(OUT_PATH)
diff --git a/README.en.md b/README.en.md
deleted file mode 100644
index cd6e641502fa0b87088bae427ba6c1864cf0878a..0000000000000000000000000000000000000000
--- a/README.en.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# security_block_chain
-
-#### Description
-{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
-
-#### Software Architecture
-Software architecture description
-
-#### Installation
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### Instructions
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### Contribution
-
-1. Fork the repository
-2. Create Feat_xxx branch
-3. Commit your code
-4. Create Pull Request
-
-
-#### Gitee Feature
-
-1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
-2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
-3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
-4. The most valuable open source project [GVP](https://gitee.com/gvp)
-5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
-6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
diff --git a/README.md b/README.md
index a3184234d20cf935008ab646e1f402286f41742d..df4f6c9a90255ef274195b5a3f17d50092b1a19b 100644
--- a/README.md
+++ b/README.md
@@ -1,39 +1,365 @@
-# security_block_chain
+# CSDK接口文档
+- [说明](#section10)
+ - [概述](#section11)
+ - [项目功能](#section12)
+ - [项目结构](#section13)
+ - [运行环境](#section14)
+- [接口说明](#section20)
+ - [日志打印回调函数](#section21)
+ - [日志时间回调函数](#section22)
+ - [日志静默函数](#section23)
+ - [日志等级函数](#section24)
+ - [时间戳回调函数](#section25)
+ - [使用x509证书初始化账户函数](#section26)
+ - [使用json初始化账户函数](#section27)
+ - [创建交易函数](#section28)
+ - [交易格式化为字符串函数](#section29)
+ - [创建大文件对象函数](#section210)
+ - [计算大文件md5散列值函数](#section211)
+ - [获取大文件md5散列值函数](#section212)
+ - [格式化大文件信息为字符串函数](#section213)
+ - [释放大文件对象函数](#section214)
-#### 介绍
-{**以下是 Gitee 平台说明,您可以替换此简介**
-Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
-无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
+---
+### 说明
+#### 概述
+本文档是Openharmony上链软件包的接口文档,旨在描述该软件包的使用说明、使用方式,为用户基于该软件包的应用开发提供说明。
+CSDK软件包在iot场景下提供了数据格式化和处理的功能,为设备数据上链提供了可能。该软件包采用回调函数方式定义、设置外部接口,支持椭圆曲线密码学算法,编程风格符合《C语言编程规范》,具有便于移植、调试方便、代码轻量化等特点。
+#### 项目功能
+ - 支持keccak256哈希运算。
+ - 支持secp256k1签名、验签、共享密钥,支持公钥恢复算法,支持rfc6979确定性随机数算法。
+ - 支持解析pem格式的X.509证书。
+ - 支持趣链jsonrpc接口,实现iot需要的extra存证接口。
-#### 软件架构
-软件架构说明
+#### 项目结构
-#### 安装教程
-1. xxxx
-2. xxxx
-3. xxxx
+项目主要包含以下内容:
+- bin:为.o文件、可执行文件、.gcda文件、.gcno文件、代码覆盖率报告等的输出目录。
+- demo:项目的demo文件目录。
+- test:项目各模块单测的目录,其中CuTest为一个轻量级的测试框架,其余文件为各模块的测试用例。
+- include:头文件目录。
+- src:源文件目录。
+其中,在二级目录中:
+- base:为基础模块的目录,ecc为计算secp256k1模块,hash为计算rfc6979的模块,keccak256为计算哈希的模块,log为日志模块,x509为解析pem证书的模块,该模块作为基础功能,通常仅会被proto文件夹下的模块调用,不会直接暴露给用户。
+- proto:为协议模块的目录,account为用户账户模块,该模块将直接暴露给用户调用,从而实现extra存证的功能。
+- types:为类型模块的目录,其中Oh_error_type定义了各模块的错误编码的定义,Oh_type定义了统一的数据类型格式,base目录和proto目录下的所有变量均采用该类型。types仅在include文件夹下存在。
+项目结构如下所示:
+```
+.
+├── CMakeLists.txt # CMake构建文件
+├── demo
+│ └── main.c # 示例程序
+├── include
+│ ├── base
+│ │ ├── ecc.h # ecc签名相关头文件
+│ │ ├── hash.h # rfc6979 hash计算头文件
+│ │ ├── json.h # cjson相关调用头文件
+│ │ ├── keccak256.h # keccak256 hash算法相关头文件
+│ │ ├── log.h # 日志打印相关头文件
+│ │ ├── md5.h # md5计算相关头文件
+│ │ └── x509.h # x509证书相关头文件
+│ ├── proto
+│ │ ├── account.h # 账户结构相关头文件
+│ │ └── largefile.h # 大文件传输相关头文件
+│ └── types
+│ ├── ql_error_type.h # 自定义错误类型
+│ └── ql_type.h # 自定义数据类型
+├── Makefile # Make构建文件
+├── README.md # 说明文档
+├── src
+│ ├── base
+│ │ ├── ecc.c # ecc签名相关实现
+│ │ ├── hash.c # rfc6979 hash计算相关实现
+│ │ ├── json.c # cjson相关调用实现
+│ │ ├── keccak256.c # keccak256 hash算法相关实现
+│ │ ├── log.c # 日志打印相关实现
+│ │ ├── md5.c # md5计算相关实现
+│ │ └── x509.c # x509证书相关实现
+│ └── proto
+│ ├── account.c # 账户操作相关实现
+│ └── largefile.c # 大文件传输相关实现
+└── test
+ ├── account_test.c # 账户操作相关测试
+ ├── all_test.c # 集成测试
+ ├── CuTest.c # CuTest基础测试实现
+ ├── CuTest.h # CuTest基础实现头文件
+ ├── ecc_test.c # ecc相关测试
+ ├── keccak256_test.c # keccak256相关测试
+ └── x509_test.c # x509相关测试
+```
-#### 使用说明
-1. xxxx
-2. xxxx
-3. xxxx
+#### 运行环境
+编译环境:gcc 3.0+(支持C99标准)
+运行环境:32位单片机裸机、Linux系统、FreeRTOS系统
-#### 参与贡献
+---
+### 接口说明
+#### 日志打印回调函数
-1. Fork 本仓库
-2. 新建 Feat_xxx 分支
-3. 提交代码
-4. 新建 Pull Request
+项目|内容
+:---:|:--:
+函数名称|SetPrintLogCallback
+功能描述|设置打印日志的回调函数
+参数|函数指针
+返回值|无
+备注|若不设置,则无法打印日志
-#### 特技
+示例:
+```
+void print_log_func(char *content){
+ printf("%s",content);
+}
-1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
-2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
-3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
-4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
-5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
-6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
+SetPrintLogCallback(print_log_func);
+```
+#### 日志时间回调函数
+
+项目|内容
+:---:|:--:
+函数名称|SetGetTimeCallback
+功能描述|设置日志打印时间的回调函数
+参数|函数指针
+返回值|无
+备注|若不设置,则日志时间无法正常显示
+
+
+示例:
+```
+void print_log_time(char * time_buf, int size){
+#if (defined(__unix)) || (defined(_WIN32) || defined(_WIN64))
+ time_t t = time(NULL);
+ struct tm* tp = localtime(&t);
+ time_buf[strftime(time_buf, size, "%H:%M:%S", tp)] = '\0';
+#else
+ time_buf[0] = '\0';
+#endif
+}
+
+SetGetTimeCallback(print_log_time);
+```
+
+#### 日志静默函数
+
+项目|内容
+:---:|:--:
+函数名称|LogSetQuiet
+功能描述|设置日志是否需要静默,即设置是否打印日志
+参数|LOG_QUIET_FALSE:不启用,即打印 LOG_QUIET_TRUE:启用,即不打印日志
+返回值|无
+备注|无
+
+
+示例:
+```
+LogSetQuiet(LOG_QUIET_FALSE);
+```
+
+#### 日志等级函数
+项目|内容
+:---:|:--:
+函数名称|LogSetLevel
+功能描述|设置日志打印的等级
+参数|LOG_DEBUG:调试等级 LOG_INFO:信息等级 LOG_WARN:警告等级 LOG_ERROR:错误等级
+返回值|无
+备注|无
+
+
+示例:
+```
+LogSetLevel(LOG_DEBUG);
+```
+#### 时间戳回调函数
+项目|内容
+:---:|:--:
+函数名称|AccountSetTimeFunc
+功能描述|设置时间戳获取函数函数指针
+参数|函数指针
+返回值|无
+备注|单位为ns,若错误设置或不设置,将直接导致数据无法上链。
+
+
+示例:
+```
+OhErrType native_get_time(OhInt64Type *dst) {
+ struct timeval t;
+ gettimeofday(&t,NULL);
+ *dst = (OhInt64Type)t.tv_sec * 1000000000 + (Oh_int64_t)t.tv_usec*1000; // ns
+ return ACCOUNT_SUCCESS;
+}
+
+AccountSetTimeFunc(native_get_time);
+```
+#### 使用x509证书初始化账户函数
+项目|内容
+:---:|:----------:
+函数名称|AccountInitX509
+功能描述|使用x509证书初始化账户
+参数|acc:AccountType*类型的账户对象 str: OhByteType*类型的私钥证书
+返回值|参见account.h文件内的错误宏定义
+备注|需要先声明一个AccountType类型的账户,之后再使用私钥证书初始化该账户。
+
+
+示例:
+```
+OhByteType priKey[] = "-----BEGIN EC PRIVATE KEY-----\n"
+"MHQCAQEEIAICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBoAcGBSuBBAAK\n"
+"oUQDQgAExUK0Fv9I2BvhZR8lVIwG0ZHPowy4GvUZEYMM8uASzJ/3/Xbd0VlMYHFg\n"
+ "qXkEMxUZJABjkW2PNh3vU4lzCsLXRA==\n"
+ "-----END EC PRIVATE KEY-----";
+AccountTpye myAccount;
+OhErrType res = AccountInitX509(&myAccount, priKey);
+```
+
+#### 使用json初始化账户函数
+项目|内容
+:---:|:-----:
+函数名称|AccountInitJson
+功能描述|使用json类型的账户数据初始化账户
+参数|acc:AccountType* 类型的账户对象 str: OhByteType* 类型的json账户数据
+返回值|参见account.h文件内的错误宏定义
+备注|需要先声明一个AccountType类型的账户,之后再初始化该账户。
+
+
+示例:
+```
+OhByteType acc_json[] =
+"{\"version\":\"4.0\",\"algo\":\"0x00\",\"privateKey\":\"0202020101010101010101010101010101010101010101010101010101010101\",\"publicKey\":\"04c542b416ff48d81be1651f25548c06d191cfa30cb81af51911830cf2e012cc9ff7fd76ddd1594c607160a97904331519240063916d8f361def5389730ac2d744\",\"address\":\"469339bdf3d3621bebea36c308de77939424e34e\"}";
+AccountType myAccount;
+OhErrType res = AccountInitJson(&myAccount, acc_json);
+```
+
+#### 创建交易函数
+项目|内容
+:---:|:-----:
+函数名称|TxSendNew
+功能描述|创建交易
+参数|tx:TxType* 类型,指向交易对象 acc:AccountType* 类型,指向账户对象 to:OhByteType* 类型,为交易的目的地址 val:OhInt32Type类型,为交易的val值,存证则设置为0 ex:OhByteType* 类型,为存证的信息,通常为json格式 exid:OhByteType* 类型,为extraid的信息,需要为带[]的字符串格式,中括号内的字符串可以用逗号隔开
+返回值|参见account.h文件内的错误宏定义
+备注|返回值直接通过http post请求发送至区块链,即可完成数据上链
+
+
+示例:
+```
+TxType tx;
+OhByteType ex[] = "{\"id\":\"0F384\",\"name\":\"tom\",\"class\":\"0808\"}";
+res = TxSendNew(&tx, &myAccount, myAccount.addr, 0, ex, (OhByteType *)"[\"123\"]");
+```
+
+#### 交易格式化为字符串函数
+项目|内容
+:---:|:-----:
+函数名称|TxPrint
+功能描述|将交易结构体格式化为字符串
+参数|tx:TxType* 类型,指向交易对象 fmtType:FORMAT_TYPE类型,为封装交易的类型,具体字段可参见宏定义 method: OhByteType* 类型,为交易的类型,具体字段可参见宏定义 outBuf:OhByteType* 类型,指向字符串的存储空间 outBufLen:字符串存储空间的长度
+返回值|参见account.h文件内的错误宏定义
+备注|若字符串存储空间的长度小于实际需要的长度,则格式化失败。
+
+
+示例:
+```
+OhByteType out[700];
+ res = TxPrint(&tx, ORIGIN_MSG, TX_TYPE_SENDTRANSACTION, out, 700);
+ if(res != ACCOUNT_SUCCESS) {
+ log_error("TxSendNew failed : %d", res);
+ }
+ else{
+ log_debug("ok");
+ }
+```
+#### 创建大文件对象函数
+项目|内容
+:---:|:-----:
+函数名称|FileInfoNew
+功能描述|新建大文件对象
+参数|f:LargefileType*类型,指向大文件对象 path:OhByteType*类型,文件路径 name:OhByteType*类型,上传大文件时使用的文件名 des:OhByteType*类型,上传大文件时使用的文件描述 node:OhByteType*类型,节点白名单,若为空,则为所有节点可见 user:OhByteType*类型,用户白名单,若为空,则为所有用户可见
+返回值|参见largefile.h文件内的错误宏定义
+备注|
+
+
+示例:
+```
+LargefileType f;
+
+OhByteType* file_name = (OhByteType*)"data.png";
+
+res = FileInfoNew(&f, file_name, (OhByteType*)"pic_upload_name.png", (OhByteType*)"des: test largefile", (OhByteType*)"", (OhByteType*)"");
+
+if(res != FILE_SUCCESS){
+ log_error("test_largefile failed : %d", res);
+ return res;
+}
+```
+#### 计算大文件md5散列值函数
+项目|内容
+:---:|:-----:
+函数名称|FileCalMd5
+功能描述|计算大文件md5散列值
+参数|f:LargefileType*类型,指向大文件对象
+返回值|参见largefile.h文件内的错误宏定义
+备注|该方法将打开f对象下path指向的文件
+
+
+示例:
+```
+res = FileCalMd5(&f);
+if(res != FILE_SUCCESS){
+ log_error("test_largefile failed : %d", res);
+ return res;
+}
+```
+#### 获取大文件md5散列值函数
+项目|内容
+:---:|:-----:
+函数名称|FileGetHash
+功能描述|将大文件md5散列值的结果导出到外部空间中
+参数|f:LargefileType*类型,指向大文件对象 buf:OhByteType*类型,指向存储空间 bufLen:存储空间的长度
+返回值|参见largefile.h文件内的错误宏定义
+备注|
+
+
+示例:
+```
+OhByteType hash[35];
+res = FileGetHash(&f, hash, 35);
+if(res != FILE_SUCCESS) {
+ log_error("TxSendNew failed : %d", res);
+ return res;
+}
+```
+#### 格式化大文件信息为字符串函数
+项目|内容
+:---:|:-----:
+函数名称|FileInfoFormat
+功能描述|将大文件信息格式化为extra json格式
+参数|f:LargefileType*类型,指向大文件对象 buf:OhByteType*类型,指向存储空间 bufLen:存储空间的长度
+返回值|参见largefile.h文件内的错误宏定义
+备注|
+
+
+示例:
+```
+OhByteType buf[400];
+res = FileInfoFormat(&f, buf, 400);
+if(res != FILE_SUCCESS){
+ log_error("test_largefile failed : %d", res);
+ return res;
+}
+```
+#### 释放大文件对象函数
+项目|内容
+:---:|:-----:
+函数名称|FileInfoFree
+功能描述|释放大文件对象
+参数|f:LargefileType*类型,指向大文件对象
+返回值|无
+备注|若不释放大文件对象,则可能会造成内存泄漏
+
+
+示例:
+```
+FileInfoFree(&f);
+```
\ No newline at end of file
diff --git a/demo/main.c b/demo/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..2f2b5a8b9b81b010110cc0f41030b89d2fc3c67a
--- /dev/null
+++ b/demo/main.c
@@ -0,0 +1,161 @@
+#include
+#include "log.h"
+#include "ql_type.h"
+#include "account.h"
+#include "largefile.h"
+// -----------------------
+// unix system
+// -----------------------
+#include
+#include
+
+void print_log_func(char *content){
+ printf("%s",content);
+}
+
+void print_log_time(char * time_buf, int size){
+#if (defined(__unix)) || (defined(_WIN32) || defined(_WIN64))
+ time_t t = time(NULL);
+ struct tm* tp = localtime(&t);
+ time_buf[strftime(time_buf, size, "%H:%M:%S", tp)] = '\0';
+#else
+ time_buf[0] = '\0';
+#endif
+}
+
+OhErrType native_get_time(OhInt64Type *dst) {
+ struct timeval t;
+ gettimeofday(&t,NULL);
+ *dst = (OhInt64Type)t.tv_sec * 1000000000 + (OhInt64Type)t.tv_usec*1000; // ns
+ return ACCOUNT_SUCCESS;
+}
+
+int test_sign(){
+ struct timeval start, end;
+
+// OhByteType acc_json[] = "{\"version\":\"4.0\",\"algo\":\"0x03\",\"privateKey\":\"0202020101010101010101010101010101010101010101010101010101010101\",\"publicKey\":\"04c542b416ff48d81be1651f25548c06d191cfa30cb81af51911830cf2e012cc9ff7fd76ddd1594c607160a97904331519240063916d8f361def5389730ac2d744\",\"address\":\"469339bdf3d3621bebea36c308de77939424e34e\"}";
+ OhByteType acc_json[] = "{\"address\":\"8399b2b7e104cebb8b8938a2c79e26cb4733b0b5\",\"algo\":\"0x03\",\"version\":\"4.0\",\"publicKey\":\"049c660da3c16fd0df820b747d82344916db69d7553d2456323c820f1b1f4f225986d1f16cde06d99d94aa8998f0a14b6aeca21d7cad7670516cc911e4b035f9e5\",\"privateKey\":\"8747be107feb7959f4e8c8936a31aac5ffd4ed4d62d0e9edee2854531e62ea5e\"}";
+ log_debug("----account test----");
+ //create account
+ AccountType my_account;
+ OhErrType res = AccountInitJson(&my_account, acc_json);
+ if(res != ACCOUNT_SUCCESS) {
+ log_error("account_new failed : %d", res);
+ return res;
+ }
+ // create tx
+ gettimeofday(&start,NULL);
+ TxType tx;
+ OhByteType ex[] = "{\"id\":\"0F384\",\"name\":\"tom\",\"class\":\"0808\"}";
+ res = TxSendNew(&tx, &my_account, my_account.addr, 0, ex, (OhByteType *)"[\"12345\",\"54321\"]");
+ if(res != ACCOUNT_SUCCESS) {
+ log_error("TxSendNew failed : %d", res);
+ return res;
+ }
+ log_debug("=================================================================================");
+ OhByteType out[1024];
+ res = TxPrint(&tx, ADD_CURL_BODY,TX_TYPE_SENDTRANSACTION, out, 1024);
+ if(res != ACCOUNT_SUCCESS) {
+ log_error("TxSendNew failed : %d", res);
+ return res;
+ }
+ log_info("%s",out);
+ log_debug("=======COPY==THE==ABOVE==COMMAND==TO==THE==COMMAND==LINE==AND==EXECUTE==IT=======");
+ gettimeofday(&end,NULL);
+ log_debug("demo run time is %ldus",(end.tv_sec-start.tv_sec)*1000000+(end.tv_usec-start.tv_usec));
+
+ return 0;
+}
+
+int test_largefile(){
+ // create account
+ OhByteType priKey[] = "-----BEGIN EC PRIVATE KEY-----\n"
+ "MHQCAQEEIAICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBoAcGBSuBBAAK\n"
+ "oUQDQgAExUK0Fv9I2BvhZR8lVIwG0ZHPowy4GvUZEYMM8uASzJ/3/Xbd0VlMYHFg\n"
+ "qXkEMxUZJABjkW2PNh3vU4lzCsLXRA==\n"
+ "-----END EC PRIVATE KEY-----";
+ AccountType my_account;
+ OhErrType res = AccountInitX509(&my_account, priKey);
+ if(res != ACCOUNT_SUCCESS) {
+ log_error("test_account_x509 failed : %d", res);
+ return res;
+ }
+ // create large file
+ LargefileType f;
+ OhByteType* file_name = (OhByteType*)"../data.png";
+ res = FileInfoNew(&f, file_name, (OhByteType*)"pic_upload_name.png", (OhByteType*)"des: test largefile", (OhByteType*)"", (OhByteType*)"");
+ if(res != FILE_SUCCESS){
+ log_error("test_largefile failed : %d", res);
+ FileInfoFree(&f);
+ return res;
+ }
+ res = FileCalMd5(&f);
+ if(res != FILE_SUCCESS){
+ log_error("test_largefile failed : %d", res);
+ FileInfoFree(&f);
+ return res;
+ }
+ OhByteType buf[400];
+ res = FileInfoFormat(&f, buf, 400);
+ if(res != FILE_SUCCESS){
+ log_error("test_largefile failed : %d", res);
+ FileInfoFree(&f);
+ return res;
+ }
+ OhByteType hash[35];
+ res = FileGetHash(&f, hash, 35);
+ if(res != FILE_SUCCESS) {
+ log_error("TxSendNew failed : %d", res);
+ FileInfoFree(&f);
+ return res;
+ }
+ FileInfoFree(&f);
+ // create extraid
+ OhByteType extraid[100];
+ memset(extraid,0,sizeof(extraid));
+ strcat((char*)extraid, "[");
+ strcat((char*)extraid, (char*)hash); // add hash
+ strcat((char*)extraid, ",");
+ strcat((char*)extraid, (char*)"\"13579\""); // add other extraid
+ strcat((char*)extraid, "]");
+ // create tx
+ TxType tx;
+ res = TxSendNew(&tx, &my_account, my_account.addr, 0, buf, extraid);
+ if(res != ACCOUNT_SUCCESS) {
+ log_error("TxSendNew failed : %d", res);
+ return res;
+ }
+ OhByteType out[1100];
+ log_debug("=============================== UPLOAD FILE =====================================");
+ memset(out, 0, sizeof(out));
+ res = TxPrint(&tx, ORIGIN_MSG,TX_TYPE_UPLOAD, out, 1100);
+ if(res != ACCOUNT_SUCCESS) {
+ log_error("TxSendNew failed : %d", res);
+ return res;
+ }
+ log_info("curl -H 'type: upload' -H 'params: %s' --data-binary @%s -H \"Content-Type: application/octet-stream\" -H \"Expect: \" 8.136.20.47:8081",out,file_name);
+ log_debug("============================== DOWNLOAD FILE =====================================");
+ memset(out, 0, sizeof(out));
+ res = TxPrint(&tx, ORIGIN_MSG,TX_TYPE_DOWNLOAD, out, 1100);
+ if(res != ACCOUNT_SUCCESS) {
+ log_error("TxSendNew failed : %d", res);
+ return res;
+ }
+ log_info("curl -H 'type: download' -H 'params: %s' 8.136.20.47:8081 -o download.png",out);
+ log_debug("=================================================================================");
+ return 0;
+}
+
+int main(){
+
+ SetPrintLogCallback(print_log_func);
+ SetGetTimeCallback(print_log_time);
+ LogSetQuiet(LOG_QUIET_FALSE);
+ LogSetLevel(LOG_DEBUG);
+ AccountSetTimeFunc(native_get_time);
+
+ test_sign();
+ test_largefile();
+
+ return 0;
+}
\ No newline at end of file
diff --git a/include/base/ecc.h b/include/base/ecc.h
new file mode 100644
index 0000000000000000000000000000000000000000..ad4ffa6497d86d29d1eb27b8544b233073cca728
--- /dev/null
+++ b/include/base/ecc.h
@@ -0,0 +1,91 @@
+/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
+
+#ifndef _MICRO_ECC_H_
+#define _MICRO_ECC_H_
+
+#include "log.h"
+#include "hash.h"
+#include "ql_error_type.h"
+#include "ql_type.h"
+
+// secp256k1 byte length, [DO NOT MODIFY!]
+#define uECC_BYTES 32
+// ----------------------------------------------
+// Platform selection options.
+// If uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros.
+// ----------------------------------------------
+#define uECC_arch_other 0
+#define uECC_x86 1
+#define uECC_x86_64 2
+#define uECC_arm 3
+#define uECC_arm_thumb 4
+#define uECC_avr 5
+#define uECC_arm_thumb2 6
+
+// ----------------------------------------------
+// Inline assembly options.
+// ----------------------------------------------
+#define uECC_asm_none 0 // Use standard C99 only
+#define uECC_asm_small 1 // Use GCC inline assembly for the target platform (if available), optimized for minimum size
+#define uECC_asm_fast 2 // Use GCC inline assembly optimized for maximum speed
+#ifndef uECC_ASM
+#define uECC_ASM uECC_asm_fast
+#endif
+
+// ----------------------------------------------
+// If desired, you can define uECC_WORD_SIZE as appropriate for your platform (4, or 8 bytes).
+// If desired, you can define uECC_SUPPORTS_INT128 to indicate whether to use 128-bit variables.
+// If uECC_WORD_SIZE and uECC_SUPPORTS_INT128 is not explicitly defined then it will be automatically set based on your platform.
+// ----------------------------------------------
+// #define uECC_WORD_SIZE 4
+// #define uECC_SUPPORTS_INT128 0
+
+// ----------------------------------------------
+// Error type definition
+// ----------------------------------------------
+#define ECC_SUCCESS (ERR_ECC_BASE + 0) // Success
+#define ECC_ERR_PUB_EQUAL_ZERO -(ERR_ECC_BASE + 1) // Public key number is 0
+#define ECC_ERR_PRI_EQUAL_ZERO -(ERR_ECC_BASE + 2) // Private key number is 0
+#define ECC_ERR_RNG_UNSUITABLE -(ERR_ECC_BASE + 3) // Inappropriate random number
+#define ECC_ERR_RNG_EQUAL_ZERO -(ERR_ECC_BASE + 4) // Random number is 0
+#define ECC_ERR_RNG_NOT_GENERATE -(ERR_ECC_BASE + 5) // Unable to generate random number
+#define ECC_ERR_SIG_EQUAL_ZERO -(ERR_ECC_BASE + 6) // The signature contains 0 (r=0 or s=0)
+#define ECC_ERR_SIG_BIGGER_N -(ERR_ECC_BASE + 7) // Inappropriate signature (r>n or s>n)
+#define ECC_ERR_SHAREKEY_EQUAL_ZERO -(ERR_ECC_BASE + 8) // Shared key number is 0
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*
+ The RNG function should fill p_size random bytes into p_dest. The filled-in values should be either truly random, or from a cryptographically-secure PRNG.
+ A correctly functioning RNG function must be set (using uECC_set_rng()) before calling uECC_make_key() or uECC_shared_secret().
+ It should return value >= 0 if p_dest was filled with random data,
+ or value < 0 if the random data could not be generated.
+ */
+typedef OhErrType (*uECC_RNG_Function)(OhUint8Type *p_dest, OhInt32Type p_size);
+
+/*
+ Set the function that will be used to generate random bytes.
+ */
+OhVoidType uECC_set_rng(uECC_RNG_Function p_rng);
+
+/*
+Generate an signature for a given hash value.
+Inputs:
+ p_privateKey - Your private key.
+ p_hash - The message hash to sign.
+Outputs:
+ p_signature - Will be filled in with the signature value.
+ Returns value >= 0 if the signature generated successfully, value < 0 if an error occurred.
+*/
+OhErrType uECC_sign(const OhUint8Type p_privateKey[uECC_BYTES], const OhUint8Type p_hash[uECC_BYTES], OhUint8Type p_signature[uECC_BYTES*2+1]);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/base/hash.h b/include/base/hash.h
new file mode 100644
index 0000000000000000000000000000000000000000..d9a74909a9794a7cb97e09e168c8b812d1915dc9
--- /dev/null
+++ b/include/base/hash.h
@@ -0,0 +1,52 @@
+/**********************************************************************
+ * Copyright (c) 2014 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+
+#ifndef _SECP256K1_HASH_
+#define _SECP256K1_HASH_
+
+#include
+#include "ql_type.h"
+
+// -----------------------
+// sha256 definition
+// -----------------------
+typedef struct {
+ OhUint32Type s[32];
+ OhUint32Type buf[16]; /* In big endian */
+ OhSizeType bytes;
+} ql_sha256_t;
+
+OhVoidType sha256_init (ql_sha256_t* hash);
+OhVoidType sha256_write(ql_sha256_t* hash, const OhByteType* data, OhSizeType len);
+OhVoidType sha256_final(ql_sha256_t* hash, OhByteType* out32);
+
+// -----------------------
+// hmac definition
+// -----------------------
+typedef struct {
+ ql_sha256_t inner, outer;
+} ql_hmac_t;
+
+OhVoidType hmac_init (ql_hmac_t* hash, const OhByteType* key , OhSizeType keylen);
+OhVoidType hmac_write(ql_hmac_t* hash, const OhByteType* data, OhSizeType size);
+OhVoidType hmac_final(ql_hmac_t* hash, OhByteType* out32);
+
+// -----------------------
+// rfc6979 definition
+// -----------------------
+typedef struct {
+ OhByteType v[32];
+ OhByteType k[32];
+ OhSizeType retry;
+} ql_rfc6979_t;
+
+OhVoidType rfc6979_init (ql_rfc6979_t* rng, const OhByteType* key, OhSizeType keylen);
+OhVoidType rfc6979_gen (ql_rfc6979_t* rng, OhByteType* out, OhSizeType outlen);
+OhVoidType rfc6979_final(ql_rfc6979_t* rng);
+OhVoidType rfc6979_nonce(OhByteType* nonce32, const OhByteType* msg32, const OhByteType* key32, const OhByteType* algo16, OhVoidType *data, OhSizeType counter);
+
+#endif
diff --git a/include/base/json.h b/include/base/json.h
new file mode 100644
index 0000000000000000000000000000000000000000..1861bf1d9a2bd6944fba6a266a8b24478dacd2a0
--- /dev/null
+++ b/include/base/json.h
@@ -0,0 +1,147 @@
+/*
+ Copyright (c) 2009 Dave Gamble
+
+ 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 _C_JSON_H_
+#define _C_JSON_H_
+
+#include
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* cJSON Types: */
+#define cJSON_False 0
+#define cJSON_True 1
+#define cJSON_NULL 2
+#define cJSON_Number 3
+#define cJSON_String 4
+#define cJSON_Array 5
+#define cJSON_Object 6
+
+#define cJSON_IsReference 256
+#define cJSON_StringIsConst 512
+
+/* The cJSON structure: */
+typedef struct cJSON {
+ struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+ struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
+ int type; /* The type of the item, as above. */
+ char *valueString; /* The item's string, if type==cJSON_String */
+ int valueint; /* The item's number, if type==cJSON_Number */
+ double valuedouble; /* The item's number, if type==cJSON_Number */
+ char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+} cJSON;
+
+typedef struct cJSON_Hooks {
+ void *(*malloc_fn)(size_t sz);
+ void (*free_fn)(void *ptr);
+} cJSON_Hooks;
+
+/* Supply malloc, realloc and free functions to cJSON */
+extern void cJSON_InitHooks(cJSON_Hooks* hooks);
+
+
+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
+extern cJSON *cJSON_Parse(const char *value);
+/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
+extern char *cJSON_Print(cJSON *item);
+/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
+extern char *cJSON_PrintUnformatted(cJSON *item);
+/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
+extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
+/* Delete a cJSON entity and all subentities. */
+extern void cJSON_Delete(cJSON *c);
+
+/* Returns the number of items in an array (or object). */
+extern int cJSON_GetArraySize(cJSON *array);
+/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
+extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
+/* Get item "string" from object. Case insensitive. */
+extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
+
+/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
+extern const char *cJSON_GetErrorPtr(void);
+
+/* These calls create a cJSON item of the appropriate type. */
+extern cJSON *cJSON_CreateNull(void);
+extern cJSON *cJSON_CreateTrue(void);
+extern cJSON *cJSON_CreateFalse(void);
+extern cJSON *cJSON_CreateBool(int b);
+extern cJSON *cJSON_CreateNumber(double num);
+extern cJSON *cJSON_CreateString(const char *string);
+extern cJSON *cJSON_CreateArray(void);
+extern cJSON *cJSON_CreateObject(void);
+
+/* These utilities create an Array of count items. */
+extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
+extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
+extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
+extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
+
+/* Append item to the specified array/object. */
+extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
+extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
+extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
+/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
+extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
+
+/* Remove/Detatch items from Arrays/Objects. */
+extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
+extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
+extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
+extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
+
+/* Update array items. */
+extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */
+extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
+extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
+
+/* Duplicate a cJSON item */
+extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
+/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
+need to be released. With recurse!=0, it will duplicate any children connected to the item.
+The item->next and ->prev pointers are always zero on return from Duplicate. */
+
+/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
+extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
+
+extern void cJSON_Minify(char *json);
+
+/* Macros for creating things quickly. */
+#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
+#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
+#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
+#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
+#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
+#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
+
+/* When assigning an integer value, it needs to be propagated to valuedouble too. */
+#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
+#define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/base/keccak256.h b/include/base/keccak256.h
new file mode 100644
index 0000000000000000000000000000000000000000..23d5b165c17d0a20cc920535f2b0332f314e836d
--- /dev/null
+++ b/include/base/keccak256.h
@@ -0,0 +1,46 @@
+/* sha3 - an implementation of Secure Hash Algorithm 3 (Keccak).
+ * based on the
+ * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011
+ * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche
+ *
+ * Copyright: 2013 Aleksey Kravchenko
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
+ */
+
+#ifndef __KECCAK256_H_
+#define __KECCAK256_H_
+
+#include
+#include "ql_type.h"
+#include "log.h"
+
+// Maximum parameters defined by SHA3, [DO NOT MODIFY!]
+#define SHA3_MAX_PERMUTATION_SIZE 25
+#define SHA3_MAX_RATE_IN_QWORDS 24
+
+/*
+Method used to calculate keccak256.
+inputs:
+ msg - Data used to calculate.
+ size - Data length.
+output:
+ hashbuf - Calculation results.
+ */
+OhVoidType keccak256(const OhByteType *msg, OhUint32Type size, OhByteType **hashbuf);
+
+/*
+Print the result of keccak. convert the hex data to string data.
+ */
+OhVoidType print_keccak_data(OhByteType *out);
+
+#endif
diff --git a/include/base/log.h b/include/base/log.h
new file mode 100644
index 0000000000000000000000000000000000000000..f8905c909152492dbec897623bc7cea6b4845fac
--- /dev/null
+++ b/include/base/log.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#include
+#include
+#include
+#include
+#include "ql_type.h"
+
+// Maximum length of log content
+#define LOG_MAX_SIZE 1024
+
+// Enumerate log types
+typedef enum {
+ LOG_DEBUG,
+ LOG_INFO,
+ LOG_WARN,
+ LOG_ERROR
+} OhLongLevel;
+
+// Define log silent state
+#define LOG_QUIET_TRUE 1
+#define LOG_QUIET_FALSE 0
+
+// Callback function of and
+typedef void (*PrintLogCallback)(char *content);
+typedef void (*GetTimeCallback)(char *time, int size);
+
+// The definition of the Logs method, used to format the output content
+OhVoidType Logs(OhLongLevel level, const char *file, int line, const char *fmt, ...);
+
+// -----------------------
+// User Function
+// -----------------------
+// If you don’t need to use colors or titles, cancel the following definitions
+#define LOG_USE_COLOR
+#define LOG_USE_TITLE
+
+// Methods for printing Logs of different levels
+#define log_debug(...) Logs(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
+#define log_info(...) Logs(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__)
+#define log_warn(...) Logs(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__)
+#define log_error(...) Logs(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
+
+// Set the lowest printing level
+OhVoidType LogSetLevel(OhLongLevel level);
+// Set whether silent mode is required
+OhVoidType LogSetQuiet(OhBoolType enable);
+// Set the callback function for printing
+OhVoidType SetPrintLogCallback(PrintLogCallback callback);
+// Set the callback function for getting time
+OhVoidType SetGetTimeCallback(GetTimeCallback callback);
+
+#endif
diff --git a/include/base/md5.h b/include/base/md5.h
new file mode 100644
index 0000000000000000000000000000000000000000..2c2b21a44c24969514492ab8b748651fbf0f4e30
--- /dev/null
+++ b/include/base/md5.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef _MD5_H_
+#define _MD5_H_
+
+#include "ql_type.h"
+#include
+
+// -----------------------
+// The MD5 structure
+// -----------------------
+typedef struct
+{
+ OhUint32Type count[2];
+ OhUint32Type state[4];
+ OhByteType buffer[64];
+}MD5_CTX;
+
+// -----------------------
+// Internal function
+// -----------------------
+OhVoidType MD5Transform(OhUint32Type state[4],OhByteType block[64]);
+OhVoidType MD5Encode(OhByteType *output,OhUint32Type *input,OhUint32Type len);
+OhVoidType MD5Decode(OhUint32Type *output,OhByteType *input,OhUint32Type len);
+
+// -----------------------
+// External function
+// -----------------------
+/*
+Initialize MD5 object
+Inputs:
+ context - MD5 object.
+*/
+OhVoidType MD5Init(MD5_CTX *context);
+
+/*
+Hash the message, long messages can be called continuously
+Inputs:
+ context - MD5 object.
+ input - message.
+ inputlen - message length.
+*/
+OhVoidType MD5Update(MD5_CTX *context,OhByteType *input,OhUint32Type inputlen);
+
+
+/*
+Filling and calculation of the last packet, and output the calculation result
+Inputs:
+ context - MD5 object.
+Outputs:
+ digest - MD5 result.
+*/
+OhVoidType MD5Final(MD5_CTX *context,OhByteType digest[16]);
+
+
+#endif
diff --git a/include/base/x509.h b/include/base/x509.h
new file mode 100644
index 0000000000000000000000000000000000000000..51572282632e6b89a77d70b28de2b99a059c56f7
--- /dev/null
+++ b/include/base/x509.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _X509_H_
+#define _X509_H_
+
+#include
+#include
+#include "ql_error_type.h"
+#include "ql_type.h"
+#include "log.h"
+
+// ----------------------------------------------
+// Error type definition
+// ----------------------------------------------
+#define X509_SUCCESS (ERR_X509_BASE + 0)
+#define X509_ERR_BASE64_INVALID_CHAR -(ERR_X509_BASE + 1)
+#define X509_ERR_BASE64_BUF_TOO_SMALL -(ERR_X509_BASE + 2)
+#define X509_ERR_PARSE_NO_FIND_SYMBAL -(ERR_X509_BASE + 3)
+#define X509_ERR_PARSE_CURVE_MISMATCH -(ERR_X509_BASE + 4)
+#define X509_ERR_PARSE_INVALID_PARAM -(ERR_X509_BASE + 5)
+
+// ----------------------------------------------
+// type definition
+// ----------------------------------------------
+// -- x509 item data structure --
+typedef struct {
+ OhByteType* title;
+ OhSizeType type;
+ OhSizeType len;
+ OhByteType* data;
+} X509ItemType;
+// -- key data structure --
+typedef struct {
+ X509ItemType version;
+ X509ItemType privateKey;
+ X509ItemType keyType;
+ X509ItemType publicKey;
+} X509KeyType;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*
+Init the key object.
+Inputs:
+key - Object storing the key.
+*/
+OhVoidType KeyInit(X509KeyType* key);
+
+/*
+Parse the key string.
+Inputs:
+ srcData - key data, string format.
+Outputs:
+ dstKey - Parse private key info.
+ If the parsing is successful, it returns X509_SUCCESS, otherwise return an error value
+ */
+OhErrType KeyParse(X509KeyType* dstKey, OhByteType* srcData);
+
+/*
+Free the memory occupied by the key.
+Inputs:
+ key - Object storing the key.
+ */
+OhVoidType KeyFree(X509KeyType* key);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/proto/account.h b/include/proto/account.h
new file mode 100644
index 0000000000000000000000000000000000000000..3aa598f84615e90bde37a4c34813bc1eb131e5a2
--- /dev/null
+++ b/include/proto/account.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ACCOUNT_H_
+#define _ACCOUNT_H_
+
+#include
+#include "ql_type.h"
+#include "log.h"
+#include "x509.h"
+#include "keccak256.h"
+#include "ecc.h"
+#include "json.h"
+#include "ql_error_type.h"
+#include "math.h"
+// [1k] space is allocated here to cache the original transaction information, which will be used to
+// calculate the keccak hash. If the space is not enough, please make changes according to actual needs
+#define MAX_BUF_SPACE_SIZE 1024
+
+// ----------------------------------------------
+// Error type definition
+// ----------------------------------------------
+#define ACCOUNT_SUCCESS (ERR_ACCOUNT_BASE + 0) // Success
+#define ACCOUNT_ERR_PARAM_INVAILD -(ERR_ACCOUNT_BASE + 1) // Invalid argument
+#define ACCOUNT_ERR_CALLOC_MEMORY -(ERR_ACCOUNT_BASE + 2) // Failed to apply for memory
+#define ACCOUNT_ERR_GETTIME_FUNC -(ERR_ACCOUNT_BASE + 3) // Get the timesTamp method error
+#define ACCOUNT_ERR_OVER_MAX_SIZE -(ERR_ACCOUNT_BASE + 4) // Space > MAX_BUF_SPACE_SIZE
+#define ACCOUNT_ERR_BUF_TOO_SMALL -(ERR_ACCOUNT_BASE + 5) // Too little space
+#define ACCOUNT_ERR_VER_UNMATCH -(ERR_ACCOUNT_BASE + 6) // Incompatible version
+#define ACCOUNT_ERR_ALGO_UNMATCH -(ERR_ACCOUNT_BASE + 7) // Incompatible algo
+#define ACCOUNT_ERR_PRIKEY_UNMATCH -(ERR_ACCOUNT_BASE + 8) // Incompatible priKey
+#define ACCOUNT_ERR_PUBKEY_UNMATCH -(ERR_ACCOUNT_BASE + 9) // Incompatible pubKey
+#define ACCOUNT_ERR_ADDR_UNMATCH -(ERR_ACCOUNT_BASE + 10) // Incompatible address
+// ----------------------------------------------
+// tx type definition
+// ----------------------------------------------
+#define TX_TYPE_SENDTRANSACTION (OhByteType*)("tx_sendTransaction")
+#define TX_TYPE_UPLOAD (OhByteType*)("fm_upload")
+#define TX_TYPE_DOWNLOAD (OhByteType*)("fm_download")
+// ----------------------------------------------
+// format message type
+// ----------------------------------------------
+typedef enum FormatType{
+ ORIGIN_MSG, // do not encapsulate message
+ ADD_HTTP_BODY, // add ORIGIN_MSG to the http body
+ ADD_CURL_BODY, // add ORIGIN_MSG to the curl body
+} FormatType;
+// ----------------------------------------------
+// type definition
+// ----------------------------------------------
+// -- account data structure --
+typedef struct {
+ OhByteType priKey[32]; // private key, hex format.
+ OhByteType pubKey[65]; // public key, hex format.
+ OhByteType addr[43]; // address, string format.
+} AccountType;
+// -- tx data structure --
+typedef struct {
+ OhByteType from[43]; // string format.
+ OhByteType to[43]; // string format.
+ OhInt32Type value; // int format.
+ OhByteType signature[133]; // string format.
+ OhInt64Type timesTamp; // int format.
+ OhByteType simulate[6]; // string format.
+ OhInt64Type nonce; // int format.
+ OhByteType type[4]; // string format.
+ OhByteType* extra;
+ OhByteType* extraid;
+} TxType;
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*
+ GetTime function should fill the timesTamp into p_dest, the unit is ns.
+ It should return ACCOUNT_SUCCESS if p_dest was filled.
+*/
+typedef OhErrType (*AccountGetTimeFunction)(OhInt64Type* p_dest);
+
+/*
+ Set the function that will be used to generate timesTamp.
+ */
+OhVoidType AccountSetTimeFunc(AccountGetTimeFunction p_t);
+
+/*
+ Initialize account by x509 certificate.
+ Inputs:
+ str - Private key certificate. string format.
+ Outputs:
+ acc - Account object.
+ */
+OhErrType AccountInitX509(AccountType* acc, OhByteType* str);
+
+/*
+ Initialize account by json account.
+ Inputs:
+ str - json account. string format.
+ Outputs:
+ acc - Account object.
+ */
+OhErrType AccountInitJson(AccountType* acc, OhByteType* str);
+
+/*
+ Initialize the transfer transaction.
+ Inputs:
+ acc - The account that issued this transaction.
+ to - The destination address of the transaction. string format.
+ val - Transfer amount.
+ ex - Deposit information.
+ Outputs:
+ tx - Transaction object.
+ */
+OhErrType TxSendNew(TxType* tx, AccountType* acc, OhByteType* to, OhInt32Type val, OhByteType* ex, OhByteType* exid);
+
+/*
+ Format the transaction to [buf]
+ Inputs:
+ tx - Transaction object.
+ fmtType - encapsulate message type
+ method - Transaction type.
+ outBufLen - Buffer size.
+ Outputs:
+ outBuf - Format string buffer.
+ */
+OhErrType TxPrint(TxType* tx, FormatType fmtType, OhByteType* method, OhByteType* outBuf, OhSizeType outBufLen);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/proto/largefile.h b/include/proto/largefile.h
new file mode 100644
index 0000000000000000000000000000000000000000..321e9d80aed78f46ff403f0962add87dfda934f1
--- /dev/null
+++ b/include/proto/largefile.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LARGEFILE_H_
+#define _LARGEFILE_H_
+
+#include "ql_type.h"
+#include "log.h"
+#include "ql_error_type.h"
+#include "md5.h"
+
+// ----------------------------------------------
+// Error type definition
+// ----------------------------------------------
+#define FILE_SUCCESS (ERR_LARGEFILE_BASE + 0) // Success
+#define FILE_ERR_CALLOC_MEMORY -(ERR_LARGEFILE_BASE + 1) // Failed to apply for memory
+#define FILE_ERR_NOT_EXIST -(ERR_LARGEFILE_BASE + 2) // Failed to open file
+#define FILE_ERR_PARAM_INVAILD -(ERR_LARGEFILE_BASE + 3) // Invalid argument
+#define FILE_ERR_BUF_TOO_SMALL -(ERR_LARGEFILE_BASE + 4) // Too little space
+
+// ----------------------------------------------
+// type definition
+// ----------------------------------------------
+// -- large file structure --
+typedef struct {
+ OhByteType *path;
+ OhByteType hash[33]; // file hash, string format
+ OhByteType *name; // file name, string format
+ OhSizeType size; // file size
+ OhByteType *node; // node list
+ OhByteType *user; // user list
+ OhByteType *des; // file description, string format
+} LargefileType;
+
+/*
+ Create file object.
+ Inputs:
+ path - file path. Need to be accurate to the file name.
+ name - The name used when uploading the file.
+ des - The description used when uploading the file.
+ node - Node whitelist, if it is empty, all nodes are visible
+ user - User whitelist, if it is empty, it will be visible to all users
+ Outputs:
+ f - file object.
+ */
+OhErrType FileInfoNew(LargefileType* f, OhByteType *path, OhByteType *name, OhByteType *des, OhByteType *node, OhByteType *user);
+
+/*
+ Calculate file MD5 result. This method will open the file under
+ Inputs:
+ f - file object.
+ */
+OhErrType FileCalMd5(LargefileType* f);
+
+/*
+ Save the file hash result to .
+ If is less than the required length, it cannot be saved.
+ Inputs:
+ f - file object.
+ bufLen - The length of buf.
+ Outputs:
+ buf - Storage buffer.
+ */
+OhErrType FileGetHash(LargefileType* f, OhByteType* buf, OhSizeType bufLen);
+
+/*
+ Format file information into extra string format.
+ Inputs:
+ f - file object.
+ bufLen - The length of buf.
+ Outputs:
+ buf - Storage buffer.
+ */
+OhErrType FileInfoFormat(LargefileType* f, OhByteType* buf, OhSizeType bufLen);
+
+/*
+ Free file object.
+ Inputs:
+ f - file object.
+ */
+OhVoidType FileInfoFree(LargefileType* f);
+
+#endif
diff --git a/include/types/ql_error_type.h b/include/types/ql_error_type.h
new file mode 100644
index 0000000000000000000000000000000000000000..da9ff4a0b8e014f6336744b6937d8d93fd441f87
--- /dev/null
+++ b/include/types/ql_error_type.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _QL_ERROR_TYPE_H_
+#define _QL_ERROR_TYPE_H_
+
+
+// Wrong definition:
+// negative value = error, positive value = success
+// BYTE 2~3 - (backup)
+// BYTE 1 - Module
+// BYTE 0 - Error reason
+#define ERR_ECC_BASE (1 << 8)
+#define ERR_X509_BASE (2 << 8)
+#define ERR_ACCOUNT_BASE (3 << 8)
+#define ERR_LARGEFILE_BASE (4 << 8)
+
+#endif
diff --git a/include/types/ql_type.h b/include/types/ql_type.h
new file mode 100644
index 0000000000000000000000000000000000000000..ef32e7ed02d6e3e038a95f75e07092ad994dd7d1
--- /dev/null
+++ b/include/types/ql_type.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _QL_TYPE_H_
+#define _QL_TYPE_H_
+
+/* cSDK basic data type definitions */
+typedef signed char OhInt8Type; /**< 8bit integer type */
+typedef signed short OhInt16Type; /**< 16bit integer type */
+typedef signed int OhInt32Type; /**< 32bit integer type */
+typedef signed long long OhInt64Type; /**< 64bit integer type */
+typedef unsigned char OhUint8Type; /**< 8bit unsigned integer type */
+typedef unsigned short OhUint16Type; /**< 16bit unsigned integer type */
+typedef unsigned int OhUint32Type; /**< 32bit unsigned integer type */
+typedef unsigned long long OhUint64Type; /**< 64bit unsigned integer type */
+
+typedef void OhVoidType; /**< void type */
+typedef OhInt32Type OhBoolType; /**< bool type */
+typedef OhUint8Type OhByteType; /**< byte type */
+typedef OhInt32Type OhErrType; /**< return type */
+typedef OhUint32Type OhSizeType;
+
+#endif
diff --git a/src/base/ecc.c b/src/base/ecc.c
new file mode 100644
index 0000000000000000000000000000000000000000..94356dae5baa5d5ae34f5f979a5536e51a4a38f1
--- /dev/null
+++ b/src/base/ecc.c
@@ -0,0 +1,1250 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ecc.h"
+
+// ----------------------------------------------
+// the code will try to guess it based on compiler macros
+// when uECC_PLATFORM is not defined.
+// ----------------------------------------------
+#ifndef uECC_PLATFORM
+#if __AVR__
+ #define uECC_PLATFORM uECC_avr
+#elif defined(__thumb2__) || defined(_M_ARMT) // I think MSVC only supports Thumb-2 targets
+ #define uECC_PLATFORM uECC_arm_thumb2
+#elif defined(__thumb__)
+ #define uECC_PLATFORM uECC_arm_thumb
+#elif defined(__arm__) || defined(_M_ARM)
+ #define uECC_PLATFORM uECC_arm
+#elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__)
+ #define uECC_PLATFORM uECC_x86
+#elif defined(__amd64__) || defined(_M_X64)
+ #define uECC_PLATFORM uECC_x86_64
+#else
+ #define uECC_PLATFORM uECC_arch_other
+#endif
+#endif
+// ----------------------------------------------
+// uECC_WORD_SIZE will be automatically set based on your platform
+// when it is not explicitly defined.
+// ----------------------------------------------
+#ifndef uECC_WORD_SIZE
+#if uECC_PLATFORM == uECC_avr
+ #define uECC_WORD_SIZE 1
+#elif (uECC_PLATFORM == uECC_x86_64)
+ #define uECC_WORD_SIZE 8
+#else
+ #define uECC_WORD_SIZE 4
+#endif
+#endif
+// Check uECC_WORD_SIZE
+#if (uECC_WORD_SIZE != 4) && (uECC_WORD_SIZE != 8)
+ #error "Unsupported value for uECC_WORD_SIZE"
+#endif
+#if (uECC_ASM && (uECC_PLATFORM == uECC_avr) && (uECC_WORD_SIZE != 1))
+ #error "uECC_WORD_SIZE must be 1 when using AVR asm"
+#endif
+#if (uECC_ASM && (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb) && (uECC_WORD_SIZE != 4))
+ #error "uECC_WORD_SIZE must be 4 when using ARM asm"
+#endif
+// ----------------------------------------------
+// system define
+// ----------------------------------------------
+#if __STDC_VERSION__ >= 199901L
+ #define RESTRICT restrict
+#else
+ #define RESTRICT
+#endif
+
+#ifndef uECC_SUPPORTS_INT128
+#if defined(__SIZEOF_INT128__) || ((__clang_major__ * 100 + __clang_minor__) >= 302)
+#define uECC_SUPPORTS_INT128 1
+#else
+#define uECC_SUPPORTS_INT128 0
+#endif
+#endif
+// ----------------------------------------------
+// Global parameter definition
+// ----------------------------------------------
+#if (uECC_WORD_SIZE == 4)
+ #define HIGH_BIT_SET 0x80000000
+ #define uECC_WORDS 8
+ #define Curve_P {0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}
+ #define Curve_B {0x00000007, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}
+ #define Curve_G { \
+ {0x16F81798, 0x59F2815B, 0x2DCE28D9, 0x029BFCDB, 0xCE870B07, 0x55A06295, 0xF9DCBBAC, 0x79BE667E}, \
+ {0xFB10D4B8, 0x9C47D08F, 0xA6855419, 0xFD17B448, 0x0E1108A8, 0x5DA4FBFC, 0x26A3C465, 0x483ADA77}}
+ #define Curve_N {0xD0364141, 0xBFD25E8C, 0xAF48A03B, 0xBAAEDCE6, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}
+ // Limbs of half the secp256k1 order
+ #define Curve_N_H {0x681B20A0, 0xDFE92F46, 0x57A4501D, 0x5D576E73, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF}
+#elif (uECC_WORD_SIZE == 8)
+ #define HIGH_BIT_SET 0x8000000000000000ull
+ #define uECC_WORDS 4
+ #define Curve_P {0xFFFFFFFEFFFFFC2Full, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull}
+ #define Curve_B {0x0000000000000007ull, 0x0000000000000000ull, 0x0000000000000000ull, 0x0000000000000000ull}
+ #define Curve_G { \
+ {0x59F2815B16F81798ull, 0x029BFCDB2DCE28D9ull, 0x55A06295CE870B07ull, 0x79BE667EF9DCBBACull}, \
+ {0x9C47D08FFB10D4B8ull, 0xFD17B448A6855419ull, 0x5DA4FBFC0E1108A8ull, 0x483ADA7726A3C465ull}}
+ #define Curve_N {0xBFD25E8CD0364141ull, 0xBAAEDCE6AF48A03Bull, 0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull}
+ // Limbs of half the secp256k1 order
+ #define Curve_N_H {0xDFE92F46681B20A0ull, 0x5D576E7357A4501Dull, 0xFFFFFFFFFFFFFFFFull, 0x7FFFFFFFFFFFFFFFull}
+#endif
+
+#define uECC_WORD_BITS (uECC_WORD_SIZE * 8) // Number of bits in a word
+// ----------------------------------------------
+// ecc type definition
+// ----------------------------------------------
+typedef OhInt32Type uECC_wordcount_t;
+typedef OhInt32Type uECC_swordcount_t;
+typedef OhInt32Type uECC_bitcount_t;
+typedef OhInt32Type uECC_cmpresult_t;
+typedef OhInt32Type uECC_scalar_t;
+typedef OhVoidType uECC_void_t;
+typedef OhInt32Type uECC_size_t;
+typedef OhErrType uECC_err_t;
+typedef OhBoolType uECC_bool_t;
+// ----- 1 word = 4 byte -----
+#if (uECC_WORD_SIZE == 4)
+ typedef OhUint8Type uECC_byte_t;
+ typedef OhUint32Type uECC_word_t;
+ typedef OhUint64Type uECC_dword_t;
+// ----- 1 word = 8 byte -----
+#elif (uECC_WORD_SIZE == 8)
+ typedef OhUint8Type uECC_byte_t;
+ typedef OhUint32Type uECC_hword_t;
+ typedef OhUint64Type uECC_word_t;
+#if uECC_SUPPORTS_INT128
+ typedef unsigned __int128 uECC_dword_t;
+#endif
+#endif
+
+// ----------------------------------------------
+// Elliptic curve type definition
+// ----------------------------------------------
+typedef struct uECC_point_t
+{
+ uECC_word_t x[uECC_WORDS];
+ uECC_word_t y[uECC_WORDS];
+} uECC_point_t;
+
+static uECC_word_t curve_p[uECC_WORDS] = Curve_P;
+static uECC_word_t curve_b[uECC_WORDS] = Curve_B;
+static uECC_point_t curve_G = Curve_G;
+static uECC_word_t curve_n[uECC_WORDS] = Curve_N;
+static uECC_word_t curve_n_h[uECC_WORDS] = Curve_N_H;
+
+// ----------------------------------------------
+// Get random number function
+// ----------------------------------------------
+// Windows System
+#if (defined(_WIN32) || defined(_WIN64))
+#include
+#include
+static uECC_err_t default_RNG(uECC_byte_t *p_dest, uECC_bitcount_t p_size)
+{
+ for (uECC_size_t i = 0; i < p_size; i++) {
+ uECC_byte_t randByte = rand()%(255);
+ p_dest[i] = randByte;
+ }
+ return ECC_SUCCESS;
+}
+
+// Unix System
+#elif defined(unix) || defined(__linux__) || defined(__unix__) || defined(__unix) || \
+ (defined(__APPLE__) && defined(__MACH__)) || defined(uECC_POSIX)
+#include
+#include
+#include
+#ifndef O_CLOEXEC
+ #define O_CLOEXEC 0
+#endif
+static uECC_err_t default_RNG(uECC_byte_t *p_dest, uECC_bitcount_t p_size)
+{
+ uECC_size_t l_fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
+ if(l_fd == -1)
+ {
+ l_fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
+ if(l_fd == -1)
+ {
+ return ECC_ERR_RNG_NOT_GENERATE;
+ }
+ }
+ char *l_ptr = (char *)p_dest;
+ ssize_t l_left = p_size;
+ while(l_left > 0)
+ {
+ ssize_t l_read = read(l_fd, l_ptr, (size_t)l_left);
+ if(l_read <= 0)
+ { // read failed
+ close(l_fd);
+ return 0;
+ }
+ l_left -= l_read;
+ l_ptr += l_read;
+ }
+ close(l_fd);
+ return ECC_SUCCESS;
+}
+
+// Some other platform
+#else
+static uECC_err_t default_RNG(uECC_byte_t *p_dest, uECC_bitcount_t p_size) {
+ return ECC_ERR_RNG_NOT_GENERATE;
+}
+#endif
+
+// Set RNG Function from default_RNG
+static uECC_RNG_Function g_rng = &default_RNG;
+uECC_void_t uECC_set_rng(uECC_RNG_Function p_rng) {
+ g_rng = p_rng;
+}
+
+uECC_void_t rfc_rng(uECC_byte_t nonce32[uECC_BYTES], const uECC_byte_t hash[uECC_BYTES], const uECC_byte_t priv_key[uECC_BYTES]){
+ rfc6979_nonce(nonce32, hash, priv_key, NULL, NULL, 0);
+}
+
+// ----------------------------------------------
+// Big Number Operation
+// ----------------------------------------------
+// -- Convert p_native(native big number) to p_bytes(bytes) --
+static uECC_void_t vli_nativeToBytes(uECC_byte_t *p_bytes, const uECC_word_t *p_native)
+{
+ uECC_size_t i;
+#if uECC_WORD_SIZE == 4
+ for(i=0; i> 24);
+ p_digit[1] = (uECC_byte_t)(p_native[i] >> 16);
+ p_digit[2] = (uECC_byte_t)(p_native[i] >> 8);
+ p_digit[3] = (uECC_byte_t)(p_native[i]);
+ }
+#elif uECC_WORD_SIZE == 8
+ for(i=0; i> 56;
+ p_digit[1] = p_native[i] >> 48;
+ p_digit[2] = p_native[i] >> 40;
+ p_digit[3] = p_native[i] >> 32;
+ p_digit[4] = p_native[i] >> 24;
+ p_digit[5] = p_native[i] >> 16;
+ p_digit[6] = p_native[i] >> 8;
+ p_digit[7] = p_native[i];
+ }
+#endif
+}
+
+// -- Convert p_bytes(bytes) to p_native(native big number) --
+static uECC_void_t vli_bytesToNative(uECC_word_t *p_native, const uECC_byte_t *p_bytes)
+{
+ uECC_size_t i;
+#if uECC_WORD_SIZE == 4
+ for(i=0; i= 0 && p_vli[i] == 0; --i){}
+ return (uECC_wordcount_t)(i + 1);
+}
+
+// -- Counts the number of bits required to represent p_vli --
+static uECC_bitcount_t vli_numBits(const uECC_word_t *p_vli, uECC_wordcount_t p_maxWords)
+{
+ uECC_word_t i;
+ uECC_word_t l_digit;
+ uECC_wordcount_t l_numDigits = vli_numDigits(p_vli, p_maxWords);
+ if(l_numDigits == 0){
+ return 0;
+ }
+ l_digit = p_vli[l_numDigits - 1];
+ for(i = 0; l_digit; ++i){
+ l_digit >>= 1;
+ }
+ return ((uECC_bitcount_t)(l_numDigits - 1) * uECC_WORD_BITS + (uECC_bitcount_t)i);
+}
+
+// -- Sets p_dest = p_src --
+static uECC_void_t vli_set(uECC_word_t *p_dest, const uECC_word_t *p_src)
+{
+ uECC_wordcount_t i;
+ for(i=0; i= 0; --i){
+ if(p_left[i] > p_right[i]){
+ return 1;
+ }
+ else if(p_left[i] < p_right[i]){
+ return -1;
+ }
+ }
+ return 0;
+}
+
+// -- Computes p_vli = p_vli >> 1 --
+static uECC_void_t vli_rshift1(uECC_word_t *p_vli)
+{
+ uECC_word_t *l_end = p_vli;
+ uECC_word_t l_carry = 0;
+ p_vli += uECC_WORDS;
+ while(p_vli-- > l_end){
+ uECC_word_t l_temp = *p_vli;
+ *p_vli = (l_temp >> 1) | l_carry;
+ l_carry = l_temp << (uECC_WORD_BITS - 1);
+ }
+}
+
+// -- Computes p_result = p_left + p_right, returning carry. Can modify in place --
+static uECC_word_t vli_add(uECC_word_t *p_result, uECC_word_t *p_left, uECC_word_t *p_right)
+{
+ uECC_word_t l_carry = 0;
+ uECC_wordcount_t i;
+ for(i = 0; i < uECC_WORDS; ++i){
+ uECC_word_t l_sum = p_left[i] + p_right[i] + l_carry;
+ if(l_sum != p_left[i]){
+ l_carry = (l_sum < p_left[i]);
+ }
+ p_result[i] = l_sum;
+ }
+ return l_carry;
+}
+
+// -- Computes p_result = p_left - p_right, returning borrow. Can modify in place --
+static uECC_word_t vli_sub_multiple(uECC_word_t *p_result, uECC_word_t *p_left, uECC_word_t *p_right, uECC_wordcount_t WordsMultiple)
+{
+ uECC_word_t l_borrow = 0;
+ uECC_wordcount_t i;
+ for(i = 0; i < uECC_WORDS * WordsMultiple; ++i){
+ uECC_word_t l_diff = p_left[i] - p_right[i] - l_borrow;
+ if(l_diff != p_left[i]){
+ l_borrow = (l_diff > p_left[i]);
+ }
+ p_result[i] = l_diff;
+ }
+ return l_borrow;
+}
+#define vli_sub(result, left, right) vli_sub_multiple((result), (left), (right), 1)
+
+// -- Compute each word mul result, maintaining the carries --
+static uECC_void_t mul2add(uECC_word_t a, uECC_word_t b, uECC_word_t *r0, uECC_word_t *r1, uECC_word_t *r2)
+{
+#if uECC_WORD_SIZE == 8 && !uECC_SUPPORTS_INT128
+ uECC_word_t a0 = a & 0xffffffffull;
+ uECC_word_t a1 = a >> 32;
+ uECC_word_t b0 = b & 0xffffffffull;
+ uECC_word_t b1 = b >> 32;
+
+ uECC_word_t i0 = a0 * b0;
+ uECC_word_t i1 = a0 * b1;
+ uECC_word_t i2 = a1 * b0;
+ uECC_word_t i3 = a1 * b1;
+
+ uECC_word_t p0, p1;
+ i2 += (i0 >> 32);
+ i2 += i1;
+ if(i2 < i1){ // overflow
+ i3 += 0x100000000ull;
+ }
+ p0 = (i0 & 0xffffffffull) | (i2 << 32);
+ p1 = i3 + (i2 >> 32);
+
+ *r0 += p0;
+ *r1 += (p1 + (*r0 < p0));
+ *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0));
+#else
+ uECC_dword_t p = (uECC_dword_t)a * b;
+ uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;
+ r01 += p;
+ *r2 += (r01 < p);
+ *r1 = r01 >> uECC_WORD_BITS;
+ *r0 = (uECC_word_t)r01;
+#endif
+}
+
+// -- Computes p_result = p_left * p_right --
+static uECC_void_t vli_mult(uECC_word_t *p_result, uECC_word_t *p_left, uECC_word_t *p_right)
+{
+ uECC_word_t r0 = 0;
+ uECC_word_t r1 = 0;
+ uECC_word_t r2 = 0;
+ uECC_wordcount_t i, k;
+ // Compute each digit of p_result in sequence, maintaining the carries
+ for(k = 0; k < uECC_WORDS; ++k){
+ for(i = 0; i <= k; ++i){
+ mul2add(p_left[i], p_right[k-i], &r0, &r1, &r2);
+ }
+ p_result[k] = r0;
+ r0 = r1;
+ r1 = r2;
+ r2 = 0;
+ }
+ for(k = uECC_WORDS; k < uECC_WORDS*2 - 1; ++k){
+ for(i = (k + 1) - uECC_WORDS; i= 0){
+ // p_result > p_mod (p_result = p_mod + remainder), so subtract p_mod to get remainder
+ vli_sub(p_result, p_result, p_mod);
+ }
+}
+
+// -- Computes p_result = (p_left - p_right) % p_mod --
+// -- Assumes that p_left < p_mod and p_right < p_mod, p_result != p_mod --
+static uECC_void_t vli_modSub(uECC_word_t *p_result, uECC_word_t *p_left, uECC_word_t *p_right, uECC_word_t *p_mod)
+{
+ uECC_word_t l_borrow = vli_sub(p_result, p_left, p_right);
+ if(l_borrow){
+ // In this case, p_result == -diff == (max int) - diff.
+ // Since -x % d == d - x, we can get the correct result from p_result + p_mod (with overflow).
+ vli_add(p_result, p_result, p_mod);
+ }
+}
+#define vli_modSub_fast(result, left, right) vli_modSub((result), (left), (right), curve_p)
+
+// -- Computes omega --
+#if uECC_WORD_SIZE == 4
+static uECC_void_t omega_mult(uECC_word_t * RESTRICT p_result, uECC_word_t * RESTRICT p_right)
+{
+ // Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1)
+ uECC_word_t l_carry = 0;
+ uECC_size_t i;
+ for(i=0; i> 32;
+ }
+ p_result[uECC_WORDS] = l_carry;
+ p_result[1 + uECC_WORDS] = vli_add(p_result + 1, p_result + 1, p_right); /* add the 2^32 multiple */
+}
+
+#elif uECC_WORD_SIZE == 8
+static uECC_void_t omega_mult(uECC_word_t * RESTRICT p_result, uECC_word_t * RESTRICT p_right)
+{
+ uECC_word_t r0 = 0;
+ uECC_word_t r1 = 0;
+ uECC_word_t r2 = 0;
+ uECC_wordcount_t k;
+ // Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1)
+ for(k = 0; k < uECC_WORDS; ++k) {
+ mul2add(0x1000003D1ull, p_right[k], &r0, &r1, &r2);
+ p_result[k] = r0;
+ r0 = r1;
+ r1 = r2;
+ r2 = 0;
+ }
+ p_result[uECC_WORDS] = r0;
+}
+#endif
+
+// -- Computes p_result = p_product % curve_p --
+// -- see http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf page 354 --
+// -- Note that this only works if log2(omega) < log2(p)/2 --
+static uECC_void_t vli_mmod_fast(uECC_word_t *RESTRICT p_result, uECC_word_t *RESTRICT p_product)
+{
+ uECC_word_t l_tmp[2*uECC_WORDS];
+ uECC_word_t l_carry;
+
+ vli_clear(l_tmp);
+ vli_clear(l_tmp + uECC_WORDS);
+
+ omega_mult(l_tmp, p_product + uECC_WORDS); // (Rq, q) = q * c
+ l_carry = vli_add(p_result, p_product, l_tmp); // (C, r) = r + q
+ if(!vli_isZero(l_tmp + uECC_WORDS)) { // if Rq > 0 */
+ vli_clear(p_product);
+ omega_mult(p_product, l_tmp + uECC_WORDS); // Rq*c
+ l_carry += vli_add(p_result, p_result, p_product); // (C1, r) = r + Rq*c
+ }
+ while(l_carry > 0){
+ --l_carry;
+ vli_sub(p_result, p_result, curve_p);
+ }
+ if(vli_cmp(p_result, curve_p) > 0) {
+ vli_sub(p_result, p_result, curve_p);
+ }
+}
+
+// -- Computes p_result = (p_left * p_right) % curve_p --
+static uECC_void_t vli_modMult_fast(uECC_word_t *p_result, uECC_word_t *p_left, uECC_word_t *p_right)
+{
+ uECC_word_t l_product[2 * uECC_WORDS];
+ vli_mult(l_product, p_left, p_right);
+ vli_mmod_fast(p_result, l_product);
+}
+
+// -- Computes p_result = (p_left * p_right) % curve_n --
+static uECC_void_t vli_modMult_n(uECC_word_t *p_result, uECC_word_t *p_left, uECC_word_t *p_right)
+{
+ uECC_word_t l_product[2 * uECC_WORDS];
+ uECC_word_t l_modMultiple[2 * uECC_WORDS];
+ uECC_word_t l_tmp[2 * uECC_WORDS];
+ uECC_word_t *v[2] = {l_tmp, l_product};
+
+ vli_mult(l_product, p_left, p_right);
+ vli_set(l_modMultiple + uECC_WORDS, curve_n); // works if curve_n has its highest bit set
+ vli_clear(l_modMultiple);
+
+ uECC_bitcount_t i;
+ uECC_word_t l_index = 1;
+ for(i=0; i<=uECC_BYTES * 8; ++i)
+ {
+ uECC_word_t l_borrow = vli_sub_multiple(v[1-l_index], v[l_index], l_modMultiple, 2);
+ l_index = !(l_index ^ l_borrow); // Swap the index if there was no borrow
+
+ vli_rshift1(l_modMultiple);
+ l_modMultiple[uECC_WORDS-1] |= l_modMultiple[uECC_WORDS] << (uECC_WORD_BITS - 1);
+ vli_rshift1(l_modMultiple + uECC_WORDS);
+ }
+ vli_set(p_result, v[l_index]);
+}
+
+// -- Computes p_result = p_left^2 % curve_p. --
+static uECC_void_t vli_modSquare_fast(uECC_word_t *p_result, uECC_word_t *p_left)
+{
+ uECC_word_t l_product[2 * uECC_WORDS];
+ vli_square(l_product, p_left);
+ vli_mmod_fast(p_result, l_product);
+}
+
+// -- Computes p_result = (1 / p_input) % p_mod. All VLIs are the same size. --
+// See "From Euclid's GCD to Montgomery Multiplication to the Great Divide"
+// https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf */
+#define EVEN(vli) (!(vli[0] & 1))
+static uECC_void_t vli_modInv(uECC_word_t *p_result, uECC_word_t *p_input, uECC_word_t *p_mod)
+{
+ uECC_word_t a[uECC_WORDS], b[uECC_WORDS], u[uECC_WORDS], v[uECC_WORDS];
+ uECC_word_t l_carry;
+ uECC_cmpresult_t l_cmpResult;
+
+ if(vli_isZero(p_input)){
+ vli_clear(p_result);
+ return;
+ }
+
+ vli_set(a, p_input);
+ vli_set(b, p_mod);
+ vli_clear(u);
+ u[0] = 1;
+ vli_clear(v);
+ while((l_cmpResult = vli_cmp(a, b)) != 0) {
+ l_carry = 0;
+ if(EVEN(a)) {
+ vli_rshift1(a);
+ if(!EVEN(u)) {
+ l_carry = vli_add(u, u, p_mod);
+ }
+ vli_rshift1(u);
+ if(l_carry) {
+ u[uECC_WORDS-1] |= HIGH_BIT_SET;
+ }
+ }
+ else if(EVEN(b)) {
+ vli_rshift1(b);
+ if(!EVEN(v)) {
+ l_carry = vli_add(v, v, p_mod);
+ }
+ vli_rshift1(v);
+ if(l_carry) {
+ v[uECC_WORDS-1] |= HIGH_BIT_SET;
+ }
+ }
+ else if(l_cmpResult > 0) {
+ vli_sub(a, a, b);
+ vli_rshift1(a);
+ if(vli_cmp(u, v) < 0) {
+ vli_add(u, u, p_mod);
+ }
+ vli_sub(u, u, v);
+ if(!EVEN(u)) {
+ l_carry = vli_add(u, u, p_mod);
+ }
+ vli_rshift1(u);
+ if(l_carry) {
+ u[uECC_WORDS-1] |= HIGH_BIT_SET;
+ }
+ }
+ else {
+ vli_sub(b, b, a);
+ vli_rshift1(b);
+ if(vli_cmp(v, u) < 0) {
+ vli_add(v, v, p_mod);
+ }
+ vli_sub(v, v, u);
+ if(!EVEN(v)) {
+ l_carry = vli_add(v, v, p_mod);
+ }
+ vli_rshift1(v);
+ if(l_carry) {
+ v[uECC_WORDS-1] |= HIGH_BIT_SET;
+ }
+ }
+ }
+ vli_set(p_result, u);
+}
+
+// -- Compute a = sqrt(a) (mod curve_p) --
+static uECC_void_t vli_modSqrt(uECC_word_t *a)
+{
+ uECC_bitcount_t i;
+ uECC_word_t p1[uECC_WORDS] = {1};
+ uECC_word_t l_result[uECC_WORDS] = {1};
+
+ // Since curve_p == 3 (mod 4) for all supported curves, we can
+ // compute sqrt(a) = a^((curve_p + 1) / 4) (mod curve_p).
+ vli_add(p1, curve_p, p1); // p1 = curve_p + 1
+ for(i = vli_numBits(p1, uECC_WORDS) - 1; i > 1; --i) {
+ vli_modSquare_fast(l_result, l_result);
+ if(vli_testBit(p1, i)) {
+ vli_modMult_fast(l_result, l_result, a);
+ }
+ }
+ vli_set(a, l_result);
+}
+
+// ----------------------------------------------
+// Point Operation
+// ----------------------------------------------
+// -- Returns 1 if p_point is the point at infinity, 0 otherwise --
+static uECC_cmpresult_t EccPoint_isZero(uECC_point_t *p_point)
+{
+ return (vli_isZero(p_point->x) && vli_isZero(p_point->y));
+}
+
+// -- Point multiplication algorithm using Montgomery's ladder with co-Z coordinates --
+// -- From http://eprint.iacr.org/2011/338.pdf --
+static uECC_void_t EccPoint_double_jacobian(uECC_word_t * RESTRICT X1, uECC_word_t * RESTRICT Y1, uECC_word_t * RESTRICT Z1)
+{
+ /* t1 = X, t2 = Y, t3 = Z */
+ uECC_word_t t4[uECC_WORDS];
+ uECC_word_t t5[uECC_WORDS];
+
+ if(vli_isZero(Z1)){
+ return;
+ }
+ vli_modSquare_fast(t5, Y1); // t5 = y1^2
+ vli_modMult_fast(t4, X1, t5); // t4 = x1*y1^2 = A
+ vli_modSquare_fast(X1, X1); // t1 = x1^2
+ vli_modSquare_fast(t5, t5); // t5 = y1^4
+ vli_modMult_fast(Z1, Y1, Z1); // t3 = y1*z1 = z3
+ vli_modAdd(Y1, X1, X1, curve_p); // t2 = 2*x1^2
+ vli_modAdd(Y1, Y1, X1, curve_p); // t2 = 3*x1^2
+ if(vli_testBit(Y1, 0)) {
+ uECC_word_t l_carry = vli_add(Y1, Y1, curve_p);
+ vli_rshift1(Y1);
+ Y1[uECC_WORDS-1] |= l_carry << (uECC_WORD_BITS - 1);
+ }
+ else {
+ vli_rshift1(Y1);
+ }
+ // t2 = 3/2*(x1^2) = B
+ vli_modSquare_fast(X1, Y1); // t1 = B^2
+ vli_modSub(X1, X1, t4, curve_p); // t1 = B^2 - A
+ vli_modSub(X1, X1, t4, curve_p); // t1 = B^2 - 2A = x3
+ vli_modSub(t4, t4, X1, curve_p); // t4 = A - x3
+ vli_modMult_fast(Y1, Y1, t4); // t2 = B * (A - x3)
+ vli_modSub(Y1, Y1, t5, curve_p); // t2 = B * (A - x3) - y1^4 = y3
+}
+
+// -- Modify (x1, y1) => (x1 * z^2, y1 * z^3) --
+static uECC_void_t apply_z(uECC_word_t * RESTRICT X1, uECC_word_t * RESTRICT Y1, uECC_word_t * RESTRICT Z)
+{
+ uECC_word_t t1[uECC_WORDS];
+ vli_modSquare_fast(t1, Z); // z^2
+ vli_modMult_fast(X1, X1, t1); // x1 * z^2
+ vli_modMult_fast(t1, t1, Z); // z^3
+ vli_modMult_fast(Y1, Y1, t1); // y1 * z^3
+}
+
+// -- P = (x1, y1) => 2P, (x2, y2) => P' --
+static uECC_void_t XYcZ_initial_double(uECC_word_t * RESTRICT X1, uECC_word_t * RESTRICT Y1,
+ uECC_word_t * RESTRICT X2, uECC_word_t * RESTRICT Y2, const uECC_word_t * RESTRICT p_initialZ)
+{
+ uECC_word_t z[uECC_WORDS];
+
+ vli_set(X2, X1);
+ vli_set(Y2, Y1);
+ vli_clear(z);
+ z[0] = 1;
+ if(p_initialZ){
+ vli_set(z, p_initialZ);
+ }
+ apply_z(X1, Y1, z);
+ EccPoint_double_jacobian(X1, Y1, z);
+ apply_z(X2, Y2, z);
+}
+
+// -- Input P = (x1, y1, Z), Q = (x2, y2, Z) --
+// -- Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) or P => P', Q => P + Q --
+static uECC_void_t XYcZ_add(uECC_word_t * RESTRICT X1, uECC_word_t * RESTRICT Y1, uECC_word_t * RESTRICT X2, uECC_word_t * RESTRICT Y2)
+{
+ // t1 = X1, t2 = Y1, t3 = X2, t4 = Y2
+ uECC_word_t t5[uECC_WORDS];
+
+ vli_modSub_fast(t5, X2, X1); // t5 = x2 - x1
+ vli_modSquare_fast(t5, t5); // t5 = (x2 - x1)^2 = A
+ vli_modMult_fast(X1, X1, t5); // t1 = x1*A = B
+ vli_modMult_fast(X2, X2, t5); // t3 = x2*A = C
+ vli_modSub_fast(Y2, Y2, Y1); // t4 = y2 - y1
+ vli_modSquare_fast(t5, Y2); // t5 = (y2 - y1)^2 = D
+
+ vli_modSub_fast(t5, t5, X1); // t5 = D - B
+ vli_modSub_fast(t5, t5, X2); // t5 = D - B - C = x3
+ vli_modSub_fast(X2, X2, X1); // t3 = C - B
+ vli_modMult_fast(Y1, Y1, X2); // t2 = y1*(C - B)
+ vli_modSub_fast(X2, X1, t5); // t3 = B - x3
+ vli_modMult_fast(Y2, Y2, X2); // t4 = (y2 - y1)*(B - x3)
+ vli_modSub_fast(Y2, Y2, Y1); // t4 = y3
+
+ vli_set(X2, t5);
+}
+
+// -- Input P = (x1, y1, Z), Q = (x2, y2, Z) --
+// -- Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3) or P => P - Q, Q => P + Q --
+static uECC_void_t XYcZ_addC(uECC_word_t * RESTRICT X1, uECC_word_t * RESTRICT Y1, uECC_word_t * RESTRICT X2, uECC_word_t * RESTRICT Y2)
+{
+ // t1 = X1, t2 = Y1, t3 = X2, t4 = Y2
+ uECC_word_t t5[uECC_WORDS];
+ uECC_word_t t6[uECC_WORDS];
+ uECC_word_t t7[uECC_WORDS];
+
+ vli_modSub_fast(t5, X2, X1); // t5 = x2 - x1
+ vli_modSquare_fast(t5, t5); // t5 = (x2 - x1)^2 = A
+ vli_modMult_fast(X1, X1, t5); // t1 = x1*A = B
+ vli_modMult_fast(X2, X2, t5); // t3 = x2*A = C
+ vli_modAdd(t5, Y2, Y1, curve_p); // t4 = y2 + y1
+ vli_modSub_fast(Y2, Y2, Y1); // t4 = y2 - y1
+
+ vli_modSub_fast(t6, X2, X1); // t6 = C - B
+ vli_modMult_fast(Y1, Y1, t6); // t2 = y1 * (C - B)
+ vli_modAdd(t6, X1, X2, curve_p); // t6 = B + C
+ vli_modSquare_fast(X2, Y2); // t3 = (y2 - y1)^2
+ vli_modSub_fast(X2, X2, t6); // t3 = x3
+
+ vli_modSub_fast(t7, X1, X2); // t7 = B - x3
+ vli_modMult_fast(Y2, Y2, t7); // t4 = (y2 - y1)*(B - x3)
+ vli_modSub_fast(Y2, Y2, Y1); // t4 = y3
+
+ vli_modSquare_fast(t7, t5); // t7 = (y2 + y1)^2 = F
+ vli_modSub_fast(t7, t7, t6); // t7 = x3'
+ vli_modSub_fast(t6, t7, X1); // t6 = x3' - B
+ vli_modMult_fast(t6, t6, t5); // t6 = (y2 + y1)*(x3' - B)
+ vli_modSub_fast(Y1, t6, Y1); // t2 = y3'
+
+ vli_set(X1, t7);
+}
+
+// -- Compute point mult --
+static uECC_void_t EccPoint_mult(uECC_point_t * RESTRICT p_result, uECC_point_t * RESTRICT p_point,
+ const uECC_word_t * RESTRICT p_scalar, const uECC_word_t * RESTRICT p_initialZ, uECC_bitcount_t p_numBits)
+{
+ // R0 and R1
+ uECC_word_t Rx[2][uECC_WORDS];
+ uECC_word_t Ry[2][uECC_WORDS];
+ uECC_word_t z[uECC_WORDS];
+ uECC_bitcount_t i;
+ uECC_word_t nb;
+
+ vli_set(Rx[1], p_point->x);
+ vli_set(Ry[1], p_point->y);
+ XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], p_initialZ);
+ for(i = p_numBits - 2; i > 0; --i){
+ nb = !vli_testBit(p_scalar, i);
+ XYcZ_addC(Rx[1-nb], Ry[1-nb], Rx[nb], Ry[nb]);
+ XYcZ_add(Rx[nb], Ry[nb], Rx[1-nb], Ry[1-nb]);
+ }
+ nb = !vli_testBit(p_scalar, 0);
+ XYcZ_addC(Rx[1-nb], Ry[1-nb], Rx[nb], Ry[nb]);
+ // Find final 1/Z value
+ vli_modSub_fast(z, Rx[1], Rx[0]); // X1 - X0
+ vli_modMult_fast(z, z, Ry[1-nb]); // Yb * (X1 - X0)
+ vli_modMult_fast(z, z, p_point->x); // xP * Yb * (X1 - X0)
+ vli_modInv(z, z, curve_p); // 1 / (xP * Yb * (X1 - X0))
+ vli_modMult_fast(z, z, p_point->y); // yP / (xP * Yb * (X1 - X0))
+ vli_modMult_fast(z, z, Rx[1-nb]); // Xb * yP / (xP * Yb * (X1 - X0))
+ // End 1/Z calculation
+ XYcZ_add(Rx[nb], Ry[nb], Rx[1-nb], Ry[1-nb]);
+ apply_z(Rx[0], Ry[0], z);
+ vli_set(p_result->x, Rx[0]);
+ vli_set(p_result->y, Ry[0]);
+}
+
+// ----------------------------------------------
+// secp256k1 scalar
+// ----------------------------------------------
+// -- Check if the scalar of secp256k1 is overflow --
+uECC_scalar_t uECC_scalar_overflow(const uECC_word_t *a) {
+ // secp256k1_scalar_check_overflow
+ uECC_size_t yes = 0;
+ uECC_size_t no = 0;
+#if uECC_WORD_SIZE == 8
+ no |= (a[3] < curve_n[3]); // No need for a > check.
+ no |= (a[2] < curve_n[2]);
+ yes |= (a[2] > curve_n[2]) & ~no;
+ no |= (a[1] < curve_n[1]);
+ yes |= (a[1] > curve_n[1]) & ~no;
+ yes |= (a[0] >= curve_n[0]) & ~no;
+#elif uECC_WORD_SIZE == 4
+ no |= (a[7] < curve_n[7]); // No need for a > check.
+ no |= (a[6] < curve_n[6]); // No need for a > check.
+ no |= (a[5] < curve_n[5]); // No need for a > check.
+ no |= (a[4] < curve_n[4]);
+ yes |= (a[4] > curve_n[4]) & ~no;
+ no |= (a[3] < curve_n[3]) & ~yes;
+ yes |= (a[3] > curve_n[3]) & ~no;
+ no |= (a[2] < curve_n[2]) & ~yes;
+ yes |= (a[2] > curve_n[2]) & ~no;
+ no |= (a[1] < curve_n[1]) & ~yes;
+ yes |= (a[1] > curve_n[1]) & ~no;
+ yes |= (a[0] >= curve_n[0]) & ~no;
+#endif
+ return yes;
+}
+
+// -- Check if the scalar of secp256k1 is high --
+uECC_scalar_t uECC_scalar_high(const uECC_word_t *a) {
+ // secp256k1_scalar_is_high
+ uECC_size_t yes = 0;
+ uECC_size_t no = 0;
+#if uECC_WORD_SIZE == 8
+ no |= (a[3] < curve_n_h[3]);
+ yes |= (a[3] > curve_n_h[3]) & ~no;
+ no |= (a[2] < curve_n_h[2]) & ~yes; // No need for a > check.
+ no |= (a[1] < curve_n_h[1]) & ~yes;
+ yes |= (a[1] > curve_n_h[1]) & ~no;
+ yes |= (a[0] > curve_n_h[0]) & ~no;
+#elif uECC_WORD_SIZE == 4
+ no |= (a[7] < curve_n_h[7]);
+ yes |= (a[7] > curve_n_h[7]) & ~no;
+ no |= (a[6] < curve_n_h[6]) & ~yes; // No need for a > check.
+ no |= (a[5] < curve_n_h[5]) & ~yes; // No need for a > check.
+ no |= (a[4] < curve_n_h[4]) & ~yes; // No need for a > check.
+ no |= (a[3] < curve_n_h[3]) & ~yes;
+ yes |= (a[3] > curve_n_h[3]) & ~no;
+ no |= (a[2] < curve_n_h[2]) & ~yes;
+ yes |= (a[2] > curve_n_h[2]) & ~no;
+ no |= (a[1] < curve_n_h[1]) & ~yes;
+ yes |= (a[1] > curve_n_h[1]) & ~no;
+ yes |= (a[0] > curve_n_h[0]) & ~no;
+#endif
+ return yes;
+}
+
+// -- secp256k1 scalar negate --
+#define LOW(a) ((uECC_hword_t)(a & 0xffffffff))
+#define HIGH(a) ((uECC_hword_t)((a >> 32) & 0xffffffff))
+uECC_void_t uECC_scalar_negate(uECC_word_t *r, const uECC_word_t *a) {
+
+
+#if uECC_WORD_SIZE == 8 && uECC_SUPPORTS_INT128
+ uECC_word_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (vli_isZero(a) == 0);
+ uECC_dword_t t = (uECC_dword_t)(~a[0]) + curve_n[0] + 1;
+ r[0] = t & nonzero; t >>= 64;
+ t += (uECC_dword_t)(~a[1]) + curve_n[1];
+ r[1] = t & nonzero; t >>= 64;
+ t += (uECC_dword_t)(~a[2]) + curve_n[2];
+ r[2] = t & nonzero; t >>= 64;
+ t += (uECC_dword_t)(~a[3]) + curve_n[3];
+ r[3] = t & nonzero;
+
+#elif uECC_WORD_SIZE == 8 && !uECC_SUPPORTS_INT128
+ uECC_hword_t a1[8], r1[8], curve_n1[8];
+ for(uECC_size_t i=0; i<4; i++){
+ curve_n1[i*2] = (uECC_hword_t)(curve_n[i] & 0xffffffff);
+ curve_n1[i*2+1] = (uECC_hword_t)((curve_n[i] >> 32) & 0xffffffff);
+ a1[i*2] = (uECC_hword_t)(a[i] & 0xffffffff);
+ a1[i*2+1] = (uECC_hword_t)((a[i] >> 32) & 0xffffffff);
+ }
+ uECC_hword_t nonzero = 0xFFFFFFFFUL * (vli_isZero(a) == 0);
+ uECC_word_t t;
+ t = (uECC_word_t)(~a1[0]) + curve_n1[0] + 1;
+ r1[0] = t & nonzero; t >>= 32;
+ t += (uECC_word_t)(~a1[1]) + curve_n1[1];
+ r1[1] = t & nonzero; t >>= 32;
+ t += (uECC_word_t)(~a1[2]) + curve_n1[2];
+ r1[2] = t & nonzero; t >>= 32;
+ t += (uECC_word_t)(~a1[3]) + curve_n1[3];
+ r1[3] = t & nonzero; t >>= 32;
+ t += (uECC_word_t)(~a1[4]) + curve_n1[4];
+ r1[4] = t & nonzero; t >>= 32;
+ t += (uECC_word_t)(~a1[5]) + curve_n1[5];
+ r1[5] = t & nonzero; t >>= 32;
+ t += (uECC_word_t)(~a1[6]) + curve_n1[6];
+ r1[6] = t & nonzero; t >>= 32;
+ t += (uECC_word_t)(~a1[7]) + curve_n1[7];
+ r1[7] = t & nonzero;
+ for(uECC_size_t i=0; i<4;i++){
+ r[i] = ((uECC_word_t)(r1[i*2+1]) << 32) | r1[i*2] ;
+ }
+
+#elif uECC_WORD_SIZE == 4
+ uECC_word_t nonzero = 0xFFFFFFFFUL * (vli_isZero(a) == 0);
+ uECC_dword_t t;
+ t = (uECC_dword_t)(~a[0]) + curve_n[0] + 1;
+ r[0] = t & nonzero; t >>= 32;
+ t += (uECC_dword_t)(~a[1]) + curve_n[1];
+ r[1] = t & nonzero; t >>= 32;
+ t += (uECC_dword_t)(~a[2]) + curve_n[2];
+ r[2] = t & nonzero; t >>= 32;
+ t += (uECC_dword_t)(~a[3]) + curve_n[3];
+ r[3] = t & nonzero; t >>= 32;
+ t += (uECC_dword_t)(~a[4]) + curve_n[4];
+ r[4] = t & nonzero; t >>= 32;
+ t += (uECC_dword_t)(~a[5]) + curve_n[5];
+ r[5] = t & nonzero; t >>= 32;
+ t += (uECC_dword_t)(~a[6]) + curve_n[6];
+ r[6] = t & nonzero; t >>= 32;
+ t += (uECC_dword_t)(~a[7]) + curve_n[7];
+ r[7] = t & nonzero;
+#endif
+}
+
+// ----------------------------------------------
+// Public Key
+// ----------------------------------------------
+// -- Create a public/private key pair --
+// -- [Output] p_publicKey - Will be filled in with the public key. --
+// -- [Output] p_privateKey - Will be filled in with the private key. --
+// -- Returns value >= 0 if the key pair was generated successfully, value < 0 if an error occurred. --
+#define MAX_TRIES 16 // Maximum number of attempts
+uECC_err_t uECC_make_key(uECC_byte_t p_publicKey[uECC_BYTES*2], uECC_byte_t p_privateKey[uECC_BYTES])
+{
+ uECC_point_t l_public;
+ uECC_word_t l_private[uECC_WORDS];
+ uECC_word_t l_tries = 0;
+
+ do{repeat:
+ if(g_rng((uECC_byte_t *)l_private, sizeof(l_private)) != ECC_SUCCESS || (l_tries++ >= MAX_TRIES)){
+ return ECC_ERR_RNG_UNSUITABLE;
+ }
+ if(vli_isZero(l_private)){
+ goto repeat;
+ }
+ EccPoint_mult(&l_public, &curve_G, l_private, 0, vli_numBits(l_private, uECC_WORDS));
+ } while(EccPoint_isZero(&l_public));
+
+ vli_nativeToBytes(p_privateKey, l_private);
+ vli_nativeToBytes(p_publicKey, l_public.x);
+ vli_nativeToBytes(p_publicKey + uECC_BYTES, l_public.y);
+ return ECC_SUCCESS;
+}
+
+// -- Create a public key --
+// -- [Input] p_privateKey - Your private key. --
+// -- [Output] p_publicKey - Will be filled in with the public key. --
+// -- Returns value >= 0 if the public key was generated successfully, value < 0 if an error occurred. --
+uECC_err_t uECC_create_pubkey(uECC_byte_t p_publicKey[uECC_BYTES*2], uECC_byte_t p_privateKey[uECC_BYTES])
+{
+ uECC_point_t l_public;
+ uECC_word_t l_private[uECC_WORDS];
+
+ vli_bytesToNative(l_private, p_privateKey);
+ EccPoint_mult(&l_public, &curve_G, l_private, 0, vli_numBits(l_private, uECC_WORDS));
+ if(EccPoint_isZero(&l_public)){
+ return ECC_ERR_PUB_EQUAL_ZERO;
+ }
+ vli_nativeToBytes(p_publicKey, l_public.x);
+ vli_nativeToBytes(p_publicKey + uECC_BYTES, l_public.y);
+ return ECC_SUCCESS;
+}
+
+// -- compress a public key --
+uECC_void_t uECC_compress(const uECC_byte_t p_publicKey[uECC_BYTES*2], uECC_byte_t p_compressed[uECC_BYTES+1])
+{
+ uECC_wordcount_t i;
+ for(i=0; i vli_numBits(u2, uECC_WORDS) ? vli_numBits(u1, uECC_WORDS) : vli_numBits(u2, uECC_WORDS));
+
+ uECC_point_t *l_point = l_points[(!!vli_testBit(u1, l_numBits-1)) | ((!!vli_testBit(u2, l_numBits-1)) << 1)];
+ vli_set(rx, l_point->x);
+ vli_set(ry, l_point->y);
+ vli_clear(z);
+ z[0] = 1;
+
+ uECC_bitcount_t i;
+ for(i = l_numBits - 2; i >= 0; --i){
+ EccPoint_double_jacobian(rx, ry, z);
+ uECC_word_t l_index = (!!vli_testBit(u1, i)) | (uECC_word_t)((!!vli_testBit(u2, i)) << 1);
+ l_point = l_points[l_index];
+ if(l_point){
+ vli_set(tx, l_point->x);
+ vli_set(ty, l_point->y);
+ apply_z(tx, ty, z);
+ vli_modSub_fast(tz, rx, tx); // Z = x2 - x1
+ XYcZ_add(tx, ty, rx, ry);
+ vli_modMult_fast(z, z, tz);
+ }
+ }
+ vli_modInv(z, z, curve_p); // Z = 1/Z
+ apply_z(rx, ry, z);
+ // v = x1 (mod n)
+ if(vli_cmp(curve_n, rx) != 1){
+ vli_sub(rx, rx, curve_n);
+ }
+ // Accept only if v == r.
+ *res = (vli_cmp(rx, r) == 0) ? 1 : 0;
+ return ECC_SUCCESS;
+}
+
+
+// -- shared secret --
+// -- Compute a shared secret given your secret key and someone else's public key. --
+// -- Note: It is recommended that you hash the result of uECC_shared_secret() before using it for symmetric encryption or HMAC. --
+// -- [Input] p_publicKey - The public key of the remote party. --
+// -- [Input] p_privateKey - Your private key. --
+// -- [Output] p_secret - Will be filled in with the shared secret value. --
+// -- Returns value >= 0 if the shared secret was generated successfully, value < 0 if an error occurred. --
+uECC_err_t uECC_shared_secret(const uECC_byte_t p_publicKey[uECC_BYTES*2], const uECC_byte_t p_privateKey[uECC_BYTES], uECC_byte_t p_secret[uECC_BYTES])
+{
+ uECC_point_t l_public;
+ uECC_word_t l_private[uECC_WORDS];
+ uECC_word_t l_random[uECC_WORDS];
+
+ uECC_err_t res = g_rng((uECC_byte_t *)l_random, sizeof(l_random));
+ if (res != ECC_SUCCESS) {
+ return res;
+ }
+ vli_bytesToNative(l_private, p_privateKey);
+ vli_bytesToNative(l_public.x, p_publicKey);
+ vli_bytesToNative(l_public.y, p_publicKey + uECC_BYTES);
+ uECC_point_t l_product;
+ EccPoint_mult(&l_product, &l_public, l_private, (vli_isZero(l_random) ? 0: l_random), vli_numBits(l_private, uECC_WORDS));
+ vli_nativeToBytes(p_secret, l_product.x);
+
+ if(EccPoint_isZero(&l_product))
+ return ECC_ERR_SHAREKEY_EQUAL_ZERO;
+ else
+ return ECC_SUCCESS;
+}
diff --git a/src/base/hash.c b/src/base/hash.c
new file mode 100644
index 0000000000000000000000000000000000000000..b0fb1501a87364fd1ec362999d346e7e8f0ea67f
--- /dev/null
+++ b/src/base/hash.c
@@ -0,0 +1,312 @@
+/**********************************************************************
+ * Copyright (c) 2014 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#include "hash.h"
+
+// -----------------------
+// sha256 operation
+// -----------------------
+// Operation macro definition
+#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
+#define Maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))
+#define Sigma0(x) (((x) >> 2 | (x) << 30) ^ ((x) >> 13 | (x) << 19) ^ ((x) >> 22 | (x) << 10))
+#define Sigma1(x) (((x) >> 6 | (x) << 26) ^ ((x) >> 11 | (x) << 21) ^ ((x) >> 25 | (x) << 7))
+#define sigma0(x) (((x) >> 7 | (x) << 25) ^ ((x) >> 18 | (x) << 14) ^ ((x) >> 3))
+#define sigma1(x) (((x) >> 17 | (x) << 15) ^ ((x) >> 19 | (x) << 13) ^ ((x) >> 10))
+#define Round(a,b,c,d,e,f,g,h,k,w) do { \
+ OhUint32Type t1 = (h) + Sigma1(e) + Ch((e), (f), (g)) + (k) + (w); \
+ OhUint32Type t2 = Sigma0(a) + Maj((a), (b), (c)); \
+ (d) += t1; \
+ (h) = t1 + t2; \
+} while(0)
+
+#ifdef WORDS_BIGENDIAN
+#define BE32(x) (x)
+#else
+#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
+#endif
+
+// Initial hash value
+OhVoidType sha256_init(ql_sha256_t* hash) {
+ hash->s[0] = 0x6a09e667ul;
+ hash->s[1] = 0xbb67ae85ul;
+ hash->s[2] = 0x3c6ef372ul;
+ hash->s[3] = 0xa54ff53aul;
+ hash->s[4] = 0x510e527ful;
+ hash->s[5] = 0x9b05688cul;
+ hash->s[6] = 0x1f83d9abul;
+ hash->s[7] = 0x5be0cd19ul;
+ hash->bytes = 0;
+}
+
+// Perform one SHA-256 transformation, processing 16 big endian 32-bit words
+OhVoidType sha256_transform(OhUint32Type* s, const OhUint32Type* chunk) {
+ OhUint32Type a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
+ OhUint32Type w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
+
+ Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = BE32(chunk[0]));
+ Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = BE32(chunk[1]));
+ Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = BE32(chunk[2]));
+ Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = BE32(chunk[3]));
+ Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = BE32(chunk[4]));
+ Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = BE32(chunk[5]));
+ Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = BE32(chunk[6]));
+ Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = BE32(chunk[7]));
+ Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = BE32(chunk[8]));
+ Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = BE32(chunk[9]));
+ Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = BE32(chunk[10]));
+ Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = BE32(chunk[11]));
+ Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = BE32(chunk[12]));
+ Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = BE32(chunk[13]));
+ Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = BE32(chunk[14]));
+ Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = BE32(chunk[15]));
+
+ Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1));
+ Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2));
+ Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3));
+ Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4));
+ Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5));
+ Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6));
+ Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7));
+ Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8));
+ Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9));
+ Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10));
+ Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11));
+ Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12));
+ Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13));
+ Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14));
+ Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15));
+ Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0));
+
+ Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1));
+ Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2));
+ Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3));
+ Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4));
+ Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5));
+ Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6));
+ Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7));
+ Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8));
+ Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9));
+ Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10));
+ Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11));
+ Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12));
+ Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13));
+ Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14));
+ Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15));
+ Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0));
+
+ Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1));
+ Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2));
+ Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3));
+ Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4));
+ Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5));
+ Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6));
+ Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7));
+ Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8));
+ Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9));
+ Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10));
+ Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11));
+ Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12));
+ Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13));
+ Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14));
+ Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15));
+ Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0));
+
+ s[0] += a;
+ s[1] += b;
+ s[2] += c;
+ s[3] += d;
+ s[4] += e;
+ s[5] += f;
+ s[6] += g;
+ s[7] += h;
+}
+
+// Perform sha-256 on data
+OhVoidType sha256_write(ql_sha256_t* hash, const OhByteType* data, OhSizeType len) {
+ OhSizeType bufsize = hash->bytes & 0x3F;
+ hash->bytes += len;
+ while (bufsize + len >= 64) {
+ // Fill the buffer, and process it.
+ memcpy(((unsigned char*)hash->buf) + bufsize, data, 64 - bufsize);
+ data += 64 - bufsize;
+ len -= 64 - bufsize;
+ sha256_transform(hash->s, hash->buf);
+ bufsize = 0;
+ }
+ if (len) {
+ // Fill the buffer with what remains.
+ memcpy(((unsigned char*)hash->buf) + bufsize, data, len);
+ }
+}
+
+// Perform last sha-256 and output hash result
+OhVoidType sha256_final(ql_sha256_t* hash, OhByteType* out32) {
+ static const OhUint8Type pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ OhUint32Type sizedesc[2];
+ OhUint32Type out[8];
+ int i = 0;
+ sizedesc[0] = BE32(hash->bytes >> 29);
+ sizedesc[1] = BE32(hash->bytes << 3);
+ sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64));
+ sha256_write(hash, (const OhByteType*)sizedesc, 8);
+ for (i = 0; i < 8; i++) {
+ out[i] = BE32(hash->s[i]);
+ hash->s[i] = 0;
+ }
+ memcpy(out32, (const unsigned char*)out, 32);
+}
+
+
+// -----------------------
+// hmac operation
+// -----------------------
+// Initial hmac parameter
+OhVoidType hmac_init(ql_hmac_t* hash, const OhByteType* key, OhSizeType keylen) {
+ int n;
+ OhByteType rkey[64];
+ if (keylen <= 64) {
+ memcpy(rkey, key, keylen);
+ memset(rkey + keylen, 0, 64 - keylen);
+ } else {
+ ql_sha256_t sha256;
+ sha256_init(&sha256);
+ sha256_write(&sha256, key, keylen);
+ sha256_final(&sha256, rkey);
+ memset(rkey + 32, 0, 32);
+ }
+ // compute outer
+ sha256_init(&hash->outer);
+ for (n = 0; n < 64; n++) {
+ rkey[n] ^= 0x5c;
+ }
+ sha256_write(&hash->outer, rkey, 64);
+ // compute inner
+ sha256_init(&hash->inner);
+ for (n = 0; n < 64; n++) {
+ rkey[n] ^= 0x5c ^ 0x36;
+ }
+ sha256_write(&hash->inner, rkey, 64);
+ memset(rkey, 0, 64);
+}
+
+// Perform hmac on data
+OhVoidType hmac_write(ql_hmac_t* hash, const OhByteType* data, OhSizeType size) {
+ sha256_write(&hash->inner, data, size);
+}
+
+// Perform last hmac and output result
+OhVoidType hmac_final(ql_hmac_t* hash, OhByteType* out32) {
+ OhByteType temp[32];
+ sha256_final(&hash->inner, temp);
+ sha256_write(&hash->outer, temp, 32);
+ memset(temp, 0, 32);
+ sha256_final(&hash->outer, out32);
+}
+
+// -----------------------
+// rfc6979 operation
+// -----------------------
+// Initial rfc6979 parameter
+OhVoidType rfc6979_init(ql_rfc6979_t* rng, const OhByteType* key, OhSizeType keylen) {
+ ql_hmac_t hmac;
+ static const OhByteType zero[1] = {0x00};
+ static const OhByteType one[1] = {0x01};
+
+ memset(rng->v, 0x01, 32); /* RFC6979 3.2.b. */
+ memset(rng->k, 0x00, 32); /* RFC6979 3.2.c. */
+
+ /* RFC6979 3.2.d. */
+ hmac_init(&hmac, rng->k, 32);
+ hmac_write(&hmac, rng->v, 32);
+ hmac_write(&hmac, zero, 1);
+ hmac_write(&hmac, key, keylen);
+ hmac_final(&hmac, rng->k);
+ hmac_init(&hmac, rng->k, 32);
+ hmac_write(&hmac, rng->v, 32);
+ hmac_final(&hmac, rng->v);
+
+ /* RFC6979 3.2.f. */
+ hmac_init(&hmac, rng->k, 32);
+ hmac_write(&hmac, rng->v, 32);
+ hmac_write(&hmac, one, 1);
+ hmac_write(&hmac, key, keylen);
+ hmac_final(&hmac, rng->k);
+ hmac_init(&hmac, rng->k, 32);
+ hmac_write(&hmac, rng->v, 32);
+ hmac_final(&hmac, rng->v);
+ rng->retry = 0;
+}
+
+// generate rfc6979 result
+OhVoidType rfc6979_gen(ql_rfc6979_t* rng, OhByteType* out, OhSizeType outlen) {
+ /* RFC6979 3.2.h. */
+ static const OhByteType zero[1] = {0x00};
+ if (rng->retry) {
+ ql_hmac_t hmac;
+ hmac_init(&hmac, rng->k, 32);
+ hmac_write(&hmac, rng->v, 32);
+ hmac_write(&hmac, zero, 1);
+ hmac_final(&hmac, rng->k);
+ hmac_init(&hmac, rng->k, 32);
+ hmac_write(&hmac, rng->v, 32);
+ hmac_final(&hmac, rng->v);
+ }
+
+ while (outlen > 0) {
+ ql_hmac_t hmac;
+ int now = outlen;
+ hmac_init(&hmac, rng->k, 32);
+ hmac_write(&hmac, rng->v, 32);
+ hmac_final(&hmac, rng->v);
+ if (now > 32) {
+ now = 32;
+ }
+ memcpy(out, rng->v, now);
+ out += now;
+ outlen -= now;
+ }
+
+ rng->retry = 1;
+}
+
+// clear global parameter
+OhVoidType rfc6979_final(ql_rfc6979_t* rng) {
+ memset(rng->k, 0, 32);
+ memset(rng->v, 0, 32);
+ rng->retry = 0;
+}
+
+// We feed a byte array to the PRNG as input, consisting of:
+// - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d.
+// - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data.
+// - optionally 16 extra bytes with the algorithm name (the extra data bytes
+// are set to zeroes when not present, while the algorithm name is).
+OhVoidType rfc6979_nonce(OhByteType* nonce32, const OhByteType* msg32, const OhByteType* key32, const OhByteType* algo16, OhVoidType *data, OhSizeType counter) {
+ OhByteType keydata[112];
+ ql_rfc6979_t rng;
+
+ int keylen = 64;
+ int i;
+ memcpy(keydata, key32, 32);
+ memcpy(keydata + 32, msg32, 32);
+ if (data != NULL) {
+ memcpy(keydata + 64, data, 32);
+ keylen = 96;
+ }
+ if (algo16 != NULL) {
+ memset(keydata + keylen, 0, 96 - keylen);
+ memcpy(keydata + 96, algo16, 16);
+ keylen = 112;
+ }
+
+ rfc6979_init(&rng, keydata, keylen);
+ memset(keydata, 0, sizeof(keydata));
+ for (i = 0; i <= counter; i++) {
+ rfc6979_gen(&rng, nonce32, 32);
+ }
+ rfc6979_final(&rng);
+}
diff --git a/src/base/json.c b/src/base/json.c
new file mode 100644
index 0000000000000000000000000000000000000000..99bdd20afbff56ce043150e645666c0813497c18
--- /dev/null
+++ b/src/base/json.c
@@ -0,0 +1,759 @@
+/*
+ Copyright (c) 2009 Dave Gamble
+
+ 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.
+*/
+#include
+#include
+#include
+#include
+#include
+#include
+#include "json.h"
+
+static const char *ep;
+static void *(*cJSON_malloc)(size_t sz) = malloc;
+static void (*cJSON_free)(void *ptr) = free;
+
+const char *cJSON_GetErrorPtr(void) {return ep;}
+static int cJSON_strcasecmp(const char *s1,const char *s2)
+{
+ if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
+ for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0;
+ return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
+}
+static char* cJSON_strdup(const char* str)
+{
+ size_t len;
+ char* copy;
+
+ len = strlen(str) + 1;
+ if (!(copy = (char*)cJSON_malloc(len))) return 0;
+ memcpy(copy,str,len);
+ return copy;
+}
+
+void cJSON_InitHooks(cJSON_Hooks* hooks)
+{
+ if (!hooks) { /* Reset hooks */
+ cJSON_malloc = malloc;
+ cJSON_free = free;
+ return;
+ }
+
+ cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
+ cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
+}
+
+/* Internal constructor. */
+static cJSON *cJSON_New_Item(void)
+{
+ cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
+ if (node) memset(node,0,sizeof(cJSON));
+ return node;
+}
+
+/* Delete a cJSON structure. */
+void cJSON_Delete(cJSON *c)
+{
+ cJSON *next;
+ while (c)
+ {
+ next=c->next;
+ if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
+ if (!(c->type&cJSON_IsReference) && c->valueString) cJSON_free(c->valueString);
+ if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string);
+ cJSON_free(c);
+ c=next;
+ }
+}
+
+
+int power2 (int x, unsigned int y)
+{
+ int temp;
+ if (y == 0)
+ return 1;
+
+ temp = power2 (x, y / 2);
+ if ((y % 2) == 0)
+ return temp * temp;
+ else
+ return x * temp * temp;
+}
+
+/* Parse the input text to generate a number, and populate the result into item. */
+static const char *parse_number(cJSON *item,const char *num)
+{
+ double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
+
+ if (*num=='-') sign=-1,num++; /* Has sign? */
+ if (*num=='0') num++; /* is zero */
+ if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
+ if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */
+ if (*num=='e' || *num=='E') /* Exponent? */
+ { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */
+ while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */
+ }
+
+ n=sign*n*power2(10,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
+
+ item->valuedouble=n;
+ item->valueint=(int)n;
+ item->type=cJSON_Number;
+ return num;
+}
+
+static int pow2gt (int x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; return x+1; }
+
+typedef struct {char *buffer; int length; int offset; } printbuffer;
+
+static char* ensure(printbuffer *p,int needed)
+{
+ char *newbuffer;int newsize;
+ if (!p || !p->buffer) return 0;
+ needed+=p->offset;
+ if (needed<=p->length) return p->buffer+p->offset;
+
+ newsize=pow2gt(needed);
+ newbuffer=(char*)cJSON_malloc(newsize);
+ if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;}
+ if (newbuffer) memcpy(newbuffer,p->buffer,p->length);
+ cJSON_free(p->buffer);
+ p->length=newsize;
+ p->buffer=newbuffer;
+ return newbuffer+p->offset;
+}
+
+static int update(printbuffer *p)
+{
+ char *str;
+ if (!p || !p->buffer) return 0;
+ str=p->buffer+p->offset;
+ return p->offset+strlen(str);
+}
+
+#define floor (int)
+#define fabs(x) ((x) > 0? (x): -(x))
+
+/* Render the number nicely from the given item into a string. */
+static char *print_number(cJSON *item,printbuffer *p)
+{
+ char *str=0;
+ double d=item->valuedouble;
+ if (d==0)
+ {
+ if (p) str=ensure(p,2);
+ else str=(char*)cJSON_malloc(2); /* special case for 0. */
+ if (str) strcpy(str,"0");
+ }
+ else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
+ {
+ if (p) str=ensure(p,21);
+ else str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
+ if (str) sprintf(str,"%d",item->valueint);
+ }
+ else
+ {
+ if (p) str=ensure(p,64);
+ else str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */
+ if (str)
+ {
+ if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
+ else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d);
+ else sprintf(str,"%f",d);
+ }
+ }
+ return str;
+}
+
+static unsigned parse_hex4(const char *str)
+{
+ unsigned h=0;
+ if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+ h=h<<4;str++;
+ if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+ h=h<<4;str++;
+ if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+ h=h<<4;str++;
+ if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+ return h;
+}
+
+/* Parse the input text into an unescaped cstring, and populate item. */
+static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+static const char *parse_string(cJSON *item,const char *str)
+{
+ const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
+ if (*str!='\"') {ep=str;return 0;} /* not a string! */
+
+ while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
+
+ out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
+ if (!out) return 0;
+
+ ptr=str+1;ptr2=out;
+ while (*ptr!='\"' && *ptr)
+ {
+ if (*ptr!='\\') *ptr2++=*ptr++;
+ else
+ {
+ ptr++;
+ switch (*ptr)
+ {
+ case 'b': *ptr2++='\b'; break;
+ case 'f': *ptr2++='\f'; break;
+ case 'n': *ptr2++='\n'; break;
+ case 'r': *ptr2++='\r'; break;
+ case 't': *ptr2++='\t'; break;
+ case 'u': /* transcode utf16 to utf8. */
+ uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */
+
+ if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */
+
+ if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */
+ {
+ if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */
+ uc2=parse_hex4(ptr+3);ptr+=6;
+ if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */
+ uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
+ }
+
+ len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
+
+ switch (len) {
+ case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+ case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+ case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+ case 1: *--ptr2 =(uc | firstByteMark[len]);
+ }
+ ptr2+=len;
+ break;
+ default: *ptr2++=*ptr; break;
+ }
+ ptr++;
+ }
+ }
+ *ptr2=0;
+ if (*ptr=='\"') ptr++;
+ item->valueString=out;
+ item->type=cJSON_String;
+ return ptr;
+}
+
+/* Render the cstring provided to an escaped version that can be printed. */
+static char *print_string_ptr(const char *str,printbuffer *p)
+{
+ const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token;
+
+ for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0;
+ if (!flag)
+ {
+ len=ptr-str;
+ if (p) out=ensure(p,len+3);
+ else out=(char*)cJSON_malloc(len+3);
+ if (!out) return 0;
+ ptr2=out;*ptr2++='\"';
+ strcpy(ptr2,str);
+ ptr2[len]='\"';
+ ptr2[len+1]=0;
+ return out;
+ }
+
+ if (!str)
+ {
+ if (p) out=ensure(p,3);
+ else out=(char*)cJSON_malloc(3);
+ if (!out) return 0;
+ strcpy(out,"\"\"");
+ return out;
+ }
+ ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
+
+ if (p) out=ensure(p,len+3);
+ else out=(char*)cJSON_malloc(len+3);
+ if (!out) return 0;
+
+ ptr2=out;ptr=str;
+ *ptr2++='\"';
+ while (*ptr)
+ {
+ if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
+ else
+ {
+ *ptr2++='\\';
+ switch (token=*ptr++)
+ {
+ case '\\': *ptr2++='\\'; break;
+ case '\"': *ptr2++='\"'; break;
+ case '\b': *ptr2++='b'; break;
+ case '\f': *ptr2++='f'; break;
+ case '\n': *ptr2++='n'; break;
+ case '\r': *ptr2++='r'; break;
+ case '\t': *ptr2++='t'; break;
+ default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */
+ }
+ }
+ }
+ *ptr2++='\"';*ptr2++=0;
+ return out;
+}
+/* Invote print_string_ptr (which is useful) on an item. */
+static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valueString,p);}
+
+/* Predeclare these prototypes. */
+static const char *parse_value(cJSON *item,const char *value);
+static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p);
+static const char *parse_array(cJSON *item,const char *value);
+static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p);
+static const char *parse_object(cJSON *item,const char *value);
+static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p);
+
+/* Utility to jump whitespace and cr/lf */
+static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
+
+/* Parse an object - create a new root, and populate. */
+cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
+{
+ const char *end=0;
+ cJSON *c=cJSON_New_Item();
+ ep=0;
+ if (!c) return 0; /* memory fail */
+
+ end=parse_value(c,skip(value));
+ if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */
+
+ /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
+ if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
+ if (return_parse_end) *return_parse_end=end;
+ return c;
+}
+/* Default options for cJSON_Parse */
+cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
+
+/* Render a cJSON item/entity/structure to text. */
+char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);}
+char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);}
+
+char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt)
+{
+ printbuffer p;
+ p.buffer=(char*)cJSON_malloc(prebuffer);
+ p.length=prebuffer;
+ p.offset=0;
+ return print_value(item,0,fmt,&p);
+ return p.buffer;
+}
+
+
+/* Parser core - when encountering text, process appropriately. */
+static const char *parse_value(cJSON *item,const char *value)
+{
+ if (!value) return 0; /* Fail on null. */
+ if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
+ if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
+ if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
+ if (*value=='\"') { return parse_string(item,value); }
+ if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
+ if (*value=='[') { return parse_array(item,value); }
+ if (*value=='{') { return parse_object(item,value); }
+
+ ep=value;return 0; /* failure. */
+}
+
+/* Render a value to text. */
+static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)
+{
+ char *out=0;
+ if (!item) return 0;
+ if (p)
+ {
+ switch ((item->type)&255)
+ {
+ case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break;}
+ case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break;}
+ case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break;}
+ case cJSON_Number: out=print_number(item,p);break;
+ case cJSON_String: out=print_string(item,p);break;
+ case cJSON_Array: out=print_array(item,depth,fmt,p);break;
+ case cJSON_Object: out=print_object(item,depth,fmt,p);break;
+ }
+ }
+ else
+ {
+ switch ((item->type)&255)
+ {
+ case cJSON_NULL: out=cJSON_strdup("null"); break;
+ case cJSON_False: out=cJSON_strdup("false");break;
+ case cJSON_True: out=cJSON_strdup("true"); break;
+ case cJSON_Number: out=print_number(item,0);break;
+ case cJSON_String: out=print_string(item,0);break;
+ case cJSON_Array: out=print_array(item,depth,fmt,0);break;
+ case cJSON_Object: out=print_object(item,depth,fmt,0);break;
+ }
+ }
+ return out;
+}
+
+/* Build an array from input text. */
+static const char *parse_array(cJSON *item,const char *value)
+{
+ cJSON *child;
+ if (*value!='[') {ep=value;return 0;} /* not an array! */
+
+ item->type=cJSON_Array;
+ value=skip(value+1);
+ if (*value==']') return value+1; /* empty array. */
+
+ item->child=child=cJSON_New_Item();
+ if (!item->child) return 0; /* memory fail */
+ value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
+ if (!value) return 0;
+
+ while (*value==',')
+ {
+ cJSON *new_item;
+ if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
+ child->next=new_item;new_item->prev=child;child=new_item;
+ value=skip(parse_value(child,skip(value+1)));
+ if (!value) return 0; /* memory fail */
+ }
+
+ if (*value==']') return value+1; /* end of array */
+ ep=value;return 0; /* malformed. */
+}
+
+/* Render an array to text */
+static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)
+{
+ char **entries;
+ char *out=0,*ptr,*ret;int len=5;
+ cJSON *child=item->child;
+ int numentries=0,i=0,fail=0;
+ size_t tmplen=0;
+
+ /* How many entries in the array? */
+ while (child) numentries++,child=child->next;
+ /* Explicitly handle numentries==0 */
+ if (!numentries)
+ {
+ if (p) out=ensure(p,3);
+ else out=(char*)cJSON_malloc(3);
+ if (out) strcpy(out,"[]");
+ return out;
+ }
+
+ if (p)
+ {
+ /* Compose the output array. */
+ i=p->offset;
+ ptr=ensure(p,1);if (!ptr) return 0; *ptr='['; p->offset++;
+ child=item->child;
+ while (child && !fail)
+ {
+ print_value(child,depth+1,fmt,p);
+ p->offset=update(p);
+ if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;}
+ child=child->next;
+ }
+ ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0;
+ out=(p->buffer)+i;
+ }
+ else
+ {
+ /* Allocate an array to hold the values for each */
+ entries=(char**)cJSON_malloc(numentries*sizeof(char*));
+ if (!entries) return 0;
+ memset(entries,0,numentries*sizeof(char*));
+ /* Retrieve all the results: */
+ child=item->child;
+ while (child && !fail)
+ {
+ ret=print_value(child,depth+1,fmt,0);
+ entries[i++]=ret;
+ if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
+ child=child->next;
+ }
+
+ /* If we didn't fail, try to malloc the output string */
+ if (!fail) out=(char*)cJSON_malloc(len);
+ /* If that fails, we fail. */
+ if (!out) fail=1;
+
+ /* Handle failure. */
+ if (fail)
+ {
+ for (i=0;itype=cJSON_Object;
+ value=skip(value+1);
+ if (*value=='}') return value+1; /* empty array. */
+
+ item->child=child=cJSON_New_Item();
+ if (!item->child) return 0;
+ value=skip(parse_string(child,skip(value)));
+ if (!value) return 0;
+ child->string=child->valueString;child->valueString=0;
+ if (*value!=':') {ep=value;return 0;} /* fail! */
+ value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
+ if (!value) return 0;
+
+ while (*value==',')
+ {
+ cJSON *new_item;
+ if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
+ child->next=new_item;new_item->prev=child;child=new_item;
+ value=skip(parse_string(child,skip(value+1)));
+ if (!value) return 0;
+ child->string=child->valueString;child->valueString=0;
+ if (*value!=':') {ep=value;return 0;} /* fail! */
+ value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
+ if (!value) return 0;
+ }
+
+ if (*value=='}') return value+1; /* end of array */
+ ep=value;return 0; /* malformed. */
+}
+
+/* Render an object to text. */
+static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)
+{
+ char **entries=0,**names=0;
+ char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
+ cJSON *child=item->child;
+ int numentries=0,fail=0;
+ size_t tmplen=0;
+ /* Count the number of entries. */
+ while (child) numentries++,child=child->next;
+ /* Explicitly handle empty object case */
+ if (!numentries)
+ {
+ if (p) out=ensure(p,fmt?depth+4:3);
+ else out=(char*)cJSON_malloc(fmt?depth+4:3);
+ if (!out) return 0;
+ ptr=out;*ptr++='{';
+ if (fmt) {*ptr++='\n';for (i=0;ioffset;
+ len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0;
+ *ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len;
+ child=item->child;depth++;
+ while (child)
+ {
+ if (fmt)
+ {
+ ptr=ensure(p,depth); if (!ptr) return 0;
+ for (j=0;joffset+=depth;
+ }
+ print_string_ptr(child->string,p);
+ p->offset=update(p);
+
+ len=fmt?2:1;
+ ptr=ensure(p,len); if (!ptr) return 0;
+ *ptr++=':';if (fmt) *ptr++='\t';
+ p->offset+=len;
+
+ print_value(child,depth,fmt,p);
+ p->offset=update(p);
+
+ len=(fmt?1:0)+(child->next?1:0);
+ ptr=ensure(p,len+1); if (!ptr) return 0;
+ if (child->next) *ptr++=',';
+ if (fmt) *ptr++='\n';*ptr=0;
+ p->offset+=len;
+ child=child->next;
+ }
+ ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0;
+ if (fmt) for (i=0;ibuffer)+i;
+ }
+ else
+ {
+ /* Allocate space for the names and the objects */
+ entries=(char**)cJSON_malloc(numentries*sizeof(char*));
+ if (!entries) return 0;
+ names=(char**)cJSON_malloc(numentries*sizeof(char*));
+ if (!names) {cJSON_free(entries);return 0;}
+ memset(entries,0,sizeof(char*)*numentries);
+ memset(names,0,sizeof(char*)*numentries);
+
+ /* Collect all the results into our arrays: */
+ child=item->child;depth++;if (fmt) len+=depth;
+ while (child)
+ {
+ names[i]=str=print_string_ptr(child->string,0);
+ entries[i++]=ret=print_value(child,depth,fmt,0);
+ if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
+ child=child->next;
+ }
+
+ /* Try to allocate the output string */
+ if (!fail) out=(char*)cJSON_malloc(len);
+ if (!out) fail=1;
+
+ /* Handle failure */
+ if (fail)
+ {
+ for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;}
+cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;}
+cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
+
+/* Utility for array list handling. */
+static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
+/* Utility for handling references. */
+static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}
+
+/* Add item to array/object. */
+void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
+void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
+void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);}
+void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));}
+void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}
+
+cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
+ if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
+void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
+cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
+void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
+
+/* Replace array/object items with new ones. */
+void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;}
+ newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;}
+void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
+ newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
+ if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
+void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}
+
+/* Create basic types: */
+cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
+cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
+cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
+cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
+cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
+cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valueString=cJSON_strdup(string);}return item;}
+cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
+cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
+
+/* Create Arrays: */
+cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;}
+
+/* Duplication */
+cJSON *cJSON_Duplicate(cJSON *item,int recurse)
+{
+ cJSON *newitem,*cptr,*nptr=0,*newchild;
+ /* Bail on bad ptr */
+ if (!item) return 0;
+ /* Create new item */
+ newitem=cJSON_New_Item();
+ if (!newitem) return 0;
+ /* Copy over all vars */
+ newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
+ if (item->valueString) {newitem->valueString=cJSON_strdup(item->valueString); if (!newitem->valueString) {cJSON_Delete(newitem);return 0;}}
+ if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}}
+ /* If non-recursive, then we're done! */
+ if (!recurse) return newitem;
+ /* Walk the ->next chain for the child. */
+ cptr=item->child;
+ while (cptr)
+ {
+ newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */
+ if (!newchild) {cJSON_Delete(newitem);return 0;}
+ if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */
+ else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */
+ cptr=cptr->next;
+ }
+ return newitem;
+}
+
+void cJSON_Minify(char *json)
+{
+ char *into=json;
+ while (*json)
+ {
+ if (*json==' ') json++;
+ else if (*json=='\t') json++; /* Whitespace characters. */
+ else if (*json=='\r') json++;
+ else if (*json=='\n') json++;
+ else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; /* double-slash comments, to end of line. */
+ else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} /* multiline comments. */
+ else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */
+ else *into++=*json++; /* All other characters. */
+ }
+ *into=0; /* and null-terminate. */
+}
diff --git a/src/base/keccak256.c b/src/base/keccak256.c
new file mode 100644
index 0000000000000000000000000000000000000000..c3e389beb3ef648595638038a1e5c6d2cdd4bd85
--- /dev/null
+++ b/src/base/keccak256.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "keccak256.h"
+
+#define BLOCK_SIZE ((1600 - 256 * 2) / 8)
+#define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n))))
+#define le2me_64(x) (x)
+#define IS_ALIGNED_64(p) (0 == (7 & ((const OhByteType *)(p) - (const OhByteType *)0)))
+#define me64_to_le_str(to, from, length) memcpy((to), (from), (length))
+
+// -----------------------
+// sub-operation process
+// THETA RHO PI CHI ROUND
+// -----------------------
+#define TYPE_ROUND_INFO 0
+#define TYPE_PI_TRANSFORM 24
+#define TYPE_RHO_TRANSFORM 48
+const OhUint8Type constants[] = {
+ 1, 26, 94, 112, 31, 33, 121, 85, 14, 12, 53, 38, 63, 79, 93, 83, 82, 72, 22, 102, 121, 88, 33, 116,
+ 1, 6, 9, 22, 14, 20, 2, 12, 13, 19, 23, 15, 4, 24, 21, 8, 16, 5, 3, 18, 17, 11, 7, 10,
+ 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14,
+};
+OhUint8Type getConstant(OhUint8Type type, OhUint8Type index) {
+ return constants[type + index];
+}
+
+// Keccak theta() transformation
+static OhVoidType keccak_theta(OhUint64Type *A) {
+
+ OhUint64Type C[5], D[5];
+ OhUint8Type i, j;
+ for (i = 0; i < 5; i++) {
+ C[i] = A[i];
+ for (j = 5; j < 25; j += 5) { C[i] ^= A[i + j]; }
+ }
+ for (i = 0; i < 5; i++) {
+ D[i] = ROTL64(C[(i + 1) % 5], 1) ^ C[(i + 4) % 5];
+ }
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 25; j += 5) { A[i + j] ^= D[i]; }
+ }
+}
+
+// Keccak pi() transformation
+static OhVoidType keccak_pi(OhUint64Type *A) {
+
+ OhUint64Type A1 = A[1];
+ OhUint8Type i;
+ for (i = 1; i < 24; i++) {
+ A[getConstant(TYPE_PI_TRANSFORM, i - 1)] = A[getConstant(TYPE_PI_TRANSFORM, i)];
+ }
+ A[10] = A1;
+}
+
+// Keccak chi() transformation
+static OhVoidType keccak_chi(OhUint64Type *A) {
+
+ OhUint8Type i;
+ for (i = 0; i < 25; i += 5) {
+ OhUint64Type A0 = A[0 + i], A1 = A[1 + i];
+ A[0 + i] ^= ~A1 & A[2 + i];
+ A[1 + i] ^= ~A[2 + i] & A[3 + i];
+ A[2 + i] ^= ~A[3 + i] & A[4 + i];
+ A[3 + i] ^= ~A[4 + i] & A0;
+ A[4 + i] ^= ~A0 & A1;
+ }
+}
+
+// Keccak l() transformation
+static OhUint64Type get_round_constant(OhUint8Type round) {
+
+ OhUint64Type result = 0;
+ OhUint8Type roundInfo = getConstant(TYPE_ROUND_INFO, round);
+ if (roundInfo & (1 << 6)) { result |= ((OhUint64Type) 1 << 63); }
+ if (roundInfo & (1 << 5)) { result |= ((OhUint64Type) 1 << 31); }
+ if (roundInfo & (1 << 4)) { result |= ((OhUint64Type) 1 << 15); }
+ if (roundInfo & (1 << 3)) { result |= ((OhUint64Type) 1 << 7); }
+ if (roundInfo & (1 << 2)) { result |= ((OhUint64Type) 1 << 3); }
+ if (roundInfo & (1 << 1)) { result |= ((OhUint64Type) 1 << 1); }
+ if (roundInfo & (1 << 0)) { result |= ((OhUint64Type) 1 << 0); }
+ return result;
+}
+
+// make a permutation of the hash
+static OhVoidType sha3_permutation(OhUint64Type *state) {
+ OhUint8Type round, i;
+ for (round = 0; round < 24; round++) {
+ keccak_theta(state); // 1
+ for (i = 1; i < 25; i++) { // 2 apply Keccak rho() transformation
+ state[i] = ROTL64(state[i], getConstant(TYPE_RHO_TRANSFORM, i - 1));
+ }
+ keccak_pi(state); // 3
+ keccak_chi(state); // 4
+ *state ^= get_round_constant(round); // 5 apply iota(state, round)
+ }
+}
+
+// The core transformation. Process the specified block of data
+static OhVoidType sha3_process_block(OhUint64Type hash[25], const OhUint64Type *block) {
+ OhUint8Type i;
+ for (i = 0; i < 17; i++) {
+ hash[i] ^= le2me_64(block[i]);
+ }
+ sha3_permutation(hash);
+}
+
+// -----------------------
+// Calculate message hash
+// -----------------------
+// define sha3 content
+typedef struct sha3_ctx_t {
+ OhUint64Type hash[SHA3_MAX_PERMUTATION_SIZE]; // 1600 bits algorithm hashing state
+ OhUint64Type message[SHA3_MAX_RATE_IN_QWORDS]; // 1536-bit buffer for leftovers
+ OhUint16Type rest; // count of bytes in the message[] buffer
+} sha3_ctx_t;
+
+// sha3 buffer init
+// ctx : the algorithm context containing current hashing state
+OhVoidType keccak_init(sha3_ctx_t *ctx) {
+ memset(ctx, 0, sizeof(sha3_ctx_t));
+}
+
+// Calculate message hash. Can be called repeatedly with chunks of the message to be hashed.
+// ctx : the algorithm context containing current hashing state
+// msg : message chunk
+OhVoidType keccak_update(sha3_ctx_t *ctx, const OhByteType *msg, OhUint16Type size) {
+
+ OhUint16Type idx = ctx->rest;
+ ctx->rest = (ctx->rest + size) % BLOCK_SIZE;
+ /* fill partial block */
+ if (idx) {
+ OhUint16Type left = BLOCK_SIZE - idx;
+ memcpy((OhByteType *) ctx->message + idx, msg, (size < left ? size : left));
+ if (size < left) return;
+ /* process partial block */
+ sha3_process_block(ctx->hash, ctx->message);
+ msg += left;
+ size -= left;
+ }
+ while (size >= BLOCK_SIZE) {
+ OhUint64Type *aligned_message_block;
+ if (IS_ALIGNED_64(msg)) {
+ // the most common case is processing of an already aligned message without copying it
+ aligned_message_block = (OhUint64Type *) (void *) msg;
+ } else {
+ memcpy(ctx->message, msg, BLOCK_SIZE);
+ aligned_message_block = ctx->message;
+ }
+ sha3_process_block(ctx->hash, aligned_message_block);
+ msg += BLOCK_SIZE;
+ size -= BLOCK_SIZE;
+ }
+ if (size) {
+ memcpy(ctx->message, msg, size); /* save leftovers */
+ }
+}
+
+// Store calculated hash into the given array.
+// ctx : the algorithm context containing current hashing state
+// param : result calculated hash in binary form
+OhVoidType keccak_final(sha3_ctx_t *ctx, OhByteType *result) {
+
+ OhUint16Type digest_length = 100 - BLOCK_SIZE / 2;
+ /* clear the rest of the data queue */
+ memset((OhByteType *) ctx->message + ctx->rest, 0, BLOCK_SIZE - ctx->rest);
+ ((OhByteType *) ctx->message)[ctx->rest ] |= 0x01;
+ ((OhByteType *) ctx->message)[BLOCK_SIZE - 1] |= 0x80;
+ /* process final block */
+ sha3_process_block(ctx->hash, ctx->message);
+ if (result) {
+ me64_to_le_str(result, ctx->hash, digest_length);
+ }
+}
+
+// keccak256 is the package of keccak_init keccak_update keccak_final.
+// msg : the raw data need to hash
+// size : data length
+// hashbuf : store result after keccak256
+OhVoidType keccak256(const OhByteType *msg, OhUint32Type size, OhByteType **hashbuf) {
+ sha3_ctx_t ctx;
+ keccak_init(&ctx);
+ keccak_update(&ctx, msg, size);
+ keccak_final(&ctx, *hashbuf);
+}
+
+// -----------------------
+// Test function
+// -----------------------
+// print result (hex data = 32 byte)
+OhVoidType print_keccak_data(OhByteType *out){
+ OhByteType buf[65];
+ OhUint8Type i;
+ for(i = 0; i < 32; i ++){
+ buf[i*2] = ((out[i] & 0xf0) >> 4) <=9 ? ((out[i] & 0xf0) >> 4) + '0' : ((out[i] & 0xf0) >> 4) + 'a' - 10;
+ buf[i*2+1] = ((out[i] & 0x0f) ) <=9 ? ((out[i] & 0x0f) ) + '0' : ((out[i] & 0x0f) ) + 'a' - 10;
+ }
+ buf[64] = '\0';
+ log_info("[keccak data] %s",buf);
+}
diff --git a/src/base/log.c b/src/base/log.c
new file mode 100644
index 0000000000000000000000000000000000000000..a8e3fed067a4a33a7dad3c566fb0e830ccefd6f9
--- /dev/null
+++ b/src/base/log.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "log.h"
+// -----------------------
+// Log Config
+// -----------------------
+static struct {
+ OhLongLevel level;
+ OhBoolType quiet;
+} L;
+OhVoidType LogSetLevel(OhLongLevel level) {
+ L.level = level;
+}
+OhVoidType LogSetQuiet(OhBoolType enable) {
+ L.quiet = enable;
+}
+
+// -----------------------
+// Log Callback Handle
+// -----------------------
+PrintLogCallback printHandle = NULL;
+OhVoidType SetPrintLogCallback(PrintLogCallback callback){
+ printHandle = callback;
+}
+GetTimeCallback getTimeHandle = NULL;
+OhVoidType SetGetTimeCallback(GetTimeCallback callback){
+ getTimeHandle = callback;
+}
+
+// -----------------------
+// Log Output
+// -----------------------
+static const char *levelStrings[] = {
+ "DEBUG", "INFO", "WARN", "ERROR"
+};
+
+#ifdef LOG_USE_COLOR
+static const char *levelColors[] = {
+ "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m"
+};
+#endif
+
+static char logTitle[160];
+static char logDetail[LOG_MAX_SIZE];
+
+OhVoidType Logs(OhLongLevel l, const char *file, int line, const char *fmt, ...) {
+
+ va_list ap;
+ // param type convert
+ int level = (int)l;
+ // Get Time
+#ifdef LOG_USE_TITLE
+ char timeBuf[16] = {'\0'};
+ if(getTimeHandle){
+ getTimeHandle(timeBuf, 16);
+ }
+#endif
+ // Format
+ if (!L.quiet && level >= L.level) {
+ memset(logTitle, 0, 160);
+ memset(logDetail, 0, LOG_MAX_SIZE);
+#ifdef LOG_USE_TITLE
+ #ifdef LOG_USE_COLOR
+ sprintf( logTitle, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ",
+ timeBuf, levelColors[level], levelStrings[level], file, line);
+ #else
+ sprintf( logTitle, "%s %-5s %s:%d: ",
+ timeBuf, levelStrings[level], file, line);
+ #endif
+#endif
+ // Get Param
+ va_start(ap, fmt);
+ vsnprintf( logDetail, sizeof(logDetail), fmt, ap);
+ va_end(ap);
+
+ if(printHandle){
+#ifdef LOG_USE_TITLE
+ printHandle(logTitle);
+#endif
+ printHandle(logDetail);
+ printHandle("\n");
+ }
+ }
+}
+
diff --git a/src/base/md5.c b/src/base/md5.c
new file mode 100644
index 0000000000000000000000000000000000000000..d2c37c0376014bc8dd94c091cd44391a05df7675
--- /dev/null
+++ b/src/base/md5.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "md5.h"
+
+#define F(x,y,z) ((x & y) | (~x & z))
+#define G(x,y,z) ((x & z) | (y & ~z))
+#define H(x,y,z) (x^y^z)
+#define I(x,y,z) (y ^ (x | ~z))
+#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))
+#define FF(a,b,c,d,x,s,ac) \
+ { \
+ a += F(b,c,d) + x + ac; \
+ a = ROTATE_LEFT(a,s); \
+ a += b; \
+ }
+#define GG(a,b,c,d,x,s,ac) \
+ { \
+ a += G(b,c,d) + x + ac; \
+ a = ROTATE_LEFT(a,s); \
+ a += b; \
+ }
+#define HH(a,b,c,d,x,s,ac) \
+ { \
+ a += H(b,c,d) + x + ac; \
+ a = ROTATE_LEFT(a,s); \
+ a += b; \
+ }
+#define II(a,b,c,d,x,s,ac) \
+ { \
+ a += I(b,c,d) + x + ac; \
+ a = ROTATE_LEFT(a,s); \
+ a += b; \
+ }
+
+OhByteType PADDING[] = {
+ 0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
+
+OhVoidType MD5Init(MD5_CTX *context) {
+ context->count[0] = 0;
+ context->count[1] = 0;
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+}
+
+OhVoidType MD5Update(MD5_CTX *context,OhByteType *input,OhUint32Type inputlen)
+{
+ OhUint32Type i = 0,index = 0,partlen = 0;
+ index = (context->count[0] >> 3) & 0x3F;
+ partlen = 64 - index;
+ context->count[0] += inputlen << 3;
+ if(context->count[0] < (inputlen << 3)) {
+ context->count[1]++;
+ }
+ context->count[1] += inputlen >> 29;
+
+ if(inputlen >= partlen) {
+ memcpy(&context->buffer[index],input,partlen);
+ MD5Transform(context->state,context->buffer);
+ for(i = partlen;i+64 <= inputlen;i+=64) {
+ MD5Transform(context->state,&input[i]);
+ }
+ index = 0;
+ } else {
+ i = 0;
+ }
+
+ memcpy(&context->buffer[index],&input[i],inputlen-i);
+}
+
+OhVoidType MD5Final(MD5_CTX *context,OhByteType digest[16]) {
+ OhUint32Type index = 0,padlen = 0;
+ OhByteType bits[8];
+ index = (context->count[0] >> 3) & 0x3F;
+ padlen = (index < 56)?(56-index):(120-index);
+ MD5Encode(bits,context->count,8);
+ MD5Update(context,PADDING,padlen);
+ MD5Update(context,bits,8);
+ MD5Encode(digest,context->state,16);
+}
+
+OhVoidType MD5Encode(OhByteType *output,OhUint32Type *input,OhUint32Type len) {
+ OhUint32Type i = 0,j = 0;
+ while(j < len) {
+ output[j] = input[i] & 0xFF;
+ output[j+1] = (input[i] >> 8) & 0xFF;
+ output[j+2] = (input[i] >> 16) & 0xFF;
+ output[j+3] = (input[i] >> 24) & 0xFF;
+ i++;
+ j+=4;
+ }
+}
+
+OhVoidType MD5Decode(OhUint32Type *output,OhByteType *input,OhUint32Type len) {
+ OhUint32Type i = 0,j = 0;
+ while(j < len) {
+ output[i] = (input[j]) | (input[j+1] << 8) | (input[j+2] << 16) | (input[j+3] << 24);
+ i++;
+ j+=4;
+ }
+}
+
+OhVoidType MD5Transform(OhUint32Type state[4],OhByteType block[64]) {
+ OhUint32Type a = state[0];
+ OhUint32Type b = state[1];
+ OhUint32Type c = state[2];
+ OhUint32Type d = state[3];
+ OhUint32Type x[64];
+
+ MD5Decode(x,block,64);
+
+ FF(a, b, c, d, x[ 0], 7, 0xd76aa478);
+ FF(d, a, b, c, x[ 1], 12, 0xe8c7b756);
+ FF(c, d, a, b, x[ 2], 17, 0x242070db);
+ FF(b, c, d, a, x[ 3], 22, 0xc1bdceee);
+ FF(a, b, c, d, x[ 4], 7, 0xf57c0faf);
+ FF(d, a, b, c, x[ 5], 12, 0x4787c62a);
+ FF(c, d, a, b, x[ 6], 17, 0xa8304613);
+ FF(b, c, d, a, x[ 7], 22, 0xfd469501);
+ FF(a, b, c, d, x[ 8], 7, 0x698098d8);
+ FF(d, a, b, c, x[ 9], 12, 0x8b44f7af);
+ FF(c, d, a, b, x[10], 17, 0xffff5bb1);
+ FF(b, c, d, a, x[11], 22, 0x895cd7be);
+ FF(a, b, c, d, x[12], 7, 0x6b901122);
+ FF(d, a, b, c, x[13], 12, 0xfd987193);
+ FF(c, d, a, b, x[14], 17, 0xa679438e);
+ FF(b, c, d, a, x[15], 22, 0x49b40821);
+
+ GG(a, b, c, d, x[ 1], 5, 0xf61e2562);
+ GG(d, a, b, c, x[ 6], 9, 0xc040b340);
+ GG(c, d, a, b, x[11], 14, 0x265e5a51);
+ GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa);
+ GG(a, b, c, d, x[ 5], 5, 0xd62f105d);
+ GG(d, a, b, c, x[10], 9, 0x2441453);
+ GG(c, d, a, b, x[15], 14, 0xd8a1e681);
+ GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8);
+ GG(a, b, c, d, x[ 9], 5, 0x21e1cde6);
+ GG(d, a, b, c, x[14], 9, 0xc33707d6);
+ GG(c, d, a, b, x[ 3], 14, 0xf4d50d87);
+ GG(b, c, d, a, x[ 8], 20, 0x455a14ed);
+ GG(a, b, c, d, x[13], 5, 0xa9e3e905);
+ GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8);
+ GG(c, d, a, b, x[ 7], 14, 0x676f02d9);
+ GG(b, c, d, a, x[12], 20, 0x8d2a4c8a);
+
+
+ HH(a, b, c, d, x[ 5], 4, 0xfffa3942);
+ HH(d, a, b, c, x[ 8], 11, 0x8771f681);
+ HH(c, d, a, b, x[11], 16, 0x6d9d6122);
+ HH(b, c, d, a, x[14], 23, 0xfde5380c);
+ HH(a, b, c, d, x[ 1], 4, 0xa4beea44);
+ HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9);
+ HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60);
+ HH(b, c, d, a, x[10], 23, 0xbebfbc70);
+ HH(a, b, c, d, x[13], 4, 0x289b7ec6);
+ HH(d, a, b, c, x[ 0], 11, 0xeaa127fa);
+ HH(c, d, a, b, x[ 3], 16, 0xd4ef3085);
+ HH(b, c, d, a, x[ 6], 23, 0x4881d05);
+ HH(a, b, c, d, x[ 9], 4, 0xd9d4d039);
+ HH(d, a, b, c, x[12], 11, 0xe6db99e5);
+ HH(c, d, a, b, x[15], 16, 0x1fa27cf8);
+ HH(b, c, d, a, x[ 2], 23, 0xc4ac5665);
+
+
+ II(a, b, c, d, x[ 0], 6, 0xf4292244);
+ II(d, a, b, c, x[ 7], 10, 0x432aff97);
+ II(c, d, a, b, x[14], 15, 0xab9423a7);
+ II(b, c, d, a, x[ 5], 21, 0xfc93a039);
+ II(a, b, c, d, x[12], 6, 0x655b59c3);
+ II(d, a, b, c, x[ 3], 10, 0x8f0ccc92);
+ II(c, d, a, b, x[10], 15, 0xffeff47d);
+ II(b, c, d, a, x[ 1], 21, 0x85845dd1);
+ II(a, b, c, d, x[ 8], 6, 0x6fa87e4f);
+ II(d, a, b, c, x[15], 10, 0xfe2ce6e0);
+ II(c, d, a, b, x[ 6], 15, 0xa3014314);
+ II(b, c, d, a, x[13], 21, 0x4e0811a1);
+ II(a, b, c, d, x[ 4], 6, 0xf7537e82);
+ II(d, a, b, c, x[11], 10, 0xbd3af235);
+ II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb);
+ II(b, c, d, a, x[ 9], 21, 0xeb86d391);
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+}
diff --git a/src/base/x509.c b/src/base/x509.c
new file mode 100644
index 0000000000000000000000000000000000000000..4615a84544e5c0999cc3f7e507bfa968ae5ecef1
--- /dev/null
+++ b/src/base/x509.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "x509.h"
+
+// ----------------------------------------------
+// x509 type definition
+// ----------------------------------------------
+typedef OhByteType X509ByteType;
+typedef OhInt32Type X509SizeType;
+typedef OhErrType X509ErrType;
+typedef OhVoidType X509VoidType;
+
+// ----------------------------------------------
+// Base64 Decoder
+// ----------------------------------------------
+static const X509ByteType base64DecMap[128] = {
+ 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+ 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+ 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+ 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+ 127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
+ 54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
+ 127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 127, 127, 127, 127, 127
+ };
+static const X509ByteType base64EncMap[64] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
+ 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', '+', '/'
+ };
+
+// -- base64 decoding function --
+X509ErrType Base64Decode(X509ByteType* dst, X509SizeType dlen, X509SizeType *olen,
+ X509ByteType* src, X509SizeType slen) {
+ X509SizeType i, n, j, x;
+ X509ByteType *p;
+ // First check for validity and get output length
+ for(i = n = j = 0; i < slen; i++) {
+ // Skip spaces before checking for EOL
+ x = 0;
+ while(i < slen && src[i] == ' '){
+ ++i;
+ ++x;
+ }
+ // Spaces at end of buffer are OK
+ if(i == slen) {
+ break;
+ }
+ if((slen - i) >= 2 && src[i] == '\r' && src[i + 1] == '\n') {
+ continue;
+ }
+ if(src[i] == '\n') {
+ continue;
+ }
+ // Space inside a line is an error (INVALID_CHARACTER)
+ if(x != 0) {
+ return X509_ERR_BASE64_INVALID_CHAR;
+ }
+ if(src[i] == '=' && ++j > 2){
+ return X509_ERR_BASE64_INVALID_CHAR;
+ }
+ if(src[i] > 127 || base64DecMap[src[i]] == 127) {
+ return X509_ERR_BASE64_INVALID_CHAR;
+ }
+ if(base64DecMap[src[i]] < 64 && j != 0) {
+ return X509_ERR_BASE64_INVALID_CHAR;
+ }
+ n++;
+ }
+ if( n == 0 ) {
+ *olen = 0;
+ return X509_SUCCESS;
+ }
+ // The following expression is to calculate the following formula without risk of integer overflow in n
+ n = (6 * ( n >> 3)) + ((6 * (n & 0x7) + 7) >> 3);
+ n -= j;
+ // BUFFER is too SMALL
+ if(dst == NULL || dlen < n) {
+ *olen = n;
+ return X509_ERR_BASE64_BUF_TOO_SMALL;
+ }
+ // decode base64
+ for(j = 3, n = x = 0, p = dst; i > 0; i--, src++) {
+ if( *src == '\r' || *src == '\n' || *src == ' ' )
+ continue;
+ j -= (base64DecMap[*src] == 64);
+ x = ( x << 6 ) | ( base64DecMap[*src] & 0x3F );
+ if(++n == 4) {
+ n = 0;
+ if( j > 0 ) {
+ *p++ = (unsigned char)( x >> 16 );
+ }
+ if( j > 1 ) {
+ *p++ = (unsigned char)( x >> 8 );
+ }
+ if( j > 2 ) {
+ *p++ = (unsigned char)( x );
+ }
+ }
+ }
+ *olen = p - dst;
+ return X509_SUCCESS;
+}
+
+// -- base64 encoding function --
+#define BASE64_SIZE_T_MAX 65535
+X509ErrType Base64Encode(X509ByteType* dst,
+ X509SizeType dlen,
+ X509SizeType *olen,
+ X509ByteType* src,
+ X509SizeType slen) {
+ X509SizeType i, n, C1, C2, C3;
+ X509ByteType *p;
+
+ if(slen == 0) {
+ *olen = 0;
+ return X509_SUCCESS;
+ }
+ n = slen / 3 + ( slen % 3 != 0 );
+ if(n > ( BASE64_SIZE_T_MAX - 1 ) / 4) {
+ *olen = BASE64_SIZE_T_MAX;
+ return X509_ERR_BASE64_BUF_TOO_SMALL;
+ }
+ n *= 4;
+ if(( dlen < n + 1 ) || ( NULL == dst )){
+ *olen = n + 1;
+ return X509_ERR_BASE64_BUF_TOO_SMALL;
+ }
+ n = (slen / 3) * 3;
+ for(i = 0, p = dst; i < n; i += 3) {
+ C1 = *src++;
+ C2 = *src++;
+ C3 = *src++;
+ *p++ = base64EncMap[(C1 >> 2) & 0x3F];
+ *p++ = base64EncMap[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+ *p++ = base64EncMap[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
+ *p++ = base64EncMap[C3 & 0x3F];
+ }
+ if(i < slen) {
+ C1 = *src++;
+ C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
+ *p++ = base64EncMap[(C1 >> 2) & 0x3F];
+ *p++ = base64EncMap[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+ if( ( i + 1 ) < slen ){
+ *p++ = base64EncMap[((C2 & 15) << 2) & 0x3F];
+ }
+ else {
+ *p++ = '=';
+ }
+ *p++ = '=';
+ }
+ *olen = p - dst;
+ *p = 0;
+ return X509_SUCCESS;
+}
+
+// ----------------------------------------------
+// item Decoder
+// ----------------------------------------------
+// -- length info data struct --
+typedef struct {
+ X509SizeType len; // data length
+ X509SizeType lenLen; // length of length
+} X509LenType;
+
+// -- Analyze the data length according to the value, the process conforms to the asn.1 standard --
+// -- data : Data array address --
+// -- i : offset --
+X509LenType GelLen(X509ByteType* data, X509SizeType i) {
+ X509SizeType lenLen, len, j;
+ X509LenType res;
+ res.lenLen = 1;
+ if (data[i] & 0x80) {
+ lenLen = data[i] & 0x7f;
+ len = 0;
+ i++;
+ for (j = 0; j < lenLen; j++) {
+ len <<= 8;
+ len += data[i + j];
+ }
+ res.len = len;
+ res.lenLen += lenLen;
+ } else {
+ res.len = data[i] & 0x7f;
+ }
+ return res;
+}
+
+// -- Init the item --
+X509VoidType ItemInit(X509ItemType* it) {
+ it->title = NULL;
+ it->data = NULL;
+ it->type = 0;
+ it->len = 0;
+}
+
+// -- Set the content of the item --
+// -- NOTE: item can only be set once! --
+X509ErrType ItemSet(X509ItemType* it, X509ByteType* title, X509SizeType type, X509ByteType* data, X509SizeType len) {
+ // set title
+ X509SizeType typeLen = strlen((char*)title);
+ if(typeLen > 0 && it->title == NULL){
+ it->title = calloc(typeLen+1, sizeof(X509ByteType));
+ memcpy(it->title, title, typeLen);
+ } else {
+ return X509_ERR_PARSE_INVALID_PARAM;
+ }
+ // set data
+ if(len > 0 && it->data == NULL){
+ it->data = calloc(len, sizeof(X509ByteType));
+ memcpy(it->data, data, len);
+ } else {
+ return X509_ERR_PARSE_INVALID_PARAM;
+ }
+ // set type
+ it->type = type;
+ // set len
+ it->len = len;
+ return X509_SUCCESS;
+}
+
+// -- Free the memory occupied by the item --
+X509VoidType ItemFree(X509ItemType* it) {
+ if(it->title != NULL){
+ free(it->title);
+ }
+ if(it->data != NULL){
+ free(it->data);
+ }
+}
+
+// -- Print hex type item --
+X509VoidType ItemPrintHex(X509ItemType* it){
+ X509SizeType i = 0;
+ log_debug("[title]: %s \t[len ]: %d", it->title, it->len);
+ X509ByteType buf[512];
+ if(it->len < 250){
+ for (i = 0; i < it->len; i++) {
+ buf[i*2] = ((it->data[i] & 0xf0) >> 4) <=9 ? ((it->data[i] & 0xf0) >> 4) + '0' : ((it->data[i] & 0xf0) >> 4) + 'a' - 10;
+ buf[i*2+1] = ((it->data[i] & 0x0f) ) <=9 ? ((it->data[i] & 0x0f) ) + '0' : ((it->data[i] & 0x0f) ) + 'a' - 10;
+ }
+ buf[i*2] = '\0';
+ log_debug("[type ]: hex \t[data ]: %s", buf);
+ } else {
+ log_warn("[type ]: hex \t[data ]: %s", "The length exceeds 250, so it cannot be printed.");
+ }
+}
+
+// -- Print string type item --
+X509VoidType ItemPrintStr(X509ItemType* it) {
+ log_debug("[title]: %s \t[len ]: %d", it->title, it->len);
+ log_debug("[type ]: hex \t[data ]: %s", it->data);
+}
+
+// ----------------------------------------------
+// key Decoder
+// ----------------------------------------------
+// -- Convert an integer number into a string and store it in an array --
+// -- Returns the real length of the parsed data (Does not contain '\0') --
+X509SizeType ConvertItoa(X509SizeType value, X509ByteType* result, X509SizeType base) {
+ if (base < 2 || base > 36) {
+ *result = '\0'; return 0;
+ }
+ X509ByteType* ptr = result;
+ X509ByteType* ptr1 = result;
+ X509ByteType tmpChar;
+ X509SizeType tmpValue;
+ X509SizeType len = 0;
+ do {
+ tmpValue = value;
+ value /= base;
+ *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmpValue - value * base)];
+ } while ( value );
+ if (tmpValue < 0) {
+ *ptr++ = '-';
+ }
+ *ptr-- = '\0';
+ while(ptr1 < ptr) {
+ tmpChar = *ptr;
+ *ptr--= *ptr1;
+ *ptr1++ = tmpChar;
+ len += 2;
+ }
+ if(ptr1 == ptr) {
+ len += 1;
+ }
+ return len;
+}
+
+// -- String search substring --
+// -- found => return index, not found => return -1, parameter error => returns -2 --
+X509SizeType StrFindStr(const X509ByteType* src,const X509ByteType* sub)
+{
+ const X509ByteType* bp;
+ const X509ByteType* sp;
+ X509SizeType index = 0;
+ if(src == NULL || sub == NULL) {
+ return -2;
+ }
+ while(*src) {
+ bp = src;
+ sp = sub;
+ do {
+ if(!*sp) {
+ return index;
+ }
+ } while(*bp++ == *sp++);
+ src += 1;
+ index ++;
+ }
+ return -1;
+}
+
+// -- Parse Object ID --
+// -- dstData: Analysis result, ascii format --
+// -- dstLen : Parsing length (contain '\0') --
+// -- srcData: Original array, hex format --
+// -- srcLen : Length of parse data needed --
+X509VoidType ParseOid(X509ByteType* dstData, X509SizeType* dstLen, X509ByteType* srcData, X509SizeType srcLen){
+
+ X509SizeType oiFirst, oiStrFirst, itoaLen, t;
+ // add first srcData
+ (*dstLen) = 0;
+ oiFirst = srcData[0] & 0x7f;
+ oiStrFirst = (oiFirst/40) < 2? (oiFirst/40) : 2;
+ itoaLen = ConvertItoa(oiStrFirst, &dstData[(*dstLen)], 10);
+ (*dstLen) += itoaLen;
+ // add .
+ dstData[(*dstLen)] = '.';
+ (*dstLen) ++;
+ // add second data
+ itoaLen = ConvertItoa(oiFirst - 40 * oiStrFirst, &dstData[(*dstLen)], 10);
+ (*dstLen) += itoaLen;
+ // add next data
+ oiFirst = 0;
+ for (t = 1; t < srcLen; t++) {
+ oiFirst <<= 7;
+ oiFirst += srcData[t] & 0x7f;
+ if (!(srcData[t] & 0x80)) {
+ // add .
+ dstData[(*dstLen)] = '.';
+ (*dstLen) ++;
+ // add number
+ itoaLen = ConvertItoa(oiFirst, &dstData[(*dstLen)], 10);
+ (*dstLen) += itoaLen;
+ oiFirst = 0;
+ }
+ }
+ dstData[(*dstLen)] = '\0';
+ (*dstLen) ++;
+}
+
+// -- Decode string according to the syntax of ASN.1. Recursive method is used in the analysis process --
+// -- [NOTE] The process can only parse the key string --
+// -- key : Object storing the key --
+// -- title : Identifies the current parsed level, the top level needs to be "" --
+// -- data : Original array, hex format --
+// -- begin : start index (contain) --
+// -- end : finish index (contain) --
+X509ErrType ParseX509(X509KeyType* key, X509ByteType* title, X509ByteType* data, X509SizeType begin, X509SizeType end) {
+
+ X509SizeType i = begin;
+ X509SizeType type;
+ X509LenType lens;
+ X509ErrType itRes;
+
+ while (i < end) {
+ // T
+ type = data[i++];
+ // L
+ lens = GelLen(data, i);
+ if (i + lens.lenLen <= end) {
+ i += lens.lenLen;
+ }
+ if (lens.len <0 || i + lens.len > end) {
+ break;
+ }
+ // V
+ switch (type) {
+ // structure type
+ case 0x30: // sequence
+ if(!strcmp((char*)title,"")){
+ ParseX509(key, (X509VoidType*)"top", data, i, i + lens.len);
+ }
+ break;
+ case 0xa0: // extern info
+ case 0xa1:
+ if(!strcmp((char*)title,"top")) {
+ ParseX509(key, (X509VoidType *) "extern", data, i, i + lens.len);
+ }
+ break;
+ //Simple type
+ case 0x02:
+ if(!strcmp((char*)title,"top")) {
+ itRes = ItemSet(&key->version, (X509VoidType*)"version", type, &data[i], lens.len);
+ if(itRes != X509_SUCCESS) {
+ return itRes;
+ }
+ }
+ break;
+ case 0x03:
+ if(!strcmp((char*)title,"extern")) {
+ itRes = ItemSet(&key->publicKey, (X509VoidType*)"pubKey", type, &data[i+1], lens.len-1 );
+ if(itRes != X509_SUCCESS) {
+ return itRes;
+ }
+ }
+ break;
+ case 0x04:
+ if(!strcmp((char*)title,"top")) {
+ itRes = ItemSet(&key->privateKey, (X509VoidType*)"priKey", type, &data[i], lens.len );
+ if(itRes != X509_SUCCESS) {
+ return itRes;
+ }
+ }
+ break;
+ case 0x06:
+ if(!strcmp((char*)title,"extern")) {
+ X509ByteType tmp[50] = {0};
+ X509SizeType length = 0;
+ ParseOid(tmp,&length,&data[i], lens.len);
+ itRes = ItemSet(&key->keyType, (X509VoidType*)"keyType", type, tmp, length);
+ if(itRes != X509_SUCCESS) {
+ return itRes;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ i += lens.len;
+ }
+ return X509_SUCCESS;
+}
+
+// -- Initialize the item object in the key --
+X509VoidType KeyInit(X509KeyType* key){
+ ItemInit(&key->version);
+ ItemInit(&key->publicKey);
+ ItemInit(&key->privateKey);
+ ItemInit(&key->keyType);
+}
+
+// -- Parse the key string --
+// -- dstKey : Object storing the key --
+// -- srcData: Original data, string format --
+X509ErrType KeyParse(X509KeyType* dstKey, X509ByteType* srcData){
+ // Locate the location of the key string
+ X509ByteType* begin = (X509ByteType*)"-----BEGIN EC PRIVATE KEY-----";
+ X509ByteType* end = (X509ByteType*)"-----END EC PRIVATE KEY-----";
+ X509SizeType i, j;
+ i = StrFindStr(srcData, begin);
+ if(i < 0) {
+ log_error("can not find begin symbol");
+ return X509_ERR_PARSE_NO_FIND_SYMBAL;
+ }
+ j = StrFindStr(srcData, end);
+ if(j < 0) {
+ log_error("can not find end symbol");
+ return X509_ERR_PARSE_NO_FIND_SYMBAL;
+ }
+ // Base64 decode
+ X509SizeType srcLen = strlen((char*)begin);
+ X509ByteType dstBuffer[130];
+ X509SizeType dstLen = 0;
+ X509SizeType res = Base64Decode(dstBuffer, sizeof(dstBuffer), &dstLen, srcData+i+srcLen, j-i-srcLen);
+ if(res != X509_SUCCESS) {
+ log_error("base64 decode failed, error code : %d", res);
+ return res;
+ }
+ log_debug("base64 decode success, [srcData len] = %d , [dstData len] = %d", j-i-srcLen, dstLen);
+ X509ByteType buf[512];
+ if(dstLen < 160){
+ for (i = 0; i < dstLen; i++) {
+ buf[i*3] = ((dstBuffer[i] & 0xf0) >> 4) <=9 ? ((dstBuffer[i] & 0xf0) >> 4) + '0' : ((dstBuffer[i] & 0xf0) >> 4) + 'a' - 10;
+ buf[i*3+1] = ((dstBuffer[i] & 0x0f) ) <=9 ? ((dstBuffer[i] & 0x0f) ) + '0' : ((dstBuffer[i] & 0x0f) ) + 'a' - 10;
+ buf[i*3+2] = ' ';
+ }
+ buf[i*3] = '\0';
+ log_debug("[base64]: decoder = %s", buf);
+ } else {
+ log_warn("[base64]: %s", "The length exceeds 160, so it cannot be printed.");
+ }
+ // parse key
+ res = ParseX509(dstKey, (X509VoidType*)"",dstBuffer,0,dstLen);
+ if(res != X509_SUCCESS) {
+ log_error("parse key failed, error code : %d", res);
+ return res;
+ }
+ ItemPrintHex(&dstKey->version);
+ ItemPrintHex(&dstKey->publicKey);
+ ItemPrintHex(&dstKey->privateKey);
+ ItemPrintStr(&dstKey->keyType);
+ // compare curve type
+ if(strcmp((char*)dstKey->keyType.data,"1.3.132.0.10") != 0){
+ log_error("key type is not secp256k1");
+ return X509_ERR_PARSE_CURVE_MISMATCH;
+ }
+ return X509_SUCCESS;
+}
+
+// -- Free the memory occupied by the key --
+X509VoidType KeyFree(X509KeyType* key){
+ ItemFree(&key->version);
+ ItemFree(&key->publicKey);
+ ItemFree(&key->privateKey);
+ ItemFree(&key->keyType);
+}
diff --git a/src/proto/account.c b/src/proto/account.c
new file mode 100644
index 0000000000000000000000000000000000000000..a7cdfbedffd62f1d8353e6784bad191fad317a38
--- /dev/null
+++ b/src/proto/account.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "account.h"
+
+// ----------------------------------------------
+// account type definition
+// ----------------------------------------------
+typedef OhByteType AccountByteType;
+typedef OhSizeType AccountSizeType;
+typedef OhErrType AccountErrType;
+typedef OhVoidType AccountVoidType;
+typedef OhInt32Type AccountInt32Type;
+typedef OhInt64Type AccountInt64Type;
+
+// ----------------------------------------------
+// Get timesTamp Function
+// ----------------------------------------------
+// -- default func --
+static AccountErrType DefaultGettime(AccountInt64Type* p_dest){
+ return ACCOUNT_ERR_GETTIME_FUNC;
+}
+static AccountGetTimeFunction getTime = &DefaultGettime;
+// -- Set Get timesTamp Function --
+AccountVoidType AccountSetTimeFunc(AccountGetTimeFunction p_t){
+ getTime = p_t;
+}
+
+// ----------------------------------------------
+// Account Function
+// ----------------------------------------------
+// -- init account according private key certificate --
+AccountErrType AccountInitX509(AccountType* acc, AccountByteType* str) {
+
+ AccountErrType res;
+ AccountSizeType i;
+
+ // parse key string
+ if(strlen((char*)str) <= 0) {
+ return ACCOUNT_ERR_PARAM_INVAILD;
+ }
+
+ X509KeyType key;
+ KeyInit(&key);
+ res = KeyParse(&key, str);
+ if(res != X509_SUCCESS) {
+ KeyFree(&key);
+ return res;
+ }
+ memcpy(acc->priKey, key.privateKey.data, 32);
+ memcpy(acc->pubKey, key.publicKey.data, 65);
+ KeyFree(&key);
+
+ // compute addr
+ AccountByteType *pubHash = calloc(32, sizeof(AccountByteType)); // public key hash, hex format.
+ keccak256(acc->pubKey + 1, 64, &pubHash);
+ for(i = 0; i < 20; i ++){ // format address, string format.
+ acc->addr[(i+1)*2] = ((pubHash[i+12] & 0xf0) >> 4) <=9 ? ((pubHash[i+12] & 0xf0) >> 4) +
+ '0' : ((pubHash[i+12] & 0xf0) >> 4) + 'a' - 10;
+ acc->addr[(i+1)*2+1] = ((pubHash[i+12] & 0x0f) ) <=9 ? ((pubHash[i+12] & 0x0f) ) +
+ '0' : ((pubHash[i+12] & 0x0f) ) + 'a' - 10;
+ }
+ acc->addr[42] = '\0';
+ acc->addr[0] = '0';
+ acc->addr[1] = 'x';
+ free(pubHash);
+
+ log_info("addr is : %s",acc->addr);
+ return ACCOUNT_SUCCESS;
+}
+
+// -- init account according account json --
+AccountErrType ParseAccountJson(cJSON* items, AccountType* acc) {
+ AccountInt32Type i;
+ char* data;
+
+ // check version
+ cJSON* version = cJSON_GetObjectItem(items, "version");
+ if (version == NULL || strcmp(version -> valueString , "4.0") != 0) {
+ log_debug("Version: incompatible or unreadable");
+ return ACCOUNT_ERR_VER_UNMATCH;
+ }
+ log_debug("account %s: %s", "version", version->valueString);
+
+ // check algo
+ cJSON* algo = cJSON_GetObjectItem(items, "algo");
+ if (algo == NULL || strcmp(algo -> valueString , "0x03") != 0) {
+ log_debug("algo: not supported!");
+ return ACCOUNT_ERR_ALGO_UNMATCH;
+ }
+ log_debug("account %s: %s", "algo", algo->valueString);
+
+ // check privateKey
+ cJSON* privateKey = cJSON_GetObjectItem(items, "privateKey");
+ if (privateKey == NULL) {
+ log_debug("privateKey: unreadable!");
+ return ACCOUNT_ERR_PRIKEY_UNMATCH;
+ }
+ if (strlen(privateKey->valueString) != 64) {
+ log_debug("privateKey: Wrong length!");
+ return ACCOUNT_ERR_PRIKEY_UNMATCH;
+ }
+ data = privateKey->valueString;
+ for(i = 0; i < 32; i++){ // format priKey from string to hex.
+ AccountByteType a_h = (*(data+i*2 ) <='9' && *(data+i*2 ) >= '0') ? (*(data+i*2 ) - '0') : (*(data+i*2 ) <='f' && *(data+i*2 ) >= 'a' ? *(data+i*2 ) - 'a' + 10 : *(data+i*2 ) - 'A' + 10);
+ AccountByteType a_l = (*(data+i*2+1) <='9' && *(data+i*2+1) >= '0') ? (*(data+i*2+1) - '0') : (*(data+i*2+1) <='f' && *(data+i*2+1) >= 'a' ? *(data+i*2+1) - 'a' + 10 : *(data+i*2+1) - 'A' + 10);
+ acc->priKey[i] = a_h << 4 | a_l;
+ }
+ log_debug("account %s: %s", "privateKey", privateKey->valueString);
+
+ // check publicKey
+ cJSON* publicKey = cJSON_GetObjectItem(items, "publicKey");
+ if (publicKey == NULL) {
+ log_debug("publicKey: unreadable!");
+ return ACCOUNT_ERR_PUBKEY_UNMATCH;
+ }
+ if (strlen(publicKey->valueString) != 130) {
+ log_debug("publicKey: Wrong length!");
+ return ACCOUNT_ERR_PUBKEY_UNMATCH;
+ }
+ data = publicKey->valueString;
+ for(i = 0; i < 65; i++){ // format priKey from string to hex.
+ AccountByteType a_h = (*(data+i*2 ) <='9' && *(data+i*2 ) >= '0') ? (*(data+i*2 ) - '0') : (*(data+i*2 ) <='f' && *(data+i*2 ) >= 'a' ? *(data+i*2 ) - 'a' + 10 : *(data+i*2 ) - 'A' + 10);
+ AccountByteType a_l = (*(data+i*2+1) <='9' && *(data+i*2+1) >= '0') ? (*(data+i*2+1) - '0') : (*(data+i*2+1) <='f' && *(data+i*2+1) >= 'a' ? *(data+i*2+1) - 'a' + 10 : *(data+i*2+1) - 'A' + 10);
+ acc->pubKey[i] = a_h << 4 | a_l;
+ }
+ log_debug("account %s: %s", "publicKey", publicKey->valueString);
+
+ // check address
+ cJSON* address = cJSON_GetObjectItem(items, "address");
+ if (address == NULL) {
+ log_debug("address: unreadable!");
+ return ACCOUNT_ERR_ADDR_UNMATCH;
+ }
+ if (strlen(address->valueString) != 40) {
+ log_debug("address: Wrong length!");
+ return ACCOUNT_ERR_ADDR_UNMATCH;
+ }
+ memcpy(acc->addr+2, address->valueString, 40);
+ acc->addr[42] = '\0';
+ acc->addr[0] = '0';
+ acc->addr[1] = 'x';
+ log_debug("account %s: %s", "address", acc->addr);
+
+ return ACCOUNT_SUCCESS;
+}
+
+AccountErrType AccountInitJson(AccountType* acc, AccountByteType* str) {
+
+ if(strlen((char*)str) <= 0) {
+ return ACCOUNT_ERR_PARAM_INVAILD;
+ }
+ // parse json string
+ cJSON* items = cJSON_Parse((char*)str);
+ if (items == NULL) {
+ log_error("pasre json file fail\n");
+ return ACCOUNT_ERR_PARAM_INVAILD;
+ }
+ AccountErrType err = ParseAccountJson(items, acc);
+ // delete buffer
+ if (items != NULL){
+ cJSON_Delete(items);
+ }
+
+ return err;
+}
+
+
+// ----------------------------------------------
+// Transaction Function
+// ----------------------------------------------
+// -- create transfer transaction --
+AccountErrType TxSendNew(TxType* tx, AccountType* acc,
+ AccountByteType* to,
+ AccountInt32Type val,
+ AccountByteType* ex,
+ AccountByteType* exid){
+
+ AccountErrType res;
+ // Check Param
+ if(strlen((char*)to) != 42) {
+ return ACCOUNT_ERR_PARAM_INVAILD;
+ }
+ // Copy tx element
+ memcpy(tx->from, acc->addr, 43);
+ memcpy(tx->to, to, 43);
+ memcpy(tx->simulate, "false\0", 6);
+ memcpy(tx->type, "EVM\0", 4);
+ tx->extra = (ex == NULL || strlen((char*)ex) <= 0)? (AccountByteType*)"" : ex ;
+ tx->extraid = (exid == NULL || strlen((char*)exid) <= 0)? (AccountByteType*)"" : exid;
+ tx->value = val;
+ // Set time and random
+ res = getTime(&tx->timesTamp);
+ if(res != ACCOUNT_SUCCESS) {
+ return res;
+ }
+ tx->nonce = 1ULL;
+ // signature tx
+ AccountByteType* hashPrefix = (AccountByteType*)"from=%s&to=%s&value=0x%#x&payload=0x0×Tamp=%#llx&nonce=%#llx&opcode=0&extra=%s&vmtype=%s&version=2.5&extraid=%s&cname=";
+ AccountSizeType formatSize = strlen((char*)hashPrefix);
+ AccountSizeType txSize = strlen((char*)tx->from) + strlen((char*)tx->to) + sizeof(tx->value)*8 +
+ sizeof(tx->timesTamp)*8 + sizeof(tx->nonce)*8 + strlen((char*)tx->extra) + strlen((char*)tx->type) + strlen((char*)tx->extraid);
+ if(formatSize + txSize > MAX_BUF_SPACE_SIZE) {
+ log_error("The planned space size needs to be greater than %d, but the maximum allowable size is %d", formatSize + txSize, MAX_BUF_SPACE_SIZE);
+ return ACCOUNT_ERR_OVER_MAX_SIZE;
+ }
+ AccountByteType buffer[MAX_BUF_SPACE_SIZE];
+ sprintf((char*)buffer, (char*)hashPrefix,
+ tx->from, tx->to, tx->value, tx->timesTamp, tx->nonce, tx->extra, tx->type, tx->extraid);
+ log_debug("need keccak data is : %s",buffer);
+
+ AccountByteType dataHash[32]; // public key hash, hex format.
+ AccountByteType* hashPtr = dataHash;
+ keccak256(buffer, strlen((char*)buffer), &hashPtr);
+ print_keccak_data(dataHash);
+
+ AccountByteType sig[65];
+ res = uECC_sign(acc->priKey, dataHash, sig);
+ if (res != ECC_SUCCESS) {
+ log_error("tx sign failed: %d", res);
+ }
+ AccountSizeType i;
+ for(i = 0; i < 65; i ++){
+ tx->signature[(i+1)*2] = ((sig[i] & 0xf0) >> 4) <=9 ? ((sig[i] & 0xf0) >> 4) + '0' : ((sig[i] & 0xf0) >> 4) + 'a' - 10;
+ tx->signature[(i+1)*2+1] = ((sig[i] & 0x0f) ) <=9 ? ((sig[i] & 0x0f) ) + '0' : ((sig[i] & 0x0f) ) + 'a' - 10;
+ }
+ tx->signature[0] = '0'; // Identity signature algorithm
+ tx->signature[1] = '0';
+ tx->signature[132] = '\0';
+ log_info("sig: %s", tx->signature);
+
+ return ACCOUNT_SUCCESS;
+}
+
+// -- escape char --
+AccountVoidType StrEscapeStr(AccountByteType* dst, AccountByteType* src){
+ AccountSizeType p=0, q=0;
+ AccountSizeType len = strlen((char*)src);
+ for(; p 0) {
+ len += 1;
+ val /= 10;
+ }
+ return len;
+}
+
+// -- format transaction --
+AccountErrType TxPrint(TxType* tx, FormatType fmtType, AccountByteType* method, AccountByteType* outBuf, AccountSizeType outBufLen){
+
+ // len=177 | actual len=153
+ AccountByteType txFmtVersion[] = "{\"jsonrpc\":\"2.0\",\"method\":\"%s\",\"params\":[{\"from\":\"%s\",\"to\":\"%s\",\"value\":%d,\"timesTamp\":%llu,\"simulate\":%s,\"nonce\":%llu,\"extra\":\"%s\",\"extraIdString\":%s,\"signature\":\"%s\"}],\"id\":1}";
+
+ // Escape character
+ AccountSizeType len = strlen((char*)tx->extra) * 2 + 1;
+ if (len > MAX_BUF_SPACE_SIZE) {
+ log_error("The planned usage of escape character space is %d, but the maximum allowable %d", len, MAX_BUF_SPACE_SIZE);
+ return ACCOUNT_ERR_OVER_MAX_SIZE;
+ }
+ AccountByteType* tmpExtP = calloc(len, sizeof(AccountByteType));
+ if (tmpExtP == NULL) {
+ return ACCOUNT_ERR_CALLOC_MEMORY;
+ }
+ StrEscapeStr(tmpExtP, tx->extra);
+
+ // calculation of space usage
+ AccountSizeType txSize = strlen((char*)method) + strlen((char*)tx->from) + strlen((char*)tx->to) + GetIntLength(tx->value) +
+ GetIntLength(tx->timesTamp) + strlen((char*)tx->simulate) + GetIntLength(tx->nonce) + strlen((char*)tmpExtP) +
+ strlen((char*)tx->extraid) + strlen((char*)tx->signature);
+ if(153 + txSize > outBufLen) {
+ log_error("The planned space size needs to be greater than %d, but the actual space size is %d", 153 + txSize, outBufLen);
+ return ACCOUNT_ERR_BUF_TOO_SMALL;
+ }
+
+ // Format output string
+ switch(fmtType) {
+ case ADD_HTTP_BODY: {
+ char httpBodyFmt[] = "POST / HTTP/1.1\r\nHost: 8.136.20.47:8081\r\nUser-Agent: curl/7.47.0\r\nAccept: */*\r\nContent-Length: %d\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n";
+ char fmt[400];
+ strcpy(fmt, (char*) httpBodyFmt);
+ strcpy(fmt+strlen(httpBodyFmt),(char*)txFmtVersion);
+
+ sprintf((char*)outBuf, (char*)fmt, 153 + txSize, method, tx->from,
+ tx->to, tx->value, tx->timesTamp, tx->simulate,
+ tx->nonce, tmpExtP, tx->extraid, tx->signature);
+ break;
+ }
+ case ADD_CURL_BODY: {
+ char curlBodyFmtPrefix[] = "curl 8.136.20.47:8081 -X POST -d '";
+ char curlBodyFmtPostfix[] = "'";
+ char fmt[400];
+ strcpy(fmt, (char*) curlBodyFmtPrefix);
+ strcpy(fmt+strlen(curlBodyFmtPrefix),(char*)txFmtVersion);
+ strcpy(fmt+strlen(curlBodyFmtPrefix)+strlen((char*)txFmtVersion) , curlBodyFmtPostfix);
+
+ sprintf((char*)outBuf, (char*)fmt, method, tx->from,
+ tx->to, tx->value, tx->timesTamp, tx->simulate,
+ tx->nonce, tmpExtP, tx->extraid, tx->signature);
+ break;
+ }
+ case ORIGIN_MSG:{
+ sprintf((char*)outBuf, (char*)txFmtVersion, method, tx->from,
+ tx->to, tx->value, tx->timesTamp, tx->simulate,
+ tx->nonce, tmpExtP, tx->extraid, tx->signature);
+ break;
+ }
+ default:
+ break;
+ }
+
+ free(tmpExtP);
+
+ return ACCOUNT_SUCCESS;
+}
diff --git a/src/proto/largefile.c b/src/proto/largefile.c
new file mode 100644
index 0000000000000000000000000000000000000000..da664b9ca6c7d655c7a179e7ccacf762dcdc1dd5
--- /dev/null
+++ b/src/proto/largefile.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "largefile.h"
+
+// ----------------------------------------------
+// large file type definition
+// ----------------------------------------------
+typedef OhByteType FileByteType;
+typedef OhSizeType FileSizeType;
+typedef OhErrType FileErrType;
+typedef OhVoidType FileVoidType;
+
+// ----------------------------------------------
+// large file Function
+// ----------------------------------------------
+// -- Create file object. --
+FileErrType FileInfoNew(LargefileType* f, FileByteType *path, FileByteType *name, FileByteType *des, FileByteType *node, FileByteType *user) {
+
+ if(f == NULL || path == NULL || name == NULL || des == NULL || node == NULL || user == NULL) {
+ return FILE_ERR_PARAM_INVAILD;
+ }
+ f->size = 0;
+ // path
+ f->path = calloc(strlen((char*)path)+1, sizeof(FileByteType));
+ if (f->path == NULL) {
+ return FILE_ERR_CALLOC_MEMORY;
+ }
+ memcpy(f->path, path, strlen((char*)path));
+ // name
+ f->name = calloc(strlen((char*)name)+1, sizeof(FileByteType));
+ if (f->name == NULL) {
+ return FILE_ERR_CALLOC_MEMORY;
+ }
+ memcpy(f->name, name, strlen((char*)name));
+ // node
+ f->node = calloc(strlen((char*)node)+1, sizeof(FileByteType));
+ if (f->node == NULL) {
+ return FILE_ERR_CALLOC_MEMORY;
+ }
+ memcpy(f->node, node, strlen((char*)node));
+ // user
+ f->user = calloc(strlen((char*)user)+1, sizeof(FileByteType));
+ if (f->user == NULL) {
+ return FILE_ERR_CALLOC_MEMORY;
+ }
+ memcpy(f->user, user, strlen((char*)user));
+ // des
+ f->des = calloc(strlen((char*)des)+1, sizeof(FileByteType));
+ if (f->des == NULL) {
+ return FILE_ERR_CALLOC_MEMORY;
+ }
+ memcpy(f->des, des, strlen((char*)des));
+ log_debug("%s",node);
+ return FILE_SUCCESS;
+}
+
+// -- Calculate file MD5 result. --
+FileErrType FileCalMd5(LargefileType* f) {
+
+ // open file
+ FILE *fp = fopen((char*)f->path, "rb");
+ if(fp == NULL) {
+ log_error("File not exists : %s", f->path);
+ return FILE_ERR_NOT_EXIST;
+ }
+ // function param
+ FileSizeType blockSize = 32 * 1024;
+ FileByteType* buf = calloc(blockSize, sizeof(FileByteType));
+ if (buf == NULL) {
+ fclose(fp);
+ return FILE_ERR_CALLOC_MEMORY;
+ }
+ FileByteType blockMd5Result[16];
+ MD5_CTX fileMd5;
+ MD5Init(&fileMd5);
+ // calculate file md5
+ while(1){
+ // read file
+ FileSizeType realSize = fread(buf, 1, blockSize, fp);
+ f->size += realSize;
+ if(realSize > 0) {
+ // calculate block md5
+ MD5_CTX blockMd5;
+ MD5Init(&blockMd5);
+ MD5Update(&blockMd5, buf, realSize);
+ MD5Final(&blockMd5, blockMd5Result);
+ // calculate file md5
+ MD5Update(&fileMd5, blockMd5Result, 16);
+ }
+ if(feof(fp)) break;
+ }
+ MD5Final(&fileMd5, blockMd5Result);
+ // format result hex to string
+ FileSizeType i;
+ for(i = 0; i < 16; i ++){
+ f->hash[i*2 ] = ((blockMd5Result[i] & 0xf0) >> 4) <=9 ? ((blockMd5Result[i] & 0xf0) >> 4) + '0' : ((blockMd5Result[i] & 0xf0) >> 4) + 'a' - 10;
+ f->hash[i*2+1] = ((blockMd5Result[i] & 0x0f) ) <=9 ? ((blockMd5Result[i] & 0x0f) ) + '0' : ((blockMd5Result[i] & 0x0f) ) + 'a' - 10;
+ }
+ f->hash[32] = '\0';
+ log_debug("file md5 is : %s", f->hash);
+ log_debug("file size is : %d", f->size);
+ // clear cache
+ fclose(fp);
+ free(buf);
+
+ return FILE_SUCCESS;
+}
+
+// -- Format file information into extra string format. --
+FileErrType FileInfoFormat(LargefileType* f, FileByteType* buf, FileSizeType bufLen) {
+
+ FileByteType ex[] = "{\"hash\":\"%s\",\"file_name\":\"%s\",\"file_size\":%d,\"node_list\":[%s],\"user_list\":[%s],\"file_description\":\"%s\"}";
+ FileSizeType formatSize = strlen((char*)ex);
+ FileSizeType infoSize = strlen((char*)f->hash) + strlen((char*)f->name) + sizeof(f->size)*32 +
+ strlen((char*)f->node) + strlen((char*)f->user) + strlen((char*)f->des);
+ if(formatSize + infoSize + 1 > bufLen) {
+ log_error("The planned space size needs to be greater than %d, but the actual space size is %d", formatSize + infoSize + 1, bufLen);
+ return FILE_ERR_BUF_TOO_SMALL;
+ }
+ sprintf((char*)buf, (char*)ex, f->hash, f->name, f->size, f->node, f->user, f->des);
+ log_info("%s", buf);
+ return FILE_SUCCESS;
+}
+
+// -- Save the file hash result to . --
+FileErrType FileGetHash(LargefileType* f, FileByteType* buf, FileSizeType bufLen) {
+
+ FileSizeType infoSize = strlen((char*)f->hash) + 3;
+ if(infoSize > bufLen) {
+ log_error("The planned space size needs to be greater than %d, but the actual space size is %d", infoSize, bufLen);
+ return FILE_ERR_BUF_TOO_SMALL;
+ }
+ memcpy(buf, "\"", 1);
+ memcpy(buf+1, (char*)f->hash, 32);
+ memcpy(buf+33, "\"", 2);
+ log_debug("%s", buf);
+ return FILE_SUCCESS;
+}
+
+// -- Free file object. --
+FileVoidType FileInfoFree(LargefileType* f) {
+
+ if (f->path != NULL){
+ free(f->path);
+ }
+ if (f->name != NULL){
+ free(f->name);
+ }
+ if (f->node != NULL){
+ free(f->node);
+ }
+ if (f->user != NULL){
+ free(f->user);
+ }
+ if (f->des != NULL){
+ free(f->des);
+ }
+}
diff --git a/test/CuTest.c b/test/CuTest.c
new file mode 100644
index 0000000000000000000000000000000000000000..31b055eea743bf1c1c9ac95079be35932d5d9206
--- /dev/null
+++ b/test/CuTest.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "CuTest.h"
+
+/*-------------------------------------------------------------------------*
+ * CuStr
+ *-------------------------------------------------------------------------*/
+
+char* CuStrAlloc(int size)
+{
+ char* newStr = (char*) malloc( sizeof(char) * (size) );
+ return newStr;
+}
+
+char* CuStrCopy(const char* old)
+{
+ int len = strlen(old);
+ char* newStr = CuStrAlloc(len + 1);
+ strcpy(newStr, old);
+ return newStr;
+}
+
+/*-------------------------------------------------------------------------*
+ * CuString
+ *-------------------------------------------------------------------------*/
+
+void CuStringInit(CuString* str)
+{
+ str->length = 0;
+ str->size = STRING_MAX;
+ str->buffer = (char*) malloc(sizeof(char) * str->size);
+ str->buffer[0] = '\0';
+}
+
+CuString* CuStringNew(void)
+{
+ CuString* str = (CuString*) malloc(sizeof(CuString));
+ str->length = 0;
+ str->size = STRING_MAX;
+ str->buffer = (char*) malloc(sizeof(char) * str->size);
+ str->buffer[0] = '\0';
+ return str;
+}
+
+void CuStringDelete(CuString *str)
+{
+ if (!str) return;
+ free(str->buffer);
+ free(str);
+}
+
+void CuStringResize(CuString* str, int newSize)
+{
+ str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize);
+ str->size = newSize;
+}
+
+void CuStringAppend(CuString* str, const char* text)
+{
+ int length;
+
+ if (text == NULL) {
+ text = "NULL";
+ }
+
+ length = strlen(text);
+ if (str->length + length + 1 >= str->size)
+ CuStringResize(str, str->length + length + 1 + STRING_INC);
+ str->length += length;
+ strcat(str->buffer, text);
+}
+
+void CuStringAppendChar(CuString* str, char ch)
+{
+ char text[2];
+ text[0] = ch;
+ text[1] = '\0';
+ CuStringAppend(str, text);
+}
+
+void CuStringAppendFormat(CuString* str, const char* format, ...)
+{
+ va_list argp;
+ char buf[HUGE_STRING_LEN];
+ va_start(argp, format);
+ vsprintf(buf, format, argp);
+ va_end(argp);
+ CuStringAppend(str, buf);
+}
+
+void CuStringInsert(CuString* str, const char* text, int pos)
+{
+ int length = strlen(text);
+ if (pos > str->length)
+ pos = str->length;
+ if (str->length + length + 1 >= str->size)
+ CuStringResize(str, str->length + length + 1 + STRING_INC);
+ memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1);
+ str->length += length;
+ memcpy(str->buffer + pos, text, length);
+}
+
+/*-------------------------------------------------------------------------*
+ * CuTest
+ *-------------------------------------------------------------------------*/
+
+void CuTestInit(CuTest* t, const char* name, TestFunction function)
+{
+ t->name = CuStrCopy(name);
+ t->failed = 0;
+ t->ran = 0;
+ t->message = NULL;
+ t->function = function;
+ t->jumpBuf = NULL;
+}
+
+CuTest* CuTestNew(const char* name, TestFunction function)
+{
+ CuTest* tc = CU_ALLOC(CuTest);
+ CuTestInit(tc, name, function);
+ return tc;
+}
+
+void CuTestDelete(CuTest *t)
+{
+ if (!t) return;
+ free(t->name);
+ free(t);
+}
+
+void CuTestRun(CuTest* tc)
+{
+ jmp_buf buf;
+ tc->jumpBuf = &buf;
+ if (setjmp(buf) == 0)
+ {
+ tc->ran = 1;
+ (tc->function)(tc);
+ }
+ tc->jumpBuf = 0;
+}
+
+static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string)
+{
+ char buf[HUGE_STRING_LEN];
+
+ sprintf(buf, "%s:%d: ", file, line);
+ CuStringInsert(string, buf, 0);
+
+ tc->failed = 1;
+ tc->message = string->buffer;
+ if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0);
+}
+
+void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message)
+{
+ CuString string;
+
+ CuStringInit(&string);
+ if (message2 != NULL)
+ {
+ CuStringAppend(&string, message2);
+ CuStringAppend(&string, ": ");
+ }
+ CuStringAppend(&string, message);
+ CuFailInternal(tc, file, line, &string);
+}
+
+void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition)
+{
+ if (condition) return;
+ CuFail_Line(tc, file, line, NULL, message);
+}
+
+void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ const char* expected, const char* actual)
+{
+ CuString string;
+ if ((expected == NULL && actual == NULL) ||
+ (expected != NULL && actual != NULL &&
+ strcmp(expected, actual) == 0))
+ {
+ return;
+ }
+
+ CuStringInit(&string);
+ if (message != NULL)
+ {
+ CuStringAppend(&string, message);
+ CuStringAppend(&string, ": ");
+ }
+ CuStringAppend(&string, "expected <");
+ CuStringAppend(&string, expected);
+ CuStringAppend(&string, "> but was <");
+ CuStringAppend(&string, actual);
+ CuStringAppend(&string, ">");
+ CuFailInternal(tc, file, line, &string);
+}
+
+void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ int expected, int actual)
+{
+ char buf[STRING_MAX];
+ if (expected == actual) return;
+ sprintf(buf, "expected <%d> but was <%d>", expected, actual);
+ CuFail_Line(tc, file, line, message, buf);
+}
+
+void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ double expected, double actual, double delta)
+{
+ char buf[STRING_MAX];
+ if (fabs(expected - actual) <= delta) return;
+/* sprintf(buf, "expected <%lf> but was <%lf>", expected, actual); */
+ sprintf(buf, "expected <%f> but was <%f>", expected, actual);
+
+ CuFail_Line(tc, file, line, message, buf);
+}
+
+void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ void* expected, void* actual)
+{
+ char buf[STRING_MAX];
+ if (expected == actual) return;
+ sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual);
+ CuFail_Line(tc, file, line, message, buf);
+}
+
+
+/*-------------------------------------------------------------------------*
+ * CuSuite
+ *-------------------------------------------------------------------------*/
+
+void CuSuiteInit(CuSuite* testSuite)
+{
+ testSuite->count = 0;
+ testSuite->failCount = 0;
+ memset(testSuite->list, 0, sizeof(testSuite->list));
+}
+
+CuSuite* CuSuiteNew(void)
+{
+ CuSuite* testSuite = CU_ALLOC(CuSuite);
+ CuSuiteInit(testSuite);
+ return testSuite;
+}
+
+void CuSuiteDelete(CuSuite *testSuite)
+{
+ unsigned int n;
+ for (n=0; n < MAX_TEST_CASES; n++)
+ {
+ if (testSuite->list[n])
+ {
+ free(testSuite->list[n]->message);
+ CuTestDelete(testSuite->list[n]);
+ }
+ }
+ free(testSuite);
+}
+
+void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase)
+{
+ assert(testSuite->count < MAX_TEST_CASES);
+ testSuite->list[testSuite->count] = testCase;
+ testSuite->count++;
+}
+
+void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2)
+{
+ int i;
+ for (i = 0 ; i < testSuite2->count ; ++i)
+ {
+ CuTest* testCase = testSuite2->list[i];
+ CuSuiteAdd(testSuite, testCase);
+ }
+ free(testSuite2);
+}
+
+void CuSuiteRun(CuSuite* testSuite)
+{
+ int i;
+ for (i = 0 ; i < testSuite->count ; ++i)
+ {
+ CuTest* testCase = testSuite->list[i];
+ CuTestRun(testCase);
+ if (testCase->failed) { testSuite->failCount += 1; }
+ }
+}
+
+void CuSuiteSummary(CuSuite* testSuite, CuString* summary)
+{
+ int i;
+ for (i = 0 ; i < testSuite->count ; ++i)
+ {
+ CuTest* testCase = testSuite->list[i];
+ CuStringAppend(summary, testCase->failed ? "F" : ".");
+ }
+ CuStringAppend(summary, "\n\n");
+}
+
+void CuSuiteDetails(CuSuite* testSuite, CuString* details)
+{
+ int i;
+ int failCount = 0;
+
+ if (testSuite->failCount == 0)
+ {
+ int passCount = testSuite->count - testSuite->failCount;
+ const char* testWord = passCount == 1 ? "test" : "tests";
+ CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord);
+ }
+ else
+ {
+ if (testSuite->failCount == 1)
+ CuStringAppend(details, "There was 1 failure:\n");
+ else
+ CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount);
+
+ for (i = 0 ; i < testSuite->count ; ++i)
+ {
+ CuTest* testCase = testSuite->list[i];
+ if (testCase->failed)
+ {
+ failCount++;
+ CuStringAppendFormat(details, "%d) %s: %s\n",
+ failCount, testCase->name, testCase->message);
+ }
+ }
+ CuStringAppend(details, "\n!!!FAILURES!!!\n");
+
+ CuStringAppendFormat(details, "Runs: %d ", testSuite->count);
+ CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount);
+ CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount);
+ }
+}
diff --git a/test/CuTest.h b/test/CuTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..9121ba3fa7cc84b18139d360b903ac7239d73833
--- /dev/null
+++ b/test/CuTest.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CU_TEST_H
+#define CU_TEST_H
+
+#include
+#include
+
+/* CuString */
+
+char* CuStrAlloc(int size);
+char* CuStrCopy(const char* old);
+
+#define CU_ALLOC(TYPE) ((TYPE*) malloc(sizeof(TYPE)))
+
+#define HUGE_STRING_LEN 8192
+#define STRING_MAX 256
+#define STRING_INC 256
+
+typedef struct
+{
+ int length;
+ int size;
+ char* buffer;
+} CuString;
+
+void CuStringInit(CuString* str);
+CuString* CuStringNew(void);
+void CuStringRead(CuString* str, const char* path);
+void CuStringAppend(CuString* str, const char* text);
+void CuStringAppendChar(CuString* str, char ch);
+void CuStringAppendFormat(CuString* str, const char* format, ...);
+void CuStringInsert(CuString* str, const char* text, int pos);
+void CuStringResize(CuString* str, int newSize);
+void CuStringDelete(CuString* str);
+
+/* CuTest */
+
+typedef struct CuTest CuTest;
+
+typedef void (*TestFunction)(CuTest *);
+
+struct CuTest
+{
+ char* name;
+ TestFunction function;
+ int failed;
+ int ran;
+ char* message;
+ jmp_buf *jumpBuf;
+};
+
+void CuTestInit(CuTest* t, const char* name, TestFunction function);
+CuTest* CuTestNew(const char* name, TestFunction function);
+void CuTestRun(CuTest* tc);
+void CuTestDelete(CuTest *t);
+
+/* Internal versions of assert functions -- use the public versions */
+void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message);
+void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition);
+void CuAssertStrEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ const char* expected, const char* actual);
+void CuAssertIntEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ int expected, int actual);
+void CuAssertDblEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ double expected, double actual, double delta);
+void CuAssertPtrEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ void* expected, void* actual);
+
+/* public assert functions */
+
+#define CuFail(tc, ms) CuFail_Line( (tc), __FILE__, __LINE__, NULL, (ms))
+#define CuAssert(tc, ms, cond) CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond))
+#define CuAssertTrue(tc, cond) CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond))
+
+#define CuAssertStrEquals(tc,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertStrEquals_Msg(tc,ms,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+#define CuAssertIntEquals(tc,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertIntEquals_Msg(tc,ms,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+#define CuAssertDblEquals(tc,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl))
+#define CuAssertDblEquals_Msg(tc,ms,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac),(dl))
+#define CuAssertPtrEquals(tc,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertPtrEquals_Msg(tc,ms,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+
+#define CuAssertPtrNotNull(tc,p) CuAssert_Line((tc),__FILE__,__LINE__,"null pointer unexpected",(p != NULL))
+#define CuAssertPtrNotNullMsg(tc,msg,p) CuAssert_Line((tc),__FILE__,__LINE__,(msg),(p != NULL))
+
+/* CuSuite */
+
+#define MAX_TEST_CASES 1024
+
+#define SUITE_ADD_TEST(SUITE,TEST) CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST))
+
+typedef struct
+{
+ int count;
+ CuTest* list[MAX_TEST_CASES];
+ int failCount;
+
+} CuSuite;
+
+
+void CuSuiteInit(CuSuite* testSuite);
+CuSuite* CuSuiteNew(void);
+void CuSuiteDelete(CuSuite *testSuite);
+void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase);
+void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2);
+void CuSuiteRun(CuSuite* testSuite);
+void CuSuiteSummary(CuSuite* testSuite, CuString* summary);
+void CuSuiteDetails(CuSuite* testSuite, CuString* details);
+
+#endif /* CU_TEST_H */
diff --git a/test/account_test.c b/test/account_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..d211147c8e0b9d5a4e920ea6dbc2f5ce24f57aa5
--- /dev/null
+++ b/test/account_test.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "account.h"
+#include "ql_type.h"
+#include "CuTest.h"
+
+OhErrType time_ret_zero(OhInt64Type *dst) {
+ *dst = 0;
+ return ACCOUNT_SUCCESS;
+}
+
+void account_test(CuTest* tc) {
+
+ AccountSetTimeFunc(time_ret_zero);
+
+ OhByteType priKey[] = "-----BEGIN EC PRIVATE KEY-----\n"
+ "MHQCAQEEIAICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBoAcGBSuBBAAK\n"
+ "oUQDQgAExUK0Fv9I2BvhZR8lVIwG0ZHPowy4GvUZEYMM8uASzJ/3/Xbd0VlMYHFg\n"
+ "qXkEMxUZJABjkW2PNh3vU4lzCsLXRA==\n"
+ "-----END EC PRIVATE KEY-----";
+ //create account
+ AccountType my_account;
+ OhErrType res = AccountInitX509(&my_account, priKey);
+ CuAssertIntEquals(tc, ACCOUNT_SUCCESS, res);
+ CuAssertStrEquals(tc, "0x469339bdf3d3621bebea36c308de77939424e34e",(char*)my_account.addr);
+ // create tx
+ TxType tx;
+ OhByteType ex[] = "{\"id\":\"0F384\",\"name\":\"tom\",\"class\":\"0808\"}";
+ res = TxSendNew(&tx, &my_account, my_account.addr, 0, ex, (OhByteType *)"[\"12345\"]");
+ CuAssertIntEquals(tc, ACCOUNT_SUCCESS, res);
+ CuAssertStrEquals(tc, "00aef433b91bf339f466f82199293dae8638370688572b1c14678f4e55b5ea55b91a1389ae0eee77c99d790c326190438225470c3d3480ed685291ed5c826e460400",(char*)tx.signature);
+
+ OhByteType *out = calloc(1000, sizeof(OhByteType));
+ res = TxPrint(&tx, ORIGIN_MSG,TX_TYPE_SENDTRANSACTION, out, 1000);
+ CuAssertIntEquals(tc, ACCOUNT_SUCCESS, res);
+ CuAssertStrEquals(tc, "{\"jsonrpc\":\"2.0\",\"method\":\"tx_sendTransaction\",\"params\":[{\"from\":\"0x469339bdf3d3621bebea36c308de77939424e34e\",\"to\":\"0x469339bdf3d3621bebea36c308de77939424e34e\",\"value\":0,\"timesTamp\":0,\"simulate\":false,\"nonce\":1,\"extra\":\"{\\\"id\\\":\\\"0F384\\\",\\\"name\\\":\\\"tom\\\",\\\"class\\\":\\\"0808\\\"}\",\"signature\":\"00aef433b91bf339f466f82199293dae8638370688572b1c14678f4e55b5ea55b91a1389ae0eee77c99d790c326190438225470c3d3480ed685291ed5c826e460400\"}],\"id\":1}",(char*)out);
+
+ free(out);
+}
+
+CuSuite* account_test_suite(void)
+{
+ CuSuite* suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, account_test);
+ return suite;
+}
diff --git a/test/all_test.c b/test/all_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..da5e1cfb7a900a3a2871530e5fc882230e1b09d2
--- /dev/null
+++ b/test/all_test.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CuTest.h"
+#include "stdio.h"
+#include "log.h"
+#include
+
+extern CuSuite* x509_test_suite(void);
+extern CuSuite* account_test_suite(void);
+extern CuSuite* keccak256_test_suite(void);
+extern CuSuite* ecc_test_suite(void);
+
+void RunAllTests(void)
+{
+ CuString *output = CuStringNew();
+ CuSuite* suite = CuSuiteNew();
+
+ CuSuiteAddSuite(suite, x509_test_suite());
+ CuSuiteAddSuite(suite, account_test_suite());
+ CuSuiteAddSuite(suite, keccak256_test_suite());
+ CuSuiteAddSuite(suite, ecc_test_suite());
+
+ CuSuiteRun(suite);
+ CuSuiteSummary(suite, output);
+ CuSuiteDetails(suite, output);
+ printf("%s\n", output->buffer);
+ CuStringDelete(output);
+ CuSuiteDelete(suite);
+}
+
+void print_log_func(char *content){
+ printf("%s",content);
+}
+void print_log_time(char * timeBuf, int size){
+ time_t t = time(NULL);
+ struct tm* tp = localtime(&t);
+ timeBuf[strftime(timeBuf, size, "%H:%M:%S", tp)] = '\0';
+}
+int main()
+{
+ SetPrintLogCallback(print_log_func);
+ SetGetTimeCallback(print_log_time);
+ LogSetQuiet(LOG_QUIET_FALSE);
+ LogSetLevel(LOG_DEBUG);
+ RunAllTests();
+ return 0;
+}
diff --git a/test/ecc_test.c b/test/ecc_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..381580fddc081cd7d9fefcf9d56d369205467549
--- /dev/null
+++ b/test/ecc_test.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ecc.h"
+#include "ql_type.h"
+#include "CuTest.h"
+
+
+// Declare internal functions
+OhErrType uECC_create_pubkey(OhByteType p_publicKey[uECC_BYTES*2], OhByteType p_privateKey[uECC_BYTES]);
+OhErrType uECC_verify(OhBoolType* res, const OhByteType p_publicKey[uECC_BYTES*2], const OhByteType p_hash[uECC_BYTES], const OhByteType p_signature[uECC_BYTES*2]);
+OhErrType uECC_make_key(OhByteType p_publicKey[uECC_BYTES*2], OhByteType p_privateKey[uECC_BYTES]);
+OhErrType uECC_shared_secret(const OhByteType p_publicKey[uECC_BYTES*2], const OhByteType p_privateKey[uECC_BYTES], OhByteType p_secret[uECC_BYTES]);
+
+
+OhVoidType print_ecc_data(OhByteType *out, OhByteType *buf, OhSizeType len){
+ OhByteType i;
+ for(i = 0; i < len; i ++){
+ buf[i*2] = ((out[i] & 0xf0) >> 4) <=9 ? ((out[i] & 0xf0) >> 4) + '0' : ((out[i] & 0xf0) >> 4) + 'a' - 10;
+ buf[i*2+1] = ((out[i] & 0x0f) ) <=9 ? ((out[i] & 0x0f) ) + '0' : ((out[i] & 0x0f) ) + 'a' - 10;
+ }
+ buf[len*2] = '\0';
+}
+
+void sign_test(CuTest* tc){
+ OhUint8Type hash[32] = {0xed,0x97,0x8a,0x28,0xe0,0x9f,0xd1,0x38,
+ 0x5f,0xc1,0x4d,0x94,0x17,0x46,0xa9,0x47,
+ 0x61,0x4c,0x92,0xb3,0x9d,0x59,0x07,0x02,
+ 0x27,0xf4,0xcd,0xd3,0xb5,0xc9,0x94,0x24};
+ OhUint8Type private[32] = {2,2,2,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1};
+ OhUint8Type sig[65], out[256];
+ OhInt32Type res = uECC_sign(private, hash, sig);
+ CuAssertIntEquals(tc, ECC_SUCCESS, res);
+ print_ecc_data(sig, out, 65);
+ CuAssertStrEquals(tc, "dfcc21d389e6614ed98702ebdfaaf06335ee3d10f0449beca6430ac4c53aa23203832a4f0d12ece5eb9969b6f0d14e86dc8e6a49c47d58c19661c8d4d888cdc701",(char*)out);
+}
+
+void create_pubkey_test(CuTest* tc){
+ OhUint8Type private[32] = {2,2,2,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1};
+ OhUint8Type public[64],public_str[256];
+ OhInt32Type res = uECC_create_pubkey(public,private);
+ CuAssertIntEquals(tc, ECC_SUCCESS, res);
+ print_ecc_data(public,public_str, 64);
+ CuAssertStrEquals(tc, "c542b416ff48d81be1651f25548c06d191cfa30cb81af51911830cf2e012cc9ff7fd76ddd1594c607160a97904331519240063916d8f361def5389730ac2d744",(char*)public_str);
+}
+
+void verify_test(CuTest* tc){
+ OhUint8Type hash[32] = {0xed,0x97,0x8a,0x28,0xe0,0x9f,0xd1,0x38,
+ 0x5f,0xc1,0x4d,0x94,0x17,0x46,0xa9,0x47,
+ 0x61,0x4c,0x92,0xb3,0x9d,0x59,0x07,0x02,
+ 0x27,0xf4,0xcd,0xd3,0xb5,0xc9,0x94,0x24};
+ OhUint8Type sig[65] = {0xdf,0xcc,0x21,0xd3,0x89,0xe6,0x61,0x4e,
+ 0xd9,0x87,0x02,0xeb,0xdf,0xaa,0xf0,0x63,
+ 0x35,0xee,0x3d,0x10,0xf0,0x44,0x9b,0xec,
+ 0xa6,0x43,0x0a,0xc4,0xc5,0x3a,0xa2,0x32,
+ 0x03,0x83,0x2a,0x4f,0x0d,0x12,0xec,0xe5,
+ 0xeb,0x99,0x69,0xb6,0xf0,0xd1,0x4e,0x86,
+ 0xdc,0x8e,0x6a,0x49,0xc4,0x7d,0x58,0xc1,
+ 0x96,0x61,0xc8,0xd4,0xd8,0x88,0xcd,0xc7,
+ 0x01};
+ OhUint8Type pub[64] = {0xc5,0x42,0xb4,0x16,0xff,0x48,0xd8,0x1b,
+ 0xe1,0x65,0x1f,0x25,0x54,0x8c,0x06,0xd1,
+ 0x91,0xcf,0xa3,0x0c,0xb8,0x1a,0xf5,0x19,
+ 0x11,0x83,0x0c,0xf2,0xe0,0x12,0xcc,0x9f,
+ 0xf7,0xfd,0x76,0xdd,0xd1,0x59,0x4c,0x60,
+ 0x71,0x60,0xa9,0x79,0x04,0x33,0x15,0x19,
+ 0x24,0x00,0x63,0x91,0x6d,0x8f,0x36,0x1d,
+ 0xef,0x53,0x89,0x73,0x0a,0xc2,0xd7,0x44};
+ OhBoolType verify_res = 0;
+ OhErrType res = uECC_verify(&verify_res, pub, hash, sig);
+ CuAssertIntEquals(tc, ECC_SUCCESS, res);
+ CuAssertIntEquals(tc, 1, verify_res);
+}
+
+void shared_secret_test(CuTest* tc){
+ OhUint8Type public[64] = {0xc5,0x42,0xb4,0x16,0xff,0x48,0xd8,0x1b,
+ 0xe1,0x65,0x1f,0x25,0x54,0x8c,0x06,0xd1,
+ 0x91,0xcf,0xa3,0x0c,0xb8,0x1a,0xf5,0x19,
+ 0x11,0x83,0x0c,0xf2,0xe0,0x12,0xcc,0x9f,
+ 0xf7,0xfd,0x76,0xdd,0xd1,0x59,0x4c,0x60,
+ 0x71,0x60,0xa9,0x79,0x04,0x33,0x15,0x19,
+ 0x24,0x00,0x63,0x91,0x6d,0x8f,0x36,0x1d,
+ 0xef,0x53,0x89,0x73,0x0a,0xc2,0xd7,0x44};
+ OhUint8Type private[32] = {2,2,2,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1};
+
+ OhUint8Type ciphertextPrivKey[32] = {0};
+ OhUint8Type ciphertextPubKey[64] = {0};
+ OhUint8Type p_secret1[32] = {0}, p_secret1_str[256];
+ OhUint8Type p_secret2[32] = {0}, p_secret2_str[256];
+ OhErrType res = uECC_make_key(ciphertextPubKey, ciphertextPrivKey);
+ CuAssertIntEquals(tc, ECC_SUCCESS, res);
+
+ res = uECC_shared_secret(public,ciphertextPrivKey,p_secret1); // Encryption
+ CuAssertIntEquals(tc, ECC_SUCCESS, res);
+ // Use the sharedECCKey for symmetric encryption.
+ // ... Transmit ciphertextPubKey and ciphertext ...
+ // Use the ciphertextPubKey for symmetric encryption.
+ res = uECC_shared_secret(ciphertextPubKey,private,p_secret2); // Decryption
+ CuAssertIntEquals(tc, ECC_SUCCESS, res);
+
+ print_ecc_data(p_secret1,p_secret1_str,32);
+ print_ecc_data(p_secret2,p_secret2_str,32);
+ CuAssertStrEquals(tc,(char*)p_secret1_str,(char*)p_secret2_str);
+
+}
+
+CuSuite* ecc_test_suite(void)
+{
+ CuSuite* suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, sign_test);
+ SUITE_ADD_TEST(suite, create_pubkey_test);
+ SUITE_ADD_TEST(suite, verify_test);
+ SUITE_ADD_TEST(suite, shared_secret_test);
+ return suite;
+}
diff --git a/test/keccak256_test.c b/test/keccak256_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..844bd9194885bf2769590d5b1a4839b40d934559
--- /dev/null
+++ b/test/keccak256_test.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "keccak256.h"
+#include "ql_type.h"
+#include "CuTest.h"
+
+// test function
+void keccak256_test(CuTest* tc){
+ log_debug("----keccak256 test----");
+ // res: bbd99bc84b4133463be1a715e57107ffbccbaf93df5d594c95dbe4a59ad3852e
+ OhByteType *in = (OhByteType *) "from=0xfa4a201392ecfb8636efc0028554df66218a1b0f&to=0xfa4a201392ecfb8636efc0028554df66218a1b0f&value=0x0&payload=0x0×Tamp=0x1660cb9be3bfba01&nonce=0x3413&opcode=0&extra=&vmtype=EVM&version=2.5&extraid=&cname=";
+ log_debug("[input data] %s",in);
+ OhByteType *out = (OhByteType *) malloc(sizeof(OhByteType) * 32);
+ if (out == NULL)
+ log_error("malloc space err");
+ keccak256(in, strlen((char*)in), &out);
+
+ OhByteType buf[65];
+ OhUint8Type i;
+ for(i = 0; i < 32; i ++){
+ buf[i*2] = ((out[i] & 0xf0) >> 4) <=9 ? ((out[i] & 0xf0) >> 4) + '0' : ((out[i] & 0xf0) >> 4) + 'a' - 10;
+ buf[i*2+1] = ((out[i] & 0x0f) ) <=9 ? ((out[i] & 0x0f) ) + '0' : ((out[i] & 0x0f) ) + 'a' - 10;
+ }
+ buf[64] = '\0';
+ CuAssertStrEquals(tc, "bbd99bc84b4133463be1a715e57107ffbccbaf93df5d594c95dbe4a59ad3852e",(char*)buf);
+
+ free(out);
+}
+
+CuSuite* keccak256_test_suite(void)
+{
+ CuSuite* suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, keccak256_test);
+ return suite;
+}
diff --git a/test/x509_test.c b/test/x509_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..bc78ae6af07607d1cc5eebfa430ebcfcb1e78cd3
--- /dev/null
+++ b/test/x509_test.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2016-2021, Hangzhou Qulian Technology Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CuTest.h"
+#include "x509.h"
+#include "ql_type.h"
+
+// Declare internal functions
+OhErrType Base64Encode(OhByteType* dst, OhSizeType dlen, OhSizeType *olen, OhByteType* src, OhSizeType slen);
+
+// Test case
+void key_parse_test_right(CuTest* tc) {
+ OhByteType srcData[] = "-----BEGIN EC PRIVATE KEY-----\n"
+ "MHQCAQEEIDyNfgAOpTNKqB430x0Vg7IioUcoUrC8ORC0WcURbu++oAcGBSuBBAAK\n"
+ "oUQDQgAEAabMhAWKawZAFURHbzPZJlUexoLyvhx9bBMBAH94mU5F8ZgEV1fJL9iV\n"
+ "LPMBIrtYFIyubrVNH5I5ww0Hj4embQ==\n"
+ "-----END EC PRIVATE KEY-----";
+ X509KeyType key;
+ KeyInit(&key);
+ OhErrType res = KeyParse(&key, srcData);
+ KeyFree(&key);
+
+ CuAssertIntEquals(tc, X509_SUCCESS, res);
+}
+
+void key_parse_test_wrong_curve(CuTest* tc) {
+ OhByteType srcData[] = "-----BEGIN EC PRIVATE KEY-----\n"
+ "MHcCAQEEIHpF5aQ5fcDYmtaCIGkb6gPUxYjDbOhnLKPM9dtUPdAxoAoGCCqGSM49\n"
+ "AwEHoUQDQgAEaTgeworBiIEf1uomYNAJMTaUHQ++VCkDkZIg+csD3MsnYtnHVBOK\n"
+ "tO9yc1w5qrOYm0a6LGu4hOuvOFDQsvoBtQ==\n"
+ "-----END EC PRIVATE KEY-----";
+ X509KeyType key;
+ KeyInit(&key);
+ OhErrType res = KeyParse(&key, srcData);
+ KeyFree(&key);
+
+ CuAssertIntEquals(tc, X509_ERR_PARSE_CURVE_MISMATCH, res);
+}
+
+void key_parse_test_wrong_key_format(CuTest* tc) {
+ OhByteType srcData[] = "MHcCAQEEIHpF5aQ5fcDYmtaCIGkb6gPUxYjDbOhnLKPM9dtUPdAxoAoGCCqGSM49\n"
+ "AwEHoUQDQgAEaTgeworBiIEf1uomYNAJMTaUHQ++VCkDkZIg+csD3MsnYtnHVBOK\n"
+ "tO9yc1w5qrOYm0a6LGu4hOuvOFDQsvoBtQ==\n"
+ "-----END EC PRIVATE KEY-----";
+ X509KeyType key;
+ KeyInit(&key);
+ OhErrType res = KeyParse(&key, srcData);
+ KeyFree(&key);
+
+ CuAssertIntEquals(tc, X509_ERR_PARSE_NO_FIND_SYMBAL, res);
+}
+
+void key_parse_test_wrong_key_format_2(CuTest* tc) {
+ OhByteType srcData[] = "-----BEGIN EC PRIVATE KEY-----\n"
+ "MHcCAQEEIHpF5aQ5fcDYmtaCIGkb6gPUxYjDbOhnLKPM9dtUPdAxoAoGCCqGSM49\n"
+ "AwEHoUQDQgAEaTgeworBiIEf1uomYNAJMTaUHQ++VCkDkZIg+csD3MsnYtnHVBOK\n"
+ "tO9yc1w5qrOYm0a6LGu4hOuvOFDQsvoBtQ==\n";
+ X509KeyType key;
+ KeyInit(&key);
+ OhErrType res = KeyParse(&key, srcData);
+ KeyFree(&key);
+
+ CuAssertIntEquals(tc, X509_ERR_PARSE_NO_FIND_SYMBAL, res);
+}
+
+void base64_encode_test(CuTest* tc) {
+ OhByteType dst_buffer2[500];
+ OhByteType template[] = {
+ 0x30,0x74,0x02,0x01,0x01,0x04,0x20,0x00, // priv key
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,
+ 0x07,0x06,0x05,0x2b,0x81,0x04,0x00,0x0a,
+ 0xa1,0x44,0x03,0x42,0x00,0x04,0x00,0x00, // pub key
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00};
+ OhByteType pri[] = { 0x02,0x02,0x02,0x01,0x01,0x01,0x01,0x01,
+ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
+ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
+ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01};
+ OhByteType pub[] = { 0xc5,0x42,0xb4,0x16,0xff,0x48,0xd8,0x1b,
+ 0xe1,0x65,0x1f,0x25,0x54,0x8c,0x06,0xd1,
+ 0x91,0xcf,0xa3,0x0c,0xb8,0x1a,0xf5,0x19,
+ 0x11,0x83,0x0c,0xf2,0xe0,0x12,0xcc,0x9f,
+ 0xf7,0xfd,0x76,0xdd,0xd1,0x59,0x4c,0x60,
+ 0x71,0x60,0xa9,0x79,0x04,0x33,0x15,0x19,
+ 0x24,0x00,0x63,0x91,0x6d,0x8f,0x36,0x1d,
+ 0xef,0x53,0x89,0x73,0x0a,0xc2,0xd7,0x44};
+ memcpy(template + 7,pri,32);
+ memcpy(template + 54,pub,64);
+ OhSizeType dst_len2;
+ Base64Encode(dst_buffer2, sizeof(dst_buffer2), &dst_len2, template, 118);
+
+ CuAssertStrEquals(tc, "MHQCAQEEIAICAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBoAcGBSuBBAAKoUQDQgAExUK0Fv9I2BvhZR8lVIwG0ZHPowy4GvUZEYMM8uASzJ/3/Xbd0VlMYHFgqXkEMxUZJABjkW2PNh3vU4lzCsLXRA==", (char*)dst_buffer2);
+}
+
+CuSuite* x509_test_suite(void)
+{
+ CuSuite* suite = CuSuiteNew();
+ SUITE_ADD_TEST(suite, key_parse_test_right);
+ SUITE_ADD_TEST(suite, key_parse_test_wrong_curve);
+ SUITE_ADD_TEST(suite, key_parse_test_wrong_key_format);
+ SUITE_ADD_TEST(suite, key_parse_test_wrong_key_format_2);
+ SUITE_ADD_TEST(suite, base64_encode_test);
+ return suite;
+}
\ No newline at end of file