├── .gitignore
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── pom.xml
├── settings.gradle
└── src
├── main
└── java
│ └── iost
│ ├── Client.java
│ ├── IOST.java
│ ├── Keychain.java
│ ├── crypto
│ ├── Algorithm.java
│ ├── Base58.java
│ ├── Ed25519.java
│ ├── KeyPair.java
│ ├── Secp256k1.java
│ ├── SimpleEncoder.java
│ ├── TweetNaCl.java
│ └── VerifyUtils.java
│ └── model
│ ├── account
│ ├── Account.java
│ ├── FrozenBalance.java
│ ├── GasInfo.java
│ ├── Group.java
│ ├── Item.java
│ ├── Permission.java
│ ├── PledgeInfo.java
│ ├── RamInfo.java
│ ├── TokenBalance.java
│ └── VoteInfo.java
│ ├── block
│ ├── Block.java
│ ├── BlockResponse.java
│ └── Info.java
│ ├── info
│ ├── ChainInfo.java
│ ├── GasRatio.java
│ ├── NetworkInfo.java
│ ├── NodeInfo.java
│ └── PeerInfo.java
│ └── transaction
│ ├── Action.java
│ ├── AmountLimit.java
│ ├── Receipt.java
│ ├── Signature.java
│ ├── SignatureAdapter.java
│ ├── Transaction.java
│ └── TxReceipt.java
└── test
└── java
├── ECDSA_secp256k1_Test.java
├── TestClient.java
├── TestCrypto.java
├── crypto_sign_open.java
└── iost
└── crypto
└── VerifyUtilsTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Gradle template
3 | .gradle
4 | /build/
5 |
6 | # Ignore Gradle GUI config
7 | gradle-app.setting
8 |
9 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
10 | !gradle-wrapper.jar
11 |
12 | # Cache of project
13 | .gradletasknamecache
14 |
15 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
16 | # gradle/wrapper/gradle-wrapper.properties
17 | ### JetBrains template
18 | .idea
19 |
20 | out/
21 |
22 | ### IntelliJ IDEA ###
23 | .idea
24 | *.iws
25 | *.iml
26 | *.ipr
27 |
28 | ### NetBeans ###
29 | /nbproject/private/
30 | /nbbuild/
31 | /dist/
32 | /nbdist/
33 | /.nb-gradle/
34 | /build/
35 |
36 | ### VS Code ###
37 | .vscode/
38 |
39 | /target/
40 | !.mvn/wrapper/maven-wrapper.jar
41 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # java-sdk
2 |
3 | IOST java SDK
4 |
5 | ## build JAR
6 | ```
7 | ./gradlew build
8 | ls build/libs/
9 | ```
10 | ## examples
11 | See [java-example](https://github.com/iost-official/java-example)
12 |
13 | ## API
14 | ```
15 | ./gradlew javadoc
16 | ls build/docs/javadoc
17 | ```
18 |
19 | ## maven
20 |
21 | **NOTE! THE FOLLOW MAVEN NOT BELONG TO IOST-OFFICIAL!**
22 |
23 | ```xml
24 |
25 | io.github.qyvlik
26 | io.iost-java-sdk
27 | broker-v3.2.0
28 |
29 | ```
30 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | group 'io.iost'
2 | version '3.2.0'
3 |
4 | apply plugin: 'java'
5 |
6 | sourceCompatibility = 1.8
7 |
8 | repositories {
9 | mavenCentral()
10 | }
11 |
12 | dependencies {
13 | testCompile group: 'junit', name: 'junit', version: '4.12'
14 | implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
15 |
16 | // https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on
17 | compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.60'
18 |
19 | // https://mvnrepository.com/artifact/org.web3j/crypto
20 | compile group: 'org.web3j', name: 'crypto', version: '3.6.0'
21 | }
22 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iost-official/java-sdk/f62dd09a3d26fc5833b2a48653cb2e414eadfc8a/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Jan 02 15:56:21 CST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | io.github.qyvlik
7 | io.iost-java-sdk
8 | broker-v3.2.0
9 | io.iost-java-sdk
10 | iost.io java-sdk
11 | https://github.com/qyvlik/io.iost-java-sdk
12 |
13 |
14 |
15 | qyvlik
16 | qyvlik@qq.com
17 |
18 |
19 |
20 |
21 | scm:git:git://github.com/qyvlik/io.iost-java-sdk.git
22 | scm:git@github.com:qyvlik/io.iost-java-sdk.git
23 | https://github.com/qyvlik/io.iost-java-sdk
24 | HEAD
25 |
26 |
27 |
28 |
29 | MIT License
30 | http://www.opensource.org/licenses/mit-license.php
31 |
32 |
33 |
34 |
35 | 1.8
36 | 1.8
37 | 1.8
38 |
39 |
40 |
41 |
42 | junit
43 | junit
44 | 4.13.1
45 | test
46 |
47 |
48 |
49 | org.bouncycastle
50 | bcprov-jdk15on
51 | 1.60
52 |
53 |
54 |
55 | org.web3j
56 | crypto
57 | 3.6.0
58 |
59 |
60 |
61 | com.google.code.gson
62 | gson
63 | 2.8.5
64 |
65 |
66 |
67 |
68 | com.squareup.okhttp3
69 | okhttp
70 | 3.12.0
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | release
80 |
81 |
82 |
83 |
84 | org.apache.maven.plugins
85 | maven-source-plugin
86 | 2.2.1
87 |
88 |
89 | package
90 |
91 | jar-no-fork
92 |
93 |
94 |
95 |
96 |
97 |
98 | org.apache.maven.plugins
99 | maven-javadoc-plugin
100 | 2.9.1
101 |
102 |
103 | package
104 |
105 | jar
106 |
107 |
108 |
109 |
110 |
111 |
112 | org.apache.maven.plugins
113 | maven-gpg-plugin
114 | 1.5
115 |
116 |
117 | verify
118 |
119 | sign
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | ossrh
130 | https://oss.sonatype.org/content/repositories/snapshots
131 |
132 |
133 | ossrh
134 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'io.iost-java-sdk'
2 |
3 |
--------------------------------------------------------------------------------
/src/main/java/iost/Client.java:
--------------------------------------------------------------------------------
1 | package iost;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.GsonBuilder;
5 | import iost.model.account.*;
6 | import iost.model.block.*;
7 | import iost.model.info.*;
8 | import iost.model.transaction.*;
9 | import okhttp3.*;
10 |
11 | import java.io.IOException;
12 | import java.util.Date;
13 | import java.util.HashMap;
14 | import java.util.Map;
15 | import java.util.concurrent.TimeoutException;
16 |
17 | /**
18 | * Client IOST RPC interface
19 | */
20 | public class Client {
21 |
22 | private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
23 | private static final MediaType TXT_PLAIN = MediaType.parse("text/plain; charset=utf-8");
24 |
25 | private OkHttpClient client;
26 | private String host;
27 | private Gson gson;
28 |
29 | /**
30 | * new client
31 | *
32 | * @param url - IOST full node http port, often at port 30001,eg. http://localhost:30001/
33 | */
34 | public Client(String url) {
35 | this.host = url;
36 | this.client = new OkHttpClient();
37 | GsonBuilder gb = new GsonBuilder();
38 | gb.registerTypeAdapter(Signature.class, new SignatureAdapter());
39 | this.gson = gb.create();
40 | }
41 |
42 | private String post(String url, Object json) throws IOException {
43 | RequestBody body = RequestBody.create(TXT_PLAIN, this.gson.toJson(json));
44 | Request request = new Request.Builder().url(host + url).header("Connection", "close").post(body).build();
45 | Response response = client.newCall(request).execute();
46 | if (response.code() != 200) throw new IOException(response.body().string());
47 | return response.body().string();
48 | }
49 |
50 | private String get(String url) throws IOException {
51 | this.client = new OkHttpClient();
52 | Request request = new Request.Builder().url(host + url).build();
53 | Response response = client.newCall(request).execute();
54 | if (response.code() != 200) throw new IOException(response.body().string());
55 | return response.body().string();
56 | }
57 |
58 |
59 | /**
60 | * get node info
61 | *
62 | * @return - node info
63 | * @throws IOException - network error
64 | */
65 | public NodeInfo getNodeInfo() throws IOException {
66 | String json = this.get("getNodeInfo");
67 | return this.gson.fromJson(json, NodeInfo.class);
68 | }
69 |
70 |
71 | /**
72 | * get blockchain info
73 | *
74 | * @return - chain info
75 | * @throws IOException -
76 | */
77 | public ChainInfo getChainInfo() throws IOException {
78 | String json = this.get("getChainInfo");
79 | return this.gson.fromJson(json, ChainInfo.class);
80 |
81 | }
82 |
83 | /**
84 | * get block by block head hash
85 | *
86 | * @param hash - hash in base58
87 | * @param complete - is full block instead of block info
88 | * @return Block
89 | * @throws IOException -
90 | */
91 | public BlockResponse getBlockByHash(String hash, boolean complete) throws IOException {
92 | String api = "getBlockByHash/" + hash + "/" + (complete ? "true" : "false");
93 | String json = this.get(api);
94 | return this.gson.fromJson(json, BlockResponse.class);
95 | }
96 |
97 |
98 | /**
99 | * get block by block number
100 | *
101 | * @param num - height of block
102 | * @param complete - is full block instead of block info
103 | * @return {response}
104 | * @throws IOException -
105 | */
106 | public BlockResponse getBlockByNumber(String num, boolean complete) throws IOException {
107 | String api = "getBlockByNumber/" + num + "/" + (complete ? "true" : "false");
108 | return this.gson.fromJson(this.get(api), BlockResponse.class);
109 | }
110 |
111 | /**
112 | * get current ram info
113 | *
114 | * @return -
115 | * @throws IOException -
116 | */
117 | public RamInfo getRamInfo() throws IOException {
118 | return this.gson.fromJson(this.get("getRAMInfo"), RamInfo.class);
119 | }
120 |
121 |
122 | /**
123 | * get balance of some token
124 | *
125 | * @param account - account
126 | * @param token - token name
127 | * @param byLongestChain - is query in longest chain (instead of irreversible chain)
128 | * @return - balance
129 | * @throws IOException - net error
130 | */
131 | public TokenBalance getBalance(String account, String token, boolean byLongestChain) throws IOException {
132 | String api = "getTokenBalance/" + account + "/" + token + "/" + byLongestChain;
133 | return this.gson.fromJson(this.get(api), TokenBalance.class);
134 | }
135 |
136 | /**
137 | * get balance of some token721
138 | *
139 | * @param address - account
140 | * @param tokenSymbol - token name
141 | * @param useLongestChain - is query in longest chain (instead of irreversible chain)
142 | * @return {json String}
143 | * @throws IOException -
144 | */
145 | public TokenBalance getToken721Balance(String address, String tokenSymbol, boolean useLongestChain) throws IOException {
146 | String api = "getToken721Balance/" + address + "/" + tokenSymbol + "/" + useLongestChain;
147 | return this.gson.fromJson(this.get(api), TokenBalance.class);
148 | }
149 |
150 | /**
151 | * get metadata of token721
152 | *
153 | * @param tokenSymbol - account
154 | * @param tokenID - token name
155 | * @param useLongestChain - is query in longest chain (instead of irreversible chain)
156 | * @return - metadata
157 | * @throws IOException -
158 | */
159 | public String getToken721Metadata(String tokenSymbol, String tokenID, boolean useLongestChain) throws IOException {
160 | String api = "getToken721Metadata/" + tokenSymbol + "/" + tokenID + "/" + useLongestChain;
161 | String s = this.get(api);
162 | Map json = this.gson.fromJson(s, Map.class);
163 | return (String) json.get("metadata");
164 |
165 | }
166 |
167 | /**
168 | * get owner of token721
169 | *
170 | * @param tokenSymbol - account
171 | * @param tokenID - token name
172 | * @param useLongestChain - is query in longest chain (instead of irreversible chain)
173 | * @return - owner
174 | * @throws IOException -
175 | */
176 | public String getToken721Owner(String tokenSymbol, String tokenID, boolean useLongestChain) throws IOException {
177 | String api = "getToken721Owner/" + tokenSymbol + "/" + tokenID + "/" + useLongestChain;
178 | String s = this.get(api);
179 | Map json = this.gson.fromJson(s, Map.class);
180 | return (String) json.get("owner");
181 |
182 | }
183 |
184 | /**
185 | * get smart contract
186 | *
187 | * @param id - contract id
188 | * @param byLongestChain - is query in longest chain (instead of irreversible chain)
189 | * @return - code of contract
190 | * @throws IOException -
191 | */
192 | public String getContract(String id, boolean byLongestChain) throws IOException {
193 | String api = "getContract/" + id + "/" + byLongestChain;
194 | return this.get(api);
195 | }
196 |
197 | /**
198 | * get smart contract states
199 | *
200 | * @param contractID - contract id
201 | * @param key - key
202 | * @param field - field (set to null if it's not a map)
203 | * @param byLongestChain - is query in longest chain (instead of irreversible chain)
204 | * @return - value to string
205 | * @throws IOException -
206 | */
207 | public String getContractStorage(String contractID, String key, String field, boolean byLongestChain) throws IOException {
208 |
209 | HashMap json = new HashMap<>();
210 | json.put("by_longest_chain", byLongestChain);
211 | json.put("field", field);
212 | json.put("key", key);
213 | json.put("id", contractID);
214 | String api = "getContractStorage";
215 | return this.post(api, json);
216 | }
217 |
218 |
219 | /**
220 | * get smart contract keys of map
221 | *
222 | * @param contractID - contract id
223 | * @param fields - key
224 | * @param by_longest_chain - is query in longest chain (instead of irreversible chain)
225 | * @return keys in json array
226 | * @throws IOException -
227 | */
228 | public String getContractStorageFields(String contractID, String fields, boolean by_longest_chain) throws IOException {
229 | HashMap json = new HashMap<>();
230 | json.put("by_longest_chain", by_longest_chain);
231 | json.put("fields", fields);
232 | json.put("id", contractID);
233 | String api = "getContractStorageFields";
234 | return this.post(api, json);
235 | }
236 |
237 |
238 | /**
239 | * get account info
240 | *
241 | * @param name - account name
242 | * @param by_longest_chain - is query in longest chain (instead of irreversible chain)
243 | * @return {response}
244 | * @throws IOException -
245 | */
246 | public Account getAccountInfo(String name, boolean by_longest_chain) throws IOException {
247 | String api = "getAccount/" + name + "/" + by_longest_chain;
248 | String s = this.get(api);
249 | return this.gson.fromJson(s, Account.class);
250 | }
251 |
252 | /**
253 | * get current gas ratio
254 | *
255 | * @return - gas ratio
256 | * @throws IOException -
257 | */
258 | public GasRatio getGasRatio() throws IOException {
259 | String s = this.get("getGasRatio");
260 | return this.gson.fromJson(s, GasRatio.class);
261 | }
262 |
263 | /**
264 | * get gas usage this acton will cost
265 | *
266 | * @param actionName - your action name
267 | * @return - gas usage
268 | */
269 | public long getGasUsage(String actionName) {
270 | switch (actionName) {
271 | case "transfer":
272 | return 7800;
273 | case "newAccount":
274 | return 115000;
275 | }
276 | return 0;
277 | }
278 |
279 |
280 | /**
281 | * sent transaction
282 | *
283 | * @param tx - transaction
284 | * @return - transaction hash
285 | * @throws IOException -
286 | */
287 | public String sendTx(Transaction tx) throws IOException {
288 | String api = "sendTx";
289 | String jsonHash = this.post(api, tx);
290 | Map m = gson.fromJson(jsonHash, Map.class);
291 | return (String) m.get("hash");
292 | }
293 |
294 | class wrappedTx {
295 | String status;
296 | Transaction transaction;
297 | }
298 |
299 | /**
300 | * find tx by tx hash
301 | *
302 | * @param hash - transaction hash
303 | * @return transaction in json
304 | * @throws IOException while net error
305 | */
306 | public Transaction getTxByHash(String hash) throws IOException { // todo return a transaction object
307 |
308 | String api = "getTxByHash/" + hash;
309 | String s = this.get(api);
310 | wrappedTx wtx = this.gson.fromJson(s, wrappedTx.class);
311 | return wtx.transaction;
312 | }
313 |
314 | /**
315 | * get TxReceipt by transaction hash
316 | *
317 | * @param txHash - Tx hash in Base58
318 | * @return tx receipt
319 | * @throws IOException -
320 | */
321 | public TxReceipt getTxReceiptByTxHash(String txHash) throws IOException {
322 | String api = "getTxReceiptByTxHash/" + txHash;
323 | String s = this.get(api);
324 | return this.gson.fromJson(s, TxReceipt.class);
325 | }
326 |
327 |
328 | /**
329 | * polling transaction receipt
330 | *
331 | * @param hash - tx hash
332 | * @param intervalInMillis -
333 | * @param times -
334 | * @return - TxReceipt
335 | * @throws TimeoutException -
336 | */
337 | public TxReceipt polling(String hash, long intervalInMillis, int times) throws TimeoutException {
338 | TxReceipt receipt;
339 | for (int i = 0; i < times; i++) {
340 | try {
341 | receipt = this.getTxReceiptByTxHash(hash);
342 | return receipt;
343 | } catch (IOException e) {
344 | try {
345 | Thread.sleep(intervalInMillis);
346 | } catch (InterruptedException e1) {
347 | e1.printStackTrace();
348 | }
349 | }
350 | }
351 |
352 | throw new TimeoutException();
353 |
354 | }
355 |
356 | /**
357 | * get current time of server
358 | * @return current time of server
359 | */
360 | public long getNow() throws IOException {
361 | return new Long(getNodeInfo().server_time);
362 | }
363 |
364 |
365 | }
366 |
--------------------------------------------------------------------------------
/src/main/java/iost/IOST.java:
--------------------------------------------------------------------------------
1 | package iost;
2 |
3 | import iost.crypto.Base58;
4 | import iost.model.transaction.Transaction;
5 |
6 | import java.io.IOException;
7 | import java.math.BigDecimal;
8 | import java.util.Date;
9 |
10 | public class IOST {
11 | private long gasLimit, gasRatio;
12 | private long expiration, delay;
13 |
14 | /**
15 | * set default params of this IOST generated transaction
16 | *
17 | * @param gasLimit -
18 | * @param gasRatio -
19 | * @param expirationInMillis -
20 | * @param delay -
21 | */
22 | public IOST(long gasLimit, long gasRatio, long expirationInMillis, long delay) {
23 | this.gasLimit = gasLimit;
24 | this.gasRatio = gasRatio;
25 | this.expiration = expirationInMillis;
26 | this.delay = delay;
27 | }
28 |
29 |
30 | /**
31 | * Use default values
32 | */
33 | public IOST() {
34 | this.gasLimit = 1000000;
35 | this.gasRatio = 1;
36 | this.delay = 0;
37 | this.expiration = 90000000000L;
38 | }
39 |
40 | /**
41 | * @param cid - contract id
42 | * @param abi - abi to call
43 | * @param data - params of abi
44 | * @return - Transaction with single action
45 | */
46 | public Transaction callABI(String cid, String abi, Object... data) {
47 | Transaction tx = new Transaction();
48 | tx.time = new Date().getTime() * 1000000;
49 | tx.expiration = tx.time + this.expiration * 1000000;
50 | tx.gas_limit = this.gasLimit;
51 | tx.gas_ratio = this.gasRatio;
52 | tx.delay = this.delay;
53 | tx.addAction(cid, abi, data);
54 | return tx;
55 | }
56 |
57 | /**
58 | * @param token -
59 | * @param from -
60 | * @param to -
61 | * @param amount -
62 | * @param memo -
63 | * @return -
64 | */
65 | public Transaction transfer(String token, String from, String to, BigDecimal amount, String memo) {
66 | Transaction tx = this.callABI("token.iost", "transfer", token, from, to, amount.toString(), memo);
67 | tx.addApprove(token, amount.toString());
68 |
69 | return tx;
70 | }
71 |
72 | /**
73 | * @param name -
74 | * @param creator -
75 | * @param ownerkey -
76 | * @param activekey -
77 | * @param initialRAM -
78 | * @param initialGasPledge -
79 | * @return -
80 | */
81 | public Transaction newAccount(String name, String creator, String ownerkey, String activekey, long initialRAM,
82 | double initialGasPledge) throws IOException {
83 | if (!this.checkPubkey(ownerkey) || !this.checkPubkey(activekey))
84 | throw new IOException("illegal public key");
85 | Transaction t = this.callABI("auth.iost", "signUp", name, ownerkey, activekey);
86 | if (initialRAM > 0) {
87 | t.addAction("ram.iost", "buy", creator, name, initialRAM);
88 | }
89 | if (initialGasPledge > 0) {
90 | t.addAction("gas.iost", "pledge", creator, name, String.format ("%.4f", initialGasPledge));
91 | }
92 | t.addApprove("iost", "unlimited");
93 | return t;
94 | }
95 |
96 | private boolean checkPubkey(String key) {
97 | try {
98 | byte[] k = Base58.decode(key);
99 | if (k.length != 32) {
100 | return false;
101 | }
102 | return true;
103 |
104 | } catch (IOException e) {
105 | return false;
106 | }
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/src/main/java/iost/Keychain.java:
--------------------------------------------------------------------------------
1 | package iost;
2 |
3 | import iost.crypto.KeyPair;
4 | import iost.model.transaction.Transaction;
5 |
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | /**
10 | * keyChain
11 | */
12 | public class Keychain {
13 | private String account;
14 | private Map keys = new HashMap<>();
15 |
16 | /**
17 | * new key chain of account
18 | * @param account -
19 | */
20 | public Keychain(String account) {
21 | this.account = account;
22 | }
23 |
24 | /**
25 | * add sign of tx
26 | * @param tx -
27 | * @param perm - permission
28 | */
29 | public void sign(Transaction tx, String perm) {
30 | byte[] buf = tx.getSignHash();
31 | KeyPair kp = this.keys.get(perm);
32 | tx.signatures.add(kp.sign(buf));
33 | }
34 |
35 | /**
36 | * add publish sign of tx
37 | * @param tx -
38 | */
39 | public void publish(Transaction tx) {
40 | byte[] buf = tx.getPublishHash();
41 | KeyPair kp = this.keys.get("active");
42 | tx.publisher_sigs.add(kp.sign(buf));
43 | tx.publisher = this.account;
44 | }
45 |
46 | /**
47 | * add key to keychain
48 | * @param perm - add key to permission
49 | * @param kp - key pair
50 | */
51 | public void addKey(String perm, KeyPair kp) {
52 | this.keys.put(perm, kp);
53 | }
54 |
55 | /**
56 | * get key from keychain
57 | * @param perm - permission
58 | * @return - key pair
59 | */
60 | public KeyPair getKey(String perm) {
61 | return this.keys.get(perm);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/iost/crypto/Algorithm.java:
--------------------------------------------------------------------------------
1 | package iost.crypto;
2 |
3 | /**
4 | * crypto algorithm of IOST
5 | */
6 | public enum Algorithm {
7 | Secp256k1,
8 | Ed25519;
9 |
10 | @Override
11 | public String toString() {
12 | switch (this) {
13 | case Ed25519:
14 | return "ed25519";
15 | case Secp256k1:
16 | return "secp256k1";
17 | }
18 | return "";
19 | }
20 |
21 | public byte toByte() {
22 | switch (this) {
23 | case Ed25519:
24 | return 2;
25 | case Secp256k1:
26 | return 1;
27 | }
28 | return 0;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/iost/crypto/Base58.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 Google Inc.
3 | * Copyright 2018 Andreas Schildbach
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package iost.crypto;
19 |
20 | import java.io.IOException;
21 | import java.math.BigInteger;
22 | import java.util.Arrays;
23 |
24 | public class Base58 {
25 | public static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
26 | private static final char ENCODED_ZERO = ALPHABET[0];
27 | private static final int[] INDEXES = new int[128];
28 | static {
29 | Arrays.fill(INDEXES, -1);
30 | for (int i = 0; i < ALPHABET.length; i++) {
31 | INDEXES[ALPHABET[i]] = i;
32 | }
33 | }
34 |
35 | public static String encode(byte[] input) {
36 | if (input.length == 0) {
37 | return "";
38 | }
39 | // Count leading zeros.
40 | int zeros = 0;
41 | while (zeros < input.length && input[zeros] == 0) {
42 | ++zeros;
43 | }
44 | // Convert base-256 digits to base-58 digits (plus conversion to ASCII characters)
45 | input = Arrays.copyOf(input, input.length); // since we modify it in-place
46 | char[] encoded = new char[input.length * 2]; // upper bound
47 | int outputStart = encoded.length;
48 | for (int inputStart = zeros; inputStart < input.length; ) {
49 | encoded[--outputStart] = ALPHABET[divmod(input, inputStart, 256, 58)];
50 | if (input[inputStart] == 0) {
51 | ++inputStart; // optimization - skip leading zeros
52 | }
53 | }
54 | // Preserve exactly as many leading encoded zeros in output as there were leading zeros in input.
55 | while (outputStart < encoded.length && encoded[outputStart] == ENCODED_ZERO) {
56 | ++outputStart;
57 | }
58 | while (--zeros >= 0) {
59 | encoded[--outputStart] = ENCODED_ZERO;
60 | }
61 | // Return encoded string (including encoded leading zeros).
62 | return new String(encoded, outputStart, encoded.length - outputStart);
63 | }
64 |
65 |
66 |
67 | /**
68 | * Decodes the given base58 string into the original data bytes.
69 | *
70 | * @param input the base58-encoded string to decode
71 | * @return the decoded data bytes
72 | * @throws java.io.IOException if the given string is not a valid base58 string
73 | */
74 | public static byte[] decode(String input) throws IOException {
75 | if (input.length() == 0) {
76 | return new byte[0];
77 | }
78 | // Convert the base58-encoded ASCII chars to a base58 byte sequence (base58 digits).
79 | byte[] input58 = new byte[input.length()];
80 | for (int i = 0; i < input.length(); ++i) {
81 | char c = input.charAt(i);
82 | int digit = c < 128 ? INDEXES[c] : -1;
83 | if (digit < 0) {
84 | throw new IOException("invalid char");
85 | }
86 | input58[i] = (byte) digit;
87 | }
88 | // Count leading zeros.
89 | int zeros = 0;
90 | while (zeros < input58.length && input58[zeros] == 0) {
91 | ++zeros;
92 | }
93 | // Convert base-58 digits to base-256 digits.
94 | byte[] decoded = new byte[input.length()];
95 | int outputStart = decoded.length;
96 | for (int inputStart = zeros; inputStart < input58.length; ) {
97 | decoded[--outputStart] = divmod(input58, inputStart, 58, 256);
98 | if (input58[inputStart] == 0) {
99 | ++inputStart; // optimization - skip leading zeros
100 | }
101 | }
102 | // Ignore extra leading zeroes that were added during the calculation.
103 | while (outputStart < decoded.length && decoded[outputStart] == 0) {
104 | ++outputStart;
105 | }
106 | // Return decoded data (including original number of leading zeros).
107 | return Arrays.copyOfRange(decoded, outputStart - zeros, decoded.length);
108 | }
109 |
110 | public static BigInteger decodeToBigInteger(String input) throws IOException {
111 | return new BigInteger(1, decode(input));
112 | }
113 |
114 | private static byte divmod(byte[] number, int firstDigit, int base, int divisor) {
115 | // this is just long division which accounts for the base of the input digits
116 | int remainder = 0;
117 | for (int i = firstDigit; i < number.length; i++) {
118 | int digit = (int) number[i] & 0xFF;
119 | int temp = remainder * base + digit;
120 | number[i] = (byte) (temp / divisor);
121 | remainder = temp % divisor;
122 | }
123 | return (byte) remainder;
124 | }
125 | }
--------------------------------------------------------------------------------
/src/main/java/iost/crypto/Ed25519.java:
--------------------------------------------------------------------------------
1 | package iost.crypto;
2 |
3 | import iost.model.transaction.Signature;
4 |
5 | /**
6 | * Ed25519 key pair
7 | */
8 | public class Ed25519 extends KeyPair {
9 | private byte[] privateKey;
10 | private byte[] publicKey;
11 |
12 | /**
13 | * new key pair with crypto-safe random key
14 | */
15 | public Ed25519() {
16 | publicKey = new byte[TweetNaCl.SIGN_PUBLIC_KEY_BYTES];
17 | privateKey = new byte[TweetNaCl.SIGN_SECRET_KEY_BYTES];
18 | TweetNaCl.crypto_sign_keypair(publicKey, privateKey, false);
19 | }
20 |
21 | /**
22 | * new key pair with given private key
23 | *
24 | * @param seckey - private key
25 | */
26 | public Ed25519(byte[] seckey) {
27 | int l = 32;
28 | if (seckey.length < 32) {
29 | l = seckey.length;
30 | }
31 | publicKey = new byte[TweetNaCl.SIGN_PUBLIC_KEY_BYTES];
32 | privateKey = new byte[TweetNaCl.SIGN_SECRET_KEY_BYTES];
33 | System.arraycopy(seckey, 0, privateKey, 0, l);
34 | TweetNaCl.crypto_sign_keypair(publicKey, privateKey, true);
35 | }
36 |
37 |
38 | @Override
39 | public Signature sign(byte[] info) {
40 | byte[] sig = TweetNaCl.crypto_sign(info, this.privateKey);
41 |
42 | Signature signature = new Signature();
43 | signature.signature = sig;
44 | signature.algorithm = Algorithm.Ed25519;
45 | signature.public_key = this.pubkey();
46 |
47 | return signature;
48 | }
49 |
50 | @Override
51 | public byte[] pubkey() {
52 | return this.publicKey;
53 | }
54 |
55 | @Override
56 | public byte[] seckey() {
57 | return this.privateKey;
58 | }
59 |
60 | @Override
61 | public boolean verify(byte[] info, byte[] signature) {
62 | return VerifyUtils.Ed25519Verify(info, signature, pubkey());
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/iost/crypto/KeyPair.java:
--------------------------------------------------------------------------------
1 | package iost.crypto;
2 |
3 | import iost.model.transaction.Signature;
4 |
5 |
6 | /**
7 | * key pair in IOST
8 | */
9 | public abstract class KeyPair {
10 |
11 | private String ID;
12 |
13 | /**
14 | * get this key pair's key id
15 | * @return - base58 encoded public key
16 | */
17 | public String getID() {
18 | if (this.ID == null) {
19 | this.ID = Base58.encode(this.pubkey());
20 | }
21 | return this.ID;
22 | }
23 |
24 | /**
25 | * get public key in base58
26 | * @return -
27 | */
28 | public String B58PubKey() {
29 | return Base58.encode(this.pubkey());
30 | }
31 |
32 | /**
33 | * get private key in base58
34 | * @return -
35 | */
36 | public String B58SecKey() {
37 | return Base58.encode(this.seckey());
38 | }
39 |
40 | /**
41 | * sign to info
42 | * @param info - 256 bit info
43 | * @return - Signature
44 | */
45 | abstract public Signature sign(byte[] info);
46 | abstract public byte[] pubkey();
47 | abstract public byte[] seckey();
48 | abstract public boolean verify(byte[] info, byte[] signature);
49 | }
50 |
51 |
--------------------------------------------------------------------------------
/src/main/java/iost/crypto/Secp256k1.java:
--------------------------------------------------------------------------------
1 | package iost.crypto;
2 |
3 | import iost.model.transaction.Signature;
4 | import org.web3j.crypto.ECDSASignature;
5 | import org.web3j.crypto.ECKeyPair;
6 | import org.web3j.crypto.Keys;
7 | import org.web3j.crypto.Sign;
8 |
9 | import java.math.BigInteger;
10 | import java.nio.ByteBuffer;
11 | import java.security.InvalidAlgorithmParameterException;
12 | import java.security.NoSuchAlgorithmException;
13 | import java.security.NoSuchProviderException;
14 | import java.util.Arrays;
15 |
16 | /**
17 | * secp256k1 key pair
18 | */
19 | public class Secp256k1 extends KeyPair {
20 | private ECKeyPair kp;
21 |
22 | /**
23 | * new key pair with given private key
24 | *
25 | * @param seckey - private key
26 | */
27 | public Secp256k1(byte[] seckey) {
28 | this.kp = ECKeyPair.create(seckey);
29 | }
30 |
31 | /**
32 | * new key pair with crypto-safe random key
33 | */
34 | public Secp256k1() {
35 | try {
36 | kp = Keys.createEcKeyPair();
37 | } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | NoSuchProviderException e) {
38 | e.printStackTrace();
39 | }
40 | }
41 |
42 | @Override
43 | public Signature sign(byte[] info) {
44 | ECDSASignature sig = this.kp.sign(info).toCanonicalised();
45 |
46 | ByteBuffer bb = ByteBuffer.allocate(64);
47 | bb.put(sig.r.toByteArray());
48 | bb.put(sig.s.toByteArray());
49 |
50 | Signature signature = new Signature();
51 | signature.signature = bb.array();
52 | signature.public_key = this.pubkey();
53 | signature.algorithm = Algorithm.Secp256k1;
54 | return signature;
55 | }
56 |
57 | @Override
58 | public byte[] pubkey() {
59 | ByteBuffer bb = ByteBuffer.allocate(33);
60 | bb.put((byte) 0x02);
61 | bb.put(Arrays.copyOf(this.kp.getPublicKey().toByteArray(), 32));
62 | return bb.array();
63 | }
64 |
65 | @Override
66 | public byte[] seckey() {
67 | return this.kp.getPrivateKey().toByteArray();
68 | }
69 |
70 | /**
71 | * verify Secp256k1 signature
72 | *
73 | * @param info info
74 | * @param signature signature
75 | * @return verify result
76 | */
77 | @Override
78 | public boolean verify(byte[] info, byte[] signature) {
79 | assert seckey() != null;
80 | // note: the Secp256k1::pubkey return part data, check full pubkey maybe necessary
81 | byte[] pubKey = Sign.publicKeyFromPrivate(new BigInteger(seckey())).toByteArray();
82 | return VerifyUtils.Secp256k1Verify(info, signature, pubKey);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/iost/crypto/SimpleEncoder.java:
--------------------------------------------------------------------------------
1 | package iost.crypto;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | public class SimpleEncoder {
6 | public ByteBuffer buffer;
7 |
8 | public SimpleEncoder(int cap) {
9 | this.buffer = ByteBuffer.allocate(cap);
10 | }
11 |
12 | public SimpleEncoder(byte[] buf) {
13 | this.buffer = ByteBuffer.allocate(65536);
14 | this.buffer.put(buf);
15 | }
16 |
17 | public SimpleEncoder putString(String s) {
18 | byte [] buf = s.getBytes();
19 |
20 | this.buffer.putInt(buf.length);
21 | this.buffer.put(buf);
22 | return this;
23 | }
24 |
25 | public SimpleEncoder putBytes(byte[] bb) {
26 | this.buffer.putInt(bb.length);
27 | this.buffer.put(bb);
28 | return this;
29 | }
30 |
31 | public byte[] toBytes() {
32 | byte[] buf = new byte[this.buffer.flip().remaining()];
33 | this.buffer.get(buf);
34 | return buf;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/iost/crypto/TweetNaCl.java:
--------------------------------------------------------------------------------
1 | package iost.crypto;
2 |
3 | import java.security.NoSuchAlgorithmException;
4 | import java.security.SecureRandom;
5 | import java.util.Arrays;
6 | import java.util.Random;
7 |
8 | /* Ported from the original C by Ian Preston and Chris Boddy
9 | * crypto_hash() is ported from TweetNaCl.js
10 | * Released under GPL 2
11 | */
12 |
13 | public class TweetNaCl {
14 |
15 | public static final int crypto_auth_hmacsha512256_tweet_BYTES = 32;
16 | public static final int crypto_auth_hmacsha512256_tweet_KEYBYTES = 32;
17 | public static final int BOX_PUBLIC_KEY_BYTES = 32;
18 | public static final int BOX_SECRET_KEY_BYTES = 32;
19 | public static final int BOX_SHARED_KEY_BYTES = 32;
20 | public static final int BOX_NONCE_BYTES = 24;
21 | public static final int BOX_OVERHEAD_BYTES = 16;
22 | public static final int SIGNATURE_SIZE_BYTES = 64;
23 | public static final int SIGN_PUBLIC_KEY_BYTES = 32;
24 | public static final int SIGN_SECRET_KEY_BYTES = 64;
25 | public static final int SIGN_KEYPAIR_SEED_BYTES = 32;
26 | public static final int SECRETBOX_KEY_BYTES = 32;
27 | public static final int SECRETBOX_NONCE_BYTES = 24;
28 | public static final int SECRETBOX_OVERHEAD_BYTES = 16;
29 | public static final int HASH_SIZE_BYTES = 64; // SHA-512
30 | private static final int SECRETBOX_INTERNAL_OVERHEAD_BYTES = 32;
31 |
32 | public static class InvalidSignatureException extends RuntimeException {
33 |
34 | /**
35 | *
36 | */
37 | private static final long serialVersionUID = 1L;}
38 | public static class InvalidCipherTextException extends RuntimeException {
39 |
40 | /**
41 | *
42 | */
43 | private static final long serialVersionUID = 1L;}
44 |
45 | public static void crypto_sign_keypair(byte[] pk, byte[] sk, boolean isSeeded)
46 | {
47 | byte[] d = new byte[64];
48 | long[][] /*gf*/ p = new long[4][GF_LEN];
49 | int i;
50 |
51 | if (!isSeeded)
52 | randombytes(sk, 32);
53 | crypto_hash(d, sk, 32);
54 | d[0] &= 248;
55 | d[31] &= 127;
56 | d[31] |= 64;
57 |
58 | scalarbase(p,d, 0);
59 | pack(pk,p);
60 |
61 | for (i=0;i < 32;++i)sk[32 + i] = pk[i];
62 | }
63 |
64 | public static int crypto_box_keypair(byte[] y,byte[] x, boolean isSeeded)
65 | {
66 | if (!isSeeded)
67 | randombytes(x,32);
68 | return crypto_scalarmult_base(y,x);
69 | }
70 |
71 | public static int crypto_scalarmult_base(byte[] q,byte[] n)
72 | {
73 | return crypto_scalarmult(q, n, _9);
74 | }
75 |
76 | public static byte[] crypto_sign(byte[] message, byte[] secretSigningKey) {
77 | byte[] signedMessage = new byte[message.length + TweetNaCl.SIGNATURE_SIZE_BYTES];
78 | TweetNaCl.crypto_sign(signedMessage, message, message.length, secretSigningKey);
79 | return Arrays.copyOfRange(signedMessage, 0, 64);
80 | }
81 |
82 | public static byte[] crypto_sign_open(byte[] signed, byte[] publicSigningKey) {
83 | byte[] message = new byte[signed.length];
84 | int res = TweetNaCl.crypto_sign_open(message, signed, signed.length, publicSigningKey);
85 | if (res != 0)
86 | throw new InvalidSignatureException();
87 | return Arrays.copyOfRange(message, 64, message.length);
88 | }
89 |
90 | public static byte[] crypto_box(byte[] message, byte[] nonce, byte[] theirPublicBoxingKey, byte[] ourSecretBoxingKey) {
91 | if (nonce.length != BOX_NONCE_BYTES)
92 | throw new IllegalStateException("Illegal nonce length: "+nonce.length);
93 | byte[] cipherText = new byte[SECRETBOX_INTERNAL_OVERHEAD_BYTES + message.length];
94 | byte[] paddedMessage = new byte[SECRETBOX_INTERNAL_OVERHEAD_BYTES + message.length];
95 | System.arraycopy(message, 0, paddedMessage, SECRETBOX_INTERNAL_OVERHEAD_BYTES, message.length);
96 | TweetNaCl.crypto_box(cipherText, paddedMessage, paddedMessage.length, nonce, theirPublicBoxingKey, ourSecretBoxingKey);
97 | return Arrays.copyOfRange(cipherText, 16, cipherText.length);
98 | }
99 |
100 | public static byte[] crypto_box_open(byte[] cipher, byte[] nonce, byte[] theirPublicBoxingKey, byte[] secretBoxingKey) {
101 | byte[] paddedCipher = new byte[cipher.length + 16];
102 | System.arraycopy(cipher, 0, paddedCipher, 16, cipher.length);
103 | byte[] rawText = new byte[paddedCipher.length];
104 | int res = TweetNaCl.crypto_box_open(rawText, paddedCipher, paddedCipher.length, nonce, theirPublicBoxingKey, secretBoxingKey);
105 | if (res != 0)
106 | throw new InvalidCipherTextException();
107 | return Arrays.copyOfRange(rawText, 32, rawText.length);
108 | }
109 |
110 | public static byte[] secretbox(byte[] mesage, byte[] nonce, byte[] key) {
111 | byte[] m = new byte[SECRETBOX_INTERNAL_OVERHEAD_BYTES + mesage.length];
112 | byte[] c = new byte[m.length];
113 | System.arraycopy(mesage, 0, m, SECRETBOX_INTERNAL_OVERHEAD_BYTES, mesage.length);
114 | crypto_secretbox(c, m, m.length, nonce, key);
115 | return Arrays.copyOfRange(c, SECRETBOX_OVERHEAD_BYTES, c.length);
116 | }
117 |
118 | public static byte[] secretbox_open(byte[] cipher, byte[] nonce, byte[] key) {
119 | byte[] c = new byte[SECRETBOX_OVERHEAD_BYTES + cipher.length];
120 | byte[] m = new byte[c.length];
121 | System.arraycopy(cipher, 0, c, SECRETBOX_OVERHEAD_BYTES, cipher.length);
122 | if (c.length < 32) throw new IllegalStateException("Cipher too small!");
123 | if (crypto_secretbox_open(m, c, c.length, nonce, key) != 0) throw new IllegalStateException("Invalid encryption!");
124 | return Arrays.copyOfRange(m, SECRETBOX_INTERNAL_OVERHEAD_BYTES, m.length);
125 | }
126 |
127 | private static byte[] _0 = new byte[16], _9 = new byte[32];
128 | static {
129 | _9[0] = 9;
130 | }
131 | private static final int GF_LEN = 16;
132 | private static long[] gf0 = new long[GF_LEN];
133 | private static long[] gf1 = new long[GF_LEN]; static{gf1[0] = 1;}
134 | private static long[] _121665 = new long[GF_LEN]; static{_121665[0] = 0xDB41; _121665[1] =1;}
135 | private static long[] D = new long[]{0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203},
136 | D2 = new long[]{0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406},
137 | X = new long[]{0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169},
138 | Y = new long[]{0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666},
139 | I = new long[]{0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83};
140 |
141 | private static int L32(int x,int c) { return (x << c) | (x >>> (32 - c)); }
142 |
143 | public static int ld32(byte[] x, int off)
144 | {
145 | int u = x[off + 3] & 0xff;
146 | u = (u<<8)|(x[off + 2] & 0xff);
147 | u = (u<<8)|(x[off + 1] & 0xff);
148 | return (u<<8)|(x[off + 0] & 0xff);
149 | }
150 |
151 | private static void st32(byte[] x, int off, int u)
152 | {
153 | int i;
154 | for (i=0;i < 4;++i){ x[off + i] = (byte)u; u >>= 8; }
155 | }
156 |
157 | private static int vn(byte[] x, int xOff, byte[] y,int n)
158 | {
159 | int i,d = 0;
160 | for (i=0;i < n;++i)d |= 0xff & (x[xOff + i]^y[i]);
161 | return (1 & ((d - 1) >> 8)) - 1;
162 | }
163 |
164 | private static int crypto_verify_16(byte[] x, int xOff, byte[] y)
165 | {
166 | return vn(x, xOff, y, 16);
167 | }
168 |
169 | private static int crypto_verify_32(byte[] x,byte[] y)
170 | {
171 | return vn(x, 0, y,32);
172 | }
173 |
174 | private static void core(byte[] out,byte[] in,byte[] k,byte[] c,int h)
175 | {
176 | int[] w = new int[16],x = new int[16],y = new int[16],t = new int[4];
177 | int i,j,m;
178 |
179 | for (i=0;i < 4;++i){
180 | x[5*i] = ld32(c,4*i);
181 | x[1+i] = ld32(k,4*i);
182 | x[6+i] = ld32(in,4*i);
183 | x[11+i] = ld32(k,16+4*i);
184 | }
185 |
186 | for (i=0;i < 16;++i)y[i] = x[i];
187 |
188 | for (i=0;i < 20;++i){
189 | for (j=0;j < 4;++j){
190 | for (m=0;m < 4;++m)t[m] = x[(5*j+4*m)%16];
191 | t[1] ^= L32(t[0]+t[3], 7);
192 | t[2] ^= L32(t[1]+t[0], 9);
193 | t[3] ^= L32(t[2]+t[1],13);
194 | t[0] ^= L32(t[3]+t[2],18);
195 | for (m=0;m < 4;++m)w[4*j+(j+m)%4] = t[m];
196 | }
197 | for (m=0;m < 16;++m)x[m] = w[m];
198 | }
199 |
200 | if (h != 0) {
201 | for (i=0;i < 16;++i)x[i] += y[i];
202 | for (i=0;i < 4;++i){
203 | x[5*i] -= ld32(c,4*i);
204 | x[6+i] -= ld32(in,4*i);
205 | }
206 | for (i=0;i < 4;++i){
207 | st32(out, 4*i,x[5*i]);
208 | st32(out, 16+4*i,x[6+i]);
209 | }
210 | } else
211 | for (i=0;i < 16;++i)st32(out, 4 * i,x[i] + y[i]);
212 | }
213 |
214 | private static int crypto_core_salsa20(byte[] out,byte[] in,byte[] k,byte[] c)
215 | {
216 | core(out,in,k,c,0);
217 | return 0;
218 | }
219 |
220 | private static int crypto_core_hsalsa20(byte[] out,byte[] in,byte[] k,byte[] c)
221 | {
222 | core(out,in,k,c,1);
223 | return 0;
224 | }
225 |
226 | private static byte[] sigma = { 101, 120, 112, 97, 110, 100, 32, 51, 50, 45, 98, 121, 116, 101, 32, 107 };
227 |
228 | private static int crypto_stream_salsa20_xor(byte[] c,byte[] m,long b,byte[] n, int nOff, byte[] k)
229 | {
230 | byte[] z = new byte[16],x = new byte[64];
231 | int u,i;
232 | if (b == 0) return 0;
233 | for (i=0;i < 16;++i)z[i] = 0;
234 | for (i=0;i < 8;++i)z[i] = n[nOff + i];
235 | int cOff = 0;
236 | int mOff = 0;
237 | while (b >= 64) {
238 | crypto_core_salsa20(x,z,k,sigma);
239 | for (i=0;i < 64; ++i) c[cOff + i] = (byte)((m != null ? m[mOff + i]:0)^ x[i]);
240 | u = 1;
241 | for (i = 8;i < 16;++i) {
242 | u += 0xff & z[i];
243 | z[i] = (byte)u;
244 | u >>= 8;
245 | }
246 | b -= 64;
247 | cOff += 64;
248 | if (m != null) mOff += 64;
249 | }
250 | if (b != 0) {
251 | crypto_core_salsa20(x,z,k,sigma);
252 | for (i=0;i < b; i++) c[cOff + i] = (byte)((m != null ? m[mOff + i]:0)^ x[i]);
253 | }
254 | return 0;
255 | }
256 |
257 | private static int crypto_stream_salsa20(byte[] c,long d,byte[] n, int nOff, byte[] k)
258 | {
259 | return crypto_stream_salsa20_xor(c,null,d,n, nOff, k);
260 | }
261 |
262 | private static int crypto_stream(byte[] c,long d,byte[] n,byte[] k)
263 | {
264 | byte[] s = new byte[32];
265 | crypto_core_hsalsa20(s,n,k,sigma);
266 | return crypto_stream_salsa20(c, d, n, 16, s);
267 | }
268 |
269 | private static int crypto_stream_xor(byte[] c,byte[] m,long d,byte[] n,byte[] k)
270 | {
271 | byte[] s = new byte[32];
272 | crypto_core_hsalsa20(s,n,k,sigma);
273 | return crypto_stream_salsa20_xor(c, m, d, n, 16, s);
274 | }
275 |
276 | private static void add1305(int[] h,int[] c)
277 | {
278 | int j,u = 0;
279 | for (j=0;j < 17;++j){
280 | u += h[j] + c[j];
281 | h[j] = u & 255;
282 | u >>= 8;
283 | }
284 | }
285 |
286 | private static int[] minusp = new int[] {
287 | 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252
288 | } ;
289 |
290 | private static int crypto_onetimeauth(byte[] out, int outOff, byte[] m, int mOff, long n,byte[] k)
291 | {
292 | int s,i,j,u;
293 | int[] x = new int[17],r = new int[17],h = new int[17],c = new int[17],g = new int[17];
294 |
295 | for (j=0;j < 17;++j)
296 | r[j]= h[j] = 0;
297 | for (j=0;j < 16;++j)
298 | r[j] = 0xff & k[j];
299 | r[3]&=15;
300 | r[4]&=252;
301 | r[7]&=15;
302 | r[8]&=252;
303 | r[11]&=15;
304 | r[12]&=252;
305 | r[15]&=15;
306 |
307 | while (n > 0) {
308 | for (j=0;j < 17;++j)
309 | c[j] = 0;
310 | for (j = 0;(j < 16) && (j < n);++j)
311 | c[j] = 0xff & m[mOff + j];
312 | c[j] = 1;
313 | mOff += j; n -= j;
314 | add1305(h,c);
315 | for (i=0;i < 17;++i){
316 | x[i] = 0;
317 | for (j=0;j < 17; ++j)
318 | x[i] += h[j] * ((j <= i)? r[i - j] : 320 * r[i + 17 - j]);
319 | }
320 | for (i=0;i < 17;++i)
321 | h[i] = x[i];
322 | u = 0;
323 | for (j=0;j < 16;++j){
324 | u += h[j];
325 | h[j] = u & 255;
326 | u >>= 8;
327 | }
328 | u += h[16]; h[16] = u & 3;
329 | u = 5 * (u >> 2);
330 | for (j=0;j < 16;++j){
331 | u += h[j];
332 | h[j] = u & 255;
333 | u >>= 8;
334 | }
335 | u += h[16]; h[16] = u;
336 | }
337 |
338 | for (j=0;j < 17;++j)g[j] = h[j];
339 | add1305(h,minusp);
340 | s = -(h[16] >> 7);
341 | for (j=0;j < 17;++j)h[j] ^= s & (g[j] ^ h[j]);
342 |
343 | for (j=0;j < 16;++j)
344 | c[j] = 0xff & k[j + 16];
345 | c[16] = 0;
346 | add1305(h,c);
347 | for (j=0;j < 16;++j)out[outOff + j] = (byte)h[j];
348 | return 0;
349 | }
350 |
351 | private static int crypto_onetimeauth_verify(byte[] h, int hOff, byte[] m, int mOff, long n,byte[] k)
352 | {
353 | byte[] x = new byte[16];
354 | crypto_onetimeauth(x, 0, m, mOff, n,k);
355 | return crypto_verify_16(h, hOff, x);
356 | }
357 |
358 | private static int crypto_secretbox(byte[] c,byte[] m,long d,byte[] n,byte[] k)
359 | {
360 | int i;
361 | if (d < 32) return -1;
362 | crypto_stream_xor(c,m,d,n,k);
363 | crypto_onetimeauth(c, 16, c, 32, d - 32, c);
364 | for (i=0;i < 16;++i)c[i] = 0;
365 | return 0;
366 | }
367 |
368 | private static int crypto_secretbox_open(byte[] m,byte[] c,long d,byte[] n,byte[] k)
369 | {
370 | int i;
371 | byte[] x = new byte[32];
372 | if (d < 32) return -1;
373 | crypto_stream(x,32,n,k);
374 | if (crypto_onetimeauth_verify(c, 16,c, 32,d - 32,x) != 0) return -1;
375 | crypto_stream_xor(m, c, d, n, k);
376 | for (i=0;i < 32;++i)m[i] = 0;
377 | return 0;
378 | }
379 |
380 | private static void set25519(long[] /*gf*/ r, long[] /*gf*/ a)
381 | {
382 | int i;
383 | for (i=0;i < 16;++i)r[i]=a[i];
384 | }
385 |
386 | private static void car25519(long[] /*gf*/ o, int oOff)
387 | {
388 | for (int i=0;i < 16;++i){
389 | o[oOff + i]+=(1<<16);
390 | long c=o[oOff + i]>>16;
391 | o[oOff + (i+1) * (i<15 ? 1:0)] += c - 1 + 37 * (c-1) * (i==15 ? 1 : 0);
392 | o[oOff + i]-=c<<16;
393 | }
394 | }
395 |
396 | private static void sel25519(long[] /*gf*/ p,long[] /*gf*/ q,int b)
397 | {
398 | long t,c=~(b-1);
399 | int i;
400 | for (i=0;i < 16;++i){
401 | t= c&(p[i]^q[i]);
402 | p[i]^=t;
403 | q[i]^=t;
404 | }
405 | }
406 |
407 | private static void pack25519(byte[] o,long[] /*gf*/ n, int nOff)
408 | {
409 | int i,j,b;
410 | long[] /*gf*/ m = new long[GF_LEN],t = new long[GF_LEN];
411 | for (i=0;i < 16;++i)t[i]=n[nOff+i];
412 | car25519(t, 0);
413 | car25519(t, 0);
414 | car25519(t, 0);
415 | for (j=0;j < 2;++j){
416 | m[0]=t[0]-0xffed;
417 | for(i=1;i<15;i++) {
418 | m[i]=t[i]-0xffff-((m[i-1]>>16)&1);
419 | m[i-1]&=0xffff;
420 | }
421 | m[15]=t[15]-0x7fff-((m[14]>>16)&1);
422 | b=(int)((m[15]>>16)&1);
423 | m[14]&=0xffff;
424 | sel25519(t,m,1-b);
425 | }
426 | for (i=0;i < 16;++i){
427 | o[2*i]=(byte)t[i];
428 | o[2*i+1]=(byte)(t[i]>>8);
429 | }
430 | }
431 |
432 | private static int neq25519(long[] /*gf*/ a, long[] /*gf*/ b)
433 | {
434 | byte[] c = new byte[32],d = new byte[32];
435 | pack25519(c,a, 0);
436 | pack25519(d,b, 0);
437 | return crypto_verify_32(c,d);
438 | }
439 |
440 | private static byte par25519(long[] /*gf*/ a)
441 | {
442 | byte[] d = new byte[32];
443 | pack25519(d,a, 0);
444 | return (byte)(d[0]&1);
445 | }
446 |
447 | private static void unpack25519(long[] /*gf*/ o, byte[] n)
448 | {
449 | int i;
450 | for (i=0;i < 16;++i)
451 | o[i] = (0xff & n[2*i])+((0xffL & n[2*i+1])<<8);
452 | o[15]&=0x7fff;
453 | }
454 |
455 | private static void A(long[] /*gf*/ o,long[] /*gf*/ a,long[] /*gf*/ b)
456 | {
457 | int i;
458 | for (i=0;i < 16;++i)o[i]=a[i]+b[i];
459 | }
460 |
461 | private static void Z(long[] /*gf*/ o,long[] /*gf*/ a,long[] /*gf*/ b)
462 | {
463 | int i;
464 | for (i=0;i < 16;++i)o[i]=a[i]-b[i];
465 | }
466 |
467 | private static void M(long[] /*gf*/ o, int oOff, long[] /*gf*/ a, int aOff, long[] /*gf*/ b, int bOff)
468 | {
469 | long[] t = new long[31];
470 | for (int i=0;i < 31;++i)t[i]=0;
471 | for (int i=0;i < 16; ++i) for(int j=0; j <16;++j)t[i+j]+=a[aOff + i]*b[bOff + j];
472 | for (int i=0;i < 15;++i)t[i]+=38*t[i+16];
473 | for (int i=0;i < 16;++i)o[oOff + i]=t[i];
474 | car25519(o, oOff);
475 | car25519(o, oOff);
476 | }
477 |
478 | private static void S(long[] /*gf*/ o,long[] /*gf*/ a)
479 | {
480 | M(o, 0, a, 0, a, 0);
481 | }
482 |
483 | private static void inv25519(long[] /*gf*/ o, int oOff, long[] /*gf*/ i, int iOff)
484 | {
485 | long[] /*gf*/ c = new long[GF_LEN];
486 | int a;
487 | for (a=0;a < 16;++a)c[a]=i[iOff + a];
488 | for(a=253;a>=0;a--) {
489 | S(c,c);
490 | if(a!=2&&a!=4) M(c, 0, c, 0, i, iOff);
491 | }
492 | for (a=0;a < 16;++a)o[oOff + a]=c[a];
493 | }
494 |
495 | private static void pow2523(long[] /*gf*/ o,long[] /*gf*/ i)
496 | {
497 | long[] /*gf*/ c = new long[GF_LEN];
498 | int a;
499 | for (a=0;a < 16;++a)c[a]=i[a];
500 | for(a=250;a>=0;a--) {
501 | S(c,c);
502 | if(a!=1) M(c, 0, c, 0, i, 0);
503 | }
504 | for (a=0;a < 16;++a)o[a]=c[a];
505 | }
506 |
507 | private static int crypto_scalarmult(byte[] q,byte[] n,byte[] p)
508 | {
509 | byte[] z = new byte[32];
510 | long[] x = new long[80];
511 | int r;
512 | int i;
513 | long[] /*gf*/ a = new long[GF_LEN],b = new long[GF_LEN],c = new long[GF_LEN],
514 | d = new long[GF_LEN],e = new long[GF_LEN],f = new long[GF_LEN];
515 | for (i=0;i < 31;++i)
516 | z[i] = n[i];
517 | z[31] = (byte)((n[31]&127)|64);
518 | z[0] &= 248;
519 | unpack25519(x,p);
520 | for (i=0;i < 16;++i){
521 | b[i]=x[i];
522 | d[i]=a[i]=c[i]=0;
523 | }
524 | a[0]=d[0]=1;
525 |
526 | for(i=254;i>=0;--i) {
527 | r=( (0xff & z[i>>3]) >> (i&7))&1;
528 | sel25519(a,b,r);
529 | sel25519(c,d,r);
530 | A(e,a,c);
531 | Z(a,a,c);
532 | A(c,b,d);
533 | Z(b,b,d);
534 | S(d,e);
535 | S(f,a);
536 | M(a, 0, c, 0, a, 0);
537 | M(c, 0, b, 0, e, 0);
538 | A(e,a,c);
539 | Z(a,a,c);
540 | S(b, a);
541 | Z(c,d,f);
542 | M(a, 0, c, 0, _121665, 0);
543 | A(a, a, d);
544 | M(c, 0, c, 0, a, 0);
545 | M(a, 0, d, 0, f, 0);
546 | M(d, 0, b, 0, x, 0);
547 | S(b,e);
548 | sel25519(a,b,r);
549 | sel25519(c,d,r);
550 | }
551 | for (i=0;i < 16;++i){
552 | x[i+16]=a[i];
553 | x[i+32]=c[i];
554 | x[i+48]=b[i];
555 | x[i+64]=d[i];
556 | }
557 |
558 | inv25519(x, 32,x, 32);
559 |
560 | M(x, 16,x, 16, x, 32);
561 |
562 | pack25519(q,x, 16);
563 | return 0;
564 | }
565 |
566 | private static int crypto_box_beforenm(byte[] k,byte[] y,byte[] x)
567 | {
568 | byte[] s = new byte[32];
569 | crypto_scalarmult(s, x, y);
570 | return crypto_core_hsalsa20(k,_0,s,sigma);
571 | }
572 |
573 | private static int crypto_box_afternm(byte[] c,byte[] m,long d,byte[] n,byte[] k)
574 | {
575 | return crypto_secretbox(c, m, d, n, k);
576 | }
577 |
578 | private static int crypto_box_open_afternm(byte[] m,byte[] c,long d,byte[] n,byte[] k)
579 | {
580 | return crypto_secretbox_open(m, c, d, n, k);
581 | }
582 |
583 | private static int crypto_box(byte[] c,byte[] m,long d,byte[] nonce, byte[] theirPublicBoxingKey, byte[] ourSecretBoxingKey)
584 | {
585 | byte[] k = new byte[32];
586 | crypto_box_beforenm(k, theirPublicBoxingKey, ourSecretBoxingKey);
587 | return crypto_box_afternm(c, m, d, nonce, k);
588 | }
589 |
590 | private static int crypto_box_open(byte[] m,byte[] c,long d,byte[] n,byte[] y,byte[] x)
591 | {
592 | byte[] k = new byte[32];
593 | crypto_box_beforenm(k,y,x);
594 | return crypto_box_open_afternm(m, c, d, n, k);
595 | }
596 |
597 | private static int crypto_hash(byte[] out, byte[] m, int n) {
598 | int[] hh = new int[8], hl = new int[8];
599 | byte[] x = new byte[256];
600 | int i, b = n;
601 |
602 | hh[0] = 0x6a09e667;
603 | hh[1] = 0xbb67ae85;
604 | hh[2] = 0x3c6ef372;
605 | hh[3] = 0xa54ff53a;
606 | hh[4] = 0x510e527f;
607 | hh[5] = 0x9b05688c;
608 | hh[6] = 0x1f83d9ab;
609 | hh[7] = 0x5be0cd19;
610 |
611 | hl[0] = 0xf3bcc908;
612 | hl[1] = 0x84caa73b;
613 | hl[2] = 0xfe94f82b;
614 | hl[3] = 0x5f1d36f1;
615 | hl[4] = 0xade682d1;
616 | hl[5] = 0x2b3e6c1f;
617 | hl[6] = 0xfb41bd6b;
618 | hl[7] = 0x137e2179;
619 |
620 | crypto_hashblocks_hl(hh, hl, m, n);
621 | n %= 128;
622 |
623 | for (i = 0; i < n; i++) x[i] = m[b-n+i];
624 | x[n] = (byte)128;
625 |
626 | n = 256-128*(n<112?1:0);
627 | x[n-9] = 0;
628 | jsts64(x, n - 8, (b / 0x20000000), b << 3);
629 | crypto_hashblocks_hl(hh, hl, x, n);
630 |
631 | for (i = 0; i < 8; i++) jsts64(out, 8 * i, hh[i], hl[i]);
632 |
633 | return 0;
634 | }
635 |
636 | private static void jsts64(byte[] x, int i, int h, int l) {
637 | x[i] = (byte)(h >> 24);
638 | x[i+1] = (byte)(h >> 16);
639 | x[i+2] = (byte)(h >> 8);
640 | x[i+3] = (byte)h;
641 | x[i+4] = (byte)(l >> 24);
642 | x[i+5] = (byte)(l >> 16);
643 | x[i+6] = (byte)(l >> 8);
644 | x[i+7] = (byte)l;
645 | }
646 |
647 | private static int[] jsK = new int[]{
648 | 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd,
649 | 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,
650 | 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019,
651 | 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,
652 | 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe,
653 | 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,
654 | 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1,
655 | 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,
656 | 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3,
657 | 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,
658 | 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483,
659 | 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,
660 | 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210,
661 | 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,
662 | 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725,
663 | 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,
664 | 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926,
665 | 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,
666 | 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8,
667 | 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,
668 | 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001,
669 | 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,
670 | 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910,
671 | 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,
672 | 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53,
673 | 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,
674 | 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb,
675 | 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,
676 | 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60,
677 | 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,
678 | 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9,
679 | 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,
680 | 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207,
681 | 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,
682 | 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6,
683 | 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,
684 | 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493,
685 | 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,
686 | 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a,
687 | 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817
688 | };
689 |
690 | private static int crypto_hashblocks_hl(int[] hh, int[] hl, byte[] m, int n) {
691 | int[] wh = new int[16], wl = new int[16];
692 | int bh0, bh1, bh2, bh3, bh4, bh5, bh6, bh7,
693 | bl0, bl1, bl2, bl3, bl4, bl5, bl6, bl7,
694 | th, tl, i, j, h, l, a, b, c, d;
695 |
696 | int ah0 = hh[0],
697 | ah1 = hh[1],
698 | ah2 = hh[2],
699 | ah3 = hh[3],
700 | ah4 = hh[4],
701 | ah5 = hh[5],
702 | ah6 = hh[6],
703 | ah7 = hh[7],
704 |
705 | al0 = hl[0],
706 | al1 = hl[1],
707 | al2 = hl[2],
708 | al3 = hl[3],
709 | al4 = hl[4],
710 | al5 = hl[5],
711 | al6 = hl[6],
712 | al7 = hl[7];
713 |
714 | int pos = 0;
715 | while (n >= 128) {
716 | for (i = 0; i < 16; i++) {
717 | j = 8 * i + pos;
718 | wh[i] = ((m[j+0] & 0xff) << 24) | ((m[j+1] & 0xff) << 16) | ((m[j+2] & 0xff) << 8) | (m[j+3] & 0xff);
719 | wl[i] = ((m[j+4] & 0xff) << 24) | ((m[j+5] & 0xff) << 16) | ((m[j+6] & 0xff) << 8) | (m[j+7] & 0xff);
720 | }
721 | for (i = 0; i < 80; i++) {
722 | bh0 = ah0;
723 | bh1 = ah1;
724 | bh2 = ah2;
725 | bh3 = ah3;
726 | bh4 = ah4;
727 | bh5 = ah5;
728 | bh6 = ah6;
729 | bh7 = ah7;
730 |
731 | bl0 = al0;
732 | bl1 = al1;
733 | bl2 = al2;
734 | bl3 = al3;
735 | bl4 = al4;
736 | bl5 = al5;
737 | bl6 = al6;
738 | bl7 = al7;
739 |
740 | // add
741 | h = ah7;
742 | l = al7;
743 |
744 | a = l & 0xffff; b = l >>> 16;
745 | c = h & 0xffff; d = h >>> 16;
746 |
747 | // Sigma1
748 | h = ((ah4 >>> 14) | (al4 << (32-14))) ^ ((ah4 >>> 18) | (al4 << (32-18))) ^ ((al4 >>> (41-32)) | (ah4 << (32-(41-32))));
749 | l = ((al4 >>> 14) | (ah4 << (32-14))) ^ ((al4 >>> 18) | (ah4 << (32-18))) ^ ((ah4 >>> (41-32)) | (al4 << (32-(41-32))));
750 |
751 | a += l & 0xffff; b += l >>> 16;
752 | c += h & 0xffff; d += h >>> 16;
753 |
754 | // Ch
755 | h = (ah4 & ah5) ^ (~ah4 & ah6);
756 | l = (al4 & al5) ^ (~al4 & al6);
757 |
758 | a += l & 0xffff; b += l >>> 16;
759 | c += h & 0xffff; d += h >>> 16;
760 |
761 | // K
762 | h = jsK[i*2];
763 | l = jsK[i*2+1];
764 |
765 | a += l & 0xffff; b += l >>> 16;
766 | c += h & 0xffff; d += h >>> 16;
767 |
768 | // w
769 | h = wh[i%16];
770 | l = wl[i%16];
771 |
772 | a += l & 0xffff; b += l >>> 16;
773 | c += h & 0xffff; d += h >>> 16;
774 |
775 | b += a >>> 16;
776 | c += b >>> 16;
777 | d += c >>> 16;
778 |
779 | th = c & 0xffff | d << 16;
780 | tl = a & 0xffff | b << 16;
781 |
782 | // add
783 | h = th;
784 | l = tl;
785 |
786 | a = l & 0xffff; b = l >>> 16;
787 | c = h & 0xffff; d = h >>> 16;
788 |
789 | // Sigma0
790 | h = ((ah0 >>> 28) | (al0 << (32-28))) ^ ((al0 >>> (34-32)) | (ah0 << (32-(34-32)))) ^ ((al0 >>> (39-32)) | (ah0 << (32-(39-32))));
791 | l = ((al0 >>> 28) | (ah0 << (32-28))) ^ ((ah0 >>> (34-32)) | (al0 << (32-(34-32)))) ^ ((ah0 >>> (39-32)) | (al0 << (32-(39-32))));
792 |
793 | a += l & 0xffff; b += l >>> 16;
794 | c += h & 0xffff; d += h >>> 16;
795 |
796 | // Maj
797 | h = (ah0 & ah1) ^ (ah0 & ah2) ^ (ah1 & ah2);
798 | l = (al0 & al1) ^ (al0 & al2) ^ (al1 & al2);
799 |
800 | a += l & 0xffff; b += l >>> 16;
801 | c += h & 0xffff; d += h >>> 16;
802 |
803 | b += a >>> 16;
804 | c += b >>> 16;
805 | d += c >>> 16;
806 |
807 | bh7 = (c & 0xffff) | (d << 16);
808 | bl7 = (a & 0xffff) | (b << 16);
809 |
810 | // add
811 | h = bh3;
812 | l = bl3;
813 |
814 | a = l & 0xffff; b = l >>> 16;
815 | c = h & 0xffff; d = h >>> 16;
816 |
817 | h = th;
818 | l = tl;
819 |
820 | a += l & 0xffff; b += l >>> 16;
821 | c += h & 0xffff; d += h >>> 16;
822 |
823 | b += a >>> 16;
824 | c += b >>> 16;
825 | d += c >>> 16;
826 |
827 | bh3 = (c & 0xffff) | (d << 16);
828 | bl3 = (a & 0xffff) | (b << 16);
829 |
830 | ah1 = bh0;
831 | ah2 = bh1;
832 | ah3 = bh2;
833 | ah4 = bh3;
834 | ah5 = bh4;
835 | ah6 = bh5;
836 | ah7 = bh6;
837 | ah0 = bh7;
838 |
839 | al1 = bl0;
840 | al2 = bl1;
841 | al3 = bl2;
842 | al4 = bl3;
843 | al5 = bl4;
844 | al6 = bl5;
845 | al7 = bl6;
846 | al0 = bl7;
847 |
848 | if (i%16 == 15) {
849 | for (j = 0; j < 16; j++) {
850 | // add
851 | h = wh[j];
852 | l = wl[j];
853 |
854 | a = l & 0xffff; b = l >>> 16;
855 | c = h & 0xffff; d = h >>> 16;
856 |
857 | h = wh[(j+9)%16];
858 | l = wl[(j+9)%16];
859 |
860 | a += l & 0xffff; b += l >>> 16;
861 | c += h & 0xffff; d += h >>> 16;
862 |
863 | // sigma0
864 | th = wh[(j+1)%16];
865 | tl = wl[(j+1)%16];
866 | h = ((th >>> 1) | (tl << (32-1))) ^ ((th >>> 8) | (tl << (32-8))) ^ (th >>> 7);
867 | l = ((tl >>> 1) | (th << (32-1))) ^ ((tl >>> 8) | (th << (32-8))) ^ ((tl >>> 7) | (th << (32-7)));
868 |
869 | a += l & 0xffff; b += l >>> 16;
870 | c += h & 0xffff; d += h >>> 16;
871 |
872 | // sigma1
873 | th = wh[(j+14)%16];
874 | tl = wl[(j+14)%16];
875 | h = ((th >>> 19) | (tl << (32-19))) ^ ((tl >>> (61-32)) | (th << (32-(61-32)))) ^ (th >>> 6);
876 | l = ((tl >>> 19) | (th << (32-19))) ^ ((th >>> (61-32)) | (tl << (32-(61-32)))) ^ ((tl >>> 6) | (th << (32-6)));
877 |
878 | a += l & 0xffff; b += l >>> 16;
879 | c += h & 0xffff; d += h >>> 16;
880 |
881 | b += a >>> 16;
882 | c += b >>> 16;
883 | d += c >>> 16;
884 |
885 | wh[j] = (c & 0xffff) | (d << 16);
886 | wl[j] = (a & 0xffff) | (b << 16);
887 | }
888 | }
889 | }
890 |
891 | // add
892 | h = ah0;
893 | l = al0;
894 |
895 | a = l & 0xffff; b = l >>> 16;
896 | c = h & 0xffff; d = h >>> 16;
897 |
898 | h = hh[0];
899 | l = hl[0];
900 |
901 | a += l & 0xffff; b += l >>> 16;
902 | c += h & 0xffff; d += h >>> 16;
903 |
904 | b += a >>> 16;
905 | c += b >>> 16;
906 | d += c >>> 16;
907 |
908 | hh[0] = ah0 = (c & 0xffff) | (d << 16);
909 | hl[0] = al0 = (a & 0xffff) | (b << 16);
910 |
911 | h = ah1;
912 | l = al1;
913 |
914 | a = l & 0xffff; b = l >>> 16;
915 | c = h & 0xffff; d = h >>> 16;
916 |
917 | h = hh[1];
918 | l = hl[1];
919 |
920 | a += l & 0xffff; b += l >>> 16;
921 | c += h & 0xffff; d += h >>> 16;
922 |
923 | b += a >>> 16;
924 | c += b >>> 16;
925 | d += c >>> 16;
926 |
927 | hh[1] = ah1 = (c & 0xffff) | (d << 16);
928 | hl[1] = al1 = (a & 0xffff) | (b << 16);
929 |
930 | h = ah2;
931 | l = al2;
932 |
933 | a = l & 0xffff; b = l >>> 16;
934 | c = h & 0xffff; d = h >>> 16;
935 |
936 | h = hh[2];
937 | l = hl[2];
938 |
939 | a += l & 0xffff; b += l >>> 16;
940 | c += h & 0xffff; d += h >>> 16;
941 |
942 | b += a >>> 16;
943 | c += b >>> 16;
944 | d += c >>> 16;
945 |
946 | hh[2] = ah2 = (c & 0xffff) | (d << 16);
947 | hl[2] = al2 = (a & 0xffff) | (b << 16);
948 |
949 | h = ah3;
950 | l = al3;
951 |
952 | a = l & 0xffff; b = l >>> 16;
953 | c = h & 0xffff; d = h >>> 16;
954 |
955 | h = hh[3];
956 | l = hl[3];
957 |
958 | a += l & 0xffff; b += l >>> 16;
959 | c += h & 0xffff; d += h >>> 16;
960 |
961 | b += a >>> 16;
962 | c += b >>> 16;
963 | d += c >>> 16;
964 |
965 | hh[3] = ah3 = (c & 0xffff) | (d << 16);
966 | hl[3] = al3 = (a & 0xffff) | (b << 16);
967 |
968 | h = ah4;
969 | l = al4;
970 |
971 | a = l & 0xffff; b = l >>> 16;
972 | c = h & 0xffff; d = h >>> 16;
973 |
974 | h = hh[4];
975 | l = hl[4];
976 |
977 | a += l & 0xffff; b += l >>> 16;
978 | c += h & 0xffff; d += h >>> 16;
979 |
980 | b += a >>> 16;
981 | c += b >>> 16;
982 | d += c >>> 16;
983 |
984 | hh[4] = ah4 = (c & 0xffff) | (d << 16);
985 | hl[4] = al4 = (a & 0xffff) | (b << 16);
986 |
987 | h = ah5;
988 | l = al5;
989 |
990 | a = l & 0xffff; b = l >>> 16;
991 | c = h & 0xffff; d = h >>> 16;
992 |
993 | h = hh[5];
994 | l = hl[5];
995 |
996 | a += l & 0xffff; b += l >>> 16;
997 | c += h & 0xffff; d += h >>> 16;
998 |
999 | b += a >>> 16;
1000 | c += b >>> 16;
1001 | d += c >>> 16;
1002 |
1003 | hh[5] = ah5 = (c & 0xffff) | (d << 16);
1004 | hl[5] = al5 = (a & 0xffff) | (b << 16);
1005 |
1006 | h = ah6;
1007 | l = al6;
1008 |
1009 | a = l & 0xffff; b = l >>> 16;
1010 | c = h & 0xffff; d = h >>> 16;
1011 |
1012 | h = hh[6];
1013 | l = hl[6];
1014 |
1015 | a += l & 0xffff; b += l >>> 16;
1016 | c += h & 0xffff; d += h >>> 16;
1017 |
1018 | b += a >>> 16;
1019 | c += b >>> 16;
1020 | d += c >>> 16;
1021 |
1022 | hh[6] = ah6 = (c & 0xffff) | (d << 16);
1023 | hl[6] = al6 = (a & 0xffff) | (b << 16);
1024 |
1025 | h = ah7;
1026 | l = al7;
1027 |
1028 | a = l & 0xffff; b = l >>> 16;
1029 | c = h & 0xffff; d = h >>> 16;
1030 |
1031 | h = hh[7];
1032 | l = hl[7];
1033 |
1034 | a += l & 0xffff; b += l >>> 16;
1035 | c += h & 0xffff; d += h >>> 16;
1036 |
1037 | b += a >>> 16;
1038 | c += b >>> 16;
1039 | d += c >>> 16;
1040 |
1041 | hh[7] = ah7 = (c & 0xffff) | (d << 16);
1042 | hl[7] = al7 = (a & 0xffff) | (b << 16);
1043 |
1044 | pos += 128;
1045 | n -= 128;
1046 | }
1047 |
1048 | return n;
1049 | }
1050 |
1051 | private static void add(long[][] /*gf*/ p/*[4]*/,long[][] /*gf*/ q/*[4]*/)
1052 | {
1053 | long[] /*gf*/ a=new long[GF_LEN],b=new long[GF_LEN],c=new long[GF_LEN],
1054 | d=new long[GF_LEN],t=new long[GF_LEN],e=new long[GF_LEN],
1055 | f=new long[GF_LEN],g=new long[GF_LEN],h=new long[GF_LEN];
1056 |
1057 | Z(a, p[1], p[0]);
1058 | Z(t, q[1], q[0]);
1059 | M(a, 0, a, 0, t, 0);
1060 | A(b, p[0], p[1]);
1061 | A(t, q[0], q[1]);
1062 | M(b, 0, b, 0, t, 0);
1063 | M(c, 0, p[3], 0, q[3], 0);
1064 | M(c, 0, c, 0, D2, 0);
1065 | M(d, 0, p[2], 0, q[2], 0);
1066 | A(d, d, d);
1067 | Z(e, b, a);
1068 | Z(f, d, c);
1069 | A(g, d, c);
1070 | A(h, b, a);
1071 |
1072 | M(p[0], 0, e, 0, f, 0);
1073 | M(p[1], 0, h, 0, g, 0);
1074 | M(p[2], 0, g, 0, f, 0);
1075 | M(p[3], 0, e, 0, h, 0);
1076 | }
1077 |
1078 | private static void cswap(long[][] /*gf*/ p/*[4]*/,long[][] /*gf*/ q/*[4]*/,byte b)
1079 | {
1080 | int i;
1081 | for(i=0; i < 4; i++)
1082 | sel25519(p[i],q[i],b & 0xff);
1083 | }
1084 |
1085 | private static void pack(byte[] r,long[][] /*gf*/ p/*[4]*/)
1086 | {
1087 | long[] /*gf*/ tx = new long[GF_LEN], ty = new long[GF_LEN], zi = new long[GF_LEN];
1088 | inv25519(zi, 0, p[2], 0);
1089 | M(tx, 0, p[0], 0, zi, 0);
1090 | M(ty, 0, p[1], 0, zi, 0);
1091 | pack25519(r, ty, 0);
1092 | r[31] ^= par25519(tx) << 7;
1093 | }
1094 |
1095 | private static void scalarmult(long[][] /*gf*/ p/*[4]*/,long[][] /*gf*/ q/*[4]*/,byte[] s, int sOff)
1096 | {
1097 | int i;
1098 | set25519(p[0], gf0);
1099 | set25519(p[1], gf1);
1100 | set25519(p[2], gf1);
1101 | set25519(p[3], gf0);
1102 | for (i = 255;i >= 0;--i) {
1103 | byte b = (byte)(( (0xff & s[sOff + i/8]) >> (i&7))&1);
1104 | cswap(p,q,b);
1105 | add(q,p);
1106 | add(p,p);
1107 | cswap(p,q,b);
1108 | }
1109 | }
1110 |
1111 | private static void scalarbase(long[][] /*gf*/ p/*[4]*/,byte[] s, int sOff)
1112 | {
1113 | long[][] /*gf*/ q = new long[4][16];
1114 | set25519(q[0],X);
1115 | set25519(q[1],Y);
1116 | set25519(q[2],gf1);
1117 | M(q[3], 0, X, 0, Y, 0);
1118 | scalarmult(p,q,s, sOff);
1119 | }
1120 |
1121 | private static long[] L = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
1122 | 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
1123 | 0, 0, 0, 0, 0, 0, 0, 0,
1124 | 0, 0, 0, 0, 0, 0, 0, 0x10};
1125 |
1126 | private static void modL(byte[] r, int rOff, long[] x/*[64]*/)
1127 | {
1128 | long carry;
1129 | int i,j;
1130 | for (i = 63;i >= 32;--i) {
1131 | carry = 0;
1132 | for (j = i - 32;j < i - 12;++j) {
1133 | x[j] += carry - 16 * x[i] * L[j - (i - 32)];
1134 | carry = (x[j] + 128) >> 8;
1135 | x[j] -= carry << 8;
1136 | }
1137 | x[j] += carry;
1138 | x[i] = 0;
1139 | }
1140 | carry = 0;
1141 | for (j=0;j < 32;++j){
1142 | x[j] += carry - (x[31] >> 4) * L[j];
1143 | carry = x[j] >> 8;
1144 | x[j] &= 255;
1145 | }
1146 | for (j=0;j < 32;++j)x[j] -= carry * L[j];
1147 | for (i=0;i < 32;++i){
1148 | x[i+1] += x[i] >> 8;
1149 | r[rOff + i] = (byte)(x[i] & 255);
1150 | }
1151 | }
1152 |
1153 | private static void reduce(byte[] r)
1154 | {
1155 | long[] x = new long[64];
1156 | for (int i=0;i < 64; i++) x[i] = 0xff & r[i];
1157 | for (int i=0;i < 64;++i)r[i] = 0;
1158 | modL(r, 0, x);
1159 | }
1160 |
1161 | private static int crypto_sign(byte[] sm, byte[] m,int n,byte[] sk)
1162 | {
1163 | byte[] d = new byte[64],h = new byte[64],r = new byte[64];
1164 | long[] x = new long[64];
1165 | long[][] /*gf*/ p/*[4]*/ = new long[4][GF_LEN];
1166 |
1167 | crypto_hash(d, sk, 32);
1168 | d[0] &= 248;
1169 | d[31] &= 127;
1170 | d[31] |= 64;
1171 |
1172 | // smlen[0] = n+64;
1173 | for (int i=0;i < n;++i)sm[64 + i] = m[i];
1174 | for (int i=0;i < 32;++i)sm[32 + i] = d[32 + i];
1175 | crypto_hash(r, Arrays.copyOfRange(sm, 32, sm.length), n + 32);
1176 | reduce(r);
1177 | scalarbase(p, r, 0);
1178 | pack(sm, p);
1179 |
1180 | for (int i=0;i < 32;++i)sm[i+32] = sk[i+32];
1181 | crypto_hash(h, sm, n + 64);
1182 | reduce(h);
1183 |
1184 | for (int i=0;i < 64;++i) x[i] = 0;
1185 | for (int i=0;i < 32; ++i) x[i] = 0xff & r[i];
1186 | for (int i=0;i < 32; ++i) for(int j=0; j < 32; ++j) x[i+j] += (0xff & h[i]) * (0xff & d[j]);
1187 | modL(sm, 32,x);
1188 |
1189 | return 0;
1190 | }
1191 |
1192 | private static int unpackneg(long[][] /*gf*/ r/*[4]*/,byte[] p/*[32]*/)
1193 | {
1194 | long[] /*gf*/ t = new long[GF_LEN], chk = new long[GF_LEN], num = new long[GF_LEN], den = new long[GF_LEN],
1195 | den2 = new long[GF_LEN], den4 = new long[GF_LEN], den6 = new long[GF_LEN];
1196 | set25519(r[2],gf1);
1197 | unpack25519(r[1],p);
1198 | S(num, r[1]);
1199 | M(den, 0, num, 0, D, 0);
1200 | Z(num,num,r[2]);
1201 | A(den,r[2],den);
1202 |
1203 | S(den2,den);
1204 | S(den4,den2);
1205 | M(den6, 0, den4, 0, den2, 0);
1206 | M(t, 0, den6, 0, num, 0);
1207 | M(t, 0, t, 0, den, 0);
1208 |
1209 | pow2523(t, t);
1210 | M(t, 0, t, 0, num, 0);
1211 | M(t, 0, t, 0, den, 0);
1212 | M(t, 0, t, 0, den, 0);
1213 | M(r[0], 0, t, 0, den, 0);
1214 |
1215 | S(chk,r[0]);
1216 | M(chk, 0, chk, 0, den, 0);
1217 | if (neq25519(chk, num) != 0) M(r[0], 0, r[0], 0, I, 0);
1218 |
1219 | S(chk, r[0]);
1220 | M(chk, 0, chk, 0, den, 0);
1221 | if (neq25519(chk, num) != 0) return -1;
1222 |
1223 | if (par25519(r[0]) == ( (0xff & p[31]) >> 7)) Z(r[0],gf0,r[0]);
1224 |
1225 | M(r[3], 0, r[0], 0, r[1], 0);
1226 | return 0;
1227 | }
1228 |
1229 | private static int crypto_sign_open(byte[] m, byte[] sm, int n, byte[] pk)
1230 | {
1231 | int i;
1232 | byte[] t = new byte[32],h = new byte[64];
1233 | long[][] /*gf*/ p = new long[4][GF_LEN],q = new long[4][GF_LEN];
1234 |
1235 | // mlen[0] = -1;
1236 | if (n < 64) return -1;
1237 |
1238 | if (unpackneg(q,pk) != 0) return -1;
1239 |
1240 | for (i=0;i < n;++i) m[i] = sm[i];
1241 | for (i=0;i < 32;++i) m[i+32] = pk[i];
1242 | crypto_hash(h, m, n);
1243 | reduce(h);
1244 | scalarmult(p, q, h, 0);
1245 |
1246 | scalarbase(q, sm, 32);
1247 | add(p, q);
1248 | pack(t, p);
1249 |
1250 | n -= 64;
1251 | if (crypto_verify_32(sm, t) != 0) {
1252 | for (i=0;i < n;++i)m[i] = 0;
1253 | return -1;
1254 | }
1255 |
1256 | for (i=0;i < n;++i)m[64 + i] = sm[i + 64];
1257 | // mlen[0] = n;
1258 | return 0;
1259 | }
1260 |
1261 | private static SecureRandom getStrongCSPRNG() {
1262 | try {
1263 | return SecureRandom.getInstanceStrong();
1264 | } catch (NoSuchAlgorithmException e) {
1265 | throw new IllegalStateException(e);
1266 | }
1267 | }
1268 |
1269 | private static Random prng = getStrongCSPRNG();
1270 |
1271 | private static void randombytes(byte[] b, int len) {
1272 | byte[] r = new byte[len];
1273 | prng.nextBytes(r);
1274 | System.arraycopy(r, 0, b, 0, len);
1275 | }
1276 | }
--------------------------------------------------------------------------------
/src/main/java/iost/crypto/VerifyUtils.java:
--------------------------------------------------------------------------------
1 | package iost.crypto;
2 |
3 | import org.web3j.crypto.ECDSASignature;
4 | import org.web3j.crypto.Sign;
5 |
6 | import java.math.BigInteger;
7 | import java.util.Arrays;
8 |
9 | public class VerifyUtils {
10 |
11 | /**
12 | * verify ed25519 signature
13 | * ref: https://github.com/iost-official/java-sdk/issues/4
14 | *
15 | * @param info info
16 | * @param signature signature
17 | * @param pubKey pubKey
18 | * @return verify result
19 | */
20 | public static boolean Ed25519Verify(byte[] info, byte[] signature, byte[] pubKey) {
21 | byte[] messageWithSignature = new byte[signature.length + info.length];
22 | System.arraycopy(signature, 0, messageWithSignature, 0, signature.length);
23 | System.arraycopy(info, 0, messageWithSignature, signature.length, info.length);
24 | byte[] openMessage = TweetNaCl.crypto_sign_open(messageWithSignature, pubKey);
25 | return Arrays.equals(info, openMessage);
26 | }
27 |
28 | /**
29 | * verify Secp256k1 signature
30 | * ref: https://github.com/web3j/web3j/blob/v3.6.0/crypto/src/test/java/org/web3j/crypto/ECRecoverTest.java
31 | *
32 | * @param info info
33 | * @param signature signature
34 | * @param pubKey pubKey
35 | * @return verify result
36 | */
37 | public static boolean Secp256k1Verify(byte[] info, byte[] signature, byte[] pubKey) {
38 | byte[] r = Arrays.copyOfRange(signature, 0, 32);
39 | byte[] s = Arrays.copyOfRange(signature, 32, 64);
40 | ECDSASignature ecdsaSignature = new ECDSASignature(new BigInteger(r), new BigInteger(s));
41 |
42 | byte[] publicKey = null;
43 | // remove head
44 | if (pubKey.length == 33) {
45 | if (pubKey[0] != (byte) 0x02) {
46 | throw new RuntimeException("Secp256k1Verify failure : pubKey is invalidate");
47 | }
48 | publicKey = Arrays.copyOfRange(pubKey, 1, 33);
49 | } else if (pubKey.length == 65) {
50 | // todo what is pubKey[0]?
51 | // if (pubKey[0] != (byte) 0x02) {
52 | // throw new RuntimeException("Secp256k1Verify failure : pubKey is invalidate");
53 | // }
54 | publicKey = Arrays.copyOfRange(pubKey, 1, 64);
55 | } else if (pubKey.length == 32) {
56 | publicKey = Arrays.copyOfRange(pubKey, 0, 32);
57 | } else if (pubKey.length == 64) {
58 | publicKey = Arrays.copyOfRange(pubKey, 0, 64);
59 | } else {
60 | throw new RuntimeException("Secp256k1Verify failure : pubKey length is invalidate");
61 | }
62 |
63 | boolean match = false;
64 | // Iterate for each possible key to recover
65 | for (int i = 0; i < 4; i++) {
66 | BigInteger recoverPublicKey = Sign.recoverFromSignature(i, ecdsaSignature, info);
67 | if (recoverPublicKey != null) {
68 | byte[] recoverPubKey = Arrays.copyOfRange(
69 | recoverPublicKey.toByteArray(), 0, publicKey.length);
70 | if (Arrays.equals(recoverPubKey, publicKey)) {
71 | match = true;
72 | break;
73 | }
74 | }
75 | }
76 | return match;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/account/Account.java:
--------------------------------------------------------------------------------
1 | package iost.model.account;
2 |
3 | import java.util.Map;
4 |
5 | public class Account {
6 |
7 | public String name;
8 | public double balance;
9 | public long create_time;
10 | public GasInfo gas_info;
11 | public RamInfo ram_info;
12 | public Map permissions;
13 | public Map groups;
14 | public FrozenBalance[] frozen_balances;
15 | public VoteInfo[] vote_infos;
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/account/FrozenBalance.java:
--------------------------------------------------------------------------------
1 | package iost.model.account;
2 |
3 | public class FrozenBalance {
4 | public double amount;
5 | public long time;
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/account/GasInfo.java:
--------------------------------------------------------------------------------
1 | package iost.model.account;
2 |
3 | public class GasInfo {
4 |
5 | public double current_total;
6 | public double transferable_gas;
7 | public double pledge_gas;
8 | public double increase_speed;
9 | public double limit;
10 | public PledgeInfo[] pledged_info;
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/account/Group.java:
--------------------------------------------------------------------------------
1 | package iost.model.account;
2 |
3 | public class Group {
4 |
5 | public String name;
6 | public Item[] items;
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/account/Item.java:
--------------------------------------------------------------------------------
1 | package iost.model.account;
2 |
3 | public class Item {
4 |
5 | public String id;
6 | public boolean is_key_pair;
7 | public long weight;
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/account/Permission.java:
--------------------------------------------------------------------------------
1 | package iost.model.account;
2 |
3 | public class Permission {
4 |
5 | public String name;
6 | public Group[] group_names;
7 | public Item[] items;
8 | public long threshold;
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/account/PledgeInfo.java:
--------------------------------------------------------------------------------
1 | package iost.model.account;
2 |
3 | public class PledgeInfo {
4 |
5 | public String pledger;
6 | public double amount;
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/account/RamInfo.java:
--------------------------------------------------------------------------------
1 | package iost.model.account;
2 |
3 | import com.google.gson.Gson;
4 |
5 | public class RamInfo {
6 |
7 | public long available_ram;
8 | public long used_ram;
9 | public long total_ram;
10 | public double buy_price;
11 | public double sell_price;
12 | public String available;
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/account/TokenBalance.java:
--------------------------------------------------------------------------------
1 | package iost.model.account;
2 |
3 | public class TokenBalance {
4 | public double balance;
5 | public FrozenBalance[] frozen_balances;
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/account/VoteInfo.java:
--------------------------------------------------------------------------------
1 | package iost.model.account;
2 |
3 | public class VoteInfo {
4 | public String option;
5 | public String votes;
6 | public String cleared_votes;
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/block/Block.java:
--------------------------------------------------------------------------------
1 | package iost.model.block;
2 |
3 | import iost.model.transaction.Transaction;
4 |
5 | public class Block {
6 | public String hash;
7 | public long version;
8 | public String parent_hash;
9 | public String tx_merkle_hash;
10 | public String tx_receipt_merkle_hash;
11 | public long number;
12 | public String witness;
13 | public long time;
14 | public double gas_usage;
15 | public long tx_count;
16 | public Info info;
17 | public Transaction[] transactions;
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/block/BlockResponse.java:
--------------------------------------------------------------------------------
1 | package iost.model.block;
2 |
3 | public class BlockResponse {
4 | public String status;
5 | public Block block;
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/block/Info.java:
--------------------------------------------------------------------------------
1 | package iost.model.block;
2 |
3 | public class Info {
4 | public int mode;
5 | public int thread;
6 | public int[] batch_index;
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/info/ChainInfo.java:
--------------------------------------------------------------------------------
1 | package iost.model.info;
2 |
3 | public class ChainInfo {
4 |
5 | public String net_name;
6 | public String protocol_version;
7 | public String head_block;
8 | public String head_block_hash;
9 | public String lib_block;
10 | public String lib_block_hash;
11 | public String[] witness_list;
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/info/GasRatio.java:
--------------------------------------------------------------------------------
1 | package iost.model.info;
2 |
3 | public class GasRatio {
4 |
5 | public String lowest_gas_ratio;
6 | public String median_gas_ratio;
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/info/NetworkInfo.java:
--------------------------------------------------------------------------------
1 | package iost.model.info;
2 |
3 | public class NetworkInfo {
4 | public String id;
5 | public int peer_count;
6 | public PeerInfo[] peer_info;
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/info/NodeInfo.java:
--------------------------------------------------------------------------------
1 | package iost.model.info;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | public class NodeInfo {
6 | public String build_time;
7 | public String git_hash;
8 | public String mode;
9 | public NetworkInfo network;
10 | public String server_time;
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/info/PeerInfo.java:
--------------------------------------------------------------------------------
1 | package iost.model.info;
2 |
3 | public class PeerInfo {
4 | public String id;
5 | public String addr;
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/transaction/Action.java:
--------------------------------------------------------------------------------
1 | package iost.model.transaction;
2 |
3 | public class Action {
4 | public String contract, action_name;
5 | public String data;
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/transaction/AmountLimit.java:
--------------------------------------------------------------------------------
1 | package iost.model.transaction;
2 |
3 | public class AmountLimit {
4 | public String token;
5 | public String value;
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/transaction/Receipt.java:
--------------------------------------------------------------------------------
1 | package iost.model.transaction;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | public class Receipt {
6 | @SerializedName("func_name")
7 | public String funcName;
8 | public String content;
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/transaction/Signature.java:
--------------------------------------------------------------------------------
1 | package iost.model.transaction;
2 |
3 | import iost.crypto.Algorithm;
4 |
5 | public class Signature {
6 | public Algorithm algorithm;
7 | public byte[] public_key,signature;
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/transaction/SignatureAdapter.java:
--------------------------------------------------------------------------------
1 | package iost.model.transaction;
2 |
3 | import com.google.gson.TypeAdapter;
4 | import com.google.gson.stream.JsonReader;
5 | import com.google.gson.stream.JsonWriter;
6 | import iost.crypto.Algorithm;
7 | import iost.crypto.Ed25519;
8 | import iost.crypto.Secp256k1;
9 |
10 | import java.io.IOException;
11 | import java.util.Base64;
12 |
13 | public class SignatureAdapter extends TypeAdapter {
14 | @Override
15 | public void write(JsonWriter out, Signature value) throws IOException {
16 | out.beginObject();
17 | out.name("algorithm").value(value.algorithm.toByte());
18 | out.name("public_key").value(Base64.getEncoder().encodeToString(value.public_key));
19 | out.name("signature").value(Base64.getEncoder().encodeToString(value.signature));
20 | out.endObject();
21 | }
22 |
23 | @Override
24 | public Signature read(JsonReader in) throws IOException {
25 | final Signature s = new Signature();
26 |
27 | in.beginObject();
28 | while (in.hasNext()) {
29 | switch (in.nextName()) {
30 | case "algorithm":
31 | s.algorithm = in.nextInt() == 1? Algorithm.Secp256k1: Algorithm.Ed25519;
32 | break;
33 | case "public_key":
34 | s.public_key = Base64.getDecoder().decode(in.nextString());
35 | break;
36 | case "signature":
37 | s.signature = Base64.getDecoder().decode(in.nextString());
38 | break;
39 | }
40 | }
41 | in.endObject();
42 |
43 | return s;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/iost/model/transaction/Transaction.java:
--------------------------------------------------------------------------------
1 | package iost.model.transaction;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.JsonArray;
5 | import iost.crypto.Base58;
6 | import iost.crypto.SimpleEncoder;
7 | import org.bouncycastle.jcajce.provider.digest.SHA3;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | public class Transaction {
13 | private String hash = "";
14 |
15 | public float gas_limit = 0;
16 | public long gas_ratio, time = 0, expiration = 0, delay = 0;
17 | public List signatures = new ArrayList<>();
18 | public List actions = new ArrayList<>();
19 | public List publisher_sigs = new ArrayList<>();
20 | public List signers = new ArrayList<>();
21 | public List amount_limit = new ArrayList<>();
22 | public TxReceipt tx_receipt;
23 | public String publisher;
24 | public int chain_id = 1024;
25 | public byte[] reserved = {};
26 | public String referred_tx = "";
27 |
28 | public byte[] signBytes() {
29 | SimpleEncoder se = new SimpleEncoder(65536);
30 | se.buffer.putLong(this.time);
31 | se.buffer.putLong(this.expiration);
32 | se.buffer.putLong(this.gas_ratio * 100);
33 | long floorGasLimit = (long) this.gas_limit;
34 | se.buffer.putLong(floorGasLimit * 100);
35 | se.buffer.putLong(this.delay);
36 | se.buffer.putInt(this.chain_id);
37 |
38 | se.buffer.putInt(this.reserved.length);
39 | for (byte b : this.reserved) {
40 | se.buffer.put(b);
41 | }
42 |
43 | se.buffer.putInt(this.signers.size());
44 | for (String signer : this.signers) {
45 | se.putString(signer);
46 | }
47 |
48 | se.buffer.putInt(this.actions.size());
49 | for (Action act : this.actions) {
50 | SimpleEncoder c2 = new SimpleEncoder(1024);
51 | c2.putString(act.contract);
52 | c2.putString(act.action_name);
53 | if (act.data != null) {
54 | c2.putString(act.data);
55 | }
56 | se.putBytes(c2.toBytes());
57 | }
58 |
59 | se.buffer.putInt(this.amount_limit.size());
60 | for (AmountLimit alo : this.amount_limit) {
61 | SimpleEncoder c2 = new SimpleEncoder(1024);
62 | c2.putString(alo.token);
63 | c2.putString(alo.value);
64 | se.putBytes(c2.toBytes());
65 | }
66 |
67 |
68 | return se.toBytes();
69 | }
70 |
71 | public byte[] getSignHash() {
72 | return (new SHA3.Digest256()).digest(this.signBytes());
73 | }
74 |
75 | public byte[] getPublishBytes() {
76 | SimpleEncoder se = new SimpleEncoder(this.signBytes());
77 | se.buffer.putInt(this.signatures.size());
78 | for (Signature sign : this.signatures) {
79 | SimpleEncoder c2 = new SimpleEncoder(1024);
80 | c2.buffer.put(sign.algorithm.toByte());
81 | c2.putBytes((sign.signature));
82 | c2.putBytes((sign.public_key));
83 | se.putBytes(c2.toBytes());
84 | }
85 | return se.toBytes();
86 |
87 | }
88 |
89 | public String getHash() {
90 | if (!this.hash.equals("")) return this.hash;
91 |
92 | SimpleEncoder se = new SimpleEncoder(this.getPublishBytes());
93 | se.buffer.putInt(0); // referred_tx
94 | System.out.println("publisher:" + this.publisher);
95 | se.putString(this.publisher);
96 |
97 | se.buffer.putInt(this.publisher_sigs.size());
98 | for (Signature sign : this.publisher_sigs) {
99 | SimpleEncoder c2 = new SimpleEncoder(1024);
100 | c2.buffer.put(sign.algorithm.toByte());
101 | c2.putBytes((sign.signature));
102 | c2.putBytes((sign.public_key));
103 | se.putBytes(c2.toBytes());
104 | }
105 | this.hash = Base58.encode((new SHA3.Digest256()).digest(se.toBytes()));
106 | return this.hash;
107 | }
108 |
109 | public byte[] getPublishHash() {
110 | return (new SHA3.Digest256()).digest(this.getPublishBytes());
111 | }
112 |
113 |
114 | /**
115 | * add approve of this transaction
116 | * approve means how much this transaction can at most use your token
117 | *
118 | * @param type - token name
119 | * @param value - token value in String, or "unlimited"
120 | * @return -
121 | */
122 | public Transaction addApprove(String type, String value) {
123 |
124 | AmountLimit al = new AmountLimit();
125 | al.token = type;
126 | al.value = value;
127 |
128 | this.amount_limit.add(al);
129 | return this;
130 | }
131 |
132 | /**
133 | * add action to transaction
134 | *
135 | * @param contract - contract id
136 | * @param abi - abi name
137 | * @param data - abi params
138 | * @return -
139 | */
140 | public Transaction addAction(String contract, String abi, Object... data) {
141 | Action act = new Action();
142 | act.contract = contract;
143 | act.action_name = abi;
144 | JsonArray ja = new JsonArray();
145 | Gson gson = new Gson();
146 | act.data = gson.toJson(data);
147 | this.actions.add(act);
148 | return this;
149 | }
150 |
151 | /**
152 | * add co-signer to this transaction, publisher should not added here
153 | *
154 | * @param s - signer@permission
155 | * @return -
156 | */
157 | public Transaction addSigner(String s) {
158 | this.signers.add(s);
159 | return this;
160 | }
161 |
162 | /**
163 | * set time, if you want send tx at some future time, use it.
164 | *
165 | * @param now - this transaction's sending time
166 | * @param lifetime - expiration
167 | * @param delay - delay time
168 | * @return -
169 | */
170 | public Transaction setTime(long now, long lifetime, long delay) {
171 | this.time = now;
172 | this.expiration = now + lifetime;
173 | this.delay = delay;
174 | return this;
175 | }
176 |
177 | }
--------------------------------------------------------------------------------
/src/main/java/iost/model/transaction/TxReceipt.java:
--------------------------------------------------------------------------------
1 | package iost.model.transaction;
2 |
3 | import java.util.Map;
4 |
5 | public class TxReceipt {
6 | public String status_code;
7 | public String message;
8 |
9 | public String tx_hash;
10 | public double gas_usage;
11 | public Map ram_usage;
12 | public String[] returns;
13 | public Receipt[] receipts;
14 | }
15 |
--------------------------------------------------------------------------------
/src/test/java/ECDSA_secp256k1_Test.java:
--------------------------------------------------------------------------------
1 | import iost.crypto.Base58;
2 | import org.bouncycastle.util.encoders.Hex;
3 | import org.junit.Test;
4 | import org.web3j.crypto.ECKeyPair;
5 | import org.web3j.crypto.Hash;
6 | import org.web3j.crypto.Sign;
7 |
8 | import java.io.IOException;
9 | import java.math.BigInteger;
10 | import java.security.SignatureException;
11 |
12 | // ECDSA with secp256k1 in Java: generate ECC keys, sign, verify
13 | // ref: https://gist.github.com/nakov/b01f9434df3350bc9b1cbf9b04ddb605
14 | // other ref: https://metamug.com/article/security/sign-verify-digital-signature-ecdsa-java.html
15 | public class ECDSA_secp256k1_Test {
16 | public static String compressPubKey(BigInteger pubKey) {
17 | String pubKeyYPrefix = pubKey.testBit(0) ? "03" : "02";
18 | String pubKeyHex = pubKey.toString(16);
19 | String pubKeyX = pubKeyHex.substring(0, 64);
20 | return pubKeyYPrefix + pubKeyX;
21 | }
22 |
23 | @Test
24 | public void test1() throws SignatureException {
25 | //BigInteger privKey = Keys.createEcKeyPair().getPrivateKey();
26 | BigInteger privKey = new BigInteger("97ddae0f3a25b92268175400149d65d6887b9cefaf28ea2c078e05cdc15a3c0a", 16);
27 | BigInteger pubKey = Sign.publicKeyFromPrivate(privKey);
28 | ECKeyPair keyPair = new ECKeyPair(privKey, pubKey);
29 | System.out.println("Private key: " + privKey.toString(16));
30 | System.out.println("Public key: " + pubKey.toString(16));
31 | System.out.println("Public key (compressed): " + compressPubKey(pubKey));
32 |
33 | String msg = "Message for signing";
34 | byte[] msgHash = Hash.sha3(msg.getBytes());
35 | Sign.SignatureData signature = Sign.signMessage(msgHash, keyPair, false);
36 | System.out.println("Msg: " + msg);
37 | System.out.println("Msg hash: " + Hex.toHexString(msgHash));
38 | System.out.printf("Signature: [v = %d, r = %s, s = %s]\n",
39 | signature.getV() - 27,
40 | Hex.toHexString(signature.getR()),
41 | Hex.toHexString(signature.getS()));
42 |
43 | System.out.println();
44 |
45 | BigInteger pubKeyRecovered = Sign.signedMessageToKey(msg.getBytes(), signature);
46 | System.out.println("Recovered public key: " + pubKeyRecovered.toString(16));
47 |
48 | boolean validSig = pubKey.equals(pubKeyRecovered);
49 | System.out.println("Signature valid? " + validSig);
50 | }
51 |
52 |
53 | @Test
54 | public void test2() throws SignatureException, IOException {
55 | byte[] seckey = Base58.decode("EhNiaU4DzUmjCrvynV3gaUeuj2VjB1v2DCmbGD5U2nSE");
56 | BigInteger privKey = new BigInteger(seckey);
57 | BigInteger pubKey = Sign.publicKeyFromPrivate(privKey);
58 | ECKeyPair keyPair = new ECKeyPair(privKey, pubKey);
59 | System.out.println("Private key: " + privKey.toString(16));
60 | System.out.println("Public key: " + pubKey.toString(16));
61 | System.out.println("Public key (compressed): " + compressPubKey(pubKey));
62 |
63 | String msg = "Message for signing";
64 | byte[] msgHash = Hash.sha3(msg.getBytes());
65 | Sign.SignatureData signature = Sign.signMessage(msgHash, keyPair, false);
66 | System.out.println("Msg: " + msg);
67 | System.out.println("Msg hash: " + Hex.toHexString(msgHash));
68 | System.out.printf("Signature: [v = %d, r = %s, s = %s]\n",
69 | signature.getV() - 27,
70 | Hex.toHexString(signature.getR()),
71 | Hex.toHexString(signature.getS()));
72 |
73 | System.out.println();
74 |
75 | BigInteger pubKeyRecovered = Sign.signedMessageToKey(msg.getBytes(), signature);
76 | System.out.println("Recovered public key: " + pubKeyRecovered.toString(16));
77 |
78 | boolean validSig = pubKey.equals(pubKeyRecovered);
79 | System.out.println("Signature valid? " + validSig);
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/test/java/TestClient.java:
--------------------------------------------------------------------------------
1 | import com.google.gson.Gson;
2 | import iost.Client;
3 | import iost.IOST;
4 | import iost.Keychain;
5 | import iost.crypto.Base58;
6 | import iost.crypto.Ed25519;
7 | import iost.crypto.KeyPair;
8 | import iost.model.block.BlockResponse;
9 | import iost.model.info.ChainInfo;
10 | import iost.model.info.NodeInfo;
11 | import iost.model.transaction.Transaction;
12 | import iost.model.transaction.TxReceipt;
13 | import org.junit.Test;
14 |
15 | import java.io.IOException;
16 | import java.math.BigDecimal;
17 | import java.util.concurrent.TimeoutException;
18 |
19 | public class TestClient {
20 | private Client client = new Client("http://localhost:30001/");
21 | private Gson gson = new Gson();
22 |
23 | @Test
24 | public void testGetNodeInfo() {
25 | try {
26 | NodeInfo ni = client.getNodeInfo();
27 | System.out.println(gson.toJson(ni));
28 | System.out.println(client.getNow());
29 | } catch (IOException e) {
30 | System.out.println("network error");
31 | e.printStackTrace();
32 | }
33 | }
34 |
35 | @Test
36 | public void testGetChainInfo() {
37 | try {
38 | ChainInfo ci = client.getChainInfo();
39 | System.out.println(gson.toJson(ci));
40 | } catch (IOException e) {
41 | System.out.println("network error");
42 | e.printStackTrace();
43 | }
44 | }
45 |
46 | @Test
47 | public void testGetBlockByHash() {
48 | try {
49 |
50 | BlockResponse br = client.getBlockByHash("2ygoSVMD3FXLEchKb7mu5HMFXeucW9u9iS6Ygy6Dz9qT", true);
51 | System.out.println(br.status);
52 | System.out.println(gson.toJson(br.block));
53 | } catch (IOException e) {
54 | System.out.println("network error");
55 | e.printStackTrace();
56 | }
57 | }
58 |
59 | @Test
60 | public void testGetBlockByNumber() {
61 | try {
62 | BlockResponse br = client.getBlockByNumber("2", true);
63 | System.out.println(br.status);
64 | System.out.println(gson.toJson(br.block));
65 | } catch (IOException e) {
66 | System.out.println("network err");
67 | e.printStackTrace();
68 | }
69 | }
70 |
71 | @Test
72 | public void testTransfer() throws IOException, TimeoutException {
73 | try {
74 | IOST iost = new IOST();
75 | Transaction tx = iost.transfer("iost", "admin", "abcdef", new BigDecimal("10.00"), "今天天气好"); //将 10.00 个 iost 从 admin 转账给 receiver
76 |
77 | byte[] privateKey = Base58.decode("2yquS3ySrGWPEKywCPzX4RTJugqRh7kJSo5aehsLYPEWkUxBWA39oMrZ7ZxuM4fgyXYs2cPwh5n8aNNpH5x2VyK1");
78 |
79 | Keychain account = new Keychain("admin");
80 | KeyPair kp = new Ed25519(privateKey);
81 | account.addKey("owner", kp);
82 | account.addKey("active", kp);
83 |
84 | account.publish(tx);
85 |
86 | String txHash = this.client.sendTx(tx);
87 |
88 | if (!txHash.equals(tx.getHash())) {
89 | System.out.println("tx hash error, should be: " + txHash + ", actual: " + tx.getHash());
90 | }
91 | TxReceipt receipt = this.client.polling(txHash, 1000, 90);
92 | if (receipt.status_code.equals("SUCCESS")) {
93 | System.out.println("tx success : gas usage " + receipt.gas_usage);
94 | } else {
95 | System.out.println("tx failed :");
96 | System.out.println(receipt.message);
97 | }
98 |
99 | Transaction tx2 = this.client.getTxByHash(txHash);
100 | if (!tx2.getHash().equals(tx.getHash())) {
101 | System.out.println("tx2 hash error, should be: " + tx2.getHash() + ", actual: " + tx.getHash());
102 | }
103 |
104 | } catch (IOException | TimeoutException e) {
105 | System.out.println("network error:");
106 | e.printStackTrace();
107 | }
108 | }
109 |
110 | @Test
111 | public void debugTransfer() {
112 | IOST iost = new IOST();
113 | Transaction tx = iost.transfer("iost", "admin", "admin", new BigDecimal("1000000000.00"), ""); //将 10.00 个 iost 从 admin 转账给 receiver
114 |
115 | System.out.println(tx.actions.get(0).data);
116 | }
117 |
118 | @Test
119 | public void debugNewAccount() {
120 | IOST iost = new IOST();
121 | try {
122 | Transaction tx = iost.newAccount("test", "admin", "ahaha", "ahaha", 0, 0);
123 | } catch (IOException e) {
124 | System.out.println("OK");
125 | }
126 |
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/test/java/TestCrypto.java:
--------------------------------------------------------------------------------
1 | import com.google.gson.GsonBuilder;
2 | import iost.Keychain;
3 | import iost.crypto.Base58;
4 | import iost.crypto.Ed25519;
5 | import iost.crypto.KeyPair;
6 | import iost.crypto.Secp256k1;
7 | import iost.model.transaction.Signature;
8 | import iost.model.transaction.SignatureAdapter;
9 | import iost.model.transaction.Transaction;
10 | import org.bouncycastle.jcajce.provider.digest.SHA3;
11 | import org.bouncycastle.util.encoders.Hex;
12 | import org.junit.Test;
13 |
14 | import java.io.IOException;
15 | import java.security.spec.InvalidKeySpecException;
16 |
17 | import static org.junit.Assert.assertEquals;
18 | import static org.junit.Assert.assertTrue;
19 |
20 | public class TestCrypto {
21 | @Test
22 | public void testSecp() throws IOException {
23 |
24 | byte[] seckey = Base58.decode("EhNiaU4DzUmjCrvynV3gaUeuj2VjB1v2DCmbGD5U2nSE");
25 | Secp256k1 s = new Secp256k1(seckey);
26 |
27 | assertEquals("02069b1abdaaf8326e7e6fc15607fd9e6c6f595e119a2484a4192b5d6b3878dd25", Hex.toHexString(s.pubkey()));
28 | byte[] info = (new SHA3.Digest256()).digest("hello".getBytes());
29 | assertEquals("3338be694f50c5f338814986cdf0686453a888b84f424d792af4b9202398f392", Hex.toHexString(info));
30 | Signature signature = s.sign(info);
31 | assertEquals("37f7731bdb9988aa330be8bbd6a791f11d9fe90601edf7f569f6b8ddcfdd7755333b299ca3a8437e71eb14c72a02a2c5cdf3562e891f5a3c1d54d92148236e10",
32 | Hex.toHexString(signature.signature));
33 |
34 | KeyPair s2 = new Secp256k1();
35 | System.out.println(s2.B58PubKey());
36 | }
37 |
38 | @Test
39 | public void testSecp256k1Verify() throws IOException {
40 | byte[] seckey = Base58.decode("EhNiaU4DzUmjCrvynV3gaUeuj2VjB1v2DCmbGD5U2nSE");
41 | Secp256k1 s = new Secp256k1(seckey);
42 |
43 | assertEquals("02069b1abdaaf8326e7e6fc15607fd9e6c6f595e119a2484a4192b5d6b3878dd25", Hex.toHexString(s.pubkey()));
44 | byte[] info = (new SHA3.Digest256()).digest("hello".getBytes());
45 | assertEquals("3338be694f50c5f338814986cdf0686453a888b84f424d792af4b9202398f392", Hex.toHexString(info));
46 | Signature signature = s.sign(info);
47 | assertEquals("37f7731bdb9988aa330be8bbd6a791f11d9fe90601edf7f569f6b8ddcfdd7755333b299ca3a8437e71eb14c72a02a2c5cdf3562e891f5a3c1d54d92148236e10",
48 | Hex.toHexString(signature.signature));
49 |
50 | assertTrue(s.verify(info, signature.signature));
51 | }
52 |
53 | @Test
54 | public void testEd25519() throws InvalidKeySpecException, IOException {
55 | byte[] seckey = Base58.decode("1rANSfcRzr4HkhbUFZ7L1Zp69JZZHiDDq5v7dNSbbEqeU4jxy3fszV4HGiaLQEyqVpS1dKT9g7zCVRxBVzuiUzB");
56 |
57 | Ed25519 e = new Ed25519(seckey);
58 | assertEquals("5731adeb5d1a807ec9c43825389e5edff70412e4643a94629a652af1bfcf2f08", Hex.toHexString(e.pubkey()));
59 |
60 | byte[] info = (new SHA3.Digest256()).digest("hello".getBytes());
61 | assertEquals("3338be694f50c5f338814986cdf0686453a888b84f424d792af4b9202398f392", Hex.toHexString(info));
62 | Signature signature = e.sign(info);
63 | assertEquals("eb436f1af8502d454f8bcea472bac4015f7827d7f90427ce22787f14bf98b83d2c2b4d1b303ad4201b1526a1a269f069dcbf2887a636799b8e733acd2fd75308",
64 | Hex.toHexString(signature.signature));
65 |
66 | KeyPair s2 = new Ed25519();
67 | System.out.println("\"" + (new Ed25519()).B58SecKey() + "\",");
68 |
69 | }
70 |
71 | @Test
72 | public void testEd25519Verify() throws InvalidKeySpecException, IOException {
73 | byte[] seckey = Base58.decode("1rANSfcRzr4HkhbUFZ7L1Zp69JZZHiDDq5v7dNSbbEqeU4jxy3fszV4HGiaLQEyqVpS1dKT9g7zCVRxBVzuiUzB");
74 |
75 | Ed25519 e = new Ed25519(seckey);
76 | assertEquals("5731adeb5d1a807ec9c43825389e5edff70412e4643a94629a652af1bfcf2f08", Hex.toHexString(e.pubkey()));
77 |
78 | byte[] info = (new SHA3.Digest256()).digest("hello".getBytes());
79 | assertEquals("3338be694f50c5f338814986cdf0686453a888b84f424d792af4b9202398f392", Hex.toHexString(info));
80 | Signature signature = e.sign(info);
81 | assertEquals("eb436f1af8502d454f8bcea472bac4015f7827d7f90427ce22787f14bf98b83d2c2b4d1b303ad4201b1526a1a269f069dcbf2887a636799b8e733acd2fd75308",
82 | Hex.toHexString(signature.signature));
83 | assertTrue(e.verify(info, signature.signature));
84 |
85 | }
86 |
87 | @Test
88 | public void testSHA3_256() {
89 | byte[] info = (new SHA3.Digest256()).digest("hello".getBytes());
90 | assertEquals("3338be694f50c5f338814986cdf0686453a888b84f424d792af4b9202398f392", Hex.toHexString(info));
91 | }
92 |
93 | @Test
94 | public void testTransaction() throws IOException, InvalidKeySpecException {
95 |
96 | Transaction tx = new Transaction();
97 | tx.time = 1544013436179000000L;
98 | tx.expiration = 1544013526179000000L;
99 | tx.gas_ratio = 1L;
100 | tx.gas_limit = 1234L;
101 | tx.delay = 0;
102 | tx.chain_id = 0;
103 |
104 | tx.addSigner("abc");
105 |
106 | tx.addAction("cont", "abi");
107 |
108 | tx.addApprove("iost", "123");
109 |
110 | assertEquals("156d700a27e12ac0156d701f1c4c2ec00000000000000064000000000001e208000000000000000000000000000000000000000100000003616263000000010000001500000004636f6e7400000003616269000000025b5d000000010000000f00000004696f737400000003313233",
111 | Hex.toHexString(tx.signBytes()));
112 |
113 | assertEquals("95e01835fb9901c26716d73884cc96342dfb2d68e48fb165e95edf6618228e4d", Hex.toHexString(tx.getSignHash()));
114 |
115 | Keychain kc = new Keychain("abc");
116 | kc.addKey("def", new Ed25519(Base58.decode("1rANSfcRzr4HkhbUFZ7L1Zp69JZZHiDDq5v7dNSbbEqeU4jxy3fszV4HGiaLQEyqVpS1dKT9g7zCVRxBVzuiUzB")));
117 | kc.sign(tx, "def");
118 | assertEquals("156d700a27e12ac0156d701f1c4c2ec00000000000000064000000000001e208000000000000000000000000000000000000000100000003616263000000010000001500000004636f6e7400000003616269000000025b5d000000010000000f00000004696f73740000000331323300000001000000690200000040fe0eb96448bbb1d3cb34a6d4e8780af98586836cba05549ffd25cb66f14e911b6f5f82479fd5d4e5c9217c6a296037bd03ed17ef3972299db80dd6bd0e989d0c000000205731adeb5d1a807ec9c43825389e5edff70412e4643a94629a652af1bfcf2f08",
119 | Hex.toHexString(tx.getPublishBytes()));
120 | assertEquals("26f1dbd162f9275a9266c9f20d6578a9e607e3ff6315ad2721f89de2f0b16c83", Hex.toHexString(tx.getPublishHash()));
121 |
122 | GsonBuilder gb = new GsonBuilder();
123 | gb.registerTypeAdapter(Signature.class, new SignatureAdapter());
124 |
125 | System.out.println(gb.create().toJson(tx));
126 | }
127 |
128 | @Test
129 | public void testDebug() throws IOException {
130 | byte[] pubkey = Base58.decode("sy8zB6MSWiyMFL7HjSsEbWN4VYwF8MfYhSqm1F8FkivWdK7y7NpW3FZP");
131 | System.out.println(pubkey.length);
132 |
133 | byte[] sec = Base58.decode("xprv9s21ZrQH143K2e7hhj5LZAeEFyREr3oaHMbKJ7dDUothtr8WbzejQmk417DbDYUDgonRsrUEGdKR4sGuFzEK4zdAmnBQ4Kb1Cgsiwk5pqXB");
134 | System.out.println(sec.length);
135 |
136 | KeyPair kp = new Ed25519(sec);
137 | System.out.println(kp.B58PubKey());
138 | System.out.println(kp.getID());
139 | System.out.println(kp.B58SecKey());
140 | }
141 |
142 | }
143 |
--------------------------------------------------------------------------------
/src/test/java/crypto_sign_open.java:
--------------------------------------------------------------------------------
1 | import iost.crypto.Ed25519;
2 | import iost.crypto.KeyPair;
3 | import iost.crypto.TweetNaCl;
4 | import org.junit.Test;
5 |
6 | // ref: https://github.com/iost-official/java-sdk/issues/4
7 | public class crypto_sign_open {
8 |
9 | @Test
10 | public void test() {
11 | String message = "hello world";
12 | KeyPair k = new Ed25519();
13 |
14 | System.out.println(k.B58SecKey());
15 | System.out.println(k.B58PubKey());
16 |
17 | byte[] info = message.getBytes();
18 |
19 | byte[] signature = TweetNaCl.crypto_sign(info, k.seckey());
20 |
21 | byte[] messageWithSignature = new byte[signature.length + info.length];
22 | System.arraycopy(signature, 0, messageWithSignature, 0, signature.length);
23 | System.arraycopy(info, 0, messageWithSignature, signature.length, info.length);
24 | byte[] openMessage = TweetNaCl.crypto_sign_open(messageWithSignature, k.pubkey());
25 |
26 | System.out.println(new String(signature));
27 | System.out.println(new String(openMessage));
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/test/java/iost/crypto/VerifyUtilsTest.java:
--------------------------------------------------------------------------------
1 | package iost.crypto;
2 |
3 | import iost.model.transaction.Signature;
4 | import org.bouncycastle.jcajce.provider.digest.SHA3;
5 | import org.bouncycastle.util.encoders.Hex;
6 | import org.junit.Test;
7 |
8 | import static org.junit.Assert.assertEquals;
9 | import static org.junit.Assert.assertTrue;
10 |
11 | public class VerifyUtilsTest {
12 | @Test
13 | public void ed25519Verify() throws Exception {
14 |
15 | byte[] seckey = Base58.decode("1rANSfcRzr4HkhbUFZ7L1Zp69JZZHiDDq5v7dNSbbEqeU4jxy3fszV4HGiaLQEyqVpS1dKT9g7zCVRxBVzuiUzB");
16 |
17 | Ed25519 e = new Ed25519(seckey);
18 | byte[] pubKey = e.pubkey();
19 | assertEquals("5731adeb5d1a807ec9c43825389e5edff70412e4643a94629a652af1bfcf2f08", Hex.toHexString(pubKey));
20 |
21 | byte[] info = (new SHA3.Digest256()).digest("hello".getBytes());
22 | assertEquals("3338be694f50c5f338814986cdf0686453a888b84f424d792af4b9202398f392", Hex.toHexString(info));
23 | Signature signature = e.sign(info);
24 | assertEquals("eb436f1af8502d454f8bcea472bac4015f7827d7f90427ce22787f14bf98b83d2c2b4d1b303ad4201b1526a1a269f069dcbf2887a636799b8e733acd2fd75308",
25 | Hex.toHexString(signature.signature));
26 | assertTrue(e.verify(info, signature.signature));
27 |
28 | // verify without seckey
29 | assertTrue(VerifyUtils.Ed25519Verify(info, signature.signature, pubKey));
30 | }
31 |
32 | @Test
33 | public void secp256k1Verify() throws Exception {
34 | byte[] seckey = Base58.decode("EhNiaU4DzUmjCrvynV3gaUeuj2VjB1v2DCmbGD5U2nSE");
35 | Secp256k1 s = new Secp256k1(seckey);
36 | byte[] pubKey = s.pubkey();
37 | assertEquals("02069b1abdaaf8326e7e6fc15607fd9e6c6f595e119a2484a4192b5d6b3878dd25", Hex.toHexString(pubKey));
38 | byte[] info = (new SHA3.Digest256()).digest("hello".getBytes());
39 | Signature signature = s.sign(info);
40 | assertEquals("37f7731bdb9988aa330be8bbd6a791f11d9fe90601edf7f569f6b8ddcfdd7755333b299ca3a8437e71eb14c72a02a2c5cdf3562e891f5a3c1d54d92148236e10",
41 | Hex.toHexString(signature.signature));
42 |
43 | assertTrue(s.verify(info, signature.signature));
44 |
45 | // verify without seckey
46 | assertTrue(VerifyUtils.Secp256k1Verify(info, signature.signature, pubKey));
47 | }
48 |
49 | }
--------------------------------------------------------------------------------