├── .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 | } --------------------------------------------------------------------------------