├── Readme.markdown ├── cpp ├── AsmX8664.hpp ├── AsmX8664.s ├── Base58Check.cpp ├── Base58Check.hpp ├── Base58CheckTest.cpp ├── CountOps.hpp ├── CurvePoint.cpp ├── CurvePoint.hpp ├── CurvePointTest.cpp ├── Ecdsa.cpp ├── Ecdsa.hpp ├── EcdsaOpCount.cpp ├── EcdsaTest.cpp ├── ExtendedPrivateKey.cpp ├── ExtendedPrivateKey.hpp ├── ExtendedPrivateKeyTest.cpp ├── FieldInt.cpp ├── FieldInt.hpp ├── FieldIntTest.cpp ├── Keccak256.cpp ├── Keccak256.hpp ├── Keccak256Test.cpp ├── Makefile ├── Ripemd160.cpp ├── Ripemd160.hpp ├── Ripemd160Test.cpp ├── Sha256.cpp ├── Sha256.hpp ├── Sha256Hash.cpp ├── Sha256Hash.hpp ├── Sha256HashTest.cpp ├── Sha256Test.cpp ├── Sha512.cpp ├── Sha512.hpp ├── Sha512Test.cpp ├── TestHelper.hpp ├── Uint256.cpp ├── Uint256.hpp ├── Uint256Test.cpp ├── Utils.cpp └── Utils.hpp └── java └── io └── nayuki └── bitcoin └── crypto ├── Base58Check.java ├── Base58CheckTest.java ├── Bech32.java ├── Bech32Test.java ├── CurvePointMath.java ├── CurvePointMathTest.java ├── Ecdsa.java ├── EcdsaTest.java ├── Int256Math.java ├── Int256MathTest.java ├── Keccak256.java ├── Keccak256Test.java ├── Ripemd160.java ├── Ripemd160Test.java ├── Sha256.java ├── Sha256Hash.java ├── Sha256Test.java ├── Sha512.java ├── Sha512Test.java └── Utils.java /Readme.markdown: -------------------------------------------------------------------------------- 1 | Nayuki's Bitcoin cryptography library 2 | ===================================== 3 | 4 | This project implements the cryptographic primitives used in the Bitcoin system, 5 | especially elliptic curve operations and hash functions. 6 | 7 | The code is written in two independent versions in C++ and Java. It includes a 8 | test suite of over a thousand test vectors that cover every feature provided by 9 | the library. 10 | 11 | The library is open-source, and is written by Nayuki from the ground up. It is 12 | designed with portability and clarity in mind, and is rigorously verified for 13 | correctness and quality. 14 | 15 | More details about features and design principles are on the main web page: 16 | [https://www.nayuki.io/page/bitcoin-cryptography-library](https://www.nayuki.io/page/bitcoin-cryptography-library) 17 | 18 | 19 | License 20 | ------- 21 | 22 | Copyright © 2019 Project Nayuki. (MIT License) 23 | 24 | Permission is hereby granted, free of charge, to any person obtaining a copy of 25 | this software and associated documentation files (the "Software"), to deal in 26 | the Software without restriction, including without limitation the rights to 27 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 28 | the Software, and to permit persons to whom the Software is furnished to do so, 29 | subject to the following conditions: 30 | 31 | * The above copyright notice and this permission notice shall be included in 32 | all copies or substantial portions of the Software. 33 | 34 | * The Software is provided "as is", without warranty of any kind, express or 35 | implied, including but not limited to the warranties of merchantability, 36 | fitness for a particular purpose and noninfringement. In no event shall the 37 | authors or copyright holders be liable for any claim, damages or other 38 | liability, whether in an action of contract, tort or otherwise, arising from, 39 | out of or in connection with the Software or the use or other dealings in the 40 | Software. 41 | -------------------------------------------------------------------------------- /cpp/AsmX8664.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * http://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | #ifndef USE_X8664_ASM_IMPL 14 | #define USE_X8664_ASM_IMPL 0 15 | #endif 16 | 17 | 18 | extern "C" { 19 | 20 | std::uint32_t asm_Uint256_add(std::uint32_t dest[8], const std::uint32_t src[8], std::uint32_t enable); 21 | 22 | std::uint32_t asm_Uint256_subtract(std::uint32_t dest[8], const std::uint32_t src[8], std::uint32_t enable); 23 | 24 | std::uint32_t asm_Uint256_shiftLeft1(std::uint32_t dest[8]); 25 | 26 | void asm_Uint256_shiftRight1(std::uint32_t dest[8], std::uint32_t enable); 27 | 28 | void asm_Uint256_replace(std::uint32_t dest[8], const std::uint32_t src[8], std::uint32_t enable); 29 | 30 | void asm_Uint256_swap(std::uint32_t left[8], std::uint32_t right[8], std::uint32_t enable); 31 | 32 | bool asm_Uint256_equalTo(const std::uint32_t left[8], const std::uint32_t right[8]); 33 | 34 | bool asm_Uint256_lessThan(const std::uint32_t left[8], const std::uint32_t right[8]); 35 | 36 | 37 | // Computes (uint512 z) = (uint256 x) * (uint256 y), correct for all input values. 38 | // (i.e. Input values are Uint256, not necessarily FieldInt.) 39 | void asm_FieldInt_multiply256x256eq512(std::uint32_t z[16], const std::uint32_t x[8], const std::uint32_t y[8]); 40 | 41 | // Computes (uint768 dest) = (uint512 src) * (2^256 + 2^32 + 0x3D1) % 2^768, 42 | // correct for all input values. If src < modulus^2, then the result does not overflow. 43 | void asm_FieldInt_multiplyBarrettStep0(std::uint32_t dest[24], const std::uint32_t src[16]); 44 | 45 | // Computes (uint512 dest) = (uint256 src) * (2^256 - 2^32 - 0x3D1), correct for all input values. 46 | void asm_FieldInt_multiplyBarrettStep1(std::uint32_t dest[16], const std::uint32_t src[8]); 47 | 48 | // Computes (uint288 z) = ((uint512 x) - (uint512 y)) % 2^288, correct for all input values. 49 | void asm_FieldInt_multiplyBarrettStep2(std::uint32_t z[9], const std::uint32_t x[16], const std::uint32_t y[16]); 50 | 51 | } 52 | -------------------------------------------------------------------------------- /cpp/AsmX8664.s: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * http://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | 10 | /* uint32_t asm_Uint256_add(uint32_t dest[8], const uint32_t src[8], uint32_t enable) */ 11 | .globl asm_Uint256_add 12 | asm_Uint256_add: 13 | negq %rdx 14 | movq 0(%rsi), %rax 15 | movq 8(%rsi), %rcx 16 | movq 16(%rsi), %r8 17 | movq 24(%rsi), %r9 18 | andq %rdx, %rax 19 | andq %rdx, %rcx 20 | andq %rdx, %r8 21 | andq %rdx, %r9 22 | addq %rax, 0(%rdi) 23 | adcq %rcx, 8(%rdi) 24 | adcq %r8 , 16(%rdi) 25 | adcq %r9 , 24(%rdi) 26 | setc %al 27 | movzbl %al, %eax 28 | retq 29 | 30 | 31 | /* uint32_t asm_Uint256_subtract(uint32_t dest[8], const uint32_t src[8], uint32_t enable) */ 32 | .globl asm_Uint256_subtract 33 | asm_Uint256_subtract: 34 | negq %rdx 35 | movq 0(%rsi), %rax 36 | movq 8(%rsi), %rcx 37 | movq 16(%rsi), %r8 38 | movq 24(%rsi), %r9 39 | andq %rdx, %rax 40 | andq %rdx, %rcx 41 | andq %rdx, %r8 42 | andq %rdx, %r9 43 | subq %rax, 0(%rdi) 44 | sbbq %rcx, 8(%rdi) 45 | sbbq %r8 , 16(%rdi) 46 | sbbq %r9 , 24(%rdi) 47 | setc %al 48 | movzbl %al, %eax 49 | retq 50 | 51 | 52 | /* uint32_t asm_Uint256_shiftLeft1(uint32_t dest[8]) */ 53 | .globl asm_Uint256_shiftLeft1 54 | asm_Uint256_shiftLeft1: 55 | shlq $1, 0(%rdi) 56 | rclq $1, 8(%rdi) 57 | rclq $1, 16(%rdi) 58 | rclq $1, 24(%rdi) 59 | setc %al 60 | movzbl %al, %eax 61 | retq 62 | 63 | 64 | /* void asm_Uint256_shiftRight1(uint32_t dest[8], uint32_t enable); */ 65 | .globl asm_Uint256_shiftRight1 66 | asm_Uint256_shiftRight1: 67 | movq 0(%rdi), %rax 68 | movq 8(%rdi), %rcx 69 | movq 16(%rdi), %r8 70 | movq 24(%rdi), %r9 71 | shrq $1, %r9 72 | rcrq $1, %r8 73 | rcrq $1, %rcx 74 | rcrq $1, %rax 75 | testl %esi, %esi 76 | movq 0(%rdi), %rdx 77 | movq 8(%rdi), %rsi 78 | cmovzq %rdx, %rax 79 | cmovzq %rsi, %rcx 80 | movq 16(%rdi), %rdx 81 | movq 24(%rdi), %rsi 82 | cmovzq %rdx, %r8 83 | cmovzq %rsi, %r9 84 | movq %rax, 0(%rdi) 85 | movq %rcx, 8(%rdi) 86 | movq %r8 , 16(%rdi) 87 | movq %r9 , 24(%rdi) 88 | retq 89 | 90 | 91 | /* void asm_Uint256_replace(uint32_t dest[8], const uint32_t src[8], uint32_t enable) */ 92 | .globl asm_Uint256_replace 93 | asm_Uint256_replace: 94 | negl %edx 95 | movd %edx, %xmm0 96 | pshufd $0, %xmm0, %xmm0 97 | movdqu 0(%rdi), %xmm1 98 | movdqu 16(%rdi), %xmm2 99 | pblendvb 0(%rsi), %xmm1 100 | pblendvb 16(%rsi), %xmm2 101 | movdqu %xmm1, 0(%rdi) 102 | movdqu %xmm2, 16(%rdi) 103 | retq 104 | 105 | 106 | /* void asm_Uint256_swap(uint32_t left[8], uint32_t right[8], uint32_t enable) */ 107 | .globl asm_Uint256_swap 108 | asm_Uint256_swap: 109 | negl %edx 110 | movd %edx, %xmm0 111 | pshufd $0, %xmm0, %xmm0 112 | movdqu 0(%rdi), %xmm1 113 | movdqu 16(%rdi), %xmm2 114 | movdqu 0(%rsi), %xmm3 115 | movdqu 16(%rsi), %xmm4 116 | movdqa %xmm1, %xmm5 117 | movdqa %xmm2, %xmm6 118 | pblendvb %xmm3, %xmm1 119 | pblendvb %xmm4, %xmm2 120 | pblendvb %xmm5, %xmm3 121 | pblendvb %xmm6, %xmm4 122 | movdqu %xmm1, 0(%rdi) 123 | movdqu %xmm2, 16(%rdi) 124 | movdqu %xmm3, 0(%rsi) 125 | movdqu %xmm4, 16(%rsi) 126 | retq 127 | 128 | 129 | /* bool asm_Uint256_equalTo(const uint32_t left[8], const uint32_t right[8]) */ 130 | .globl asm_Uint256_equalTo 131 | asm_Uint256_equalTo: 132 | movdqu 0(%rdi), %xmm0 133 | movdqu 16(%rdi), %xmm1 134 | pcmpeqb 0(%rsi), %xmm0 135 | pcmpeqb 16(%rsi), %xmm1 136 | pand %xmm1, %xmm0 137 | pmovmskb %xmm0, %eax 138 | cmpl $0xFFFF, %eax 139 | sete %al 140 | movzbl %al, %eax 141 | retq 142 | 143 | 144 | /* bool asm_Uint256_lessThan(const uint32_t left[8], const uint32_t right[8]) */ 145 | .globl asm_Uint256_lessThan 146 | asm_Uint256_lessThan: 147 | movq 0(%rdi), %rcx 148 | movq 8(%rdi), %rdx 149 | movq 16(%rdi), %r8 150 | movq 24(%rdi), %r9 151 | xorl %edi, %edi 152 | cmpq 0(%rsi), %rcx 153 | movl $1, %ecx 154 | setb %al 155 | movzbl %al, %eax 156 | cmpq 8(%rsi), %rdx 157 | cmovbl %ecx, %eax 158 | cmoval %edi, %eax 159 | cmpq 16(%rsi), %r8 160 | cmovbl %ecx, %eax 161 | cmoval %edi, %eax 162 | cmpq 24(%rsi), %r9 163 | cmovbl %ecx, %eax 164 | cmoval %edi, %eax 165 | retq 166 | 167 | 168 | /* void asm_FieldInt_multiply256x256eq512(uint32_t z[16], const uint32_t x[8], const uint32_t y[8]) */ 169 | .globl asm_FieldInt_multiply256x256eq512 170 | asm_FieldInt_multiply256x256eq512: 171 | movq %rdx, %rcx 172 | 173 | movq 0(%rsi), %r9 174 | movq %r9, %rax 175 | mulq 0(%rcx) 176 | movq %rax, 0(%rdi) 177 | movq %rdx, %r8 178 | movq %r9, %rax 179 | mulq 8(%rcx) 180 | addq %r8, %rax 181 | adcq $0, %rdx 182 | movq %rax, 8(%rdi) 183 | movq %rdx, %r8 184 | movq %r9, %rax 185 | mulq 16(%rcx) 186 | addq %r8, %rax 187 | adcq $0, %rdx 188 | movq %rax, 16(%rdi) 189 | movq %rdx, %r8 190 | movq %r9, %rax 191 | mulq 24(%rcx) 192 | addq %r8, %rax 193 | adcq $0, %rdx 194 | movq %rax, 24(%rdi) 195 | movq %rdx, 32(%rdi) 196 | 197 | movq 8(%rsi), %r9 198 | movq %r9, %rax 199 | mulq 0(%rcx) 200 | addq %rax, 8(%rdi) 201 | adcq $0, %rdx 202 | movq %rdx, %r8 203 | movq %r9, %rax 204 | mulq 8(%rcx) 205 | addq %r8, %rax 206 | adcq $0, %rdx 207 | addq %rax, 16(%rdi) 208 | adcq $0, %rdx 209 | movq %rdx, %r8 210 | movq %r9, %rax 211 | mulq 16(%rcx) 212 | addq %r8, %rax 213 | adcq $0, %rdx 214 | addq %rax, 24(%rdi) 215 | adcq $0, %rdx 216 | movq %rdx, %r8 217 | movq %r9, %rax 218 | mulq 24(%rcx) 219 | addq %r8, %rax 220 | adcq $0, %rdx 221 | addq %rax, 32(%rdi) 222 | adcq $0, %rdx 223 | movq %rdx, 40(%rdi) 224 | 225 | movq 16(%rsi), %r9 226 | movq %r9, %rax 227 | mulq 0(%rcx) 228 | addq %rax, 16(%rdi) 229 | adcq $0, %rdx 230 | movq %rdx, %r8 231 | movq %r9, %rax 232 | mulq 8(%rcx) 233 | addq %r8, %rax 234 | adcq $0, %rdx 235 | addq %rax, 24(%rdi) 236 | adcq $0, %rdx 237 | movq %rdx, %r8 238 | movq %r9, %rax 239 | mulq 16(%rcx) 240 | addq %r8, %rax 241 | adcq $0, %rdx 242 | addq %rax, 32(%rdi) 243 | adcq $0, %rdx 244 | movq %rdx, %r8 245 | movq %r9, %rax 246 | mulq 24(%rcx) 247 | addq %r8, %rax 248 | adcq $0, %rdx 249 | addq %rax, 40(%rdi) 250 | adcq $0, %rdx 251 | movq %rdx, 48(%rdi) 252 | 253 | movq 24(%rsi), %r9 254 | movq %r9, %rax 255 | mulq 0(%rcx) 256 | addq %rax, 24(%rdi) 257 | adcq $0, %rdx 258 | movq %rdx, %r8 259 | movq %r9, %rax 260 | mulq 8(%rcx) 261 | addq %r8, %rax 262 | adcq $0, %rdx 263 | addq %rax, 32(%rdi) 264 | adcq $0, %rdx 265 | movq %rdx, %r8 266 | movq %r9, %rax 267 | mulq 16(%rcx) 268 | addq %r8, %rax 269 | adcq $0, %rdx 270 | addq %rax, 40(%rdi) 271 | adcq $0, %rdx 272 | movq %rdx, %r8 273 | movq %r9, %rax 274 | mulq 24(%rcx) 275 | addq %r8, %rax 276 | adcq $0, %rdx 277 | addq %rax, 48(%rdi) 278 | adcq $0, %rdx 279 | movq %rdx, 56(%rdi) 280 | 281 | retq 282 | 283 | 284 | /* void asm_FieldInt_multiplyBarrettStep0(uint32_t dest[24], const uint32_t src[16]) */ 285 | .globl asm_FieldInt_multiplyBarrettStep0 286 | asm_FieldInt_multiplyBarrettStep0: 287 | movq 0(%rsi), %rax 288 | movq 8(%rsi), %rdx 289 | movq 16(%rsi), %r8 290 | movq 24(%rsi), %r9 291 | movq %rax, 32(%rdi) 292 | movq %rdx, 40(%rdi) 293 | movq %r8 , 48(%rdi) 294 | movq %r9 , 56(%rdi) 295 | movq 32(%rsi), %rax 296 | movq 40(%rsi), %rdx 297 | movq 48(%rsi), %r8 298 | movq 56(%rsi), %r9 299 | movq %rax, 64(%rdi) 300 | movq %rdx, 72(%rdi) 301 | movq %r8 , 80(%rdi) 302 | movq %r9 , 88(%rdi) 303 | 304 | movl 0(%rsi), %eax 305 | movl $0, 0(%rdi) 306 | movl %eax, 4(%rdi) 307 | movq 4(%rsi), %rax 308 | movq 12(%rsi), %rcx 309 | movq 20(%rsi), %rdx 310 | movq %rax, 8(%rdi) 311 | movq %rcx, 16(%rdi) 312 | movq %rdx, 24(%rdi) 313 | 314 | movq 28(%rsi), %rax 315 | addq %rax, 32(%rdi) 316 | movq 36(%rsi), %rax 317 | adcq %rax, 40(%rdi) 318 | movq 44(%rsi), %rax 319 | adcq %rax, 48(%rdi) 320 | movq 52(%rsi), %rax 321 | adcq %rax, 56(%rdi) 322 | 323 | movl 60(%rsi), %eax 324 | adcq %rax, 64(%rdi) 325 | adcq $0, 72(%rdi) 326 | adcq $0, 80(%rdi) 327 | adcq $0, 88(%rdi) 328 | 329 | movl $0, %ecx 330 | movq $0, %r8 331 | .loop0: 332 | movl $0x3D1, %eax 333 | mulq (%rsi,%rcx) 334 | addq %r8, %rax 335 | adcq $0, %rdx 336 | addq %rax, (%rdi,%rcx) 337 | adcq $0, %rdx 338 | movq %rdx, %r8 339 | addl $8, %ecx 340 | cmpl $64, %ecx 341 | jb .loop0 342 | 343 | addq %r8, 64(%rdi) 344 | adcq $0, 72(%rdi) 345 | adcq $0, 80(%rdi) 346 | adcq $0, 88(%rdi) 347 | retq 348 | 349 | 350 | /* void asm_FieldInt_multiplyBarrettStep1(uint32_t dest[16], const uint32_t src[8]) */ 351 | .globl asm_FieldInt_multiplyBarrettStep1 352 | asm_FieldInt_multiplyBarrettStep1: 353 | movq 0(%rsi), %rax 354 | movq 8(%rsi), %rcx 355 | movq 16(%rsi), %r8 356 | movq 24(%rsi), %r9 357 | movq %rax, 32(%rdi) 358 | movq %rcx, 40(%rdi) 359 | movq %r8 , 48(%rdi) 360 | movq %r9 , 56(%rdi) 361 | 362 | movl 0(%rsi), %eax 363 | shlq $32, %rax 364 | negq %rax 365 | movq %rax, 0(%rdi) 366 | movl $0, %eax 367 | sbbq 4(%rsi), %rax 368 | movq %rax, 8(%rdi) 369 | movl $0, %eax 370 | sbbq 12(%rsi), %rax 371 | movq %rax, 16(%rdi) 372 | movl $0, %eax 373 | sbbq 20(%rsi), %rax 374 | movq %rax, 24(%rdi) 375 | movl 28(%rsi), %eax 376 | sbbq %rax, 32(%rdi) 377 | sbbq $0, 40(%rdi) 378 | sbbq $0, 48(%rdi) 379 | sbbq $0, 56(%rdi) 380 | 381 | movl $0, %ecx 382 | movq $0, %r8 383 | movl $0, %r9d 384 | .loop1: 385 | movl $0x3D1, %eax 386 | mulq (%rsi,%rcx) 387 | addq %r8, %rax 388 | adcq $0, %rdx 389 | negl %r9d 390 | sbbq %rax, (%rdi,%rcx) 391 | movl $0, %r9d 392 | sbbl $0, %r9d 393 | movq %rdx, %r8 394 | addl $8, %ecx 395 | cmpl $32, %ecx 396 | jb .loop1 397 | 398 | negl %r9d 399 | sbbq %r8, 32(%rdi) 400 | sbbq $0, 40(%rdi) 401 | sbbq $0, 48(%rdi) 402 | sbbq $0, 56(%rdi) 403 | retq 404 | 405 | 406 | /* void asm_FieldInt_multiplyBarrettStep2(uint32_t z[9], const uint32_t x[16], const uint32_t y[16]) */ 407 | .globl asm_FieldInt_multiplyBarrettStep2 408 | asm_FieldInt_multiplyBarrettStep2: 409 | movq 0(%rsi), %rax 410 | subq 0(%rdx), %rax 411 | movq %rax, 0(%rdi) 412 | movq 8(%rsi), %rax 413 | sbbq 8(%rdx), %rax 414 | movq %rax, 8(%rdi) 415 | movq 16(%rsi), %rax 416 | sbbq 16(%rdx), %rax 417 | movq %rax, 16(%rdi) 418 | movq 24(%rsi), %rax 419 | sbbq 24(%rdx), %rax 420 | movq %rax, 24(%rdi) 421 | movl 32(%rsi), %eax 422 | sbbl 32(%rdx), %eax 423 | movl %eax, 32(%rdi) 424 | retq 425 | -------------------------------------------------------------------------------- /cpp/Base58Check.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #include 10 | #include 11 | #include "Base58Check.hpp" 12 | #include "Sha256.hpp" 13 | #include "Sha256Hash.hpp" 14 | #include "Utils.hpp" 15 | 16 | using std::uint8_t; 17 | using std::uint32_t; 18 | using std::size_t; 19 | 20 | 21 | 22 | /*---- Public and private functions for bytes-to-Base58 conversion ----*/ 23 | 24 | void Base58Check::pubkeyHashToBase58Check(const uint8_t pubkeyHash[Ripemd160::HASH_LEN], uint8_t version, char outStr[36]) { 25 | assert(pubkeyHash != nullptr && outStr != nullptr); 26 | constexpr size_t arrayLen = 1 + static_cast(Ripemd160::HASH_LEN) + 4; 27 | uint8_t toEncode[arrayLen]; 28 | toEncode[0] = version; 29 | std::memcpy(&toEncode[1], pubkeyHash, Ripemd160::HASH_LEN); 30 | uint8_t temp[arrayLen]; 31 | bytesToBase58Check(toEncode, temp, arrayLen - 4, outStr); 32 | } 33 | 34 | 35 | void Base58Check::privateKeyToBase58Check(const Uint256 &privKey, uint8_t version, bool isCompressed, char outStr[53]) { 36 | assert(outStr != nullptr); 37 | constexpr size_t arrayLen = 1 + 32 + 1 + 4; 38 | uint8_t toEncode[arrayLen]; 39 | toEncode[0] = version; 40 | privKey.getBigEndianBytes(&toEncode[1]); 41 | toEncode[33] = 0x01; // Compressed marker 42 | uint8_t temp[arrayLen]; 43 | bytesToBase58Check(toEncode, temp, arrayLen - (isCompressed ? 4 : 5), outStr); 44 | } 45 | 46 | 47 | void Base58Check::extendedPrivateKeyToBase58Check(const ExtendedPrivateKey &key, char outStr[112]) { 48 | assert(outStr != nullptr); 49 | constexpr size_t arrayLen = 4 + 1 + 4 + 4 + 32 + 1 + 32 + 4; 50 | uint8_t toEncode[arrayLen]; 51 | Utils::storeBigUint32(0x0488ADE4, &toEncode[0]); 52 | toEncode[ 4] = key.depth; 53 | std::memcpy(&toEncode[5], key.parentPubkeyHash, sizeof(key.parentPubkeyHash)); 54 | Utils::storeBigUint32(key.index, &toEncode[9]); 55 | std::memcpy(&toEncode[13], key.chainCode, sizeof(key.chainCode)); 56 | toEncode[45] = 0x00; 57 | key.privateKey.getBigEndianBytes(&toEncode[46]); 58 | uint8_t temp[arrayLen]; 59 | bytesToBase58Check(toEncode, temp, arrayLen - 4, outStr); 60 | } 61 | 62 | 63 | void Base58Check::bytesToBase58Check(uint8_t data[], uint8_t temp[], size_t dataLen, char *outStr) { 64 | // Append 4-byte hash 65 | assert(data != nullptr && temp != nullptr && outStr != nullptr); 66 | const Sha256Hash sha256Hash = Sha256::getDoubleHash(data, dataLen); 67 | for (int i = 0; i < 4; i++, dataLen++) 68 | data[dataLen] = sha256Hash.value[i]; 69 | 70 | // Count leading zero bytes 71 | size_t leadingZeros = 0; 72 | while (leadingZeros < dataLen && data[leadingZeros] == 0) 73 | leadingZeros++; 74 | 75 | // Encode to Base 58 76 | size_t outLen = 0; 77 | while (!isZero(data, dataLen)) { // Extract digits in little-endian 78 | outStr[outLen] = ALPHABET[mod58(data, dataLen)]; 79 | outLen++; 80 | divide58(data, temp, dataLen); // temp = floor(data / 58) 81 | Utils::copyBytes(data, temp, dataLen); // data = temp 82 | } 83 | for (size_t i = 0; i < leadingZeros; i++) { // Append leading zeros 84 | outStr[outLen] = ALPHABET[0]; 85 | outLen++; 86 | } 87 | outStr[outLen] = '\0'; 88 | 89 | // Reverse the string 90 | if (outLen == 0) 91 | return; // Exit early to ensure that j does not overflow 92 | for (size_t i = 0, j = outLen - 1; i < j; i++, j--) { 93 | char tp = outStr[i]; 94 | outStr[i] = outStr[j]; 95 | outStr[j] = tp; 96 | } 97 | } 98 | 99 | 100 | bool Base58Check::isZero(const uint8_t x[], size_t len) { 101 | assert(len == 0 || x != nullptr); 102 | for (size_t i = 0; i < len; i++) { 103 | if (x[i] != 0) 104 | return false; 105 | } 106 | return true; 107 | } 108 | 109 | 110 | uint8_t Base58Check::mod58(const uint8_t x[], size_t len) { 111 | assert(len == 0 || x != nullptr); 112 | unsigned int sum = 0; 113 | for (size_t i = 0; i < len; i++) 114 | sum = ((sum * 24) + x[i]) % 58; // Note: 256 % 58 = 24 115 | return static_cast(sum); 116 | } 117 | 118 | 119 | void Base58Check::divide58(const uint8_t x[], uint8_t y[], size_t len) { 120 | assert(x != nullptr && y != nullptr); 121 | std::memset(y, 0, len); 122 | unsigned int dividend = 0; 123 | for (size_t i = 0; i < len; i++) { // For each input and output byte 124 | assert(dividend < 58); 125 | dividend = (dividend << 8) | x[i]; // Shift next byte into right side 126 | assert(dividend < 14848); 127 | y[i] = static_cast(dividend / 58); 128 | dividend %= 58; 129 | } 130 | } 131 | 132 | 133 | 134 | /*---- Public and private functions for Base58-to-bytes conversion ----*/ 135 | 136 | bool Base58Check::pubkeyHashFromBase58Check(const char *addrStr, uint8_t outPubkeyHash[Ripemd160::HASH_LEN], uint8_t *outVersion) { 137 | // Preliminary checks 138 | assert(addrStr != nullptr && outPubkeyHash != nullptr); 139 | if (std::strlen(addrStr) < 25 || std::strlen(addrStr) > 35) 140 | return false; 141 | 142 | // Perform Base58 decoding 143 | uint8_t decoded[1 + Ripemd160::HASH_LEN + 4]; 144 | if (!base58CheckToBytes(addrStr, decoded, sizeof(decoded) / sizeof(decoded[0]))) 145 | return false; 146 | 147 | // Successfully set the output and version 148 | std::memcpy(outPubkeyHash, &decoded[1], Ripemd160::HASH_LEN * sizeof(uint8_t)); 149 | if (outVersion != nullptr) 150 | *outVersion = decoded[0]; 151 | return true; 152 | } 153 | 154 | 155 | bool Base58Check::privateKeyFromBase58Check(const char wifStr[53], Uint256 &outPrivKey, uint8_t *outVersion, bool *outIsCompressed) { 156 | // Preliminary checks 157 | assert(wifStr != nullptr); 158 | if (std::strlen(wifStr) < 38 || std::strlen(wifStr) > 52) 159 | return false; 160 | 161 | // Perform Base58 decoding 162 | constexpr size_t arrayLen = 1 + 32 + 1 + 4; 163 | uint8_t decoded[arrayLen]; 164 | if (base58CheckToBytes(wifStr, decoded, arrayLen - 1)) { // Try decoding uncompressed 165 | if (outIsCompressed != nullptr) 166 | *outIsCompressed = false; 167 | } else if (base58CheckToBytes(wifStr, decoded, arrayLen)) { // Try decoding compressed 168 | if (decoded[33] != 0x01) // Check compressed marker byte 169 | return false; 170 | if (outIsCompressed != nullptr) 171 | *outIsCompressed = true; 172 | } else 173 | return false; 174 | 175 | // Successfully set the value and version 176 | outPrivKey = Uint256(&decoded[1]); 177 | if (outVersion != nullptr) 178 | *outVersion = decoded[0]; 179 | return true; 180 | } 181 | 182 | 183 | bool Base58Check::extendedPrivateKeyFromBase58Check(const char xprvStr[112], ExtendedPrivateKey &outKey) { 184 | // Preliminary checks 185 | assert(xprvStr != nullptr); 186 | if (std::strlen(xprvStr) != 111) 187 | return false; 188 | 189 | // Perform Base58 decoding 190 | uint8_t decoded[4 + 1 + 4 + 4 + 32 + 1 + 32 + 4]; 191 | if (!base58CheckToBytes(xprvStr, decoded, sizeof(decoded) / sizeof(decoded[0]))) 192 | return false; 193 | 194 | // Load fields 195 | uint8_t depth = decoded[4]; 196 | const uint8_t *parentPubkeyHash = &decoded[5]; 197 | uint32_t index = static_cast(decoded[ 9]) << 24 198 | | static_cast(decoded[10]) << 16 199 | | static_cast(decoded[11]) << 8 200 | | static_cast(decoded[12]) << 0; 201 | const uint8_t *chainCode = &decoded[13]; 202 | Uint256 privateKey(&decoded[46]); 203 | 204 | // Check format 205 | if (decoded[0] != 0x04 || decoded[1] != 0x88 || decoded[2] != 0xAD || decoded[3] != 0xE4) // Header for Bitcoin 206 | return false; 207 | if (decoded[45] != 0) // Version byte for Bitcoin 208 | return false; 209 | if (privateKey == Uint256::ZERO || privateKey >= CurvePoint::ORDER) 210 | return false; 211 | 212 | // Successfully set the value 213 | outKey = ExtendedPrivateKey(privateKey, chainCode, depth, index, parentPubkeyHash); 214 | return true; 215 | } 216 | 217 | 218 | bool Base58Check::base58CheckToBytes(const char *inStr, uint8_t outData[], size_t outDataLen) { 219 | assert(inStr != nullptr && outData != nullptr && outDataLen >= 4); 220 | 221 | // Convert from Base 58 to base 256 222 | std::memset(outData, 0, outDataLen * sizeof(outData[0])); 223 | for (size_t i = 0; inStr[i] != '\0'; i++) { 224 | if (multiply58(outData, outDataLen)) 225 | return false; 226 | const char *p = std::strchr(ALPHABET, inStr[i]); 227 | if (p == nullptr) 228 | return false; 229 | if (addUint8(outData, static_cast(p - &ALPHABET[0]), outDataLen)) 230 | return false; 231 | } 232 | 233 | // Verify number of leading zeros 234 | for (size_t i = 0; ; i++) { 235 | if (inStr[i] != '1' && (i >= outDataLen || outData[i] != 0)) 236 | break; // Success 237 | else if (inStr[i] == '1' && i < outDataLen && outData[i] == 0) 238 | continue; // Keep scanning 239 | else 240 | return false; // Mismatch 241 | } 242 | 243 | // Compute and check hash 244 | const Sha256Hash sha256Hash = Sha256::getDoubleHash(outData, outDataLen - 4); 245 | for (unsigned int i = 0; i < 4; i++) { 246 | if (outData[outDataLen - 4 + i] != sha256Hash.value[i]) 247 | return false; 248 | } 249 | return true; 250 | } 251 | 252 | 253 | bool Base58Check::addUint8(uint8_t x[], uint8_t y, size_t len) { 254 | assert(len >= 1 && x != nullptr); 255 | int carry = 0; 256 | for (size_t i = len - 1; ; i--) { 257 | int sum = x[i] + carry; 258 | assert(0 <= sum && sum <= 256); 259 | if (i == len - 1) 260 | sum += y; 261 | x[i] = static_cast(sum); 262 | carry = sum >> 8; 263 | assert((carry >> 1) == 0); 264 | if (i == 0) 265 | break; 266 | } 267 | return carry > 0; 268 | } 269 | 270 | 271 | bool Base58Check::multiply58(uint8_t x[], size_t len) { 272 | assert(len >= 1 && x != nullptr); 273 | int carry = 0; 274 | for (size_t i = len - 1; ; i--) { 275 | int temp = x[i] * 58 + carry; 276 | x[i] = static_cast(temp); 277 | carry = temp >> 8; 278 | assert(0 <= carry && carry < 58); 279 | if (i == 0) 280 | break; 281 | } 282 | return carry > 0; 283 | } 284 | 285 | 286 | 287 | /*---- Miscellaneous definitions ----*/ 288 | 289 | // Static initializers 290 | const char *Base58Check::ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; 291 | -------------------------------------------------------------------------------- /cpp/Base58Check.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | #include "ExtendedPrivateKey.hpp" 14 | #include "Ripemd160.hpp" 15 | #include "Uint256.hpp" 16 | 17 | 18 | /* 19 | * Converts a pubkey hash, private key, or extended private key to and from a Base58Check ASCII string. 20 | */ 21 | class Base58Check final { 22 | 23 | /*---- Public export-to-string functions ----*/ 24 | 25 | // Exports the given 20-byte public key hash with the given version prefix byte as a public address. 26 | // The outStr array must have length >= 36 (including null terminator). 27 | // The output text length is between 25 and 35 characters, inclusive. Not constant-time. 28 | public: static void pubkeyHashToBase58Check(const std::uint8_t pubkeyHash[Ripemd160::HASH_LEN], std::uint8_t version, char outStr[36]); 29 | 30 | 31 | // Exports the given private key with the given version prefix byte as WIF. 32 | // The isCompressed parameter controls whether the private key should generate a compressed 33 | // public curve point, and should almost always be set to true (except for legacy applications). 34 | // The outStr array must have length >= 53 (including null terminator). 35 | // The output text length is between 38 and 52 characters, inclusive. Not constant-time. 36 | public: static void privateKeyToBase58Check(const Uint256 &privKey, std::uint8_t version, bool isCompressed, char outStr[53]); 37 | 38 | 39 | // Exports the given extended private key with the Bitcoin header and version prefix byte. 40 | // The outStr array must have length >= 112 (including null terminator). 41 | // The output text length is always 111 characters. Not constant-time. 42 | public: static void extendedPrivateKeyToBase58Check(const ExtendedPrivateKey &key, char outStr[112]); 43 | 44 | 45 | /*---- Public import-from-string functions ----*/ 46 | 47 | // Parses the given public address string. If the syntax and check digits are correct, then the 48 | // output array is set to the decoded value, the version byte is set if not null, and true is returned. 49 | // Otherwise the output array and version are unchanged, and false is returned. Not constant-time. 50 | public: static bool pubkeyHashFromBase58Check(const char *addrStr, std::uint8_t outPubkeyHash[Ripemd160::HASH_LEN], std::uint8_t *outVersion); 51 | 52 | 53 | // Parses the given WIF string. If the syntax, optional compressed marker, and check digits are correct, 54 | // then the private key Uint256 is set to the decoded value, the version byte is set if not null, 55 | // the compressed status is set if not null, and true is returned. Otherwise the Uint256, 56 | // version, and compressed status are unchanged, and false is returned. Not constant-time. 57 | // Note that the decoded integer may be outside the normal private key range of [1, CurvePoint::ORDER). 58 | public: static bool privateKeyFromBase58Check(const char wifStr[53], Uint256 &outPrivKey, std::uint8_t *outVersion, bool *outIsCompressed); 59 | 60 | 61 | // Parses the given extended private key string. If the syntax and check digits are correct, 62 | // then the extended private key object is set to the decoded value, and true is returned. 63 | // Otherwise the object is unchanged, and false is returned. Not constant-time. 64 | public: static bool extendedPrivateKeyFromBase58Check(const char xprvStr[112], ExtendedPrivateKey &outKey); 65 | 66 | 67 | 68 | /*---- Private high-level Base58Check functions ----*/ 69 | 70 | // Computes the 4-byte hash of the given byte array, concatenates it, and converts it to Base58Check. 71 | // This overwrites data and temp for indices 0 <= i < len+4. The caller is responsible for leaving 4 free bytes 72 | // starting at data[len], allocating len+4 bytes for temp, and allocating enough space in outStr. Not constant-time. 73 | private: static void bytesToBase58Check(std::uint8_t data[], std::uint8_t temp[], std::size_t dataLen, char *outStr); 74 | 75 | 76 | // Converts the given Base58Check string to an array of bytes. Returns true if the conversion succeeded; 77 | // otherwise returns false if the string contains non-Base58 characters, decodes to 78 | // shorter or longer data than the output array length, or fails the hash check. 79 | // The output array elements may be changed even if false is returned. Not constant-time. 80 | private: static bool base58CheckToBytes(const char *inStr, std::uint8_t outData[], std::size_t outDataLen); 81 | 82 | 83 | 84 | /*---- Private low-level arithmetic functions ----*/ 85 | 86 | // These functions perform unsigned big-endian arbitrary-precision arithmetic on byte arrays that represent numbers. 87 | // These algorithms differ from Uint256 because Uint256 is fixed-width, little-endian, and 32-bit-word-oriented. 88 | 89 | // Tests whether the given bigint is zero. Not constant-time. 90 | private: static bool isZero(const std::uint8_t x[], std::size_t len); 91 | 92 | 93 | // Returns the given bigint modulo 58. Not constant-time. 94 | private: static std::uint8_t mod58(const std::uint8_t x[], std::size_t len); 95 | 96 | 97 | // Computes the quotient y = floor(x / 58). Not constant-time. 98 | private: static void divide58(const std::uint8_t x[], std::uint8_t y[], std::size_t len); 99 | 100 | 101 | // Computes the sum (x = (x + y) mod 256^len) in place. Returns whether the 102 | // carry-out is non-zero. Constant-time with respect to x's values and the value of y. 103 | private: static bool addUint8(std::uint8_t x[], std::uint8_t y, std::size_t len); 104 | 105 | 106 | // Computes the product (x = (x * 58) mod 256^len) in place. Returns whether 107 | // the carry-out is non-zero. Constant-time with respect to x's values. 108 | private: static bool multiply58(std::uint8_t x[], std::size_t len); 109 | 110 | 111 | 112 | /*---- Miscellaneous ----*/ 113 | 114 | Base58Check() = delete; // Not instantiable 115 | 116 | 117 | public: static const char *ALPHABET; 118 | 119 | }; 120 | -------------------------------------------------------------------------------- /cpp/CountOps.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #pragma once 10 | 11 | 12 | #ifdef COUNT_OPS 13 | 14 | void countOps(long n); 15 | 16 | enum { 17 | functionOps = 1, 18 | arithmeticOps = 1, 19 | loopBodyOps = 3, // Increment, compare, jump 20 | uint256CopyOps = 17, 21 | fieldintCopyOps = 18, // 1 + uint256CopyOps 22 | curvepointCopyOps = 55, // 1 + 3 * fieldintCopyOps 23 | }; 24 | 25 | #else 26 | 27 | #define countOps(n) 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /cpp/CurvePoint.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #include 10 | #include "CountOps.hpp" 11 | #include "CurvePoint.hpp" 12 | 13 | using std::uint8_t; 14 | using std::uint32_t; 15 | 16 | 17 | CurvePoint::CurvePoint(const FieldInt &x_, const FieldInt &y_) : 18 | x(x_), y(y_), z(FI_ONE) {} 19 | 20 | 21 | CurvePoint::CurvePoint(const char *xStr, const char *yStr) : 22 | x(xStr), y(yStr), z(FI_ONE) {} 23 | 24 | 25 | CurvePoint::CurvePoint() : 26 | x(FI_ZERO), y(FI_ONE), z(FI_ZERO) {} 27 | 28 | 29 | void CurvePoint::add(const CurvePoint &other) { 30 | countOps(functionOps); 31 | 32 | /* 33 | * (See https://www.nayuki.io/page/elliptic-curve-point-addition-in-projective-coordinates) 34 | * Algorithm pseudocode: 35 | * if (this == ZERO) 36 | * this = other 37 | * else if (other == ZERO) 38 | * this = this 39 | * else { 40 | * t0 = y0 * z1 41 | * t1 = y1 * z0 42 | * u0 = x0 * z1 43 | * u1 = x1 * z0 44 | * if (u0 == u1) { // Same x coordinates 45 | * if (t0 == t1) // Same y coordinates 46 | * this = twice() 47 | * else 48 | * this = ZERO 49 | * } else { 50 | * t = t0 - t1 51 | * u = u0 - u1 52 | * u2 = u^2 53 | * v = z0 * z1 54 | * w = t^2 * v - u2 * (u0 + u1) 55 | * x' = u * w 56 | * u3 = u2 * u 57 | * y' = t * (u0 * u2 - w) - t0 * u3 58 | * z' = u3 * v 59 | * } 60 | * } 61 | */ 62 | bool thisZero = this->isZero(); 63 | bool otherZero = other.isZero(); 64 | CurvePoint temp = *this; 65 | temp.twice(); 66 | temp.replace(*this, static_cast(otherZero)); 67 | temp.replace(other, static_cast(thisZero )); 68 | 69 | FieldInt u0 = this->x; 70 | FieldInt u1 = other.x; 71 | FieldInt t0 = this->y; 72 | FieldInt &t1 = x; // Reuse memory 73 | t1 = other.y; 74 | u0.multiply(other.z); 75 | u1.multiply(this->z); 76 | t0.multiply(other.z); 77 | t1.multiply(this->z); 78 | bool sameX = u0 == u1; 79 | bool sameY = t0 == t1; 80 | temp.replace(ZERO, static_cast(!thisZero & !otherZero & sameX & !sameY)); 81 | 82 | FieldInt &t = y; // Reuse memory 83 | t = t0; 84 | t.subtract(t1); 85 | FieldInt u = u0; 86 | u.subtract(u1); 87 | FieldInt u2 = u; 88 | u2.square(); 89 | FieldInt &v = z; // Reuse memory 90 | v.multiply(other.z); 91 | 92 | FieldInt w = t; 93 | w.square(); 94 | w.multiply(v); 95 | u1.add(u0); 96 | u1.multiply(u2); 97 | w.subtract(u1); 98 | 99 | x = u; 100 | x.multiply(w); 101 | 102 | FieldInt &u3 = u1; // Reuse memory 103 | u3 = u; 104 | u3.multiply(u2); 105 | 106 | u0.multiply(u2); 107 | u0.subtract(w); 108 | t.multiply(u0); 109 | t0.multiply(u3); 110 | t.subtract(t0); // Assigns to y 111 | 112 | v.multiply(u3); // Assigns to z 113 | 114 | this->replace(temp, static_cast(thisZero | otherZero | sameX)); 115 | countOps(8 * arithmeticOps); 116 | countOps(10 * fieldintCopyOps); 117 | countOps(1 * curvepointCopyOps); 118 | } 119 | 120 | 121 | void CurvePoint::twice() { 122 | countOps(functionOps); 123 | 124 | /* 125 | * (See https://www.nayuki.io/page/elliptic-curve-point-addition-in-projective-coordinates) 126 | * Algorithm pseudocode: 127 | * if (this == ZERO || y == 0) 128 | * this = ZERO 129 | * else { 130 | * a = 0 (curve parameter) 131 | * t = 3 * x^2 + a * z^2 132 | * u = 2 * y * z 133 | * v = 2 * u * x * y 134 | * w = t^2 - 2 * v 135 | * x' = u * w 136 | * y' = t * (v - w) - 2 * (u * y)^2 137 | * z' = u^3 138 | * } 139 | */ 140 | 141 | bool zeroResult = isZero() | (y == FI_ZERO); 142 | countOps(1 * arithmeticOps); 143 | 144 | FieldInt u = y; 145 | u.multiply(z); 146 | u.multiply2(); 147 | 148 | FieldInt v = u; 149 | v.multiply(x); 150 | v.multiply(y); 151 | v.multiply2(); 152 | 153 | x.square(); 154 | FieldInt t = x; 155 | t.multiply2(); 156 | t.add(x); 157 | 158 | FieldInt &w = z; // Reuse memory 159 | w = t; 160 | w.square(); 161 | x = v; 162 | x.multiply2(); 163 | w.subtract(x); 164 | 165 | x = v; 166 | x.subtract(w); 167 | x.multiply(t); 168 | y.multiply(u); 169 | y.square(); 170 | y.multiply2(); 171 | x.subtract(y); 172 | y = x; 173 | 174 | x = u; 175 | x.multiply(w); 176 | 177 | z = u; 178 | z.square(); 179 | z.multiply(u); 180 | 181 | this->replace(ZERO, static_cast(zeroResult)); 182 | countOps(10 * fieldintCopyOps); 183 | } 184 | 185 | 186 | void CurvePoint::multiply(const Uint256 &n) { 187 | // Precompute [this*0, this*1, ..., this*15] 188 | countOps(functionOps); 189 | constexpr int tableBits = 4; // Do not modify 190 | constexpr unsigned int tableLen = 1U << tableBits; 191 | CurvePoint table[tableLen]; // Default-initialized with ZERO 192 | table[1] = *this; 193 | table[2] = *this; 194 | countOps(18 * curvepointCopyOps); 195 | table[2].twice(); 196 | for (unsigned int i = 3; i < tableLen; i++) { 197 | countOps(loopBodyOps); 198 | table[i] = table[i - 1]; 199 | table[i].add(*this); 200 | countOps(2 * arithmeticOps); 201 | countOps(1 * curvepointCopyOps); 202 | } 203 | 204 | // Process tableBits per iteration (windowed method) 205 | *this = ZERO; 206 | countOps(1 * curvepointCopyOps); 207 | for (int i = Uint256::NUM_WORDS * 32 - tableBits; i >= 0; i -= tableBits) { 208 | countOps(loopBodyOps); 209 | unsigned int inc = (n.value[i >> 5] >> (i & 31)) & (tableLen - 1); 210 | CurvePoint q = ZERO; // Dummy initial value 211 | countOps(5 * arithmeticOps); 212 | countOps(1 * curvepointCopyOps); 213 | for (unsigned int j = 0; j < tableLen; j++) { 214 | countOps(loopBodyOps); 215 | q.replace(table[j], static_cast(j == inc)); 216 | countOps(1 * arithmeticOps); 217 | } 218 | this->add(q); 219 | if (i != 0) { 220 | for (int j = 0; j < tableBits; j++) { 221 | countOps(loopBodyOps); 222 | this->twice(); 223 | } 224 | } 225 | } 226 | } 227 | 228 | 229 | void CurvePoint::normalize() { 230 | /* 231 | * Algorithm pseudocode: 232 | * if (z != 0) { 233 | * x /= z 234 | * y /= z 235 | * z = 1 236 | * } else { 237 | * x = x != 0 ? 1 : 0 238 | * y = y != 0 ? 1 : 0 239 | * z = 0 240 | * } 241 | */ 242 | countOps(functionOps); 243 | CurvePoint norm = *this; 244 | norm.z.reciprocal(); 245 | norm.x.multiply(norm.z); 246 | norm.y.multiply(norm.z); 247 | norm.z = FI_ONE; 248 | x.replace(FI_ONE, static_cast(x != FI_ZERO)); 249 | y.replace(FI_ONE, static_cast(y != FI_ZERO)); 250 | this->replace(norm, static_cast(z != FI_ZERO)); 251 | countOps(1 * fieldintCopyOps); 252 | countOps(1 * curvepointCopyOps); 253 | } 254 | 255 | 256 | void CurvePoint::replace(const CurvePoint &other, uint32_t enable) { 257 | assert((enable >> 1) == 0); 258 | countOps(functionOps); 259 | this->x.replace(other.x, enable); 260 | this->y.replace(other.y, enable); 261 | this->z.replace(other.z, enable); 262 | } 263 | 264 | 265 | bool CurvePoint::isOnCurve() const { 266 | countOps(functionOps); 267 | FieldInt left = y; 268 | left.square(); 269 | FieldInt right = x; 270 | right.square(); 271 | right.add(A); 272 | right.multiply(x); 273 | right.add(B); 274 | countOps(2 * arithmeticOps); 275 | countOps(2 * fieldintCopyOps); 276 | return (left == right) & !isZero(); 277 | } 278 | 279 | 280 | bool CurvePoint::isZero() const { 281 | countOps(functionOps); 282 | countOps(2 * arithmeticOps); 283 | return (x == FI_ZERO) & (y != FI_ZERO) & (z == FI_ZERO); 284 | } 285 | 286 | 287 | bool CurvePoint::operator==(const CurvePoint &other) const { 288 | countOps(functionOps); 289 | countOps(2 * arithmeticOps); 290 | return (x == other.x) & (y == other.y) & (z == other.z); 291 | } 292 | 293 | bool CurvePoint::operator!=(const CurvePoint &other) const { 294 | countOps(functionOps); 295 | countOps(1 * arithmeticOps); 296 | return !(*this == other); 297 | } 298 | 299 | 300 | void CurvePoint::toCompressedPoint(uint8_t output[33]) const { 301 | assert(output != nullptr); 302 | output[0] = static_cast((y.value[0] & 1) + 0x02); 303 | x.getBigEndianBytes(&output[1]); 304 | } 305 | 306 | 307 | CurvePoint CurvePoint::privateExponentToPublicPoint(const Uint256 &privExp) { 308 | assert((Uint256::ZERO < privExp) & (privExp < CurvePoint::ORDER)); 309 | CurvePoint result = CurvePoint::G; 310 | result.multiply(privExp); 311 | result.normalize(); 312 | return result; 313 | } 314 | 315 | 316 | // Static initializers 317 | const FieldInt CurvePoint::FI_ZERO("0000000000000000000000000000000000000000000000000000000000000000"); 318 | const FieldInt CurvePoint::FI_ONE ("0000000000000000000000000000000000000000000000000000000000000001"); 319 | const FieldInt CurvePoint::A ("0000000000000000000000000000000000000000000000000000000000000000"); 320 | const FieldInt CurvePoint::B ("0000000000000000000000000000000000000000000000000000000000000007"); 321 | const Uint256 CurvePoint::ORDER("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); 322 | const CurvePoint CurvePoint::G( 323 | "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 324 | "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"); 325 | const CurvePoint CurvePoint::ZERO; // Default constructor 326 | -------------------------------------------------------------------------------- /cpp/CurvePoint.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #include "FieldInt.hpp" 13 | #include "Uint256.hpp" 14 | 15 | 16 | /* 17 | * A point on the secp256k1 elliptic curve for Bitcoin use, in projective coordinates. 18 | * Contains methods for computing point addition, doubling, and multiplication, and testing equality. 19 | * The ordinary affine coordinates of a point is (x/z, y/z). Instances of this class are mutable. 20 | * 21 | * Points MUST be normalized before comparing for equality. Example of correct usage: 22 | * CurvePoint a(...); 23 | * CurvePoint b(...); 24 | * CurvePoint c(...); 25 | * 26 | * a.add(b); 27 | * a.multiply(50); 28 | * 29 | * a.normalize(); 30 | * c.normalize(); 31 | * if (a == c) { ... } 32 | */ 33 | class CurvePoint final { 34 | 35 | /*---- Fields ----*/ 36 | 37 | public: FieldInt x; 38 | public: FieldInt y; 39 | public: FieldInt z; // The point is normalized iff (z = 1 OR (x,y,z)=(0,1,0)) 40 | 41 | 42 | 43 | /*---- Constructors ----*/ 44 | 45 | // Constructs a normalized point (z=1) from the given coordinates. Constant-time with respect to the values. 46 | public: explicit CurvePoint(const FieldInt &x_, const FieldInt &y_); 47 | 48 | 49 | // Constructs a normalized point (z=1) from the given string coordinates. Not constant-time. 50 | public: explicit CurvePoint(const char *xStr, const char *yStr); 51 | 52 | 53 | // Constructs the special "point at infinity" (normalized), which is used by ZERO and in multiply(). 54 | private: CurvePoint(); 55 | 56 | 57 | 58 | /*---- Arithmetic methods ----*/ 59 | 60 | // Adds the given curve point to this point. The resulting state is 61 | // usually not normalized. Constant-time with respect to both values. 62 | public: void add(const CurvePoint &other); 63 | 64 | 65 | // Doubles this curve point. The resulting state is usually 66 | // not normalized. Constant-time with respect to this value. 67 | public: void twice(); 68 | 69 | 70 | // Multiplies this point by the given unsigned integer. The resulting state 71 | // is usually not normalized. Constant-time with respect to both values. 72 | public: void multiply(const Uint256 &n); 73 | 74 | 75 | // Normalizes the coordinates of this point. Idempotent operation. 76 | // Constant-time with respect to this value. 77 | public: void normalize(); 78 | 79 | 80 | // Copies the given point into this point if enable is 1, or does nothing if enable is 0. 81 | // Constant-time with respect to both values and the enable. 82 | public: void replace(const CurvePoint &other, std::uint32_t enable); 83 | 84 | 85 | // Tests whether this point is on the elliptic curve. 86 | // This point needs to be normalized before the method is called. 87 | // Zero is considered to be off the curve. Constant-time with respect to this value. 88 | public: bool isOnCurve() const; 89 | 90 | 91 | // Tests whether this point is equal to the special zero point. 92 | // This point need not be normalized. Constant-time with respect to this value. 93 | // This method is equivalent to, but more convenient than: 94 | // { CurvePoint temp(*this); temp.normalize(); return temp == ZERO; } 95 | public: bool isZero() const; 96 | 97 | 98 | // Tests whether this point equals the given point in all 3 coordinates. This comparison is 99 | // meaningful only if both points are normalized. Constant-time with respect to both values. 100 | public: bool operator==(const CurvePoint &other) const; 101 | 102 | // Tests whether this point mismatches the given point in any of the 3 coordinates. This comparison 103 | // is meaningful only if both points are normalized. Constant-time with respect to both values. 104 | public: bool operator!=(const CurvePoint &other) const; 105 | 106 | 107 | // Serializes this point in compressed format (header byte, x-coordinate in big-endian). 108 | // This point needs to be normalized before the method is called. Constant-time with respect to this value. 109 | public: void toCompressedPoint(std::uint8_t output[33]) const; 110 | 111 | 112 | /*---- Static functions ----*/ 113 | 114 | // Returns a normalized public curve point for the given private exponent key. 115 | // Requires 0 < privExp < ORDER. Constant-time with respect to the value. 116 | public: static CurvePoint privateExponentToPublicPoint(const Uint256 &privExp); 117 | 118 | 119 | /*---- Class constants ----*/ 120 | 121 | public: static const FieldInt FI_ZERO; // These FieldInt constants are declared here because they are only needed in this class, 122 | public: static const FieldInt FI_ONE; // and because of C++'s lack of guarantee of static initialization order. 123 | public: static const FieldInt A; // Curve equation parameter 124 | public: static const FieldInt B; // Curve equation parameter 125 | public: static const Uint256 ORDER; // Order of base point, which is a prime number 126 | public: static const CurvePoint G; // Base point (normalized) 127 | public: static const CurvePoint ZERO; // Dummy point at infinity (normalized) 128 | 129 | }; 130 | -------------------------------------------------------------------------------- /cpp/Ecdsa.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include "CountOps.hpp" 13 | #include "Ecdsa.hpp" 14 | #include "FieldInt.hpp" 15 | #include "Sha256.hpp" 16 | 17 | using std::uint8_t; 18 | using std::uint32_t; 19 | 20 | 21 | bool Ecdsa::sign(const Uint256 &privateKey, const Sha256Hash &msgHash, const Uint256 &nonce, Uint256 &outR, Uint256 &outS) { 22 | /* 23 | * Algorithm pseudocode: 24 | * if (nonce outside range [1, order-1]) return false 25 | * p = nonce * G 26 | * r = p.x % order 27 | * if (r == 0) return false 28 | * s = nonce^-1 * (msgHash + r * privateKey) % order 29 | * if (s == 0) return false 30 | * s = min(s, order - s) 31 | */ 32 | countOps(functionOps); 33 | 34 | const Uint256 &order = CurvePoint::ORDER; 35 | const Uint256 &zero = Uint256::ZERO; 36 | if (nonce == zero || nonce >= order) 37 | return false; 38 | countOps(2 * arithmeticOps); 39 | 40 | const CurvePoint p = CurvePoint::privateExponentToPublicPoint(nonce); 41 | Uint256 r(p.x); 42 | r.subtract(order, static_cast(r >= order)); 43 | if (r == zero) 44 | return false; 45 | assert(r < order); 46 | countOps(1 * arithmeticOps); 47 | countOps(1 * uint256CopyOps); 48 | countOps(1 * curvepointCopyOps); 49 | 50 | Uint256 s = r; 51 | const Uint256 z(msgHash.value); 52 | multiplyModOrder(s, privateKey); 53 | uint32_t carry = s.add(z); 54 | s.subtract(order, carry | static_cast(s >= order)); 55 | countOps(1 * arithmeticOps); 56 | countOps(2 * uint256CopyOps); 57 | 58 | Uint256 kInv = nonce; 59 | kInv.reciprocal(order); 60 | multiplyModOrder(s, kInv); 61 | if (s == zero) 62 | return false; 63 | countOps(1 * arithmeticOps); 64 | countOps(1 * uint256CopyOps); 65 | 66 | Uint256 negS = order; 67 | negS.subtract(s); 68 | s.replace(negS, static_cast(negS < s)); // To ensure low S values for BIP 62 69 | outR = r; 70 | outS = s; 71 | countOps(3 * uint256CopyOps); 72 | return true; 73 | } 74 | 75 | 76 | bool Ecdsa::signWithHmacNonce(const Uint256 &privateKey, const Sha256Hash &msgHash, Uint256 &outR, Uint256 &outS) { 77 | uint8_t privkeyBytes[Uint256::NUM_WORDS * 4]; 78 | privateKey.getBigEndianBytes(privkeyBytes); 79 | const Sha256Hash hmac = Sha256::getHmac(privkeyBytes, sizeof(privkeyBytes), msgHash.value, Sha256Hash::HASH_LEN); 80 | const Uint256 nonce(hmac.value); 81 | return sign(privateKey, msgHash, nonce, outR, outS); 82 | } 83 | 84 | 85 | bool Ecdsa::verify(const CurvePoint &publicKey, const Sha256Hash &msgHash, const Uint256 &r, const Uint256 &s) { 86 | /* 87 | * Algorithm pseudocode: 88 | * if (pubKey == zero || !(pubKey is normalized) || 89 | * !(pubKey on curve) || n * pubKey != zero) 90 | * return false 91 | * if (!(0 < r, s < order)) 92 | * return false 93 | * w = s^-1 % order 94 | * u1 = (msgHash * w) % order 95 | * u2 = (r * w) % order 96 | * p = u1 * G + u2 * pubKey 97 | * if (p == zero) 98 | * return false 99 | * return r == p.x % order 100 | */ 101 | countOps(functionOps); 102 | countOps(11 * arithmeticOps); 103 | 104 | const Uint256 &order = CurvePoint::ORDER; 105 | const Uint256 &zero = Uint256::ZERO; 106 | countOps(5 * arithmeticOps); 107 | if (!(zero < r && r < order && zero < s && s < order)) 108 | return false; 109 | 110 | CurvePoint q = publicKey; 111 | q.multiply(CurvePoint::ORDER); 112 | countOps(4 * arithmeticOps); 113 | countOps(1 * curvepointCopyOps); 114 | if (publicKey.isZero() || publicKey.z != CurvePoint::FI_ONE || !publicKey.isOnCurve() || !q.isZero()) 115 | return false; 116 | 117 | Uint256 w = s; 118 | w.reciprocal(order); 119 | const Uint256 z(msgHash.value); 120 | Uint256 u1 = w; 121 | Uint256 u2 = w; 122 | multiplyModOrder(u1, z); 123 | multiplyModOrder(u2, r); 124 | countOps(4 * uint256CopyOps); 125 | 126 | CurvePoint p = CurvePoint::G; 127 | q = publicKey; 128 | p.multiply(u1); 129 | q.multiply(u2); 130 | p.add(q); 131 | p.normalize(); 132 | countOps(2 * curvepointCopyOps); 133 | if (p.isZero()) 134 | return false; 135 | 136 | Uint256 px(p.x); 137 | px.subtract(order, static_cast(px >= order)); 138 | countOps(1 * uint256CopyOps); 139 | return r == px; 140 | } 141 | 142 | 143 | void Ecdsa::multiplyModOrder(Uint256 &x, const Uint256 &y) { 144 | /* 145 | * Russian peasant multiplication with modular reduction at each step. Algorithm pseudocode: 146 | * z = 0 147 | * for (i = 255 .. 0) { 148 | * z = (z * 2) % order 149 | * if (y.bit[i] == 1) 150 | * z = (z + x) % order 151 | * } 152 | * x = z 153 | */ 154 | countOps(functionOps); 155 | const Uint256 &mod = CurvePoint::ORDER; 156 | assert(&x != &y && x < mod); 157 | Uint256 z = Uint256::ZERO; 158 | countOps(1 * uint256CopyOps); 159 | 160 | for (int i = Uint256::NUM_WORDS * 32 - 1; i >= 0; i--) { 161 | countOps(loopBodyOps); 162 | // Multiply by 2 163 | uint32_t c = z.shiftLeft1(); 164 | z.subtract(mod, c | static_cast(z >= mod)); 165 | // Conditionally add x 166 | uint32_t enable = (y.value[i >> 5] >> (i & 31)) & 1; 167 | c = z.add(x, enable); 168 | z.subtract(mod, c | static_cast(z >= mod)); 169 | assert(z < mod); 170 | countOps(7 * arithmeticOps); 171 | } 172 | x = z; 173 | countOps(1 * uint256CopyOps); 174 | } 175 | -------------------------------------------------------------------------------- /cpp/Ecdsa.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #pragma once 10 | 11 | #include "CurvePoint.hpp" 12 | #include "Sha256Hash.hpp" 13 | #include "Uint256.hpp" 14 | 15 | 16 | /* 17 | * Performs ECDSA signature generation and verification. Provides just three static functions. 18 | */ 19 | class Ecdsa final { 20 | 21 | // Computes the signature (deterministically) when given the private key, message hash, and random nonce. 22 | // Returns true if signing was successful (overwhelming probability), or false if a new nonce must be chosen 23 | // (vanishing probability). Both privateKey and nonce must be in the range [1, CurvePoint::ORDER). 24 | // outR and outS will be in the same range too; their values are assigned iff signing is successful. 25 | // Note: The nonce must be unique, unpredictable, and secret. Otherwise the signature may leak the private key. 26 | // All successful executions are constant-time with respect to the input values; in order words 27 | // one successful execution is indistinguishable from another one based on side channel information. 28 | public: static bool sign(const Uint256 &privateKey, const Sha256Hash &msgHash, const Uint256 &nonce, Uint256 &outR, Uint256 &outS); 29 | 30 | 31 | // Computes a deterministic nonce based on the HMAC-SHA-256 of the message hash with the private key, 32 | // and then performs ECDSA signing. Returns true iff signing is successful (with overwhelming probability). 33 | // This has the same constant-time behavior as sign(). 34 | public: static bool signWithHmacNonce(const Uint256 &privateKey, const Sha256Hash &msgHash, Uint256 &outR, Uint256 &outS); 35 | 36 | 37 | // Checks whether the given signature, message, and public key are valid together. The public key point 38 | // must be normalized. This function does not need to be constant-time because all inputs are public. 39 | public: static bool verify(const CurvePoint &publicKey, const Sha256Hash &msgHash, const Uint256 &r, const Uint256 &s); 40 | 41 | 42 | // Computes x = (x * y) % CurvePoint::ORDER. Requires x < CurvePoint::ORDER, but y is unrestricted. 43 | private: static void multiplyModOrder(Uint256 &x, const Uint256 &y); 44 | 45 | 46 | Ecdsa() = delete; // Not instantiable 47 | 48 | }; 49 | -------------------------------------------------------------------------------- /cpp/EcdsaOpCount.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * A runnable main program that calculates and prints the approximate 3 | * number of 32-bit arithmetic operations needed to perform 4 | * elliptic curve point multiplication, in this C++ implementation. 5 | * 6 | * Bitcoin cryptography library 7 | * Copyright (c) Project Nayuki 8 | * 9 | * https://www.nayuki.io/page/bitcoin-cryptography-library 10 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "CountOps.hpp" 18 | #include "CurvePoint.hpp" 19 | #include "Ecdsa.hpp" 20 | #include "FieldInt.hpp" 21 | #include "Sha256.hpp" 22 | #include "Sha256Hash.hpp" 23 | #include "Uint256.hpp" 24 | 25 | 26 | static long long opsCount; 27 | 28 | 29 | void countOps(long n) { 30 | opsCount += n; 31 | } 32 | 33 | 34 | static void printOps(const char *name); 35 | static void doUint256(); 36 | static void doFieldInt(); 37 | static void doCurvePoint(); 38 | static void doEcdsa(); 39 | 40 | 41 | int main() { 42 | doUint256(); 43 | doFieldInt(); 44 | doCurvePoint(); 45 | doEcdsa(); 46 | return EXIT_SUCCESS; 47 | } 48 | 49 | 50 | static void doUint256() { 51 | { 52 | Uint256 x = Uint256::ONE; 53 | Uint256 y = Uint256::ONE; 54 | opsCount = 0; 55 | x.replace(y, 1); 56 | printOps("uiReplace"); 57 | } 58 | { 59 | Uint256 x = Uint256::ONE; 60 | Uint256 y = Uint256::ONE; 61 | opsCount = 0; 62 | x.swap(y, 1); 63 | printOps("uiSwap"); 64 | } 65 | { 66 | Uint256 x = Uint256::ONE; 67 | Uint256 y = Uint256::ONE; 68 | opsCount = 0; 69 | x == y; 70 | printOps("uiEquals"); 71 | } 72 | { 73 | Uint256 x = Uint256::ONE; 74 | Uint256 y = Uint256::ONE; 75 | opsCount = 0; 76 | x < y; 77 | printOps("uiLessThan"); 78 | } 79 | { 80 | Uint256 x = Uint256::ONE; 81 | Uint256 y = Uint256::ONE; 82 | opsCount = 0; 83 | x.add(y); 84 | printOps("uiAdd"); 85 | } 86 | { 87 | Uint256 x = Uint256::ONE; 88 | Uint256 y = Uint256::ONE; 89 | opsCount = 0; 90 | x.subtract(y); 91 | printOps("uiSubtract"); 92 | } 93 | { 94 | Uint256 x = Uint256::ONE; 95 | opsCount = 0; 96 | x.shiftLeft1(); 97 | printOps("uiShiftLeft1"); 98 | } 99 | { 100 | Uint256 x = Uint256::ONE; 101 | opsCount = 0; 102 | x.shiftRight1(); 103 | printOps("uiShiftRight1"); 104 | } 105 | { 106 | Uint256 x = Uint256::ONE; 107 | Uint256 y = CurvePoint::ORDER; 108 | opsCount = 0; 109 | x.reciprocal(y); 110 | printOps("uiReciprocal"); 111 | } 112 | std::cout << std::endl; 113 | } 114 | 115 | 116 | static void doFieldInt() { 117 | { 118 | FieldInt x(Uint256::ONE); 119 | FieldInt y(Uint256::ONE); 120 | opsCount = 0; 121 | x.replace(y, 1); 122 | printOps("fiReplace"); 123 | } 124 | { 125 | FieldInt x(Uint256::ONE); 126 | FieldInt y(Uint256::ONE); 127 | opsCount = 0; 128 | x == y; 129 | printOps("fiEquals"); 130 | } 131 | { 132 | FieldInt x(Uint256::ONE); 133 | FieldInt y(Uint256::ONE); 134 | opsCount = 0; 135 | x < y; 136 | printOps("fiLessThan"); 137 | } 138 | { 139 | FieldInt x(Uint256::ONE); 140 | FieldInt y(Uint256::ONE); 141 | opsCount = 0; 142 | x.add(y); 143 | printOps("fiAdd"); 144 | } 145 | { 146 | FieldInt x(Uint256::ONE); 147 | FieldInt y(Uint256::ONE); 148 | opsCount = 0; 149 | x.subtract(y); 150 | printOps("fiSubtract"); 151 | } 152 | { 153 | FieldInt x(Uint256::ONE); 154 | opsCount = 0; 155 | x.multiply2(); 156 | printOps("fiMultiply2"); 157 | } 158 | { 159 | FieldInt x(Uint256::ONE); 160 | FieldInt y(Uint256::ONE); 161 | opsCount = 0; 162 | x.multiply(y); 163 | printOps("fiMultiply"); 164 | } 165 | { 166 | FieldInt x(Uint256::ONE); 167 | opsCount = 0; 168 | x.square(); 169 | printOps("fiSquare"); 170 | } 171 | { 172 | FieldInt x(Uint256::ONE); 173 | opsCount = 0; 174 | x.reciprocal(); 175 | printOps("fiReciprocal"); 176 | } 177 | std::cout << std::endl; 178 | } 179 | 180 | 181 | static void doCurvePoint() { 182 | { 183 | CurvePoint x = CurvePoint::G; 184 | CurvePoint y = CurvePoint::G; 185 | opsCount = 0; 186 | x.replace(y, 1); 187 | printOps("cpReplace"); 188 | } 189 | { 190 | CurvePoint x = CurvePoint::G; 191 | opsCount = 0; 192 | x.isZero(); 193 | printOps("cpIsZero"); 194 | } 195 | { 196 | CurvePoint x = CurvePoint::G; 197 | CurvePoint y = CurvePoint::G; 198 | opsCount = 0; 199 | x == y; 200 | printOps("cpEquals"); 201 | } 202 | { 203 | CurvePoint x = CurvePoint::G; 204 | opsCount = 0; 205 | x.twice(); 206 | printOps("cpTwice"); 207 | } 208 | { 209 | CurvePoint x = CurvePoint::G; 210 | CurvePoint y = CurvePoint::G; 211 | opsCount = 0; 212 | x.add(y); 213 | printOps("cpAdd"); 214 | } 215 | { 216 | CurvePoint x = CurvePoint::G; 217 | Uint256 y = Uint256::ONE; 218 | opsCount = 0; 219 | x.multiply(y); 220 | printOps("cpMultiply"); 221 | } 222 | { 223 | CurvePoint x = CurvePoint::G; 224 | opsCount = 0; 225 | x.normalize(); 226 | printOps("cpNormalize"); 227 | } 228 | { 229 | CurvePoint x = CurvePoint::G; 230 | opsCount = 0; 231 | x.isOnCurve(); 232 | printOps("cpIsOnCurve"); 233 | } 234 | std::cout << std::endl; 235 | } 236 | 237 | 238 | static void doEcdsa() { 239 | { 240 | Uint256 privKey = Uint256::ONE; 241 | Sha256Hash msgHash = Sha256::getHash(nullptr, 0); 242 | Uint256 nonce = Uint256::ONE; 243 | Uint256 outR, outS; 244 | opsCount = 0; 245 | Ecdsa::sign(privKey, msgHash, nonce, outR, outS); 246 | printOps("edSign"); 247 | } 248 | { 249 | CurvePoint pubKey = CurvePoint::G; 250 | Sha256Hash msgHash = Sha256::getHash(nullptr, 0); 251 | Uint256 r = Uint256::ONE; 252 | Uint256 s = Uint256::ONE; 253 | opsCount = 0; 254 | Ecdsa::verify(pubKey, msgHash, r, s); 255 | printOps("edVerify"); 256 | } 257 | std::cout << std::endl; 258 | } 259 | 260 | 261 | static void printOps(const char *name) { 262 | std::string s = std::to_string(opsCount); 263 | while (s.size() < 9) 264 | s.insert(0, " ", 1); 265 | for (std::size_t i = s.size(); i >= 4; i -= 3) 266 | s.insert(i - 3, " ", 1); 267 | std::cout << s << " " << name << std::endl; 268 | } 269 | -------------------------------------------------------------------------------- /cpp/ExtendedPrivateKey.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #include 10 | #include "ExtendedPrivateKey.hpp" 11 | #include "Ripemd160.hpp" 12 | #include "Sha256.hpp" 13 | #include "Sha256Hash.hpp" 14 | #include "Sha512.hpp" 15 | #include "Utils.hpp" 16 | 17 | using std::uint8_t; 18 | using std::uint32_t; 19 | 20 | 21 | ExtendedPrivateKey::ExtendedPrivateKey() : 22 | privateKey(Uint256::ZERO), 23 | publicKey(CurvePoint::ZERO), 24 | chainCode(), 25 | depth(0), 26 | index(0), 27 | parentPubkeyHash() {} 28 | 29 | 30 | ExtendedPrivateKey::ExtendedPrivateKey( 31 | const Uint256 &privKey, const uint8_t chcd[32], uint8_t dep, uint32_t idx, const uint8_t ppkh[4]) : 32 | privateKey(privKey), 33 | publicKey(CurvePoint::privateExponentToPublicPoint(privKey)), 34 | depth(dep), 35 | index(idx) { 36 | std::memcpy(chainCode, chcd, sizeof(chainCode)); 37 | std::memcpy(parentPubkeyHash, ppkh, sizeof(parentPubkeyHash)); 38 | } 39 | 40 | 41 | ExtendedPrivateKey ExtendedPrivateKey::getChildKey(uint32_t index) const { 42 | uint8_t msg[37]; 43 | if (index < HARDEN) // Normal child key 44 | publicKey.toCompressedPoint(msg); 45 | else { // Hardened child key 46 | msg[0] = 0; 47 | privateKey.getBigEndianBytes(&msg[1]); 48 | } 49 | Utils::storeBigUint32(index, &msg[33]); 50 | uint8_t hash[Sha512::HASH_LEN]; 51 | Sha512::getHmac(chainCode, sizeof(chainCode) / sizeof(chainCode[0]), msg, sizeof(msg) / sizeof(msg[0]), hash); 52 | 53 | Uint256 num(hash); 54 | if (num >= CurvePoint::ORDER) 55 | return ExtendedPrivateKey(); 56 | uint32_t carry = num.add(privateKey); 57 | num.subtract(CurvePoint::ORDER, carry | static_cast(num >= CurvePoint::ORDER)); 58 | if (num == Uint256::ZERO) 59 | return ExtendedPrivateKey(); 60 | 61 | uint8_t pubKeyBytes[33]; 62 | publicKey.toCompressedPoint(pubKeyBytes); 63 | Sha256Hash innerHash = Sha256::getHash(pubKeyBytes, sizeof(pubKeyBytes) / sizeof(pubKeyBytes[0])); 64 | uint8_t pubKeyHash[Ripemd160::HASH_LEN]; 65 | Ripemd160::getHash(innerHash.value, Sha256Hash::HASH_LEN, pubKeyHash); 66 | return ExtendedPrivateKey(num, &hash[32], static_cast(depth + 1), index, pubKeyHash); 67 | } 68 | -------------------------------------------------------------------------------- /cpp/ExtendedPrivateKey.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #include "CurvePoint.hpp" 13 | #include "Uint256.hpp" 14 | 15 | 16 | class ExtendedPrivateKey final { 17 | 18 | public: static constexpr std::uint32_t HARDEN = UINT32_C(0x80000000); 19 | 20 | 21 | /*---- Fields ----*/ 22 | 23 | public: Uint256 privateKey; 24 | public: CurvePoint publicKey; 25 | 26 | public: std::uint8_t chainCode[32]; 27 | public: std::uint8_t depth; 28 | public: std::uint32_t index; 29 | public: std::uint8_t parentPubkeyHash[4]; 30 | 31 | 32 | 33 | /*---- Constructors ----*/ 34 | 35 | public: explicit ExtendedPrivateKey(); 36 | 37 | 38 | public: explicit ExtendedPrivateKey( 39 | const Uint256 &privKey, const std::uint8_t chcd[32], 40 | std::uint8_t dep, uint32_t idx, const std::uint8_t ppkh[4]); 41 | 42 | 43 | 44 | /*---- Methods ----*/ 45 | 46 | public: ExtendedPrivateKey getChildKey(std::uint32_t index) const; 47 | 48 | }; 49 | -------------------------------------------------------------------------------- /cpp/ExtendedPrivateKeyTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * A runnable main program that tests the functionality of class ExtendedPrivateKey. 3 | * 4 | * Bitcoin cryptography library 5 | * Copyright (c) Project Nayuki 6 | * 7 | * https://www.nayuki.io/page/bitcoin-cryptography-library 8 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 9 | */ 10 | 11 | #include "TestHelper.hpp" 12 | #include 13 | #include 14 | #include 15 | #include "ExtendedPrivateKey.hpp" 16 | #include "Uint256.hpp" 17 | 18 | using std::uint8_t; 19 | 20 | 21 | int main() { 22 | int numTestCases = 0; 23 | const std::uint32_t HARDEN = ExtendedPrivateKey::HARDEN; 24 | ExtendedPrivateKey master, child; 25 | 26 | { 27 | Uint256 priv("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); 28 | Bytes chain = hexBytes("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); 29 | uint8_t ppkh[4] = {}; 30 | master = ExtendedPrivateKey(priv, chain.data(), 0, 0, ppkh); 31 | } 32 | 33 | child = master.getChildKey(HARDEN | 44); 34 | assert(child.privateKey == Uint256("EE1E0BD16BE7A49942867FB5E48470E25255F2E2AD0373D2D25DAE444786F096")); 35 | numTestCases++; 36 | 37 | child = child.getChildKey(HARDEN | 0); 38 | assert(child.privateKey == Uint256("06C1859D27BD395018FCFCDA42D94E7BCC640882DFB0FFFE96089C908DBDB28C")); 39 | numTestCases++; 40 | 41 | child = child.getChildKey(HARDEN | 0); 42 | assert(child.privateKey == Uint256("B6956AE327F4396F1C9DE1EB4B8D750F9B37639B93C112100B543723C4781557")); 43 | numTestCases++; 44 | 45 | child = child.getChildKey(0); 46 | assert(child.privateKey == Uint256("A43AFB4645AF3D89B5DE5EC4FF5D16FFA5935D10CC132E6FC772CC069C46B0B7")); 47 | numTestCases++; 48 | 49 | child = child.getChildKey(1); 50 | assert(child.privateKey == Uint256("40A439D20E45DB7977006A796652CA238743C2261D6024FC70DBC71AB62E77BF")); 51 | numTestCases++; 52 | 53 | { 54 | Uint256 priv("26CC9417B89CD77C4ACDBE2E3CD286070A015D8E380F9CD1244AE103B7D89D81"); 55 | Bytes chain = hexBytes("E3B01A74C45227C555EDE5348162B92FC0F278A593E233FDA6EF64F41C3027E3"); 56 | uint8_t ppkh[4] = {}; 57 | master = ExtendedPrivateKey(priv, chain.data(), 0, 0, ppkh); 58 | } 59 | 60 | child = master.getChildKey(HARDEN | 44); 61 | assert(child.privateKey == Uint256("1851C97DFAE902B85DD116D92E5A38E75442176EABCA3032EB95E7ED29BBF027")); 62 | numTestCases++; 63 | 64 | child = child.getChildKey(HARDEN | 0); 65 | assert(child.privateKey == Uint256("80E7F81FCEF47E24C32B024CEDC5FCD1E0FC8B5C95DB080540958519089E4E10")); 66 | numTestCases++; 67 | 68 | child = child.getChildKey(HARDEN | UINT32_C(0x7FFFFFFF)); 69 | assert(child.privateKey == Uint256("CEB5D208995C380E23D263C3AA3377F53FEDD317CA87E0DA20E2CFB92AC33F30")); 70 | numTestCases++; 71 | 72 | child = child.getChildKey(1); 73 | assert(child.privateKey == Uint256("E9ADAD6FDAE70FED72AEB16721E50A16A2AC6578097A6CFC29A98984CCA396C1")); 74 | numTestCases++; 75 | 76 | child = child.getChildKey(UINT32_C(65536)); 77 | assert(child.privateKey == Uint256("A03A015E0936119558D022514AC8326B340FC69C3266442603A3C212004054E3")); 78 | numTestCases++; 79 | 80 | std::printf("All %d test cases passed\n", numTestCases); 81 | return EXIT_SUCCESS; 82 | } 83 | -------------------------------------------------------------------------------- /cpp/FieldInt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #include 10 | #include 11 | #include "AsmX8664.hpp" 12 | #include "CountOps.hpp" 13 | #include "FieldInt.hpp" 14 | 15 | using std::uint32_t; 16 | using std::uint64_t; 17 | 18 | 19 | FieldInt::FieldInt(const char *str) : 20 | Uint256(str) { 21 | // C++ does not guarantee the order of initialization of static variables. If another class is 22 | // initializing a FieldInt constant, this class's modulus might not have been initialized yet. 23 | // Thus the assertion must be exempted in this situation. This logic relies on the fact that uninitialized 24 | // static variables are set to zero. Hence, only do the assertion if the modulus has been initialized already. 25 | if (MODULUS.value[0] != 0) 26 | assert(*this < MODULUS); 27 | } 28 | 29 | 30 | FieldInt::FieldInt(const Uint256 &val) : 31 | Uint256(val) { 32 | Uint256::subtract(MODULUS, static_cast(*this >= MODULUS)); 33 | assert(*this < MODULUS); 34 | } 35 | 36 | 37 | void FieldInt::add(const FieldInt &other) { 38 | countOps(functionOps); 39 | uint32_t c = Uint256::add(other); // Perform addition 40 | assert((c >> 1) == 0); 41 | Uint256::subtract(MODULUS, c | static_cast(*this >= MODULUS)); // Conditionally subtract modulus 42 | countOps(1 * arithmeticOps); 43 | } 44 | 45 | 46 | void FieldInt::subtract(const FieldInt &other) { 47 | countOps(functionOps); 48 | uint32_t b = Uint256::subtract(other); // Perform subtraction 49 | assert((b >> 1) == 0); 50 | Uint256::add(MODULUS, b); // Conditionally add modulus 51 | } 52 | 53 | 54 | void FieldInt::multiply2() { 55 | countOps(functionOps); 56 | uint32_t c = shiftLeft1(); 57 | assert((c >> 1) == 0); 58 | Uint256::subtract(MODULUS, c | static_cast(*this >= MODULUS)); // Conditionally subtract modulus 59 | countOps(1 * arithmeticOps); 60 | } 61 | 62 | 63 | void FieldInt::square() { 64 | countOps(functionOps); 65 | multiply(*this); 66 | } 67 | 68 | 69 | void FieldInt::multiply(const FieldInt &other) { 70 | countOps(functionOps); 71 | uint32_t difference[NUM_WORDS + 1]; 72 | 73 | if (USE_X8664_ASM_IMPL) { 74 | // Compute raw product of (uint256 this->value) * (uint256 other.value) = (uint512 product0), via long multiplication 75 | uint32_t product0[NUM_WORDS * 2]; 76 | asm_FieldInt_multiply256x256eq512(&product0[0], &this->value[0], &other.value[0]); 77 | countOps(105 * arithmeticOps); 78 | 79 | // Barrett reduction algorithm begins here (see https://www.nayuki.io/page/barrett-reduction-algorithm). 80 | // Multiply by floor(2^512 / MODULUS), which is 2^256 + 2^32 + 0x3D1. Guaranteed to fit in a uint768. 81 | uint32_t product1[NUM_WORDS * 3]; 82 | asm_FieldInt_multiplyBarrettStep0(product1, product0); 83 | countOps((40 + 10*8 + 4) * arithmeticOps); 84 | 85 | // Virtually shift right by 512 bits, then multiply by MODULUS. 86 | // Note that MODULUS = 2^256 - 2^32 - 0x3D1. Result fits in a uint512. 87 | uint32_t product2[NUM_WORDS * 2]; 88 | asm_FieldInt_multiplyBarrettStep1(product2, &product1[NUM_WORDS * 2]); 89 | countOps((29 + 12*4 + 5) * arithmeticOps); 90 | 91 | // Compute product0 - product2, which fits in a uint257 (sic) 92 | asm_FieldInt_multiplyBarrettStep2(difference, product0, product2); 93 | countOps(15 * arithmeticOps); 94 | 95 | } else { 96 | // Compute raw product of (uint256 this->value) * (uint256 other.value) = (uint512 product0), via long multiplication 97 | uint32_t product0[NUM_WORDS * 2] = {}; 98 | countOps(NUM_WORDS * 2 * arithmeticOps); 99 | for (int i = 0; i < NUM_WORDS; i++) { 100 | countOps(loopBodyOps); 101 | uint32_t carry = 0; 102 | countOps(1 * arithmeticOps); 103 | for (int j = 0; j < NUM_WORDS; j++) { 104 | countOps(loopBodyOps); 105 | uint64_t sum = static_cast(this->value[i]) * other.value[j]; 106 | sum += static_cast(product0[i + j]) + carry; // Does not overflow 107 | product0[i + j] = static_cast(sum); 108 | carry = static_cast(sum >> 32); 109 | countOps(11 * arithmeticOps); 110 | } 111 | product0[i + NUM_WORDS] = carry; 112 | countOps(1 * arithmeticOps); 113 | } 114 | 115 | // Barrett reduction algorithm begins here (see https://www.nayuki.io/page/barrett-reduction-algorithm). 116 | // Multiply by floor(2^512 / MODULUS), which is 2^256 + 2^32 + 0x3D1. Guaranteed to fit in a uint768. 117 | uint32_t product1[NUM_WORDS * 3]; 118 | { 119 | uint32_t carry = 0; 120 | countOps(1 * arithmeticOps); 121 | for (int i = 0; i < NUM_WORDS * 3; i++) { 122 | countOps(loopBodyOps); 123 | uint64_t sum = carry; 124 | countOps(2 * arithmeticOps); 125 | if (i < NUM_WORDS * 2) { 126 | sum += static_cast(product0[i]) * 0x3D1; 127 | countOps(4 * arithmeticOps); 128 | } 129 | countOps(4 * arithmeticOps); 130 | if (1 <= i && i < NUM_WORDS * 2 + 1) { 131 | sum += product0[i - 1]; 132 | countOps(3 * arithmeticOps); 133 | } 134 | countOps(2 * arithmeticOps); 135 | if (i >= NUM_WORDS) { 136 | sum += product0[i - NUM_WORDS]; 137 | countOps(3 * arithmeticOps); 138 | } 139 | product1[i] = static_cast(sum); 140 | carry = static_cast(sum >> 32); 141 | assert(carry <= 0x3D3); 142 | countOps(2 * arithmeticOps); 143 | } 144 | assert(carry == 0); 145 | } 146 | 147 | // Virtually shift right by 512 bits, then multiply by MODULUS. 148 | // Note that MODULUS = 2^256 - 2^32 - 0x3D1. Result fits in a uint512. 149 | uint32_t *product1Shifted = &product1[NUM_WORDS * 2]; // Length NUM_WORDS 150 | uint32_t product2[NUM_WORDS * 2]; 151 | countOps(1 * arithmeticOps); 152 | { 153 | uint32_t borrow = 0; 154 | countOps(1 * arithmeticOps); 155 | for (int i = 0; i < NUM_WORDS * 2; i++) { 156 | countOps(loopBodyOps); 157 | uint64_t diff = -static_cast(borrow); 158 | countOps(1 * arithmeticOps); 159 | countOps(2 * arithmeticOps); 160 | if (i < NUM_WORDS) { 161 | diff -= static_cast(product1Shifted[i]) * 0x3D1; 162 | countOps(4 * arithmeticOps); 163 | } 164 | countOps(4 * arithmeticOps); 165 | if (1 <= i && i < NUM_WORDS + 1) { 166 | diff -= product1Shifted[i - 1]; 167 | countOps(3 * arithmeticOps); 168 | } 169 | countOps(2 * arithmeticOps); 170 | if (i >= NUM_WORDS) { 171 | diff += product1Shifted[i - NUM_WORDS]; 172 | countOps(3 * arithmeticOps); 173 | } 174 | product2[i] = static_cast(diff); 175 | borrow = -static_cast(diff >> 32); 176 | assert(borrow <= 0x3D3); 177 | countOps(3 * arithmeticOps); 178 | } 179 | assert(borrow == 0); 180 | } 181 | 182 | // Compute product0 - product2, which fits in a uint257 (sic) 183 | { 184 | uint32_t borrow = 0; 185 | countOps(1 * arithmeticOps); 186 | for (int i = 0; i < NUM_WORDS + 1; i++) { 187 | countOps(loopBodyOps); 188 | uint64_t diff = static_cast(product0[i]) - product2[i] - borrow; 189 | difference[i] = static_cast(diff); 190 | borrow = -static_cast(diff >> 32); 191 | assert((borrow >> 1) == 0); 192 | countOps(9 * arithmeticOps); 193 | } 194 | } 195 | } 196 | 197 | // Final conditional subtraction to yield a FieldInt value 198 | std::memcpy(this->value, difference, sizeof(value)); 199 | countOps(functionOps); 200 | countOps(NUM_WORDS * arithmeticOps); 201 | uint32_t dosub = static_cast((difference[NUM_WORDS] != 0) | (*this >= MODULUS)); 202 | Uint256::subtract(MODULUS, dosub); 203 | countOps(2 * arithmeticOps); 204 | } 205 | 206 | 207 | void FieldInt::reciprocal() { 208 | countOps(functionOps); 209 | Uint256::reciprocal(MODULUS); 210 | } 211 | 212 | 213 | void FieldInt::replace(const FieldInt &other, uint32_t enable) { 214 | countOps(functionOps); 215 | Uint256::replace(other, enable); 216 | } 217 | 218 | 219 | bool FieldInt::operator==(const FieldInt &other) const { 220 | countOps(functionOps); 221 | return Uint256::operator==(other); 222 | } 223 | 224 | bool FieldInt::operator!=(const FieldInt &other) const { 225 | countOps(functionOps); 226 | return Uint256::operator!=(other); 227 | } 228 | 229 | bool FieldInt::operator<(const FieldInt &other) const { 230 | countOps(functionOps); 231 | return Uint256::operator<(other); 232 | } 233 | 234 | bool FieldInt::operator<=(const FieldInt &other) const { 235 | countOps(functionOps); 236 | return Uint256::operator<=(other); 237 | } 238 | 239 | bool FieldInt::operator>(const FieldInt &other) const { 240 | countOps(functionOps); 241 | return Uint256::operator>(other); 242 | } 243 | 244 | bool FieldInt::operator>=(const FieldInt &other) const { 245 | countOps(functionOps); 246 | return Uint256::operator>=(other); 247 | } 248 | 249 | 250 | bool FieldInt::operator<(const Uint256 &other) const { 251 | countOps(functionOps); 252 | return Uint256::operator<(other); 253 | } 254 | 255 | bool FieldInt::operator>=(const Uint256 &other) const { 256 | countOps(functionOps); 257 | return Uint256::operator>=(other); 258 | } 259 | 260 | 261 | // Static initializers 262 | const Uint256 FieldInt::MODULUS("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"); 263 | -------------------------------------------------------------------------------- /cpp/FieldInt.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #include "Uint256.hpp" 13 | 14 | 15 | /* 16 | * An unsigned 256-bit integer modulo a specific prime number, for Bitcoin and secp256k1. 17 | * The input and output values of each method are always in the range [0, MODULUS). 18 | * 19 | * Some behaviors are specific to FieldInt (such as reciprocal()), while others are 20 | * the same as Uint256 (such as comparisons). The number representation format is 21 | * the same as Uint256. It is illegal to set the value to be greater than or equal 22 | * to MODULUS; undefined behavior will result. Instances of this class are mutable. 23 | */ 24 | class FieldInt final : private Uint256 { 25 | 26 | public: using Uint256::NUM_WORDS; 27 | 28 | /*---- Fields ----*/ 29 | 30 | public: using Uint256::value; 31 | 32 | 33 | 34 | /*---- Constructors ----*/ 35 | 36 | // Constructs a FieldInt from the given 64-character hexadecimal string. Not constant-time. 37 | // If the syntax of the string is invalid, then an assertion will fail. 38 | public: explicit FieldInt(const char *str); 39 | 40 | 41 | // Constructs a FieldInt from the given Uint256, reducing it as necessary. 42 | // Constant-time with respect to the given value. 43 | public: explicit FieldInt(const Uint256 &val); 44 | 45 | 46 | 47 | /*---- Arithmetic methods ----*/ 48 | 49 | // Adds the given number into this number, modulo the prime. Constant-time with respect to both values. 50 | public: void add(const FieldInt &other); 51 | 52 | 53 | // Subtracts the given number from this number, modulo the prime. Constant-time with respect to both values. 54 | public: void subtract(const FieldInt &other); 55 | 56 | 57 | // Doubles this number, modulo the prime. Constant-time with respect to this value. 58 | public: void multiply2(); 59 | 60 | 61 | // Squares this number, modulo the prime. Constant-time with respect to this value. 62 | public: void square(); 63 | 64 | 65 | // Multiplies the given number into this number, modulo the prime. Constant-time with respect to both values. 66 | public: void multiply(const FieldInt &other); 67 | 68 | 69 | // Computes the multiplicative inverse of this number with respect to the modulus. 70 | // If this number is zero, the reciprocal is zero. Constant-time with respect to this value. 71 | public: void reciprocal(); 72 | 73 | 74 | /*---- Miscellaneous methods ----*/ 75 | 76 | public: void replace(const FieldInt &other, std::uint32_t enable); 77 | 78 | public: using Uint256::getBigEndianBytes; 79 | 80 | 81 | /*---- Equality and inequality operators ----*/ 82 | 83 | public: bool operator==(const FieldInt &other) const; 84 | 85 | public: bool operator!=(const FieldInt &other) const; 86 | 87 | public: bool operator<(const FieldInt &other) const; 88 | 89 | public: bool operator<=(const FieldInt &other) const; 90 | 91 | public: bool operator>(const FieldInt &other) const; 92 | 93 | public: bool operator>=(const FieldInt &other) const; 94 | 95 | 96 | private: bool operator<(const Uint256 &other) const; 97 | 98 | private: bool operator>=(const Uint256 &other) const; 99 | 100 | 101 | 102 | /*---- Class constants ----*/ 103 | 104 | private: static const Uint256 MODULUS; // Prime number 105 | 106 | }; 107 | -------------------------------------------------------------------------------- /cpp/Keccak256.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #include 10 | #include "Keccak256.hpp" 11 | 12 | using std::uint8_t; 13 | using std::uint64_t; 14 | using std::size_t; 15 | 16 | 17 | void Keccak256::getHash(const uint8_t msg[], size_t len, uint8_t hashResult[HASH_LEN]) { 18 | assert((msg != nullptr || len == 0) && hashResult != nullptr); 19 | uint64_t state[5][5] = {}; 20 | 21 | // XOR each message byte into the state, and absorb full blocks 22 | int blockOff = 0; 23 | for (size_t i = 0; i < len; i++) { 24 | int j = blockOff >> 3; 25 | state[j % 5][j / 5] ^= static_cast(msg[i]) << ((blockOff & 7) << 3); 26 | blockOff++; 27 | if (blockOff == BLOCK_SIZE) { 28 | absorb(state); 29 | blockOff = 0; 30 | } 31 | } 32 | 33 | // Final block and padding 34 | { 35 | int i = blockOff >> 3; 36 | state[i % 5][i / 5] ^= UINT64_C(0x01) << ((blockOff & 7) << 3); 37 | blockOff = BLOCK_SIZE - 1; 38 | int j = blockOff >> 3; 39 | state[j % 5][j / 5] ^= UINT64_C(0x80) << ((blockOff & 7) << 3); 40 | absorb(state); 41 | } 42 | 43 | // Uint64 array to bytes in little endian 44 | for (int i = 0; i < HASH_LEN; i++) { 45 | int j = i >> 3; 46 | hashResult[i] = static_cast(state[j % 5][j / 5] >> ((i & 7) << 3)); 47 | } 48 | } 49 | 50 | 51 | void Keccak256::absorb(uint64_t state[5][5]) { 52 | uint64_t (*a)[5] = state; 53 | uint8_t r = 1; // LFSR 54 | for (int i = 0; i < NUM_ROUNDS; i++) { 55 | // Theta step 56 | uint64_t c[5] = {}; 57 | for (int x = 0; x < 5; x++) { 58 | for (int y = 0; y < 5; y++) 59 | c[x] ^= a[x][y]; 60 | } 61 | for (int x = 0; x < 5; x++) { 62 | uint64_t d = c[(x + 4) % 5] ^ rotl64(c[(x + 1) % 5], 1); 63 | for (int y = 0; y < 5; y++) 64 | a[x][y] ^= d; 65 | } 66 | 67 | // Rho and pi steps 68 | uint64_t b[5][5]; 69 | for (int x = 0; x < 5; x++) { 70 | for (int y = 0; y < 5; y++) 71 | b[y][(x * 2 + y * 3) % 5] = rotl64(a[x][y], ROTATION[x][y]); 72 | } 73 | 74 | // Chi step 75 | for (int x = 0; x < 5; x++) { 76 | for (int y = 0; y < 5; y++) 77 | a[x][y] = b[x][y] ^ (~b[(x + 1) % 5][y] & b[(x + 2) % 5][y]); 78 | } 79 | 80 | // Iota step 81 | for (int j = 0; j < 7; j++) { 82 | a[0][0] ^= static_cast(r & 1) << ((1 << j) - 1); 83 | r = static_cast((r << 1) ^ ((r >> 7) * 0x171)); 84 | } 85 | } 86 | } 87 | 88 | 89 | uint64_t Keccak256::rotl64(uint64_t x, int i) { 90 | return ((0U + x) << i) | (x >> ((64 - i) & 63)); 91 | } 92 | 93 | 94 | // Static initializers 95 | const unsigned char Keccak256::ROTATION[5][5] = { 96 | { 0, 36, 3, 41, 18}, 97 | { 1, 44, 10, 45, 2}, 98 | {62, 6, 43, 15, 61}, 99 | {28, 55, 25, 21, 56}, 100 | {27, 20, 39, 8, 14}, 101 | }; 102 | -------------------------------------------------------------------------------- /cpp/Keccak256.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | 14 | 15 | /* 16 | * Computes the Keccak-256 hash of a sequence of bytes. The hash value is 32 bytes long. 17 | * Provides just one static method. 18 | */ 19 | class Keccak256 final { 20 | 21 | public: static constexpr int HASH_LEN = 32; 22 | private: static constexpr int BLOCK_SIZE = 200 - HASH_LEN * 2; 23 | private: static constexpr int NUM_ROUNDS = 24; 24 | 25 | 26 | public: static void getHash(const std::uint8_t msg[], std::size_t len, std::uint8_t hashResult[HASH_LEN]); 27 | 28 | 29 | private: static void absorb(std::uint64_t state[5][5]); 30 | 31 | 32 | // Requires 0 <= i <= 63 33 | private: static std::uint64_t rotl64(std::uint64_t x, int i); 34 | 35 | 36 | Keccak256() = delete; // Not instantiable 37 | 38 | 39 | private: static const unsigned char ROTATION[5][5]; 40 | 41 | }; 42 | -------------------------------------------------------------------------------- /cpp/Keccak256Test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * A runnable main program that tests the functionality of class Keccak256. 3 | * 4 | * Bitcoin cryptography library 5 | * Copyright (c) Project Nayuki 6 | * 7 | * https://www.nayuki.io/page/bitcoin-cryptography-library 8 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 9 | */ 10 | 11 | #include "TestHelper.hpp" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "Keccak256.hpp" 17 | 18 | 19 | int main() { 20 | struct TestCase { 21 | bool matches; 22 | const char *expectedHash; 23 | Bytes message; 24 | }; 25 | const vector cases{ 26 | // ASCII vectors 27 | {true, "C5D2460186F7233C927E7DB2DCC703C0E500B653CA82273B7BFAD8045D85A470", asciiBytes("")}, 28 | {true, "4D741B6F1EB29CB2A9B9911C82F56FA8D73B04959D3D9D222895DF6C0B28AA15", asciiBytes("The quick brown fox jumps over the lazy dog")}, 29 | {true, "578951E24EFD62A3D63A86F7CD19AAA53C898FE287D2552133220370240B572D", asciiBytes("The quick brown fox jumps over the lazy dog.")}, 30 | // Binary vectors 31 | {true, "6A769F93F255B078FE73AFF68F0422A279939920E4690B4AFF0E433CFA3D3DF3", hexBytes("13BD2811F6ED2B6F04FF3895ACEED7BEF8DCD45EB121791BC194A0F806206BFFC3B9281C2B308B1A729CE008119DD3066E9378ACDCC50A98A82E20738800B6CDDBE5FE9694AD6D")}, 32 | {true, "C06DD4261638C44AFCB186F0AF5DE20EA53AA63316FBB71728F874FF3DACEB0D", hexBytes("1EED9CBA179A009EC2EC5508773DD305477CA117E6D569E66B5F64C6BC64801CE25A8424CE4A26D575B8A6FB10EAD3FD1992EDDDEEC2EBE7150DC98F63ADC3237EF57B91397AA8A7")}, 33 | {true, "52CBC5DBE49B009663C43F079DD180E38A77533778062A72A29E864A58522922", hexBytes("F13C972C52CB3CC4A4DF28C97F2DF11CE089B815466BE88863243EB318C2ADB1A417CB1041308598541720197B9B1CB5BA2318BD5574D1DF2174AF14884149BA9B2F446D609DF240CE335599957B8EC80876D9A085AE084907BC5961B20BF5F6CA58D5DAB38ADB")}, 34 | {true, "3A8DFCFD1B362003DDFA17910727539E64B18021ABBA018B5F58D71F7A449733", hexBytes("E35780EB9799AD4C77535D4DDB683CF33EF367715327CF4C4A58ED9CBDCDD486F669F80189D549A9364FA82A51A52654EC721BB3AAB95DCEB4A86A6AFA93826DB923517E928F33E3FBA850D45660EF83B9876ACCAFA2A9987A254B137C6E140A21691E1069413848")}, 35 | {true, "BD6F5492582A7C1B116304DE28314DF9FFFE95B0DA11AF52FE9440A717A34859", hexBytes("B771D5CEF5D1A41A93D15643D7181D2A2EF0A8E84D91812F20ED21F147BEF732BF3A60EF4067C3734B85BC8CD471780F10DC9E8291B58339A677B960218F71E793F2797AEA349406512829065D37BB55EA796FA4F56FD8896B49B2CD19B43215AD967C712B24E5032D065232E02C127409D2ED4146B9D75D763D52DB98D949D3B0FED6A8052FBB")}, 36 | {true, "E717A7769448ABBE5FEF8187954A88AC56DED1D22E63940AB80D029585A21921", hexBytes("B32D95B0B9AAD2A8816DE6D06D1F86008505BD8C14124F6E9A163B5A2ADE55F835D0EC3880EF50700D3B25E42CC0AF050CCD1BE5E555B23087E04D7BF9813622780C7313A1954F8740B6EE2D3F71F768DD417F520482BD3A08D4F222B4EE9DBD015447B33507DD50F3AB4247C5DE9A8ABD62A8DECEA01E3B87C8B927F5B08BEB37674C6F8E380C04")}, 37 | {true, "344D129C228359463C40555D94213D015627E5871C04F106A0FEEF9361CDECB6", hexBytes("EA40E83CB18B3A242C1ECC6CCD0B7853A439DAB2C569CFC6DC38A19F5C90ACBF76AEF9EA3742FF3B54EF7D36EB7CE4FF1C9AB3BC119CFF6BE93C03E208783335C0AB8137BE5B10CDC66FF3F89A1BDDC6A1EED74F504CBE7290690BB295A872B9E3FE2CEE9E6C67C41DB8EFD7D863CF10F840FE618E7936DA3DCA5CA6DF933F24F6954BA0801A1294CD8D7E66DFAFEC")}, 38 | {true, "4CE7C2B935F21FC34C5E56D940A555C593872AEC2F896DE4E68F2A017060F535", hexBytes("157D5B7E4507F66D9A267476D33831E7BB768D4D04CC3438DA12F9010263EA5FCAFBDE2579DB2F6B58F911D593D5F79FB05FE3596E3FA80FF2F761D1B0E57080055C118C53E53CDB63055261D7C9B2B39BD90ACC32520CBBDBDA2C4FD8856DBCEE173132A2679198DAF83007A9B5C51511AE49766C792A29520388444EBEFE28256FB33D4260439CBA73A9479EE00C63")}, 39 | // secp256k1 curve point public key vectors 40 | {true, "72F15D6555488541650CE62C0BED7ABD61247635C1973EB38474A2516ED1D884", hexBytes("836B35A026743E823A90A0EE3B91BF615C6A757E2B60B9E1DC1826FD0DD16106F7BC1E8179F665015F43C6C81F39062FC2086ED849625C06E04697698B21855E")}, 41 | {true, "500625E5A55B726C0FC56C62C2D7CF95645D33006175B78989035C7C9061D3F9", hexBytes("EFB99D9860F4DEC4CB548A5722C27E9EF58E37FBAB9719C5B33D55C216DB49311221A01F638CE5F255875B194E0ACAA58B19A89D2E56A864427298F826A7F887")}, 42 | {true, "6F68D681DE0407D447C30E14DD4ECCD742D17887F50C27AEBB14D99BFD7571B6", hexBytes("C5BC5C47FFA548D0F2B63D4F05FA7064D72FA3657C287F38CC87140A639C9465D4C9EDEC42F06B631C443311FD91585BCAB873136EAC50AF6DAA5363F0405544")}, 43 | }; 44 | 45 | int numTestCases = 0; 46 | for (const TestCase &tc : cases) { 47 | Bytes expectHash = hexBytes(tc.expectedHash); 48 | assert(expectHash.size() == Keccak256::HASH_LEN); 49 | std::uint8_t actualHash[Keccak256::HASH_LEN]; 50 | Keccak256::getHash(tc.message.data(), tc.message.size(), actualHash); 51 | assert((std::memcmp(actualHash, expectHash.data(), Keccak256::HASH_LEN) == 0) == tc.matches); 52 | numTestCases++; 53 | } 54 | std::printf("All %d test cases passed\n", numTestCases); 55 | return EXIT_SUCCESS; 56 | } 57 | -------------------------------------------------------------------------------- /cpp/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This makefile builds and runs the test programs in this directory. They check 3 | # the functionality and correctness of the C++ cryptography implementations. 4 | # 5 | # Requires a C++11 compiler, because of features like move constructors and 6 | # libraries like cstdint being used. 7 | # 8 | # Bitcoin cryptography library 9 | # Copyright (c) Project Nayuki 10 | # 11 | # https://www.nayuki.io/page/bitcoin-cryptography-library 12 | # https://github.com/nayuki/Bitcoin-Cryptography-Library 13 | # 14 | 15 | 16 | # ---- Configuration options ---- 17 | 18 | # External/implicit variables: 19 | # - CXX: The C++ compiler, such as g++ or clang++. 20 | # - CXXFLAGS: Any extra user-specified compiler flags (can be blank). 21 | # - AR: The archiver, such as ar. 22 | 23 | # Mandatory compiler flags 24 | CXXFLAGS += -std=c++11 25 | # Diagnostics. Adding '-fsanitize=address' is helpful for most versions of Clang and newer versions of GCC. 26 | CXXFLAGS += -Wall -fsanitize=undefined 27 | # Optimization level 28 | CXXFLAGS += -O1 29 | # Choose "pure-cpp" or "x8664" 30 | IMPLEMENTATION = pure-cpp 31 | 32 | 33 | # ---- Controlling make ---- 34 | 35 | # Clear default suffix rules 36 | .SUFFIXES: 37 | 38 | # Don't delete object files 39 | .SECONDARY: 40 | 41 | # Stuff concerning goals 42 | .DEFAULT_GOAL = all 43 | .PHONY: all check clean 44 | 45 | 46 | # ---- Targets to build ---- 47 | 48 | LIB = bitcoincrypto 49 | LIBFILE = lib$(LIB).a 50 | LIBSRC = Base58Check.cpp CurvePoint.cpp Ecdsa.cpp ExtendedPrivateKey.cpp FieldInt.cpp Keccak256.cpp Ripemd160.cpp Sha256.cpp Sha256Hash.cpp Sha512.cpp Uint256.cpp Utils.cpp 51 | LIBOBJ := $(LIBSRC:%.cpp=%.o) 52 | ifeq ($(IMPLEMENTATION), x8664) 53 | LIBSRC += AsmX8664.s 54 | LIBOBJ += AsmX8664.o 55 | CXXFLAGS += -DUSE_X8664_ASM_IMPL 56 | endif 57 | TESTS = Base58CheckTest CurvePointTest EcdsaTest ExtendedPrivateKeyTest FieldIntTest Keccak256Test Ripemd160Test Sha256HashTest Sha256Test Sha512Test Uint256Test 58 | 59 | # Build all binaries 60 | all: $(LIBFILE) $(TESTS) EcdsaOpCount 61 | 62 | # Run tests 63 | check: $(TESTS) 64 | @for name in $^; do echo ./$$name; ./$$name; done 65 | 66 | # Delete build output 67 | clean: 68 | rm -f -- $(LIBOBJ) $(LIBFILE) $(TESTS:=.o) $(TESTS) EcdsaOpCount 69 | rm -rf .deps 70 | 71 | # Executable files 72 | %: %.o $(LIBFILE) 73 | $(CXX) $(CXXFLAGS) -o $@ $< -L . -l $(LIB) 74 | 75 | # Special executable 76 | EcdsaOpCount: EcdsaOpCount.cpp $(LIBSRC) 77 | $(CXX) $(CXXFLAGS) -DCOUNT_OPS -DNDEBUG -o $@ $^ 78 | 79 | # The library 80 | $(LIBFILE): $(LIBOBJ) 81 | $(AR) -crs $@ -- $^ 82 | 83 | # Object files 84 | %.o: %.cpp .deps/timestamp 85 | $(CXX) $(CXXFLAGS) -c -o $@ -MMD -MF .deps/$*.d $< 86 | 87 | AsmX8664.o: AsmX8664.s 88 | $(CXX) $(CXXFLAGS) -c -o $@ $< 89 | 90 | # Have a place to store header dependencies automatically generated by compiler 91 | .deps/timestamp: 92 | mkdir -p .deps 93 | touch .deps/timestamp 94 | 95 | # Make use of said dependencies if available 96 | -include .deps/*.d 97 | -------------------------------------------------------------------------------- /cpp/Ripemd160.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #include 10 | #include 11 | #include "Ripemd160.hpp" 12 | #include "Utils.hpp" 13 | 14 | using std::uint8_t; 15 | using std::uint32_t; 16 | using std::size_t; 17 | 18 | 19 | void Ripemd160::getHash(const uint8_t msg[], size_t len, uint8_t hashResult[HASH_LEN]) { 20 | // Compress whole message blocks 21 | assert((msg != nullptr || len == 0) && hashResult != nullptr); 22 | uint32_t state[5] = {UINT32_C(0x67452301), UINT32_C(0xEFCDAB89), UINT32_C(0x98BADCFE), UINT32_C(0x10325476), UINT32_C(0xC3D2E1F0)}; 23 | size_t off = len & ~static_cast(BLOCK_LEN - 1); 24 | compress(state, msg, off); 25 | 26 | // Final blocks, padding, and length 27 | uint8_t block[BLOCK_LEN] = {}; 28 | Utils::copyBytes(block, &msg[off], len - off); 29 | off = len & (BLOCK_LEN - 1); 30 | block[off] = 0x80; 31 | off++; 32 | if (off + 8 > BLOCK_LEN) { 33 | compress(state, block, BLOCK_LEN); 34 | std::memset(block, 0, BLOCK_LEN); 35 | } 36 | block[BLOCK_LEN - 8] = static_cast((len & 0x1FU) << 3); 37 | len >>= 5; 38 | for (int i = 1; i < 8; i++, len >>= 8) 39 | block[BLOCK_LEN - 8 + i] = static_cast(len); 40 | compress(state, block, BLOCK_LEN); 41 | 42 | // Uint32 array to bytes in little endian 43 | for (int i = 0; i < HASH_LEN; i++) 44 | hashResult[i] = static_cast(state[i >> 2] >> ((i & 3) << 3)); 45 | } 46 | 47 | 48 | void Ripemd160::compress(uint32_t state[5], const uint8_t blocks[], size_t len) { 49 | assert(len % BLOCK_LEN == 0); 50 | uint32_t schedule[16]; 51 | for (size_t i = 0; i < len; ) { 52 | 53 | // Message schedule 54 | for (int j = 0; j < 16; j++, i += 4) { 55 | schedule[j] = static_cast(blocks[i + 0]) << 0 56 | | static_cast(blocks[i + 1]) << 8 57 | | static_cast(blocks[i + 2]) << 16 58 | | static_cast(blocks[i + 3]) << 24; 59 | } 60 | 61 | // The 80 rounds 62 | uint32_t al = state[0], ar = state[0]; 63 | uint32_t bl = state[1], br = state[1]; 64 | uint32_t cl = state[2], cr = state[2]; 65 | uint32_t dl = state[3], dr = state[3]; 66 | uint32_t el = state[4], er = state[4]; 67 | for (int j = 0; j < NUM_ROUNDS; j++) { 68 | uint32_t temp; 69 | temp = 0U + rotl32(0U + al + f(j, bl, cl, dl) + schedule[RL[j]] + KL[j >> 4], SL[j]) + el; 70 | al = el; 71 | el = dl; 72 | dl = rotl32(cl, 10); 73 | cl = bl; 74 | bl = temp; 75 | temp = 0U + rotl32(0U + ar + f(NUM_ROUNDS - 1 - j, br, cr, dr) + schedule[RR[j]] + KR[j >> 4], SR[j]) + er; 76 | ar = er; 77 | er = dr; 78 | dr = rotl32(cr, 10); 79 | cr = br; 80 | br = temp; 81 | } 82 | uint32_t temp = 0U + state[1] + cl + dr; 83 | state[1] = 0U + state[2] + dl + er; 84 | state[2] = 0U + state[3] + el + ar; 85 | state[3] = 0U + state[4] + al + br; 86 | state[4] = 0U + state[0] + bl + cr; 87 | state[0] = temp; 88 | } 89 | } 90 | 91 | 92 | uint32_t Ripemd160::f(int i, uint32_t x, uint32_t y, uint32_t z) { 93 | switch (i >> 4) { 94 | case 0: return x ^ y ^ z; 95 | case 1: return (x & y) | (~x & z); 96 | case 2: return (x | ~y) ^ z; 97 | case 3: return (x & z) | (y & ~z); 98 | case 4: return x ^ (y | ~z); 99 | default: assert(false); return 0; // Dummy value to please the compiler 100 | } 101 | } 102 | 103 | 104 | uint32_t Ripemd160::rotl32(uint32_t x, int i) { 105 | return ((0U + x) << i) | (x >> (32 - i)); 106 | } 107 | 108 | 109 | // Static initializers 110 | const uint32_t Ripemd160::KL[5] = { 111 | UINT32_C(0x00000000), UINT32_C(0x5A827999), UINT32_C(0x6ED9EBA1), UINT32_C(0x8F1BBCDC), UINT32_C(0xA953FD4E)}; 112 | const uint32_t Ripemd160::KR[5] = { 113 | UINT32_C(0x50A28BE6), UINT32_C(0x5C4DD124), UINT32_C(0x6D703EF3), UINT32_C(0x7A6D76E9), UINT32_C(0x00000000)}; 114 | const unsigned char Ripemd160::RL[NUM_ROUNDS] = { 115 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 116 | 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, 117 | 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, 118 | 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, 119 | 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13}; 120 | const unsigned char Ripemd160::RR[NUM_ROUNDS] = { 121 | 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 122 | 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, 123 | 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, 124 | 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, 125 | 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11}; 126 | const unsigned char Ripemd160::SL[NUM_ROUNDS] = { 127 | 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, 128 | 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, 129 | 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, 130 | 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, 131 | 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6}; 132 | const unsigned char Ripemd160::SR[NUM_ROUNDS] = { 133 | 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, 134 | 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, 135 | 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, 136 | 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, 137 | 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11}; 138 | -------------------------------------------------------------------------------- /cpp/Ripemd160.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | 14 | 15 | /* 16 | * Computes the RIPEMD-160 hash of a sequence of bytes. The hash value is 20 bytes long. 17 | * Provides just one static method. 18 | */ 19 | class Ripemd160 final { 20 | 21 | public: static constexpr int HASH_LEN = 20; 22 | private: static constexpr int BLOCK_LEN = 64; 23 | private: static constexpr int NUM_ROUNDS = 80; 24 | 25 | /*---- Static functions ----*/ 26 | 27 | public: static void getHash(const std::uint8_t msg[], std::size_t len, std::uint8_t hashResult[HASH_LEN]); 28 | 29 | 30 | private: static void compress(std::uint32_t state[5], const std::uint8_t blocks[], std::size_t len); 31 | 32 | private: static std::uint32_t f(int i, std::uint32_t x, std::uint32_t y, std::uint32_t z); 33 | 34 | // Requires 1 <= i <= 31 35 | private: static std::uint32_t rotl32(std::uint32_t x, int i); 36 | 37 | Ripemd160() = delete; // Not instantiable 38 | 39 | 40 | 41 | /*---- Class constants ----*/ 42 | 43 | private: static const std::uint32_t KL[5]; // Round constants for left line 44 | private: static const std::uint32_t KR[5]; // Round constants for right line 45 | private: static const unsigned char RL[NUM_ROUNDS]; // Message schedule for left line 46 | private: static const unsigned char RR[NUM_ROUNDS]; // Message schedule for right line 47 | private: static const unsigned char SL[NUM_ROUNDS]; // Left-rotation for left line 48 | private: static const unsigned char SR[NUM_ROUNDS]; // Left-rotation for right line 49 | 50 | }; 51 | -------------------------------------------------------------------------------- /cpp/Sha256.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #include 10 | #include 11 | #include "Sha256.hpp" 12 | #include "Utils.hpp" 13 | 14 | using std::uint8_t; 15 | using std::uint32_t; 16 | using std::uint64_t; 17 | using std::size_t; 18 | 19 | 20 | Sha256::Sha256() : 21 | length(0), 22 | bufferLen(0) {} 23 | 24 | 25 | Sha256 &Sha256::append(const uint8_t bytes[], size_t len) { 26 | assert(bytes != nullptr || len == 0); 27 | for (size_t i = 0; i < len; i++) { 28 | buffer[bufferLen] = bytes[i]; 29 | bufferLen++; 30 | if (bufferLen == BLOCK_LEN) { 31 | compress(state, buffer); 32 | bufferLen = 0; 33 | } 34 | } 35 | length += len; 36 | return *this; 37 | } 38 | 39 | 40 | Sha256Hash Sha256::getHash() { 41 | uint64_t bitLength = length << 3; 42 | uint8_t temp = 0x80; 43 | append(&temp, 1); 44 | temp = 0x00; 45 | while (bufferLen != 56) 46 | append(&temp, 1); 47 | for (int i = 0; i < 8; i++) { 48 | temp = static_cast(bitLength >> ((7 - i) << 3)); 49 | append(&temp, 1); 50 | } 51 | uint8_t result[Sha256Hash::HASH_LEN]; 52 | for (size_t i = 0; i < sizeof(state) / sizeof(state[0]); i++) 53 | Utils::storeBigUint32(state[i], &result[i * 4]); 54 | return Sha256Hash(result, Sha256Hash::HASH_LEN); 55 | } 56 | 57 | 58 | Sha256Hash Sha256::getHash(const uint8_t msg[], size_t len) { 59 | return Sha256().append(msg, len).getHash(); 60 | } 61 | 62 | 63 | Sha256Hash Sha256::getDoubleHash(const uint8_t msg[], size_t len) { 64 | const Sha256Hash innerHash = getHash(msg, len); 65 | return getHash(innerHash.value, Sha256Hash::HASH_LEN); 66 | } 67 | 68 | 69 | Sha256Hash Sha256::getHmac(const uint8_t key[], size_t keyLen, const uint8_t msg[], size_t msgLen) { 70 | assert(key != nullptr || keyLen == 0); 71 | 72 | // Preprocess key 73 | uint8_t tempKey[BLOCK_LEN] = {}; 74 | if (keyLen <= BLOCK_LEN) 75 | Utils::copyBytes(tempKey, key, keyLen); 76 | else { 77 | const Sha256Hash keyHash = getHash(key, keyLen); 78 | std::memcpy(tempKey, keyHash.value, Sha256Hash::HASH_LEN); 79 | } 80 | 81 | // Compute inner hash 82 | for (int i = 0; i < BLOCK_LEN; i++) 83 | tempKey[i] ^= 0x36; 84 | const Sha256Hash innerHash = Sha256() 85 | .append(tempKey, BLOCK_LEN) 86 | .append(msg, msgLen) 87 | .getHash(); 88 | 89 | // Compute outer hash 90 | for (int i = 0; i < BLOCK_LEN; i++) 91 | tempKey[i] ^= 0x36 ^ 0x5C; 92 | return Sha256() 93 | .append(tempKey, BLOCK_LEN) 94 | .append(innerHash.value, Sha256Hash::HASH_LEN) 95 | .getHash(); 96 | } 97 | 98 | 99 | void Sha256::compress(uint32_t state[8], const uint8_t block[BLOCK_LEN]) { 100 | assert(state != nullptr && block != nullptr); 101 | 102 | // Message schedule 103 | uint32_t schedule[NUM_ROUNDS] = {}; 104 | for (int i = 0; i < 64; i++) 105 | schedule[i >> 2] |= static_cast(block[i]) << ((3 - (i & 3)) << 3); 106 | 107 | for (int i = 16; i < NUM_ROUNDS; i++) { 108 | schedule[i] = 0U + schedule[i - 16] + schedule[i - 7] 109 | + (rotr32(schedule[i - 15], 7) ^ rotr32(schedule[i - 15], 18) ^ (schedule[i - 15] >> 3)) 110 | + (rotr32(schedule[i - 2], 17) ^ rotr32(schedule[i - 2], 19) ^ (schedule[i - 2] >> 10)); 111 | } 112 | 113 | // The 64 rounds 114 | uint32_t a = state[0]; 115 | uint32_t b = state[1]; 116 | uint32_t c = state[2]; 117 | uint32_t d = state[3]; 118 | uint32_t e = state[4]; 119 | uint32_t f = state[5]; 120 | uint32_t g = state[6]; 121 | uint32_t h = state[7]; 122 | for (int i = 0; i < NUM_ROUNDS; i++) { 123 | uint32_t t1 = 0U + h + (rotr32(e, 6) ^ rotr32(e, 11) ^ rotr32(e, 25)) + (g ^ (e & (f ^ g))) + ROUND_CONSTANTS[i] + schedule[i]; 124 | uint32_t t2 = 0U + (rotr32(a, 2) ^ rotr32(a, 13) ^ rotr32(a, 22)) + ((a & (b | c)) | (b & c)); 125 | h = g; 126 | g = f; 127 | f = e; 128 | e = 0U + d + t1; 129 | d = c; 130 | c = b; 131 | b = a; 132 | a = 0U + t1 + t2; 133 | } 134 | state[0] = 0U + state[0] + a; 135 | state[1] = 0U + state[1] + b; 136 | state[2] = 0U + state[2] + c; 137 | state[3] = 0U + state[3] + d; 138 | state[4] = 0U + state[4] + e; 139 | state[5] = 0U + state[5] + f; 140 | state[6] = 0U + state[6] + g; 141 | state[7] = 0U + state[7] + h; 142 | } 143 | 144 | 145 | uint32_t Sha256::rotr32(uint32_t x, int i) { 146 | return ((0U + x) << (32 - i)) | (x >> i); 147 | } 148 | 149 | 150 | const uint32_t Sha256::ROUND_CONSTANTS[NUM_ROUNDS] = { 151 | UINT32_C(0x428A2F98), UINT32_C(0x71374491), UINT32_C(0xB5C0FBCF), UINT32_C(0xE9B5DBA5), 152 | UINT32_C(0x3956C25B), UINT32_C(0x59F111F1), UINT32_C(0x923F82A4), UINT32_C(0xAB1C5ED5), 153 | UINT32_C(0xD807AA98), UINT32_C(0x12835B01), UINT32_C(0x243185BE), UINT32_C(0x550C7DC3), 154 | UINT32_C(0x72BE5D74), UINT32_C(0x80DEB1FE), UINT32_C(0x9BDC06A7), UINT32_C(0xC19BF174), 155 | UINT32_C(0xE49B69C1), UINT32_C(0xEFBE4786), UINT32_C(0x0FC19DC6), UINT32_C(0x240CA1CC), 156 | UINT32_C(0x2DE92C6F), UINT32_C(0x4A7484AA), UINT32_C(0x5CB0A9DC), UINT32_C(0x76F988DA), 157 | UINT32_C(0x983E5152), UINT32_C(0xA831C66D), UINT32_C(0xB00327C8), UINT32_C(0xBF597FC7), 158 | UINT32_C(0xC6E00BF3), UINT32_C(0xD5A79147), UINT32_C(0x06CA6351), UINT32_C(0x14292967), 159 | UINT32_C(0x27B70A85), UINT32_C(0x2E1B2138), UINT32_C(0x4D2C6DFC), UINT32_C(0x53380D13), 160 | UINT32_C(0x650A7354), UINT32_C(0x766A0ABB), UINT32_C(0x81C2C92E), UINT32_C(0x92722C85), 161 | UINT32_C(0xA2BFE8A1), UINT32_C(0xA81A664B), UINT32_C(0xC24B8B70), UINT32_C(0xC76C51A3), 162 | UINT32_C(0xD192E819), UINT32_C(0xD6990624), UINT32_C(0xF40E3585), UINT32_C(0x106AA070), 163 | UINT32_C(0x19A4C116), UINT32_C(0x1E376C08), UINT32_C(0x2748774C), UINT32_C(0x34B0BCB5), 164 | UINT32_C(0x391C0CB3), UINT32_C(0x4ED8AA4A), UINT32_C(0x5B9CCA4F), UINT32_C(0x682E6FF3), 165 | UINT32_C(0x748F82EE), UINT32_C(0x78A5636F), UINT32_C(0x84C87814), UINT32_C(0x8CC70208), 166 | UINT32_C(0x90BEFFFA), UINT32_C(0xA4506CEB), UINT32_C(0xBEF9A3F7), UINT32_C(0xC67178F2), 167 | }; 168 | -------------------------------------------------------------------------------- /cpp/Sha256.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | #include "Sha256Hash.hpp" 14 | 15 | 16 | /* 17 | * Computes the SHA-256 hash of a sequence of bytes, returning a Sha256Hash object. 18 | * Provides three static methods, and an instantiable stateful hasher. 19 | */ 20 | class Sha256 final { 21 | 22 | /*---- Public constants ----*/ 23 | 24 | public: static constexpr int BLOCK_LEN = 64; // In bytes 25 | 26 | 27 | 28 | /*---- Instance members ----*/ 29 | 30 | private: std::uint32_t state[8] = { 31 | UINT32_C(0x6A09E667), UINT32_C(0xBB67AE85), UINT32_C(0x3C6EF372), UINT32_C(0xA54FF53A), 32 | UINT32_C(0x510E527F), UINT32_C(0x9B05688C), UINT32_C(0x1F83D9AB), UINT32_C(0x5BE0CD19), 33 | }; 34 | private: std::uint64_t length; 35 | private: std::uint8_t buffer[BLOCK_LEN]; 36 | private: int bufferLen; 37 | 38 | 39 | // Constructs a new SHA-256 hasher with an initially blank message. 40 | public: explicit Sha256(); 41 | 42 | 43 | // Appends message bytes to this ongoing hasher, and returns this object itself. 44 | public: Sha256 &append(const std::uint8_t bytes[], std::size_t len); 45 | 46 | 47 | // Returns the SHA-256 hash of all the bytes seen. Destroys the state so that no further append() or getHash() will be valid. 48 | public: Sha256Hash getHash(); 49 | 50 | 51 | 52 | /*---- Static functions ----*/ 53 | 54 | public: static Sha256Hash getHash(const std::uint8_t msg[], std::size_t len); 55 | 56 | 57 | public: static Sha256Hash getDoubleHash(const std::uint8_t msg[], std::size_t len); 58 | 59 | 60 | public: static Sha256Hash getHmac(const std::uint8_t key[], std::size_t keyLen, const std::uint8_t msg[], std::size_t msgLen); 61 | 62 | 63 | public: static void compress(std::uint32_t state[8], const std::uint8_t block[BLOCK_LEN]); 64 | 65 | 66 | // Requires 1 <= i <= 31 67 | private: static std::uint32_t rotr32(std::uint32_t x, int i); 68 | 69 | 70 | 71 | /*---- Private constants ----*/ 72 | 73 | private: static constexpr int NUM_ROUNDS = 64; 74 | private: static const std::uint32_t ROUND_CONSTANTS[NUM_ROUNDS]; 75 | 76 | }; 77 | -------------------------------------------------------------------------------- /cpp/Sha256Hash.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #include 10 | #include 11 | #include "Sha256Hash.hpp" 12 | #include "Utils.hpp" 13 | 14 | using std::uint8_t; 15 | using std::size_t; 16 | 17 | 18 | Sha256Hash::Sha256Hash(const uint8_t hash[HASH_LEN], size_t len) { 19 | assert(hash != nullptr && len == HASH_LEN); 20 | std::memcpy(value, hash, sizeof(value)); 21 | } 22 | 23 | 24 | Sha256Hash::Sha256Hash(const char *str) : 25 | value() { 26 | assert(str != nullptr && std::strlen(str) == HASH_LEN * 2); 27 | for (int i = 0; i < HASH_LEN * 2; i++) { 28 | int digit = Utils::parseHexDigit(str[HASH_LEN * 2 - 1 - i]); 29 | assert(digit != -1); 30 | value[i >> 1] |= digit << ((i & 1) << 2); 31 | } 32 | } 33 | 34 | 35 | bool Sha256Hash::operator==(const Sha256Hash &other) const { 36 | int diff = 0; 37 | for (int i = 0; i < HASH_LEN; i++) 38 | diff |= value[i] ^ other.value[i]; 39 | return diff == 0; 40 | } 41 | 42 | 43 | bool Sha256Hash::operator!=(const Sha256Hash &other) const { 44 | return !(*this == other); 45 | } 46 | -------------------------------------------------------------------------------- /cpp/Sha256Hash.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | 14 | 15 | /* 16 | * Represents a 32-byte SHA-256 hash value. 17 | * 18 | * Note that by Bitcoin convention, SHA-256 hash strings are serialized in byte-reversed order. 19 | * For example, these three lines all represent the same hash value: 20 | * - Bigint: 0x0102030405060708091011121314151617181920212223242526272829303132. 21 | * - Byte array: {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x11,0x12,0x13,0x14,0x15,0x16, 22 | * 0x17,0x18,0x19,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x30,0x31,0x32}. 23 | * - Hex string: "3231302928272625242322212019181716151413121110090807060504030201". 24 | */ 25 | class Sha256Hash final { 26 | 27 | public: static constexpr int HASH_LEN = 32; 28 | 29 | /*---- Fields ----*/ 30 | 31 | public: std::uint8_t value[HASH_LEN]; 32 | 33 | 34 | 35 | /*---- Constructors ----*/ 36 | 37 | // Constructs a Sha256Hash from the given array of 32 bytes (len is a dummy parameter that must equal 32). 38 | // Constant-time with respect to the given array of values. 39 | public: explicit Sha256Hash(const std::uint8_t hash[HASH_LEN], std::size_t len); 40 | 41 | 42 | // Constructs a Sha256Hash from the given 64-character byte-reversed hexadecimal string. Not constant-time. 43 | public: explicit Sha256Hash(const char *str); 44 | 45 | 46 | 47 | /*---- Instance methods ----*/ 48 | 49 | // Tests whether the given hash is equal to this one. Constant-time with respect to both values. 50 | public: bool operator==(const Sha256Hash &other) const; 51 | 52 | 53 | // Tests whether the given hash is unequal to this one. Constant-time with respect to both values. 54 | public: bool operator!=(const Sha256Hash &other) const; 55 | 56 | }; 57 | -------------------------------------------------------------------------------- /cpp/Sha256HashTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * A runnable main program that tests the functionality of class Sha256Hash. 3 | * 4 | * Bitcoin cryptography library 5 | * Copyright (c) Project Nayuki 6 | * 7 | * https://www.nayuki.io/page/bitcoin-cryptography-library 8 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 9 | */ 10 | 11 | #include "TestHelper.hpp" 12 | #include 13 | #include 14 | #include 15 | #include "Sha256Hash.hpp" 16 | 17 | 18 | int main() { 19 | // Test equality 20 | struct TestCase { 21 | bool matches; 22 | const char *hexHash; 23 | Bytes byteHash; 24 | }; 25 | const vector cases{ 26 | {true , "0000000000000000000000000000000000000000000000000000000000000000", hexBytes("0000000000000000000000000000000000000000000000000000000000000000")}, 27 | {true , "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", hexBytes("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")}, 28 | {true , "00112233445566778899AABBCCDDEEFF0112233445566778899AABBCCDDEEFF0", hexBytes("F0EFDECDBCAB9A897867564534231201FFEEDDCCBBAA99887766554433221100")}, 29 | {true , "FD1A91CA0B85A52ECE4F73EB7C55A5021FA852F78D0390236219EA458C2CE991", hexBytes("91E92C8C45EA19622390038DF752A81F02A5557CEB734FCE2EA5850BCA911AFD")}, 30 | {false, "0000000000000000000000000000000000000000000000000000000000000001", hexBytes("0000000000000000000000000000000000000000000000000000000000000000")}, 31 | {false, "8000000000000000000000000000000000000000000000000000000000000000", hexBytes("0000000000000000000000000000000000000000000000000000000000000000")}, 32 | {false, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFF", hexBytes("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")}, 33 | }; 34 | int numTestCases = 0; 35 | for (const TestCase &tc : cases) { 36 | assert(std::strlen(tc.hexHash) == Sha256Hash::HASH_LEN * 2 && tc.byteHash.size() == Sha256Hash::HASH_LEN); 37 | assert((Sha256Hash(tc.byteHash.data(), Sha256Hash::HASH_LEN) == Sha256Hash(tc.hexHash)) == tc.matches); 38 | numTestCases++; 39 | } 40 | 41 | // Test get byte 42 | const Sha256Hash hash("FD1A91CA0B85A52ECE4F73EB7C55A5021FA852F78D0390236219EA458C2CE991"); 43 | assert(hash.value[ 0] == 0x91); 44 | assert(hash.value[ 1] == 0xE9); 45 | assert(hash.value[ 2] == 0x2C); 46 | assert(hash.value[30] == 0x1A); 47 | assert(hash.value[31] == 0xFD); 48 | numTestCases++; 49 | 50 | // Epilog 51 | std::printf("All %d test cases passed\n", numTestCases); 52 | return EXIT_SUCCESS; 53 | } 54 | -------------------------------------------------------------------------------- /cpp/Sha512.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #include 10 | #include "Sha512.hpp" 11 | #include "Utils.hpp" 12 | 13 | using std::uint8_t; 14 | using std::uint64_t; 15 | using std::size_t; 16 | 17 | 18 | Sha512::Sha512() : 19 | length(0), 20 | bufferLen(0) {} 21 | 22 | 23 | Sha512 &Sha512::append(const uint8_t bytes[], size_t len) { 24 | assert(bytes != nullptr || len == 0); 25 | for (size_t i = 0; i < len; i++) { 26 | buffer[bufferLen] = bytes[i]; 27 | bufferLen++; 28 | if (bufferLen == BLOCK_LEN) { 29 | compress(); 30 | bufferLen = 0; 31 | } 32 | } 33 | length += len; 34 | return *this; 35 | } 36 | 37 | 38 | void Sha512::getHash(uint8_t result[HASH_LEN]) { 39 | assert(result != nullptr); 40 | uint64_t bitLength = length << 3; 41 | uint8_t temp = 0x80; 42 | append(&temp, 1); 43 | temp = 0x00; 44 | while (bufferLen != 112) 45 | append(&temp, 1); 46 | for (int i = 0; i < 8; i++) 47 | append(&temp, 1); 48 | for (int i = 0; i < 8; i++) { 49 | temp = static_cast(bitLength >> ((7 - i) << 3)); 50 | append(&temp, 1); 51 | } 52 | for (int i = 0; i < HASH_LEN; i++) 53 | result[i] = static_cast(state[i >> 3] >> ((7 - (i & 7)) << 3)); 54 | } 55 | 56 | 57 | void Sha512::compress() { 58 | // Message schedule 59 | uint64_t schedule[NUM_ROUNDS] = {}; 60 | for (int i = 0; i < 128; i++) 61 | schedule[i >> 3] |= static_cast(buffer[i]) << ((7 - (i & 7)) << 3); 62 | 63 | for (int i = 16; i < NUM_ROUNDS; i++) { 64 | schedule[i] = 0U + schedule[i - 16] + schedule[i - 7] 65 | + (rotr64(schedule[i - 15], 1) ^ rotr64(schedule[i - 15], 8) ^ (schedule[i - 15] >> 7)) 66 | + (rotr64(schedule[i - 2], 19) ^ rotr64(schedule[i - 2], 61) ^ (schedule[i - 2] >> 6)); 67 | } 68 | 69 | // The 80 rounds 70 | uint64_t a = state[0]; 71 | uint64_t b = state[1]; 72 | uint64_t c = state[2]; 73 | uint64_t d = state[3]; 74 | uint64_t e = state[4]; 75 | uint64_t f = state[5]; 76 | uint64_t g = state[6]; 77 | uint64_t h = state[7]; 78 | for (int i = 0; i < NUM_ROUNDS; i++) { 79 | uint64_t t1 = 0U + h + (rotr64(e, 14) ^ rotr64(e, 18) ^ rotr64(e, 41)) + (g ^ (e & (f ^ g))) + ROUND_CONSTANTS[i] + schedule[i]; 80 | uint64_t t2 = 0U + (rotr64(a, 28) ^ rotr64(a, 34) ^ rotr64(a, 39)) + ((a & (b | c)) | (b & c)); 81 | h = g; 82 | g = f; 83 | f = e; 84 | e = 0U + d + t1; 85 | d = c; 86 | c = b; 87 | b = a; 88 | a = 0U + t1 + t2; 89 | } 90 | state[0] = 0U + state[0] + a; 91 | state[1] = 0U + state[1] + b; 92 | state[2] = 0U + state[2] + c; 93 | state[3] = 0U + state[3] + d; 94 | state[4] = 0U + state[4] + e; 95 | state[5] = 0U + state[5] + f; 96 | state[6] = 0U + state[6] + g; 97 | state[7] = 0U + state[7] + h; 98 | } 99 | 100 | 101 | void Sha512::getHash(const uint8_t msg[], size_t len, uint8_t hashResult[HASH_LEN]) { 102 | Sha512().append(msg, len).getHash(hashResult); 103 | } 104 | 105 | 106 | void Sha512::getHmac(const uint8_t key[], size_t keyLen, const uint8_t msg[], size_t msgLen, uint8_t result[HASH_LEN]) { 107 | assert(key != nullptr || keyLen == 0); 108 | 109 | // Preprocess key 110 | uint8_t tempKey[BLOCK_LEN] = {}; 111 | if (keyLen <= BLOCK_LEN) 112 | Utils::copyBytes(tempKey, key, keyLen); 113 | else 114 | getHash(key, keyLen, tempKey); 115 | 116 | // Compute inner hash 117 | for (int i = 0; i < BLOCK_LEN; i++) 118 | tempKey[i] ^= 0x36; 119 | uint8_t innerHash[HASH_LEN] = {}; 120 | Sha512() 121 | .append(tempKey, BLOCK_LEN) 122 | .append(msg, msgLen) 123 | .getHash(innerHash); 124 | 125 | // Compute outer hash 126 | for (int i = 0; i < BLOCK_LEN; i++) 127 | tempKey[i] ^= 0x36 ^ 0x5C; 128 | Sha512() 129 | .append(tempKey, BLOCK_LEN) 130 | .append(innerHash, HASH_LEN) 131 | .getHash(result); 132 | } 133 | 134 | 135 | uint64_t Sha512::rotr64(uint64_t x, int i) { 136 | return ((0U + x) << (64 - i)) | (x >> i); 137 | } 138 | 139 | 140 | const uint64_t Sha512::ROUND_CONSTANTS[NUM_ROUNDS] = { 141 | UINT64_C(0x428A2F98D728AE22), UINT64_C(0x7137449123EF65CD), UINT64_C(0xB5C0FBCFEC4D3B2F), UINT64_C(0xE9B5DBA58189DBBC), 142 | UINT64_C(0x3956C25BF348B538), UINT64_C(0x59F111F1B605D019), UINT64_C(0x923F82A4AF194F9B), UINT64_C(0xAB1C5ED5DA6D8118), 143 | UINT64_C(0xD807AA98A3030242), UINT64_C(0x12835B0145706FBE), UINT64_C(0x243185BE4EE4B28C), UINT64_C(0x550C7DC3D5FFB4E2), 144 | UINT64_C(0x72BE5D74F27B896F), UINT64_C(0x80DEB1FE3B1696B1), UINT64_C(0x9BDC06A725C71235), UINT64_C(0xC19BF174CF692694), 145 | UINT64_C(0xE49B69C19EF14AD2), UINT64_C(0xEFBE4786384F25E3), UINT64_C(0x0FC19DC68B8CD5B5), UINT64_C(0x240CA1CC77AC9C65), 146 | UINT64_C(0x2DE92C6F592B0275), UINT64_C(0x4A7484AA6EA6E483), UINT64_C(0x5CB0A9DCBD41FBD4), UINT64_C(0x76F988DA831153B5), 147 | UINT64_C(0x983E5152EE66DFAB), UINT64_C(0xA831C66D2DB43210), UINT64_C(0xB00327C898FB213F), UINT64_C(0xBF597FC7BEEF0EE4), 148 | UINT64_C(0xC6E00BF33DA88FC2), UINT64_C(0xD5A79147930AA725), UINT64_C(0x06CA6351E003826F), UINT64_C(0x142929670A0E6E70), 149 | UINT64_C(0x27B70A8546D22FFC), UINT64_C(0x2E1B21385C26C926), UINT64_C(0x4D2C6DFC5AC42AED), UINT64_C(0x53380D139D95B3DF), 150 | UINT64_C(0x650A73548BAF63DE), UINT64_C(0x766A0ABB3C77B2A8), UINT64_C(0x81C2C92E47EDAEE6), UINT64_C(0x92722C851482353B), 151 | UINT64_C(0xA2BFE8A14CF10364), UINT64_C(0xA81A664BBC423001), UINT64_C(0xC24B8B70D0F89791), UINT64_C(0xC76C51A30654BE30), 152 | UINT64_C(0xD192E819D6EF5218), UINT64_C(0xD69906245565A910), UINT64_C(0xF40E35855771202A), UINT64_C(0x106AA07032BBD1B8), 153 | UINT64_C(0x19A4C116B8D2D0C8), UINT64_C(0x1E376C085141AB53), UINT64_C(0x2748774CDF8EEB99), UINT64_C(0x34B0BCB5E19B48A8), 154 | UINT64_C(0x391C0CB3C5C95A63), UINT64_C(0x4ED8AA4AE3418ACB), UINT64_C(0x5B9CCA4F7763E373), UINT64_C(0x682E6FF3D6B2B8A3), 155 | UINT64_C(0x748F82EE5DEFB2FC), UINT64_C(0x78A5636F43172F60), UINT64_C(0x84C87814A1F0AB72), UINT64_C(0x8CC702081A6439EC), 156 | UINT64_C(0x90BEFFFA23631E28), UINT64_C(0xA4506CEBDE82BDE9), UINT64_C(0xBEF9A3F7B2C67915), UINT64_C(0xC67178F2E372532B), 157 | UINT64_C(0xCA273ECEEA26619C), UINT64_C(0xD186B8C721C0C207), UINT64_C(0xEADA7DD6CDE0EB1E), UINT64_C(0xF57D4F7FEE6ED178), 158 | UINT64_C(0x06F067AA72176FBA), UINT64_C(0x0A637DC5A2C898A6), UINT64_C(0x113F9804BEF90DAE), UINT64_C(0x1B710B35131C471B), 159 | UINT64_C(0x28DB77F523047D84), UINT64_C(0x32CAAB7B40C72493), UINT64_C(0x3C9EBE0A15C9BEBC), UINT64_C(0x431D67C49C100D4C), 160 | UINT64_C(0x4CC5D4BECB3E42B6), UINT64_C(0x597F299CFC657E2A), UINT64_C(0x5FCB6FAB3AD6FAEC), UINT64_C(0x6C44198C4A475817), 161 | }; 162 | -------------------------------------------------------------------------------- /cpp/Sha512.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | 14 | 15 | /* 16 | * Computes the SHA-512 hash of a sequence of bytes. The hash value is 64 bytes long. 17 | * Provides two static methods, and an instantiable stateful hasher. 18 | */ 19 | class Sha512 final { 20 | 21 | /*---- Scalar constants ----*/ 22 | 23 | public: static constexpr int HASH_LEN = 64; 24 | private: static constexpr int BLOCK_LEN = 128; 25 | private: static constexpr int NUM_ROUNDS = 80; 26 | 27 | 28 | 29 | /*---- Instance members ----*/ 30 | 31 | private: std::uint64_t state[8] = { 32 | UINT64_C(0x6A09E667F3BCC908), UINT64_C(0xBB67AE8584CAA73B), UINT64_C(0x3C6EF372FE94F82B), UINT64_C(0xA54FF53A5F1D36F1), 33 | UINT64_C(0x510E527FADE682D1), UINT64_C(0x9B05688C2B3E6C1F), UINT64_C(0x1F83D9ABFB41BD6B), UINT64_C(0x5BE0CD19137E2179), 34 | }; 35 | private: std::uint64_t length; 36 | private: std::uint8_t buffer[BLOCK_LEN]; 37 | private: int bufferLen; 38 | 39 | 40 | // Constructs a new SHA-512 hasher with an initially blank message. 41 | public: explicit Sha512(); 42 | 43 | 44 | // Appends message bytes to this ongoing hasher, and returns this object itself. 45 | public: Sha512 &append(const std::uint8_t bytes[], std::size_t len); 46 | 47 | 48 | // Returns the SHA-512 hash of all the bytes seen. Destroys the state so that no further append() or getHash() will be valid. 49 | public: void getHash(std::uint8_t result[HASH_LEN]); 50 | 51 | 52 | private: void compress(); 53 | 54 | 55 | 56 | /*---- Static functions ----*/ 57 | 58 | public: static void getHash(const std::uint8_t msg[], std::size_t len, std::uint8_t hashResult[HASH_LEN]); 59 | 60 | 61 | public: static void getHmac(const std::uint8_t key[], std::size_t keyLen, const std::uint8_t msg[], std::size_t msgLen, std::uint8_t result[HASH_LEN]); 62 | 63 | 64 | // Requires 1 <= i <= 63 65 | private: static std::uint64_t rotr64(std::uint64_t x, int i); 66 | 67 | 68 | 69 | /*---- Array constants ----*/ 70 | 71 | private: static const std::uint64_t ROUND_CONSTANTS[NUM_ROUNDS]; 72 | 73 | }; 74 | -------------------------------------------------------------------------------- /cpp/TestHelper.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Helper definitions and functions for runnable test suite programs. 3 | * 4 | * Bitcoin cryptography library 5 | * Copyright (c) Project Nayuki 6 | * 7 | * https://www.nayuki.io/page/bitcoin-cryptography-library 8 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 9 | */ 10 | 11 | #pragma once 12 | 13 | #undef NDEBUG 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | using std::size_t; 22 | using std::vector; 23 | 24 | typedef vector Bytes; 25 | 26 | 27 | Bytes asciiBytes(const char *str) { 28 | return Bytes(str, str + std::strlen(str)); 29 | } 30 | 31 | 32 | Bytes hexBytes(const char *str) { 33 | Bytes result; 34 | size_t length = std::strlen(str); 35 | assert(length % 2 == 0); 36 | for (size_t i = 0; i < length; i += 2) { 37 | unsigned int temp; 38 | std::sscanf(&str[i], "%02x", &temp); 39 | result.push_back(static_cast(temp)); 40 | } 41 | return result; 42 | } 43 | -------------------------------------------------------------------------------- /cpp/Uint256.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #include 10 | #include 11 | #include "AsmX8664.hpp" 12 | #include "CountOps.hpp" 13 | #include "Uint256.hpp" 14 | #include "Utils.hpp" 15 | 16 | using std::uint8_t; 17 | using std::uint32_t; 18 | using std::uint64_t; 19 | 20 | 21 | Uint256::Uint256() : 22 | value() {} 23 | 24 | 25 | Uint256::Uint256(const char *str) : 26 | value() { 27 | assert(str != nullptr && std::strlen(str) == NUM_WORDS * 8); 28 | for (int i = 0; i < NUM_WORDS * 8; i++) { 29 | int digit = Utils::parseHexDigit(str[NUM_WORDS * 8 - 1 - i]); 30 | assert(digit != -1); 31 | value[i >> 3] |= static_cast(digit) << ((i & 7) << 2); 32 | } 33 | } 34 | 35 | 36 | Uint256::Uint256(const uint8_t b[NUM_WORDS * 4]) : 37 | value() { 38 | assert(b != nullptr); 39 | for (int i = 0; i < NUM_WORDS * 4; i++) 40 | value[i >> 2] |= static_cast(b[NUM_WORDS * 4 - 1 - i]) << ((i & 3) << 3); 41 | } 42 | 43 | 44 | Uint256::Uint256(const FieldInt &val) { 45 | std::memcpy(this->value, val.value, sizeof(value)); 46 | } 47 | 48 | 49 | uint32_t Uint256::add(const Uint256 &other, uint32_t enable) { 50 | assert(&other != this && (enable >> 1) == 0); 51 | countOps(functionOps); 52 | if (USE_X8664_ASM_IMPL) { 53 | countOps(15 * arithmeticOps); 54 | return asm_Uint256_add(&this->value[0], &other.value[0], enable); 55 | } 56 | 57 | uint32_t mask = -enable; 58 | uint32_t carry = 0; 59 | countOps(2 * arithmeticOps); 60 | for (int i = 0; i < NUM_WORDS; i++) { 61 | countOps(loopBodyOps); 62 | uint64_t sum = static_cast(value[i]) + (other.value[i] & mask) + carry; 63 | value[i] = static_cast(sum); 64 | carry = static_cast(sum >> 32); 65 | assert((carry >> 1) == 0); 66 | countOps(8 * arithmeticOps); 67 | } 68 | return carry; 69 | } 70 | 71 | 72 | uint32_t Uint256::subtract(const Uint256 &other, uint32_t enable) { 73 | assert(&other != this && (enable >> 1) == 0); 74 | countOps(functionOps); 75 | if (USE_X8664_ASM_IMPL) { 76 | countOps(15 * arithmeticOps); 77 | return asm_Uint256_subtract(&this->value[0], &other.value[0], enable); 78 | } 79 | 80 | uint32_t mask = -enable; 81 | uint32_t borrow = 0; 82 | countOps(2 * arithmeticOps); 83 | for (int i = 0; i < NUM_WORDS; i++) { 84 | countOps(loopBodyOps); 85 | uint64_t diff = static_cast(value[i]) - (other.value[i] & mask) - borrow; 86 | value[i] = static_cast(diff); 87 | borrow = -static_cast(diff >> 32); 88 | assert((borrow >> 1) == 0); 89 | countOps(9 * arithmeticOps); 90 | } 91 | return borrow; 92 | } 93 | 94 | 95 | uint32_t Uint256::shiftLeft1() { 96 | countOps(functionOps); 97 | if (USE_X8664_ASM_IMPL) { 98 | countOps(6 * arithmeticOps); 99 | return asm_Uint256_shiftLeft1(&this->value[0]); 100 | } 101 | 102 | uint32_t prev = 0; 103 | countOps(1 * arithmeticOps); 104 | for (int i = 0; i < NUM_WORDS; i++) { 105 | countOps(loopBodyOps); 106 | uint32_t cur = value[i]; 107 | value[i] = (0U + cur) << 1 | prev >> 31; 108 | prev = cur; 109 | countOps(5 * arithmeticOps); 110 | } 111 | countOps(1 * arithmeticOps); 112 | return prev >> 31; 113 | } 114 | 115 | 116 | void Uint256::shiftRight1(uint32_t enable) { 117 | assert((enable >> 1) == 0); 118 | countOps(functionOps); 119 | if (USE_X8664_ASM_IMPL) { 120 | asm_Uint256_shiftRight1(&this->value[0], enable); 121 | countOps(21 * arithmeticOps); 122 | return; 123 | } 124 | 125 | uint32_t mask = -enable; 126 | uint32_t cur = value[0]; 127 | countOps(2 * arithmeticOps); 128 | for (int i = 0; i < NUM_WORDS - 1; i++) { 129 | countOps(loopBodyOps); 130 | uint32_t next = value[i + 1]; 131 | value[i] = ((cur >> 1 | (0U + next) << 31) & mask) | (cur & ~mask); 132 | cur = next; 133 | countOps(11 * arithmeticOps); 134 | } 135 | value[NUM_WORDS - 1] = ((cur >> 1) & mask) | (cur & ~mask); 136 | countOps(6 * arithmeticOps); 137 | } 138 | 139 | 140 | void Uint256::reciprocal(const Uint256 &modulus) { 141 | // Extended binary GCD algorithm 142 | assert(&modulus != this && (modulus.value[0] & 1) == 1 && modulus > ONE && *this < modulus); 143 | countOps(functionOps); 144 | Uint256 x = modulus; 145 | Uint256 y = *this; 146 | Uint256 a = ZERO; 147 | Uint256 b = ONE; 148 | Uint256 halfModulus = modulus; 149 | countOps(5 * uint256CopyOps); 150 | halfModulus.add(ONE); 151 | halfModulus.shiftRight1(); 152 | 153 | // Loop invariant: x = a*this mod modulus, and y = b*this mod modulus 154 | for (int i = 0; i < NUM_WORDS * 32 * 2; i++) { 155 | countOps(loopBodyOps); 156 | 157 | // Try to reduce a trailing zero of y. Pseudocode: 158 | // if (y % 2 == 0) { 159 | // y /= 2 160 | // b = b % 2 == 0 ? b / 2 : modulus - (modulus - b) / 2 161 | // } 162 | assert((x.value[0] & 1) == 1); 163 | uint32_t yEven = (y.value[0] & 1) ^ 1; 164 | uint32_t bOdd = b.value[0] & 1; 165 | y.shiftRight1(yEven); 166 | b.shiftRight1(yEven); 167 | b.add(halfModulus, yEven & bOdd); 168 | countOps(4 * arithmeticOps); 169 | 170 | // If allowed, try to swap so that y >= x and then do y -= x. Pseudocode: 171 | // if (y % 2 == 1) { 172 | // if (x > y) { 173 | // x, y = y, x 174 | // a, b = b, a 175 | // } 176 | // y -= x 177 | // b -= a 178 | // b %= modulus 179 | // } 180 | uint32_t enable = y.value[0] & 1; 181 | uint32_t doswap = enable & static_cast(x > y); 182 | x.swap(y, doswap); 183 | y.subtract(x, enable); 184 | a.swap(b, doswap); 185 | uint32_t borrow = b.subtract(a, enable); 186 | b.add(modulus, borrow); 187 | countOps(2 * arithmeticOps); 188 | } 189 | assert((x == ONE) | (x == modulus)); // Either gcd(this, modulus) = 1 or this = 0 190 | this->replace(a, static_cast(*this != ZERO)); 191 | } 192 | 193 | 194 | void Uint256::replace(const Uint256 &other, uint32_t enable) { 195 | assert((enable >> 1) == 0); 196 | countOps(functionOps); 197 | if (USE_X8664_ASM_IMPL) { 198 | asm_Uint256_replace(&this->value[0], &other.value[0], enable); 199 | countOps(9 * arithmeticOps); 200 | return; 201 | } 202 | 203 | uint32_t mask = -enable; 204 | countOps(1 * arithmeticOps); 205 | for (int i = 0; i < NUM_WORDS; i++) { 206 | countOps(loopBodyOps); 207 | value[i] = (other.value[i] & mask) | (value[i] & ~mask); 208 | countOps(6 * arithmeticOps); 209 | } 210 | } 211 | 212 | 213 | void Uint256::swap(Uint256 &other, uint32_t enable) { 214 | assert((enable >> 1) == 0); 215 | countOps(functionOps); 216 | if (USE_X8664_ASM_IMPL) { 217 | asm_Uint256_swap(&this->value[0], &other.value[0], enable); 218 | countOps(17 * arithmeticOps); 219 | return; 220 | } 221 | 222 | uint32_t mask = -enable; 223 | countOps(1 * arithmeticOps); 224 | for (int i = 0; i < NUM_WORDS; i++) { 225 | countOps(loopBodyOps); 226 | uint32_t x = this->value[i]; 227 | uint32_t y = other.value[i]; 228 | this->value[i] = (y & mask) | (x & ~mask); 229 | other.value[i] = (x & mask) | (y & ~mask); 230 | countOps(10 * arithmeticOps); 231 | } 232 | } 233 | 234 | 235 | void Uint256::getBigEndianBytes(uint8_t b[NUM_WORDS * 4]) const { 236 | assert(b != nullptr); 237 | for (int i = 0; i < NUM_WORDS; i++) 238 | Utils::storeBigUint32(value[i], &b[(NUM_WORDS - 1 - i) * 4]); 239 | } 240 | 241 | 242 | bool Uint256::operator==(const Uint256 &other) const { 243 | countOps(functionOps); 244 | if (USE_X8664_ASM_IMPL) { 245 | countOps(9 * arithmeticOps); 246 | return asm_Uint256_equalTo(&this->value[0], &other.value[0]); 247 | } 248 | 249 | uint32_t diff = 0; 250 | countOps(1 * arithmeticOps); 251 | for (int i = 0; i < NUM_WORDS; i++) { 252 | countOps(loopBodyOps); 253 | diff |= value[i] ^ other.value[i]; 254 | countOps(4 * arithmeticOps); 255 | } 256 | countOps(1 * arithmeticOps); 257 | return diff == 0; 258 | } 259 | 260 | 261 | bool Uint256::operator!=(const Uint256 &other) const { 262 | countOps(functionOps); 263 | countOps(1 * arithmeticOps); 264 | return !(*this == other); 265 | } 266 | 267 | 268 | bool Uint256::operator<(const Uint256 &other) const { 269 | countOps(functionOps); 270 | if (USE_X8664_ASM_IMPL) { 271 | countOps(18 * arithmeticOps); 272 | return asm_Uint256_lessThan(&this->value[0], &other.value[0]); 273 | } 274 | 275 | bool result = false; 276 | countOps(1 * arithmeticOps); 277 | for (int i = 0; i < NUM_WORDS; i++) { 278 | countOps(loopBodyOps); 279 | bool eq = value[i] == other.value[i]; 280 | result = (eq & result) | (!eq & (value[i] < other.value[i])); 281 | countOps(8 * arithmeticOps); 282 | } 283 | return result; 284 | } 285 | 286 | 287 | bool Uint256::operator<=(const Uint256 &other) const { 288 | countOps(functionOps); 289 | countOps(1 * arithmeticOps); 290 | return !(other < *this); 291 | } 292 | 293 | 294 | bool Uint256::operator>(const Uint256 &other) const { 295 | countOps(functionOps); 296 | return other < *this; 297 | } 298 | 299 | 300 | bool Uint256::operator>=(const Uint256 &other) const { 301 | countOps(functionOps); 302 | countOps(1 * arithmeticOps); 303 | return !(*this < other); 304 | } 305 | 306 | 307 | // Static initializers 308 | const Uint256 Uint256::ZERO; 309 | const Uint256 Uint256::ONE("0000000000000000000000000000000000000000000000000000000000000001"); 310 | -------------------------------------------------------------------------------- /cpp/Uint256.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | class FieldInt; // Forward declaration 14 | 15 | 16 | /* 17 | * An unsigned 256-bit integer, represented as eight unsigned 32-bit words in little endian. 18 | * All arithmetic operations are performed modulo 2^256 (the standard unsigned overflow behavior). 19 | * Instances of this class are mutable. All possible values are valid. 20 | * 21 | * For example, the integer 0x0123456789ABCDEF000000001111111122222222333333334444444455555555 is represented by 22 | * the array {0x55555555, 0x44444444, 0x33333333, 0x22222222, 0x11111111, 0x00000000, 0x89ABCDEF, 0x01234567}. 23 | */ 24 | class Uint256 { 25 | 26 | public: static constexpr int NUM_WORDS = 8; 27 | 28 | /*---- Fields ----*/ 29 | 30 | // The mutable words representing this number in little endian, conceptually like this: 31 | // actualValue = value[0] << 0 | value[1] << 32 | ... | value[7] << 224. 32 | public: std::uint32_t value[NUM_WORDS]; 33 | 34 | 35 | 36 | /*---- Constructors ----*/ 37 | 38 | // Constructs a Uint256 initialized to zero. Constant-time. 39 | // For clarity, only use this constructor if the variable will be overwritten immediately 40 | // (pretend that this constructor leaves the value array uninitialized). 41 | // For actual zero values, please explicitly initialize them with: Uint256 num(Uint256::ZERO); 42 | public: explicit Uint256(); 43 | 44 | 45 | // Constructs a Uint256 from the given 64-character hexadecimal string. Not constant-time. 46 | // If the syntax of the string is invalid, then an assertion will fail. 47 | public: explicit Uint256(const char *str); 48 | 49 | 50 | // Constructs a Uint256 from the given 32 bytes encoded in big-endian. 51 | // Constant-time with respect to the input array values. All possible values are valid. 52 | public: explicit Uint256(const std::uint8_t b[NUM_WORDS * 4]); 53 | 54 | 55 | // Constructs a Uint256 from the given FieldInt. Constant-time with respect to the given value. 56 | // All possible FieldInt values are valid. 57 | public: explicit Uint256(const FieldInt &val); 58 | 59 | 60 | 61 | /*---- Arithmetic methods ----*/ 62 | 63 | // Adds the given number into this number, modulo 2^256. The other number must be a distinct object. 64 | // Enable must be 1 to perform the operation or 0 to do nothing. Returns the carry-out bit, which is 0 or 1. 65 | // Constant-time with respect to both values and the enable. 66 | public: std::uint32_t add(const Uint256 &other, std::uint32_t enable=1); 67 | 68 | 69 | // Subtracts the given number from this number, modulo 2^256. The other number must be a distinct object. 70 | // Enable must be 1 to perform the operation or 0 to do nothing. Returns the borrow-out bit, which is 0 or 1. 71 | // Constant-time with respect to both values and the enable. 72 | public: std::uint32_t subtract(const Uint256 &other, std::uint32_t enable=1); 73 | 74 | 75 | // Shifts this number left by 1 bit (same as multiplying by 2), modulo 2^256. 76 | // Returns the old leftmost bit, which is 0 or 1. Constant-time with respect to this value. 77 | public: std::uint32_t shiftLeft1(); 78 | 79 | 80 | // Shifts this number right by 1 bit (same as dividing by 2 and flooring). 81 | // Enable must be 1 to perform the operation or 0 to do nothing. 82 | // Constant-time with respect to this value and the enable. 83 | public: void shiftRight1(std::uint32_t enable=1); 84 | 85 | 86 | // Computes the multiplicative inverse of this number with respect to the given modulus. 87 | // The modulus must be odd and coprime to this number. This number must be less than the modulus. 88 | // If this number is zero, the reciprocal is zero. Constant-time with respect to this value. 89 | public: void reciprocal(const Uint256 &modulus); 90 | 91 | 92 | /*---- Miscellaneous methods ----*/ 93 | 94 | // Copies the given number into this number if enable is 1, or does nothing if enable is 0. 95 | // Constant-time with respect to both values and the enable. 96 | public: void replace(const Uint256 &other, std::uint32_t enable); 97 | 98 | 99 | // Swaps the value of this number with the given number if enable is 1, or does nothing if enable is 0. 100 | // Constant-time with respect to both values and the enable. 101 | public: void swap(Uint256 &other, std::uint32_t enable); 102 | 103 | 104 | // Writes this 256-bit integer as 32 bytes encoded in big endian to the given array. 105 | // Constant-time with respect to this value. 106 | public: void getBigEndianBytes(std::uint8_t b[NUM_WORDS * 4]) const; 107 | 108 | 109 | /*---- Equality/inequality operators ----*/ 110 | 111 | // Tests whether this number is equal to the given number. Constant-time with respect to both values. 112 | public: bool operator==(const Uint256 &other) const; 113 | 114 | // Tests whether this number is unequal to the given number. Constant-time with respect to both values. 115 | public: bool operator!=(const Uint256 &other) const; 116 | 117 | 118 | // Tests whether this number is less than the given number. Constant-time with respect to both values. 119 | public: bool operator<(const Uint256 &other) const; 120 | 121 | // Tests whether this number is less than or equal to the given number. Constant-time with respect to both values. 122 | public: bool operator<=(const Uint256 &other) const; 123 | 124 | // Tests whether this number is greater than the given number. Constant-time with respect to both values. 125 | public: bool operator>(const Uint256 &other) const; 126 | 127 | // Tests whether this number is greater than or equal to the given number. Constant-time with respect to both values. 128 | public: bool operator>=(const Uint256 &other) const; 129 | 130 | 131 | 132 | /*---- Class constants ----*/ 133 | 134 | public: static const Uint256 ZERO; 135 | public: static const Uint256 ONE; 136 | 137 | }; 138 | 139 | 140 | #include "FieldInt.hpp" 141 | -------------------------------------------------------------------------------- /cpp/Utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #include 10 | #include "Utils.hpp" 11 | 12 | using std::uint8_t; 13 | 14 | 15 | int Utils::parseHexDigit(int ch) { 16 | if ('0' <= ch && ch <= '9') 17 | return ch - '0'; 18 | else if ('a' <= ch && ch <= 'f') 19 | return ch - 'a' + 10; 20 | else if ('A' <= ch && ch <= 'F') 21 | return ch - 'A' + 10; 22 | else 23 | return -1; 24 | } 25 | 26 | 27 | void Utils::copyBytes(void *dest, const void *src, std::size_t count) { 28 | if (count > 0) 29 | std::memmove(dest, src, count); 30 | } 31 | 32 | 33 | void Utils::storeBigUint32(std::uint32_t x, uint8_t arr[4]) { 34 | arr[0] = static_cast(x >> 24); 35 | arr[1] = static_cast(x >> 16); 36 | arr[2] = static_cast(x >> 8); 37 | arr[3] = static_cast(x >> 0); 38 | } 39 | 40 | 41 | const char *Utils::HEX_DIGITS = "0123456789abcdef"; 42 | -------------------------------------------------------------------------------- /cpp/Utils.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | 14 | 15 | /* 16 | * Miscellaneous utilities used in a variety of places. 17 | */ 18 | class Utils final { 19 | 20 | public: static const char *HEX_DIGITS; 21 | 22 | 23 | // Returns the numerical value of a hexadecimal digit character 24 | // (e.g. '9' -> 9, 'a' -> 10, 'B' -> 11), or -1 if the character is invalid. 25 | public: static int parseHexDigit(int ch); 26 | 27 | 28 | // A safe wrapper over memmove() to avoid undefined behavior. This function can be a drop-in replacement 29 | // for both memcpy() and memmove(). It is useful when count is a variable number that is sometimes zero. 30 | // Note that src and dest can overlap. 31 | // The function returns immediately if count is 0. This is safer than calling memmove() with a count of 0, because 32 | // it would be undefined behavior if src or dest is null, or if either one is pointing to the end of an array. 33 | // The function is not helpful for code that calls memcpy/memmove with a known positive constant count value. 34 | public: static void copyBytes(void *dest, const void *src, std::size_t count); 35 | 36 | 37 | public: static void storeBigUint32(std::uint32_t x, std::uint8_t arr[4]); 38 | 39 | 40 | Utils() = delete; // Not instantiable 41 | 42 | }; 43 | -------------------------------------------------------------------------------- /java/io/nayuki/bitcoin/crypto/Base58Check.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | package io.nayuki.bitcoin.crypto; 10 | 11 | import java.io.ByteArrayOutputStream; 12 | import java.io.IOException; 13 | import java.math.BigInteger; 14 | import java.util.Arrays; 15 | 16 | 17 | /** 18 | * Converts between an array of bytes and a Base58Check string. Not instantiable. 19 | */ 20 | public final class Base58Check { 21 | 22 | /*---- Static functions ----*/ 23 | 24 | // Adds the checksum and converts to Base58Check. Note that the caller needs to prepend the version byte(s). 25 | public static String bytesToBase58(byte[] data) { 26 | return rawBytesToBase58(addCheckHash(data)); 27 | } 28 | 29 | 30 | // Directly converts to Base58Check without adding a checksum. 31 | static String rawBytesToBase58(byte[] data) { 32 | // Convert to base-58 string 33 | StringBuilder sb = new StringBuilder(); 34 | BigInteger num = new BigInteger(1, data); 35 | while (num.signum() != 0) { 36 | BigInteger[] quotrem = num.divideAndRemainder(ALPHABET_SIZE); 37 | sb.append(ALPHABET.charAt(quotrem[1].intValue())); 38 | num = quotrem[0]; 39 | } 40 | 41 | // Add '1' characters for leading 0-value bytes 42 | for (int i = 0; i < data.length && data[i] == 0; i++) 43 | sb.append(ALPHABET.charAt(0)); 44 | return sb.reverse().toString(); 45 | } 46 | 47 | 48 | // Returns a new byte array by concatenating the given array with its checksum. 49 | static byte[] addCheckHash(byte[] data) { 50 | try { 51 | byte[] hash = Arrays.copyOf(Sha256.getDoubleHash(data).toBytes(), 4); 52 | ByteArrayOutputStream buf = new ByteArrayOutputStream(); 53 | buf.write(data); 54 | buf.write(hash); 55 | return buf.toByteArray(); 56 | } catch (IOException e) { 57 | throw new AssertionError(e); 58 | } 59 | } 60 | 61 | 62 | // Converts the given Base58Check string to a byte array, verifies the checksum, and removes the checksum to return the payload. 63 | // The caller is responsible for handling the version byte(s). 64 | public static byte[] base58ToBytes(String s) { 65 | byte[] concat = base58ToRawBytes(s); 66 | byte[] data = Arrays.copyOf(concat, concat.length - 4); 67 | byte[] hash = Arrays.copyOfRange(concat, concat.length - 4, concat.length); 68 | byte[] rehash = Arrays.copyOf(Sha256.getDoubleHash(data).toBytes(), 4); 69 | if (!Arrays.equals(rehash, hash)) 70 | throw new IllegalArgumentException("Checksum mismatch"); 71 | return data; 72 | } 73 | 74 | 75 | // Converts the given Base58Check string to a byte array, without checking or removing the trailing 4-byte checksum. 76 | static byte[] base58ToRawBytes(String s) { 77 | // Parse base-58 string 78 | BigInteger num = BigInteger.ZERO; 79 | for (int i = 0; i < s.length(); i++) { 80 | num = num.multiply(ALPHABET_SIZE); 81 | int digit = ALPHABET.indexOf(s.charAt(i)); 82 | if (digit == -1) 83 | throw new IllegalArgumentException("Invalid character for Base58Check"); 84 | num = num.add(BigInteger.valueOf(digit)); 85 | } 86 | 87 | // Strip possible leading zero due to mandatory sign bit 88 | byte[] b = num.toByteArray(); 89 | if (b[0] == 0) 90 | b = Arrays.copyOfRange(b, 1, b.length); 91 | 92 | try { 93 | // Convert leading '1' characters to leading 0-value bytes 94 | ByteArrayOutputStream buf = new ByteArrayOutputStream(); 95 | for (int i = 0; i < s.length() && s.charAt(i) == ALPHABET.charAt(0); i++) 96 | buf.write(0); 97 | buf.write(b); 98 | return buf.toByteArray(); 99 | } catch (IOException e) { 100 | throw new AssertionError(e); 101 | } 102 | } 103 | 104 | 105 | 106 | /*---- Class constants ----*/ 107 | 108 | public static final String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; // Everything except 0OIl 109 | private static final BigInteger ALPHABET_SIZE = BigInteger.valueOf(ALPHABET.length()); 110 | 111 | 112 | 113 | /*---- Miscellaneous ----*/ 114 | 115 | private Base58Check() {} // Not instantiable 116 | 117 | } 118 | -------------------------------------------------------------------------------- /java/io/nayuki/bitcoin/crypto/Base58CheckTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | package io.nayuki.bitcoin.crypto; 10 | 11 | import java.security.SecureRandom; 12 | import java.util.Random; 13 | import org.junit.Assert; 14 | import org.junit.Test; 15 | 16 | 17 | /** 18 | * Tests the functions of the Base58Check class. 19 | * @see Base58Check 20 | */ 21 | public final class Base58CheckTest { 22 | 23 | /*---- Test cases ----*/ 24 | 25 | // Tests simple fixed test vectors. 26 | @Test public void testBasic() { 27 | test("", "3QJmnh"); 28 | test("FF", "VrZDWwe"); 29 | test("00", "1Wh4bh"); 30 | test("0000", "112edB6q"); 31 | test("00010966776006953D5567439E5E39F86A0D273BEE", "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM"); 32 | } 33 | 34 | 35 | // Tests a round trip from bytes to Base58Check string and back to bytes. 36 | @Test public void testRandom() { 37 | for (int i = 0; i < 10000; i++) { 38 | byte[] b = new byte[rand.nextInt(300) + 1]; 39 | rand.nextBytes(b); 40 | String s = Base58Check.bytesToBase58(b); 41 | Assert.assertArrayEquals(b, Base58Check.base58ToBytes(s)); 42 | } 43 | } 44 | 45 | 46 | // Tests perturbing the checksum. 47 | @Test public void testRandomCorrupt() { 48 | for (int i = 0; i < 3000; i++) { 49 | byte[] b = new byte[rand.nextInt(300) + 1]; 50 | rand.nextBytes(b); 51 | byte[] temp = Base58Check.addCheckHash(b); 52 | boolean changed = false; 53 | for (int j = 0; j < 4; j++) { 54 | if (rand.nextDouble() < 0.8) { 55 | temp[temp.length - 1 - j] += rand.nextInt(255) + 1; 56 | changed = true; 57 | } 58 | } 59 | if (changed) { 60 | try { 61 | String bad = Base58Check.rawBytesToBase58(temp); 62 | String good = Base58Check.bytesToBase58(b); 63 | Assert.assertFalse(bad.equals(good)); 64 | Base58Check.base58ToBytes(bad); 65 | Assert.fail(); 66 | } catch (IllegalArgumentException e) {} // Pass 67 | } 68 | } 69 | } 70 | 71 | 72 | 73 | /*---- Helper functions ----*/ 74 | 75 | private static void test(String hexBytes, String expectBase58) { 76 | byte[] bytes = Utils.hexToBytes(hexBytes); 77 | Assert.assertEquals(expectBase58, Base58Check.bytesToBase58(bytes)); 78 | Assert.assertArrayEquals(bytes, Base58Check.base58ToBytes(expectBase58)); 79 | } 80 | 81 | 82 | private static Random rand = new SecureRandom(); 83 | 84 | } 85 | -------------------------------------------------------------------------------- /java/io/nayuki/bitcoin/crypto/Bech32.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | package io.nayuki.bitcoin.crypto; 10 | 11 | import java.io.ByteArrayOutputStream; 12 | import java.io.IOException; 13 | import java.util.Arrays; 14 | import java.util.Objects; 15 | 16 | 17 | /** 18 | * Converts data to and from Bech32 strings. Not instantiable. 19 | */ 20 | public final class Bech32 { 21 | 22 | /*---- Static functions for segregated witness addresses ----*/ 23 | 24 | /** 25 | * Encodes the specified segregated witness output into a Bech32 address string. 26 | * @param humanPart the prefix given to the resulting string, which should be a mnemonic for 27 | * the cryptocurrency name; must be not {@code null}, must have length in the range [1, 83], 28 | * must have all characters in the ASCII range [33, 126] but excluding uppercase characters 29 | * @param witVer the witness version number; must be in the range [0, 16] 30 | * @param witProg the raw witness program, without the length byte; 31 | * must be not {@code null}, must have length in the range [2, 40] 32 | * @return the Bech32 address of the specified segregated witness output; 33 | * the result is entirely ASCII, lacks uppercase, and at most 90 characters long 34 | * @throws NullPointerException if humanPart or witProg is {@code null} 35 | * @throws IllegalArgumentException if any argument violates the stated preconditions, 36 | * or the combination of humanPart and witProg would make the result exceed 90 characters 37 | */ 38 | public static String segwitToBech32(String humanPart, int witVer, byte[] witProg) { 39 | // Check arguments 40 | Objects.requireNonNull(humanPart); 41 | Objects.requireNonNull(witProg); 42 | if (witVer < 0 || witVer > 16) 43 | throw new IllegalArgumentException("Invalid witness version"); 44 | if (witProg.length < 2 || witProg.length > 40) 45 | throw new IllegalArgumentException("Invalid witness program length"); 46 | 47 | // Create buffer of 5-bit groups 48 | ByteArrayOutputStream data = new ByteArrayOutputStream(); // Every element is uint5 49 | assert (witVer >>> 5) == 0; 50 | data.write(witVer); // uint5 51 | 52 | // Variables/constants for bit processing 53 | final int IN_BITS = 8; 54 | final int OUT_BITS = 5; 55 | int inputIndex = 0; 56 | int bitBuffer = 0; // Topmost bitBufferLen bits are valid; remaining lower bits are zero 57 | int bitBufferLen = 0; // Always in the range [0, 12] 58 | 59 | // Repack all 8-bit bytes into 5-bit groups, adding padding 60 | while (inputIndex < witProg.length || bitBufferLen > 0) { 61 | assert 0 <= bitBufferLen && bitBufferLen <= IN_BITS + OUT_BITS - 1; 62 | assert (bitBuffer << bitBufferLen) == 0; 63 | 64 | if (bitBufferLen < OUT_BITS) { 65 | if (inputIndex < witProg.length) { // Read a byte 66 | bitBuffer |= (witProg[inputIndex] & 0xFF) << (32 - IN_BITS - bitBufferLen); 67 | inputIndex++; 68 | bitBufferLen += IN_BITS; 69 | } else // Create final padding 70 | bitBufferLen = OUT_BITS; 71 | } 72 | assert bitBufferLen >= 5; 73 | 74 | // Write a 5-bit group 75 | data.write(bitBuffer >>> (32 - OUT_BITS)); // uint5 76 | bitBuffer <<= OUT_BITS; 77 | bitBufferLen -= OUT_BITS; 78 | } 79 | return bitGroupsToBech32(humanPart, data.toByteArray()); 80 | } 81 | 82 | 83 | /** 84 | * Decodes the specified Bech32 address string into a segregated witness output. 85 | * The result is a triple (human-readable part, witness version, witness program). 86 | * @param s the Bech32 string to decode, which must be either 87 | * all-lowercase or all-uppercase, and at most 90 characters long 88 | * @return a triple where index 0 is a {@code String} representing the human-readable part 89 | * (which obeys all the rules as stated in the encoder), index 1 is an {@code Integer} 90 | * representing the witness version (in the range [0, 16]), and index 2 is a new 91 | * {@code byte[]} containing the witness program (whose length is in the range [2, 40]; 92 | * the array contains 8-bit data) 93 | * @throws NullPointerException if the string is {@code null} 94 | * @throws IllegalArgumentException if the string is too long, has mixed case, 95 | * lacks a separator, has an invalid human-readable part, has non-base-32 96 | * characters in the data, lacks a full checksum, has an incorrect checksum, 97 | * has an invalid witness version, or has an invalid length of witness program 98 | */ 99 | public static Object[] bech32ToSegwit(String s) { 100 | Object[] decoded = bech32ToBitGroups(s); 101 | byte[] data = (byte[])decoded[1]; 102 | 103 | // Extract leading value representing version 104 | if (data.length < 1) 105 | throw new IllegalArgumentException("Missing witness version"); 106 | int witVer = data[0]; 107 | if (witVer < 0 || witVer > 16) 108 | throw new IllegalArgumentException("Invalid witness version"); 109 | 110 | // Initialize output array 111 | byte[] witProg = new byte[(data.length - 1) * 5 / 8]; // Discard version prefix and padding suffix 112 | if (witProg.length < 2 || witProg.length > 40) 113 | throw new IllegalArgumentException("Invalid witness program length"); 114 | 115 | // Variables/constants for bit processing 116 | final int IN_BITS = 5; 117 | final int OUT_BITS = 8; 118 | int outputIndex = 0; 119 | int bitBuffer = 0; // Topmost bitBufferLen bits are valid; remaining lower bits are zero 120 | int bitBufferLen = 0; // Always in the range [0, 10] 121 | 122 | // Repack all 5-bit groups into 8-bit bytes, discarding padding 123 | for (int i = 1; i < data.length; i++) { 124 | int b = data[i]; 125 | assert 0 <= bitBufferLen && bitBufferLen <= IN_BITS * 2; 126 | assert (bitBuffer << bitBufferLen) == 0; 127 | 128 | bitBuffer |= b << (32 - IN_BITS - bitBufferLen); 129 | bitBufferLen += IN_BITS; 130 | 131 | if (bitBufferLen >= OUT_BITS) { 132 | witProg[outputIndex] = (byte)(bitBuffer >>> (32 - OUT_BITS)); 133 | outputIndex++; 134 | bitBuffer <<= OUT_BITS; 135 | bitBufferLen -= OUT_BITS; 136 | } 137 | } 138 | 139 | // Final checks and return 140 | assert outputIndex == witProg.length; 141 | if (bitBuffer != 0) 142 | throw new IllegalArgumentException("Non-zero padding"); 143 | return new Object[]{decoded[0], witVer, witProg}; 144 | } 145 | 146 | 147 | 148 | /*---- Static functions for bit groups ----*/ 149 | 150 | /** 151 | * Encodes the specified human-readable part prefix plus 152 | * the specified array of 5-bit data into a Bech32 string. 153 | * @param humanPart the prefix given to the resulting string, which should be a mnemonic for 154 | * the cryptocurrency name; must be not {@code null}, must have length in the range [1, 83], 155 | * must have all characters in the ASCII range [33, 126] but excluding uppercase characters 156 | * @param data a non-{@code null} sequence of zero or more values, where each value is a uint5 157 | * @return the Bech32 string representing the specified two pieces of data; 158 | * the result is entirely ASCII, lacks uppercase, and at most 90 characters long 159 | * @throws NullPointerException if the string or data is {@code null} 160 | * @throws IllegalArgumentException if any argument violates the stated 161 | * preconditions, or {@code humanPart.length() + data.length > 83} 162 | */ 163 | public static String bitGroupsToBech32(String humanPart, byte[] data) { 164 | // Check arguments 165 | Objects.requireNonNull(humanPart); 166 | Objects.requireNonNull(data); 167 | char[] human = humanPart.toCharArray(); 168 | checkHumanReadablePart(human); 169 | for (byte b : data) { 170 | if ((b >>> 5) != 0) 171 | throw new IllegalArgumentException("Expected 5-bit groups"); 172 | } 173 | if (human.length + 1 + data.length + 6 > 90) 174 | throw new IllegalArgumentException("Output too long"); 175 | 176 | // Compute checksum 177 | int checksum; 178 | try { 179 | ByteArrayOutputStream temp = expandHumanReadablePart(human); // Every element is uint5 180 | temp.write(data); 181 | temp.write(new byte[CHECKSUM_LEN]); 182 | checksum = polymod(temp.toByteArray()) ^ 1; 183 | } catch (IOException e) { 184 | throw new AssertionError(e); // Impossible 185 | } 186 | 187 | // Encode to base-32 188 | StringBuilder sb = new StringBuilder(humanPart).append('1'); 189 | for (byte b : data) 190 | sb.append(ALPHABET.charAt(b)); 191 | for (int i = 0; i < CHECKSUM_LEN; i++) { 192 | int b = (checksum >>> ((CHECKSUM_LEN - 1 - i) * 5)) & 0x1F; // uint5 193 | sb.append(ALPHABET.charAt(b)); 194 | } 195 | return sb.toString(); 196 | } 197 | 198 | 199 | /** 200 | * Decodes the specified Bech32 string into a human-readable part and an array of 5-bit data. 201 | * @param s the Bech32 string to decode, which must be either 202 | * all-lowercase or all-uppercase, and at most 90 characters long 203 | * @return a pair where index 0 is a {@code String} representing the human-readable part 204 | * (which obeys all the rules as stated in the encoder), and index 1 is a new 205 | * {@code byte[]} containing the 5-bit data (whose length is in the range [0, 82]) 206 | * @throws NullPointerException if the string is {@code null} 207 | * @throws IllegalArgumentException if the string is too long, has mixed case, 208 | * lacks a separator, has an invalid human-readable part, has non-base-32 209 | * characters in the data, lacks a full checksum, or has an incorrect checksum 210 | */ 211 | public static Object[] bech32ToBitGroups(String s) { 212 | // Basic checks 213 | Objects.requireNonNull(s); 214 | if (s.length() > 90) 215 | throw new IllegalArgumentException("Input too long"); 216 | 217 | { // Normalize to lowercase, rejecting mixed case 218 | boolean hasLower = false; 219 | char[] temp = s.toCharArray(); 220 | for (int i = 0; i < temp.length; i++) { 221 | char c = temp[i]; 222 | hasLower |= 'a' <= c && c <= 'z'; 223 | if ('A' <= c && c <= 'Z') { 224 | if (hasLower) 225 | throw new IllegalArgumentException("String has mixed case"); 226 | temp[i] += 'a' - 'A'; 227 | } 228 | } 229 | s = new String(temp); 230 | } 231 | 232 | // Split human-readable part and data 233 | String humanPart; 234 | { 235 | int i = s.lastIndexOf('1'); 236 | if (i == -1) 237 | throw new IllegalArgumentException("No separator found"); 238 | humanPart = s.substring(0, i); 239 | s = s.substring(i + 1); 240 | } 241 | char[] human = humanPart.toCharArray(); 242 | checkHumanReadablePart(human); 243 | 244 | // Decode from base-32 245 | if (s.length() < CHECKSUM_LEN) 246 | throw new IllegalArgumentException("Data too short"); 247 | byte[] dataAndCheck = new byte[s.length()]; // Every element is uint5 248 | for (int i = 0; i < s.length(); i++) { 249 | int index = ALPHABET.indexOf(s.charAt(i)); 250 | if (index == -1) 251 | throw new IllegalArgumentException("Invalid data character"); 252 | dataAndCheck[i] = (byte)index; 253 | } 254 | 255 | try { // Verify checksum 256 | ByteArrayOutputStream temp = expandHumanReadablePart(human); 257 | temp.write(dataAndCheck); 258 | if (polymod(temp.toByteArray()) != 1) 259 | throw new IllegalArgumentException("Checksum mismatch"); 260 | } catch (IOException e) { 261 | throw new AssertionError(e); // Impossible 262 | } 263 | 264 | // Remove checksum, return pair 265 | byte[] data = Arrays.copyOf(dataAndCheck, dataAndCheck.length - CHECKSUM_LEN); 266 | return new Object[]{humanPart, data}; 267 | } 268 | 269 | 270 | // Throws an exception if any of the following: 271 | // * Its length is outside the range [1, 83]. 272 | // * It contains non-ASCII characters outside the range [33, 126]. 273 | // * It contains uppercase characters. 274 | // Otherwise returns silently. 275 | static void checkHumanReadablePart(char[] s) { 276 | int n = s.length; 277 | if (n < 1 || n > 83) 278 | throw new IllegalArgumentException("Invalid length of human-readable part string"); 279 | 280 | for (char c : s) { 281 | if (c < 33 || c > 126) 282 | throw new IllegalArgumentException("Invalid character in human-readable part string"); 283 | if ('A' <= c && c <= 'Z') 284 | throw new IllegalArgumentException("Human-readable part string must be lowercase"); 285 | } 286 | } 287 | 288 | 289 | // Returns a new byte buffer containing uint5 values, representing the given string 290 | // expanded into the prefix data for the purpose of computing/verifying a checksum. 291 | private static ByteArrayOutputStream expandHumanReadablePart(char[] s) { 292 | ByteArrayOutputStream result = new ByteArrayOutputStream(); // Every element is uint5 293 | for (char c : s) 294 | result.write(c >>> 5); // uint3 from high bits 295 | result.write(0); 296 | for (char c : s) 297 | result.write(c & 0x1F); // uint5 from low bits 298 | return result; 299 | } 300 | 301 | 302 | // Computes the polynomial remainder of the given sequence of 5-bit groups. The result is a uint30. 303 | private static int polymod(byte[] data) { 304 | int result = 1; 305 | for (byte b : data) { 306 | assert 0 <= b && b < 32; // uint5 307 | int x = result >>> 25; 308 | result = ((result & ((1 << 25) - 1)) << 5) | b; 309 | for (int i = 0; i < GENERATOR.length; i++) 310 | result ^= ((x >>> i) & 1) * GENERATOR[i]; 311 | assert (result >>> 30) == 0; // uint30 312 | } 313 | return result; 314 | } 315 | 316 | 317 | 318 | /*---- Class constants ----*/ 319 | 320 | // The base-32 alphabet. Designed so that visually similar characters having small bit differences. 321 | private static final String ALPHABET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; 322 | 323 | // For computing/verifying checksums. Each element is a uint30. 324 | private static final int[] GENERATOR = {0x3B6A57B2, 0x26508E6D, 0x1EA119FA, 0x3D4233DD, 0x2A1462B3}; 325 | 326 | // Number of uint5 groups. Do not modify. 327 | private static final int CHECKSUM_LEN = 6; 328 | 329 | 330 | 331 | /*---- Miscellaneous ----*/ 332 | 333 | private Bech32() {} // Not instantiable 334 | 335 | } 336 | -------------------------------------------------------------------------------- /java/io/nayuki/bitcoin/crypto/Bech32Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | package io.nayuki.bitcoin.crypto; 10 | 11 | import static org.junit.Assert.assertArrayEquals; 12 | import static org.junit.Assert.assertEquals; 13 | import org.junit.Assert; 14 | import org.junit.Test; 15 | 16 | 17 | /** 18 | * Tests the functions of the Bech32 class. 19 | * @see Bech32 20 | */ 21 | public final class Bech32Test { 22 | 23 | @Test public void testSegwitToAndFromBech32() { 24 | String[][] cases = { 25 | {"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", "bc", "0", "751E76E8199196D454941C45D1B3A323F1433BD6"}, 26 | {"tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx", "tb", "0", "751E76E8199196D454941C45D1B3A323F1433BD6"}, 27 | {"bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3", "bc", "0", "1863143C14C5166804BD19203356DA136C985678CD4D27A1B8C6329604903262"}, 28 | {"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", "tb", "0", "1863143C14C5166804BD19203356DA136C985678CD4D27A1B8C6329604903262"}, 29 | }; 30 | for (String[] cs : cases) { 31 | assertEquals(cs[0], Bech32.segwitToBech32(cs[1], Integer.parseInt(cs[2]), Utils.hexToBytes(cs[3]))); 32 | Object[] temp = Bech32.bech32ToSegwit(cs[0]); 33 | assertEquals(cs[1], temp[0]); 34 | assertEquals(Integer.valueOf(cs[2]), temp[1]); 35 | assertArrayEquals((byte[])temp[2], Utils.hexToBytes(cs[3])); 36 | } 37 | } 38 | 39 | 40 | @Test public void testBitGroupsToAndFromBech32() { 41 | Object[][] cases = { 42 | {"a12uel5l", "a", new byte[0]}, 43 | {"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio", new byte[0]}, 44 | {"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", "abcdef", new byte[]{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31}}, 45 | {"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", "1", new byte[82]}, 46 | {"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", "split", new byte[]{24,23,25,24,22,28,1,16,11,29,8,25,23,29,19,13,16,23,29,22,25,28,1,16,11,3,25,29,27,25,3,3,29,19,11,25,3,3,25,13,24,29,1,25,3,3,25,13}}, 47 | {"?1ezyfcl", "?", new byte[0]}, 48 | }; 49 | for (Object[] cs : cases) { 50 | assertEquals(cs[0], Bech32.bitGroupsToBech32((String)cs[1], (byte[])cs[2])); 51 | Object[] temp = Bech32.bech32ToBitGroups((String)cs[0]); 52 | assertEquals(cs[1], temp[0]); 53 | assertArrayEquals((byte[])cs[2], (byte[])temp[1]); 54 | } 55 | } 56 | 57 | 58 | @Test public void testCheckHumanReadablePartValid() { 59 | String[] cases = { 60 | "a", 61 | "bc", 62 | "1", 63 | "111", 64 | "the-quick.brown*fox", 65 | }; 66 | for (String cs : cases) 67 | Bech32.checkHumanReadablePart(cs.toCharArray()); 68 | } 69 | 70 | 71 | @Test public void testCheckHumanReadablePartInvalid() { 72 | String[] cases = { 73 | "", 74 | "012345678901234567890123456789012345678901234567890123456789012345678901234567890123", 75 | "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", 76 | "A", 77 | "xXx", 78 | "\u0020", 79 | "\u007F", 80 | "\u0080", 81 | "\u2000", 82 | "\uD852\uDF62", 83 | }; 84 | for (String cs : cases) { 85 | try { 86 | Bech32.checkHumanReadablePart(cs.toCharArray()); 87 | Assert.fail(); 88 | } catch (IllegalArgumentException e) {} // Pass 89 | } 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /java/io/nayuki/bitcoin/crypto/CurvePointMath.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | package io.nayuki.bitcoin.crypto; 10 | 11 | import static io.nayuki.bitcoin.crypto.Int256Math.NUM_WORDS; 12 | import java.util.Arrays; 13 | 14 | 15 | /** 16 | * Performs arithmetic on elliptic curve points, which are represented as 24 consecutive ints. 17 | * A curve point is a tuple of 3 field integers (x, y, z) in projective coordinates. 18 | * The ordinary affine coordinates of the point is (x/z, y/z), which can be obtained by normalizing. 19 | */ 20 | public final class CurvePointMath { 21 | 22 | /*---- Critical class constants ----*/ 23 | 24 | static final int POINT_WORDS = 3 * NUM_WORDS; 25 | 26 | 27 | /*---- Arithmetic functions ----*/ 28 | 29 | // Doubles the given curve point. Requires 64 words of temporary space. 30 | // The resulting point is usually not normalized. Constant-time with respect to the point. 31 | public static void twice(int[] val, int pOff, int tempOff) { 32 | /* 33 | * (See https://www.nayuki.io/page/elliptic-curve-point-addition-in-projective-coordinates) 34 | * Algorithm pseudocode: 35 | * if (this == ZERO || y == 0) 36 | * this = ZERO 37 | * else { 38 | * a = 0 (curve parameter) 39 | * t = 3 * x^2 + a * z^2 40 | * u = 2 * y * z 41 | * v = 2 * u * x * y 42 | * w = t^2 - 2 * v 43 | * x' = u * w 44 | * y' = t * (v - w) - 2 * (u * y)^2 45 | * z' = u^3 46 | * } 47 | */ 48 | 49 | checkPoint(val, pOff); 50 | Int256Math.checkUint(val, tempOff); 51 | assert val.length - tempOff >= TWICE_TEMP_WORDS; 52 | 53 | int zeroResult = CurvePointMath.isZero(val, pOff) | Int256Math.isZero(val, pOff + YCOORD); 54 | int newTempOff = tempOff + 3 * NUM_WORDS; 55 | 56 | int uOff = tempOff + 0 * NUM_WORDS; 57 | Int256Math.fieldMultiply(val, pOff + YCOORD, pOff + ZCOORD, uOff, newTempOff); 58 | Int256Math.fieldMultiply2(val, uOff, uOff, newTempOff); 59 | 60 | int vOff = tempOff + 1 * NUM_WORDS; 61 | Int256Math.fieldMultiply(val, uOff, pOff + XCOORD, vOff, newTempOff); 62 | Int256Math.fieldMultiply(val, vOff, pOff + YCOORD, vOff, newTempOff); 63 | Int256Math.fieldMultiply2(val, vOff, vOff, newTempOff); 64 | 65 | Int256Math.fieldSquare(val, pOff + XCOORD, pOff + XCOORD, newTempOff); 66 | int tOff = tempOff + 2 * NUM_WORDS; 67 | Int256Math.fieldMultiply2(val, pOff + XCOORD, tOff, newTempOff); 68 | Int256Math.fieldAdd(val, tOff, pOff + XCOORD, tOff, newTempOff); 69 | 70 | int wOff = pOff + ZCOORD; // Reuses space 71 | Int256Math.fieldSquare(val, tOff, wOff, newTempOff); 72 | Int256Math.fieldMultiply2(val, vOff, pOff + XCOORD, newTempOff); 73 | Int256Math.fieldSubtract(val, wOff, pOff + XCOORD, wOff, newTempOff); 74 | 75 | Int256Math.fieldSubtract(val, vOff, wOff, pOff + XCOORD, newTempOff); 76 | Int256Math.fieldMultiply(val, pOff + XCOORD, tOff, pOff + XCOORD, newTempOff); 77 | Int256Math.fieldMultiply(val, pOff + YCOORD, uOff, pOff + YCOORD, newTempOff); 78 | Int256Math.fieldSquare(val, pOff + YCOORD, pOff + YCOORD, newTempOff); 79 | Int256Math.fieldMultiply2(val, pOff + YCOORD, pOff + YCOORD, newTempOff); 80 | Int256Math.fieldSubtract(val, pOff + XCOORD, pOff + YCOORD, pOff + YCOORD, newTempOff); 81 | 82 | Int256Math.fieldMultiply(val, uOff, wOff, pOff + XCOORD, newTempOff); 83 | 84 | Int256Math.fieldSquare(val, uOff, pOff + ZCOORD, newTempOff); 85 | Int256Math.fieldMultiply(val, uOff, pOff + ZCOORD, pOff + ZCOORD, newTempOff); 86 | 87 | copy(ZERO_POINT, 0, val, tempOff); // Reuses space 88 | CurvePointMath.replace(val, pOff, tempOff, zeroResult); 89 | } 90 | 91 | public static final int TWICE_TEMP_WORDS = 3 * NUM_WORDS + Int256Math.FIELD_MULTIPLY_TEMP_WORDS; 92 | 93 | 94 | // Adds the point q into point p. Requires 112 words of temporary space. 95 | // The resulting point is usually not normalized. Constant-time with respect to both points. 96 | public static void add(int[] val, int pOff, int qOff, int tempOff) { 97 | /* 98 | * (See https://www.nayuki.io/page/elliptic-curve-point-addition-in-projective-coordinates) 99 | * Algorithm pseudocode: 100 | * if (p == ZERO) 101 | * p = q 102 | * else if (q == ZERO) 103 | * p = p 104 | * else { 105 | * t0 = p.y * q.z 106 | * t1 = q.y * p.z 107 | * u0 = p.x * q.z 108 | * u1 = q.x * p.z 109 | * if (u0 == u1) { // Same x coordinates 110 | * if (t0 == t1) // Same y coordinates 111 | * p = twice(p) 112 | * else 113 | * p = ZERO 114 | * } else { 115 | * t = t0 - t1 116 | * u = u0 - u1 117 | * u2 = u^2 118 | * v = p.z * q.z 119 | * w = t^2 * v - u2 * (u0 + u1) 120 | * p.x' = u * w 121 | * u3 = u2 * u 122 | * p.y' = t * (u0 * u2 - w) - t0 * u3 123 | * p.z' = u3 * v 124 | * } 125 | * } 126 | */ 127 | 128 | checkPoint(val, pOff); 129 | checkPoint(val, qOff); 130 | Int256Math.checkUint(val, tempOff); 131 | assert val.length - tempOff >= ADD_TEMP_WORDS; 132 | 133 | int pIsZero = CurvePointMath.isZero(val, pOff); 134 | int qIsZero = CurvePointMath.isZero(val, qOff); 135 | int rOff = tempOff + 0 * NUM_WORDS; 136 | copy(val, pOff, val, rOff); 137 | CurvePointMath.twice(val, rOff, tempOff + POINT_WORDS); 138 | CurvePointMath.replace(val, rOff, pOff, qIsZero); 139 | CurvePointMath.replace(val, rOff, qOff, pIsZero); 140 | 141 | int newTempOff = tempOff + 9 * NUM_WORDS; 142 | int u0Off = tempOff + 3 * NUM_WORDS; 143 | int u1Off = tempOff + 4 * NUM_WORDS; 144 | int t0Off = tempOff + 5 * NUM_WORDS; 145 | int t1Off = pOff + XCOORD; // Reuses space 146 | Int256Math.fieldMultiply(val, pOff + XCOORD, qOff + ZCOORD, u0Off, newTempOff); 147 | Int256Math.fieldMultiply(val, qOff + XCOORD, pOff + ZCOORD, u1Off, newTempOff); 148 | Int256Math.fieldMultiply(val, pOff + YCOORD, qOff + ZCOORD, t0Off, newTempOff); 149 | Int256Math.fieldMultiply(val, qOff + YCOORD, pOff + ZCOORD, t1Off, newTempOff); 150 | int sameX = Int256Math.equalTo(val, u0Off, u1Off); 151 | int sameY = Int256Math.equalTo(val, t0Off, t1Off); 152 | copy(ZERO_POINT, 0, val, tempOff + 6 * NUM_WORDS); 153 | CurvePointMath.replace(val, rOff, tempOff + 6 * NUM_WORDS, (pIsZero ^ 1) & (qIsZero ^ 1) & sameX & (sameY ^ 1)); 154 | 155 | int tOff = pOff + YCOORD; // Reuses space 156 | int uOff = tempOff + 6 * NUM_WORDS; 157 | int u2Off = tempOff + 7 * NUM_WORDS; 158 | int vOff = pOff + ZCOORD; // Reuses space 159 | Int256Math.fieldSubtract(val, t0Off, t1Off, tOff, newTempOff); 160 | Int256Math.fieldSubtract(val, u0Off, u1Off, uOff, newTempOff); 161 | Int256Math.fieldSquare(val, uOff, u2Off, newTempOff); 162 | Int256Math.fieldMultiply(val, pOff + ZCOORD, qOff + ZCOORD, vOff, newTempOff); 163 | 164 | int wOff = tempOff + 8 * NUM_WORDS; 165 | Int256Math.fieldSquare(val, tOff, wOff, newTempOff); 166 | Int256Math.fieldMultiply(val, wOff, vOff, wOff, newTempOff); 167 | Int256Math.fieldAdd(val, u0Off, u1Off, u1Off, newTempOff); 168 | Int256Math.fieldMultiply(val, u1Off, u2Off, u1Off, newTempOff); 169 | Int256Math.fieldSubtract(val, wOff, u1Off, wOff, newTempOff); 170 | 171 | Int256Math.fieldMultiply(val, uOff, wOff, pOff + XCOORD, newTempOff); 172 | 173 | int u3Off = u1Off; // Reuses space 174 | Int256Math.fieldMultiply(val, uOff, u2Off, u3Off, newTempOff); 175 | 176 | Int256Math.fieldMultiply(val, u0Off, u2Off, u0Off, newTempOff); 177 | Int256Math.fieldSubtract(val, u0Off, wOff, u0Off, newTempOff); 178 | Int256Math.fieldMultiply(val, tOff, u0Off, tOff, newTempOff); 179 | Int256Math.fieldMultiply(val, t0Off, u3Off, t0Off, newTempOff); 180 | Int256Math.fieldSubtract(val, tOff, t0Off, pOff + YCOORD, newTempOff); 181 | 182 | Int256Math.fieldMultiply(val, vOff, u3Off, pOff + ZCOORD, newTempOff); 183 | 184 | CurvePointMath.replace(val, pOff, rOff, pIsZero | qIsZero | sameX); 185 | } 186 | 187 | public static final int ADD_TEMP_WORDS = 9 * NUM_WORDS + Int256Math.FIELD_MULTIPLY_TEMP_WORDS; 188 | 189 | 190 | // Multiplies the given point by the given unsigned integer. The resulting point is usually not normalized. 191 | // Requires 552 words of temporary space. Constant-time with respect to both values. 192 | public static void multiply(int[] val, int pOff, int nOff, int tempOff) { 193 | checkPoint(val, pOff); 194 | Int256Math.checkUint(val, nOff); 195 | Int256Math.checkUint(val, tempOff); 196 | assert val.length - tempOff >= MULTIPLY_TEMP_WORDS; 197 | 198 | // Precompute [p*0, p*1, ..., p*15] 199 | final int tableBits = 4; // Do not modify 200 | final int tableLen = 1 << tableBits; 201 | int newTempOff = tempOff + (tableLen + 1) * POINT_WORDS; 202 | int tableOff = tempOff; // Uses tableLen * POINT_WORDS elements 203 | copy(ZERO_POINT, 0, val, tableOff); 204 | copy(val, pOff, val, tableOff + 1 * POINT_WORDS); 205 | copy(val, pOff, val, tableOff + 2 * POINT_WORDS); 206 | CurvePointMath.twice(val, tableOff + 2 * POINT_WORDS, newTempOff); 207 | for (int i = 3; i < tableLen; i++) { 208 | copy(val, tableOff + (i - 1) * POINT_WORDS, val, tableOff + i * POINT_WORDS); 209 | CurvePointMath.add(val, tableOff + i * POINT_WORDS, pOff, newTempOff); 210 | } 211 | 212 | // Process tableBits bits per iteration (windowed method) 213 | copy(ZERO_POINT, 0, val, pOff); 214 | int qOff = tempOff + tableLen * POINT_WORDS; 215 | for (int i = Int256Math.NUM_WORDS * 32 - tableBits; i >= 0; i -= tableBits) { 216 | int inc = (val[nOff + (i >>> 5)] >>> (i & 31)) & (tableLen - 1); 217 | for (int j = 0; j < tableLen; j++) 218 | CurvePointMath.replace(val, qOff, tableOff + j * POINT_WORDS, Int256Math.equalTo(j, inc)); 219 | CurvePointMath.add(val, pOff, qOff, newTempOff); 220 | if (i != 0) { 221 | for (int j = 0; j < tableBits; j++) 222 | CurvePointMath.twice(val, pOff, newTempOff); 223 | } 224 | } 225 | } 226 | 227 | public static final int MULTIPLY_TEMP_WORDS = 17 * POINT_WORDS + ADD_TEMP_WORDS; 228 | 229 | 230 | // Normalizes the coordinates of the given point. Idempotent operation. 231 | // Requires 72 words of temporary space. Constant-time with respect to the point. 232 | public static void normalize(int[] val, int pOff, int tempOff) { 233 | /* 234 | * Algorithm pseudocode: 235 | * if (z != 0) { 236 | * x /= z 237 | * y /= z 238 | * z = 1 239 | * } else { 240 | * x = x != 0 ? 1 : 0 241 | * y = y != 0 ? 1 : 0 242 | * z = 0 243 | * } 244 | */ 245 | 246 | checkPoint(val, pOff); 247 | Int256Math.checkUint(val, tempOff); 248 | assert val.length - tempOff >= NORMALIZE_TEMP_WORDS; 249 | 250 | int nonzero = Int256Math.isZero(val, pOff + ZCOORD) ^ 1; 251 | int newTempOff = tempOff + POINT_WORDS; 252 | int normOff = tempOff; 253 | Int256Math.copy(Int256Math.FIELD_MODULUS, 0, val, tempOff); // Reuses space 254 | Int256Math.reciprocal(val, pOff + ZCOORD, tempOff, normOff + ZCOORD, newTempOff); 255 | Int256Math.fieldMultiply(val, pOff + XCOORD, normOff + ZCOORD, normOff + XCOORD, newTempOff); 256 | Int256Math.fieldMultiply(val, pOff + YCOORD, normOff + ZCOORD, normOff + YCOORD, newTempOff); 257 | 258 | val[normOff + ZCOORD] = 1; 259 | Arrays.fill(val, normOff + ZCOORD + 1, normOff + ZCOORD + NUM_WORDS, 0); 260 | Int256Math.replace(val, pOff + XCOORD, normOff + ZCOORD, Int256Math.isZero(val, pOff + XCOORD) ^ 1); 261 | Int256Math.replace(val, pOff + YCOORD, normOff + ZCOORD, Int256Math.isZero(val, pOff + YCOORD) ^ 1); 262 | CurvePointMath.replace(val, pOff, normOff, nonzero); 263 | } 264 | 265 | public static final int NORMALIZE_TEMP_WORDS = POINT_WORDS + Int256Math.RECIPROCAL_TEMP_WORDS; 266 | 267 | 268 | /*---- Miscellaneous functions ----*/ 269 | 270 | // Copies the point from src to dst. 271 | public static void copy(int[] src, int srcOff, int[] dst, int dstOff) { 272 | System.arraycopy(src, srcOff, dst, dstOff, POINT_WORDS); 273 | } 274 | 275 | 276 | // Copies the point q into point p if enable is 1, or does nothing if enable is 0. 277 | // Constant-time with respect to both values and the enable. 278 | public static void replace(int[] val, int pOff, int qOff, int enable) { 279 | checkPoint(val, pOff); 280 | checkPoint(val, qOff); 281 | Int256Math.checkEnable(enable); 282 | 283 | int mask = -enable; 284 | for (int i = 0; i < POINT_WORDS; i++) 285 | val[pOff + i] = (val[qOff + i] & mask) | (val[pOff + i] & ~mask); 286 | } 287 | 288 | 289 | // Tests whether the given point is on the elliptic curve, returning 0 or 1. 290 | // The point needs to be normalized before the method is called. Zero is considered to be off the curve. 291 | // Requires 56 words of temporary space. Constant-time with respect to the point. 292 | public static int isOnCurve(int[] val, int pOff, int tempOff) { 293 | checkPoint(val, pOff); 294 | Int256Math.checkUint(val, tempOff); 295 | assert val.length - tempOff >= ISONCURVE_TEMP_WORDS; 296 | 297 | int rightOff = tempOff + 0 * NUM_WORDS; 298 | int constOff = tempOff + 1 * NUM_WORDS; 299 | int newTempOff = tempOff + 2 * NUM_WORDS; 300 | Int256Math.fieldSquare(val, pOff + XCOORD, rightOff, newTempOff); 301 | Int256Math.copy(A, 0, val, constOff); 302 | Int256Math.fieldAdd(val, rightOff, constOff, rightOff, newTempOff); 303 | Int256Math.fieldMultiply(val, rightOff, pOff + XCOORD, rightOff, newTempOff); 304 | Int256Math.copy(B, 0, val, constOff); 305 | Int256Math.fieldAdd(val, rightOff, constOff, rightOff, newTempOff); 306 | 307 | int leftOff = tempOff + 1 * NUM_WORDS; // Reuses space 308 | Int256Math.fieldSquare(val, pOff + YCOORD, leftOff, newTempOff); 309 | return Int256Math.equalTo(val, leftOff, rightOff) & (isZero(val, pOff) ^ 1); 310 | } 311 | 312 | public static final int ISONCURVE_TEMP_WORDS = 2 * NUM_WORDS + Int256Math.FIELD_MULTIPLY_TEMP_WORDS; 313 | 314 | 315 | // Tests whether the given point is equal to the special zero point. 316 | // The point need not be normalized. Constant-time with respect to the point. 317 | public static int isZero(int[] val, int pOff) { 318 | // p.x == 0 && p.y != 0 && p.z == 0 319 | checkPoint(val, pOff); 320 | return Int256Math.isZero(val, pOff + XCOORD) & Int256Math.isZero(val, pOff + ZCOORD) 321 | & (Int256Math.isZero(val, pOff + YCOORD) ^ 1); 322 | } 323 | 324 | 325 | public static int[] getBasePoint() { 326 | return BASE_POINT.clone(); 327 | } 328 | 329 | 330 | 331 | /*---- Helper functions ----*/ 332 | 333 | private static void checkPoint(int[] arr, int off) { 334 | Int256Math.checkFieldInt(arr, off + XCOORD); 335 | Int256Math.checkFieldInt(arr, off + YCOORD); 336 | Int256Math.checkFieldInt(arr, off + ZCOORD); 337 | } 338 | 339 | 340 | /*---- Class constants ----*/ 341 | 342 | // Sizes and offsets 343 | static final int XCOORD = 0 * NUM_WORDS; 344 | static final int YCOORD = 1 * NUM_WORDS; 345 | static final int ZCOORD = 2 * NUM_WORDS; 346 | 347 | // Curve parameters 348 | static final int[] A = {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}; 349 | static final int[] B = {0x00000007, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}; 350 | static final int[] ORDER = {0xD0364141, 0xBFD25E8C, 0xAF48A03B, 0xBAAEDCE6, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}; 351 | 352 | // Elliptic curve points 353 | static final int[] ZERO_POINT = {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // (0, 1, 0) 354 | static final int[] BASE_POINT = { 355 | 0x16F81798, 0x59F2815B, 0x2DCE28D9, 0x029BFCDB, 0xCE870B07, 0x55A06295, 0xF9DCBBAC, 0x79BE667E, 356 | 0xFB10D4B8, 0x9C47D08F, 0xA6855419, 0xFD17B448, 0x0E1108A8, 0x5DA4FBFC, 0x26A3C465, 0x483ADA77, 357 | 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}; 358 | 359 | } 360 | -------------------------------------------------------------------------------- /java/io/nayuki/bitcoin/crypto/Ecdsa.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | package io.nayuki.bitcoin.crypto; 10 | 11 | import static io.nayuki.bitcoin.crypto.Int256Math.NUM_WORDS; 12 | import java.util.Arrays; 13 | import java.util.Objects; 14 | 15 | 16 | /** 17 | * Performs ECDSA signature generation and verification. Provides just three static functions. 18 | */ 19 | public final class Ecdsa { 20 | 21 | /*---- Static functions ----*/ 22 | 23 | // Computes the signature (deterministically) when given the private key, message hash, and random nonce. 24 | // Returns true if signing was successful (overwhelming probability), or false if a new nonce must be chosen 25 | // (vanishing probability). Both privateKey and nonce must be in the range [1, CurvePointMath.ORDER). 26 | // outR and outS will be in the same range too; their values are assigned iff signing is successful. 27 | // Note: The nonce must be unique, unpredictable, and secret. Otherwise the signature may leak the private key. 28 | // All successful executions are constant-time with respect to the input values; in order words 29 | // one successful execution is indistinguishable from another one based on side channel information. 30 | public static boolean sign(int[] privateKey, Sha256Hash msgHash, int[] nonce, int[] outR, int[] outS) { 31 | Objects.requireNonNull(privateKey); 32 | Objects.requireNonNull(msgHash); 33 | Objects.requireNonNull(nonce); 34 | Objects.requireNonNull(outR); 35 | Objects.requireNonNull(outS); 36 | if (privateKey.length != NUM_WORDS || nonce.length != NUM_WORDS || outR.length != NUM_WORDS || outS.length != NUM_WORDS) 37 | throw new IllegalArgumentException(); 38 | 39 | /* 40 | * Algorithm pseudocode: 41 | * if (nonce outside range [1, order-1]) return false 42 | * p = nonce * G 43 | * r = p.x % order 44 | * if (r == 0) return false 45 | * s = nonce^-1 * (msgHash + r * privateKey) % order 46 | * if (s == 0) return false 47 | * s = min(s, order - s) 48 | */ 49 | 50 | int[] val = new int[2 * NUM_WORDS + CurvePointMath.POINT_WORDS + CurvePointMath.MULTIPLY_TEMP_WORDS]; // Temporary scratch space for all values 51 | int tempOff = 5 * NUM_WORDS; 52 | int nonceOff = 0 * NUM_WORDS; // Uint256 53 | int orderOff = 1 * NUM_WORDS; // Uint256 54 | Int256Math.copy(nonce, 0, val, nonceOff); 55 | Int256Math.copy(CurvePointMath.ORDER, 0, val, orderOff); 56 | if (Int256Math.isZero(nonce, 0) == 1 || Int256Math.lessThan(val, nonceOff, orderOff) == 0) 57 | return false; 58 | 59 | int pOff = 2 * NUM_WORDS; // CurvePoint 60 | CurvePointMath.copy(CurvePointMath.BASE_POINT, 0, val, pOff); 61 | CurvePointMath.multiply(val, pOff, nonceOff, tempOff); 62 | CurvePointMath.normalize(val, pOff, tempOff); 63 | 64 | int rOff = pOff + CurvePointMath.XCOORD; // Uint256, aliasing p.x 65 | Int256Math.uintSubtract(val, rOff, orderOff, Int256Math.lessThan(val, rOff, orderOff) ^ 1, rOff); 66 | if (Int256Math.isZero(val, rOff) == 1) 67 | return false; 68 | assert Int256Math.lessThan(val, rOff, orderOff) == 1; 69 | 70 | int sOff = pOff + CurvePointMath.YCOORD; // Uint256, reuses space 71 | int zOff = pOff + CurvePointMath.ZCOORD; // Uint256, reuses space 72 | Int256Math.copy(val, rOff, val, sOff); 73 | Arrays.fill(val, zOff, zOff + NUM_WORDS, 0); 74 | Int256Math.bytesToUint(msgHash.toBytes(), val, zOff); 75 | multiplyModOrder(val, sOff, privateKey, 0, tempOff); 76 | int carry = Int256Math.uintAdd(val, sOff, zOff, 1, sOff); 77 | Int256Math.uintSubtract(val, sOff, orderOff, carry | (Int256Math.lessThan(val, sOff, orderOff) ^ 1), sOff); 78 | 79 | int kInvOff = zOff; // Uint256, reuses space 80 | Int256Math.reciprocal(val, nonceOff, orderOff, kInvOff, tempOff); 81 | multiplyModOrder(val, sOff, val, kInvOff, tempOff); 82 | if (Int256Math.isZero(val, sOff) == 1) 83 | return false; 84 | 85 | int negSOff = zOff; // Uint256, reuses space 86 | Int256Math.uintSubtract(val, orderOff, sOff, 1, negSOff); 87 | Int256Math.replace(val, sOff, negSOff, Int256Math.lessThan(val, negSOff, sOff)); // To ensure low S values for BIP 62 88 | Int256Math.copy(val, rOff, outR, 0); 89 | Int256Math.copy(val, sOff, outS, 0); 90 | return true; 91 | } 92 | 93 | 94 | // Computes a deterministic nonce based on the HMAC-SHA-256 of the message hash with the private key, 95 | // and then performs ECDSA signing. Returns true iff signing is successful (with overwhelming probability). 96 | // This has the same constant-time behavior as sign(). 97 | public static boolean signWithHmacNonce(int[] privateKey, Sha256Hash msgHash, int[] outR, int[] outS) { 98 | Objects.requireNonNull(privateKey); 99 | Objects.requireNonNull(msgHash); 100 | Objects.requireNonNull(outR); 101 | Objects.requireNonNull(outS); 102 | if (privateKey.length != NUM_WORDS || outR.length != NUM_WORDS || outS.length != NUM_WORDS) 103 | throw new IllegalArgumentException(); 104 | 105 | byte[] privkeyBytes = Int256Math.uintToBytes(privateKey, 0); 106 | byte[] msghashBytes = msgHash.toBytes(); 107 | byte[] hmac = Sha256.getHmac(privkeyBytes, msghashBytes).toBytes(); 108 | int[] nonce = new int[Int256Math.NUM_WORDS]; 109 | Int256Math.bytesToUint(hmac, nonce, 0); 110 | return sign(privateKey, msgHash, nonce, outR, outS); 111 | } 112 | 113 | 114 | // Checks whether the given signature, message, and public key are valid together. 115 | // publicKey is a normalized CurvePoint, r is a Uint256, and s is a Uint256. 116 | // This function does not need to be constant-time because all inputs are public. 117 | public static boolean verify(int[] publicKey, Sha256Hash msgHash, int[] r, int[] s) { 118 | Objects.requireNonNull(publicKey); 119 | Objects.requireNonNull(msgHash); 120 | Objects.requireNonNull(r); 121 | Objects.requireNonNull(s); 122 | if (publicKey.length != CurvePointMath.POINT_WORDS || r.length != NUM_WORDS || s.length != NUM_WORDS) 123 | throw new IllegalArgumentException(); 124 | 125 | /* 126 | * Algorithm pseudocode: 127 | * if (pubKey == zero || !(pubKey is normalized) || 128 | * !(pubKey on curve) || n * pubKey != zero) 129 | * return false 130 | * if (!(0 < r, s < order)) 131 | * return false 132 | * w = s^-1 % order 133 | * u1 = (msgHash * w) % order 134 | * u2 = (r * w) % order 135 | * p = u1 * G + u2 * pubKey 136 | * if (p == zero) 137 | * return false 138 | * return r == p.x % order 139 | */ 140 | 141 | int[] val = new int[9 * NUM_WORDS + CurvePointMath.MULTIPLY_TEMP_WORDS]; 142 | int tempOff = 9 * NUM_WORDS; 143 | int orderOff = 0 * NUM_WORDS; // Uint256 144 | Int256Math.copy(CurvePointMath.ORDER, 0, val, orderOff); 145 | 146 | int rOff = 1 * NUM_WORDS; // Uint256 147 | int sOff = 2 * NUM_WORDS; // Uint256 148 | Int256Math.copy(r, 0, val, rOff); 149 | Int256Math.copy(s, 0, val, sOff); 150 | if ( Int256Math.isZero(r, 0) == 1 || Int256Math.lessThan(val, rOff, orderOff) == 0 || 151 | Int256Math.isZero(s, 0) == 1 || Int256Math.lessThan(val, sOff, orderOff) == 0) 152 | return false; 153 | 154 | int qOff = 3 * NUM_WORDS; // CurvePoint 155 | int oneOff = 6 * NUM_WORDS; // Uint256 156 | CurvePointMath.copy(publicKey, 0, val, qOff); 157 | Int256Math.copy(Int256Math.ONE, 0, val, oneOff); 158 | if (CurvePointMath.isZero(publicKey, 0) == 1 || Int256Math.equalTo(val, qOff + CurvePointMath.ZCOORD, oneOff) == 0 159 | || CurvePointMath.isOnCurve(val, qOff, tempOff) == 0) 160 | return false; 161 | CurvePointMath.multiply(val, qOff, orderOff, tempOff); 162 | if (CurvePointMath.isZero(val, qOff) == 0) 163 | return false; 164 | 165 | int wOff = 2 * NUM_WORDS; // Uint256, reuses space 166 | Int256Math.reciprocal(val, sOff, orderOff, wOff, tempOff); 167 | 168 | int u1Off = 3 * NUM_WORDS; // Uint256, reuses space 169 | int u2Off = 2 * NUM_WORDS; // Uint256, reuses space 170 | int zOff = 4 * NUM_WORDS; // Uint256, reuses space 171 | Int256Math.bytesToUint(msgHash.toBytes(), val, zOff); 172 | Int256Math.copy(val, wOff, val, u1Off); 173 | multiplyModOrder(val, u1Off, val, zOff, tempOff); 174 | multiplyModOrder(val, u2Off, r, 0, tempOff); 175 | 176 | int pOff = 6 * NUM_WORDS; // CurvePoint, reuses space 177 | CurvePointMath.copy(CurvePointMath.BASE_POINT, 0, val, pOff); 178 | CurvePointMath.multiply(val, pOff, u1Off, tempOff); 179 | CurvePointMath.copy(publicKey, 0, val, qOff); 180 | CurvePointMath.multiply(val, qOff, u2Off, tempOff); 181 | CurvePointMath.add(val, pOff, qOff, tempOff); 182 | CurvePointMath.normalize(val, pOff, tempOff); 183 | if (CurvePointMath.isZero(val, pOff) == 1) 184 | return false; 185 | 186 | int reduce = Int256Math.lessThan(val, pOff + CurvePointMath.XCOORD, orderOff) ^ 1; 187 | Int256Math.uintSubtract(val, pOff + CurvePointMath.XCOORD, orderOff, reduce, pOff + CurvePointMath.XCOORD); 188 | return Int256Math.equalTo(val, rOff, pOff + CurvePointMath.XCOORD) == 1; 189 | } 190 | 191 | 192 | 193 | /*---- Private functions ----*/ 194 | 195 | // Computes x = (x * y) % CurvePointMath.ORDER. Requires x < CurvePointMath.ORDER, but y is unrestricted. 196 | // tempOff indexes into the x array, and uses 16 words of temporary space. 197 | private static void multiplyModOrder(int[] x, int xOff, int[] y, int yOff, int tempOff) { 198 | /* 199 | * Russian peasant multiplication with modular reduction at each step. Algorithm pseudocode: 200 | * z = 0 201 | * for (i = 255 .. 0) { 202 | * z = (z * 2) % order 203 | * if (y.bit[i] == 1) 204 | * z = (z + x) % order 205 | * } 206 | * x = z 207 | */ 208 | int modOff = tempOff + 0 * NUM_WORDS; 209 | int zOff = tempOff + 1 * NUM_WORDS; 210 | Int256Math.copy(CurvePointMath.ORDER, 0, x, modOff); 211 | Int256Math.copy(Int256Math.ZERO, 0, x, zOff); 212 | assert Int256Math.lessThan(x, xOff, modOff) == 1; 213 | 214 | for (int i = Int256Math.NUM_WORDS * 32 - 1; i >= 0; i--) { 215 | // Multiply by 2 216 | int c = Int256Math.uintShiftLeft1(x, zOff, zOff); 217 | Int256Math.uintSubtract(x, zOff, modOff, c | (Int256Math.lessThan(x, zOff, modOff) ^ 1), zOff); 218 | // Conditionally add x 219 | int enable = (y[yOff + (i >>> 5)] >>> (i & 31)) & 1; 220 | c = Int256Math.uintAdd(x, zOff, xOff, enable, zOff); 221 | Int256Math.uintSubtract(x, zOff, modOff, c | (Int256Math.lessThan(x, zOff, modOff) ^ 1), zOff); 222 | assert Int256Math.lessThan(x, zOff, modOff) == 1; 223 | } 224 | Int256Math.copy(x, zOff, x, xOff); 225 | } 226 | 227 | 228 | 229 | /*---- Miscellaneous ----*/ 230 | 231 | private Ecdsa() {} // Not instantiable 232 | 233 | } 234 | -------------------------------------------------------------------------------- /java/io/nayuki/bitcoin/crypto/Keccak256.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | package io.nayuki.bitcoin.crypto; 10 | 11 | import static java.lang.Long.rotateLeft; 12 | import java.util.Objects; 13 | 14 | 15 | /** 16 | * Computes the Keccak-256 hash of an array of bytes. Not instantiable. 17 | */ 18 | public final class Keccak256 { 19 | 20 | private static final int HASH_LEN = 32; // In bytes 21 | private static final int BLOCK_SIZE = 200 - HASH_LEN * 2; 22 | 23 | 24 | /*---- Static functions ----*/ 25 | 26 | /** 27 | * Computes and returns a 32-byte (256-bit) hash of the specified binary message. 28 | * Each call will return a new byte array object instance. 29 | * @param msg the message to compute the hash of 30 | * @return a 32-byte array representing the message's Keccak-256 hash 31 | * @throws NullPointerException if the message is {@code null} 32 | */ 33 | public static byte[] getHash(byte[] msg) { 34 | Objects.requireNonNull(msg); 35 | long[] state = new long[25]; 36 | 37 | // XOR each message byte into the state, and absorb full blocks 38 | int blockOff = 0; 39 | for (int i = 0; i < msg.length; i++) { 40 | state[blockOff / 8] ^= (msg[i] & 0xFFL) << (blockOff % 8 * 8); 41 | blockOff++; 42 | if (blockOff == BLOCK_SIZE) { 43 | absorb(state); 44 | blockOff = 0; 45 | } 46 | } 47 | 48 | // Final block and padding 49 | state[blockOff / 8] ^= 0x01L << (blockOff % 8 * 8); 50 | blockOff = BLOCK_SIZE - 1; 51 | state[blockOff / 8] ^= 0x80L << (blockOff % 8 * 8); 52 | absorb(state); 53 | 54 | // Int64 array to bytes in little endian 55 | byte[] result = new byte[HASH_LEN]; 56 | for (int i = 0; i < result.length; i++) 57 | result[i] = (byte)(state[i / 8] >>> (i % 8 * 8)); 58 | return result; 59 | } 60 | 61 | 62 | /*---- Private functions ----*/ 63 | 64 | private static void absorb(long[] state) { 65 | long a00 = state[ 0], a01 = state[ 1], a02 = state[ 2], a03 = state[ 3], a04 = state[ 4]; 66 | long a05 = state[ 5], a06 = state[ 6], a07 = state[ 7], a08 = state[ 8], a09 = state[ 9]; 67 | long a10 = state[10], a11 = state[11], a12 = state[12], a13 = state[13], a14 = state[14]; 68 | long a15 = state[15], a16 = state[16], a17 = state[17], a18 = state[18], a19 = state[19]; 69 | long a20 = state[20], a21 = state[21], a22 = state[22], a23 = state[23], a24 = state[24]; 70 | 71 | for (long rc : ROUND_CONSTANTS) { 72 | // Theta step 73 | long c0 = a00 ^ a05 ^ a10 ^ a15 ^ a20; 74 | long c1 = a01 ^ a06 ^ a11 ^ a16 ^ a21; 75 | long c2 = a02 ^ a07 ^ a12 ^ a17 ^ a22; 76 | long c3 = a03 ^ a08 ^ a13 ^ a18 ^ a23; 77 | long c4 = a04 ^ a09 ^ a14 ^ a19 ^ a24; 78 | long d0 = c4 ^ rotateLeft(c1, 1); 79 | long d1 = c0 ^ rotateLeft(c2, 1); 80 | long d2 = c1 ^ rotateLeft(c3, 1); 81 | long d3 = c2 ^ rotateLeft(c4, 1); 82 | long d4 = c3 ^ rotateLeft(c0, 1); 83 | a00 ^= d0; a05 ^= d0; a10 ^= d0; a15 ^= d0; a20 ^= d0; 84 | a01 ^= d1; a06 ^= d1; a11 ^= d1; a16 ^= d1; a21 ^= d1; 85 | a02 ^= d2; a07 ^= d2; a12 ^= d2; a17 ^= d2; a22 ^= d2; 86 | a03 ^= d3; a08 ^= d3; a13 ^= d3; a18 ^= d3; a23 ^= d3; 87 | a04 ^= d4; a09 ^= d4; a14 ^= d4; a19 ^= d4; a24 ^= d4; 88 | 89 | // Rho and pi steps 90 | long b00 = rotateLeft(a00, 0); 91 | long b16 = rotateLeft(a05, 36); 92 | long b07 = rotateLeft(a10, 3); 93 | long b23 = rotateLeft(a15, 41); 94 | long b14 = rotateLeft(a20, 18); 95 | long b10 = rotateLeft(a01, 1); 96 | long b01 = rotateLeft(a06, 44); 97 | long b17 = rotateLeft(a11, 10); 98 | long b08 = rotateLeft(a16, 45); 99 | long b24 = rotateLeft(a21, 2); 100 | long b20 = rotateLeft(a02, 62); 101 | long b11 = rotateLeft(a07, 6); 102 | long b02 = rotateLeft(a12, 43); 103 | long b18 = rotateLeft(a17, 15); 104 | long b09 = rotateLeft(a22, 61); 105 | long b05 = rotateLeft(a03, 28); 106 | long b21 = rotateLeft(a08, 55); 107 | long b12 = rotateLeft(a13, 25); 108 | long b03 = rotateLeft(a18, 21); 109 | long b19 = rotateLeft(a23, 56); 110 | long b15 = rotateLeft(a04, 27); 111 | long b06 = rotateLeft(a09, 20); 112 | long b22 = rotateLeft(a14, 39); 113 | long b13 = rotateLeft(a19, 8); 114 | long b04 = rotateLeft(a24, 14); 115 | 116 | // Chi step 117 | a00 = b00 ^ (~b01 & b02) ^ rc; // Iota step 118 | a05 = b05 ^ (~b06 & b07); 119 | a10 = b10 ^ (~b11 & b12); 120 | a15 = b15 ^ (~b16 & b17); 121 | a20 = b20 ^ (~b21 & b22); 122 | a01 = b01 ^ (~b02 & b03); 123 | a06 = b06 ^ (~b07 & b08); 124 | a11 = b11 ^ (~b12 & b13); 125 | a16 = b16 ^ (~b17 & b18); 126 | a21 = b21 ^ (~b22 & b23); 127 | a02 = b02 ^ (~b03 & b04); 128 | a07 = b07 ^ (~b08 & b09); 129 | a12 = b12 ^ (~b13 & b14); 130 | a17 = b17 ^ (~b18 & b19); 131 | a22 = b22 ^ (~b23 & b24); 132 | a03 = b03 ^ (~b04 & b00); 133 | a08 = b08 ^ (~b09 & b05); 134 | a13 = b13 ^ (~b14 & b10); 135 | a18 = b18 ^ (~b19 & b15); 136 | a23 = b23 ^ (~b24 & b20); 137 | a04 = b04 ^ (~b00 & b01); 138 | a09 = b09 ^ (~b05 & b06); 139 | a14 = b14 ^ (~b10 & b11); 140 | a19 = b19 ^ (~b15 & b16); 141 | a24 = b24 ^ (~b20 & b21); 142 | } 143 | 144 | state[ 0] = a00; state[ 1] = a01; state[ 2] = a02; state[ 3] = a03; state[ 4] = a04; 145 | state[ 5] = a05; state[ 6] = a06; state[ 7] = a07; state[ 8] = a08; state[ 9] = a09; 146 | state[10] = a10; state[11] = a11; state[12] = a12; state[13] = a13; state[14] = a14; 147 | state[15] = a15; state[16] = a16; state[17] = a17; state[18] = a18; state[19] = a19; 148 | state[20] = a20; state[21] = a21; state[22] = a22; state[23] = a23; state[24] = a24; 149 | } 150 | 151 | 152 | /*---- Class constants ----*/ 153 | 154 | private static final long[] ROUND_CONSTANTS = { 155 | 0x0000000000000001L, 0x0000000000008082L, 0x800000000000808AL, 0x8000000080008000L, 156 | 0x000000000000808BL, 0x0000000080000001L, 0x8000000080008081L, 0x8000000000008009L, 157 | 0x000000000000008AL, 0x0000000000000088L, 0x0000000080008009L, 0x000000008000000AL, 158 | 0x000000008000808BL, 0x800000000000008BL, 0x8000000000008089L, 0x8000000000008003L, 159 | 0x8000000000008002L, 0x8000000000000080L, 0x000000000000800AL, 0x800000008000000AL, 160 | 0x8000000080008081L, 0x8000000000008080L, 0x0000000080000001L, 0x8000000080008008L, 161 | }; 162 | 163 | 164 | /*---- Miscellaneous ----*/ 165 | 166 | private Keccak256() {} // Not instantiable 167 | 168 | } 169 | -------------------------------------------------------------------------------- /java/io/nayuki/bitcoin/crypto/Keccak256Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | package io.nayuki.bitcoin.crypto; 10 | 11 | import static org.junit.Assert.assertArrayEquals; 12 | import org.junit.Test; 13 | 14 | 15 | /** 16 | * Tests the Keccak-256 hash function class. 17 | * @see Keccak256Test 18 | */ 19 | public final class Keccak256Test { 20 | 21 | @Test public void testBasic() { 22 | String[][] CASES = { 23 | // ASCII vectors 24 | {"A", "C5D2460186F7233C927E7DB2DCC703C0E500B653CA82273B7BFAD8045D85A470", ""}, 25 | {"A", "4D741B6F1EB29CB2A9B9911C82F56FA8D73B04959D3D9D222895DF6C0B28AA15", "The quick brown fox jumps over the lazy dog"}, 26 | {"A", "578951E24EFD62A3D63A86F7CD19AAA53C898FE287D2552133220370240B572D", "The quick brown fox jumps over the lazy dog."}, 27 | // Binary vectors 28 | {"H", "6A769F93F255B078FE73AFF68F0422A279939920E4690B4AFF0E433CFA3D3DF3", "13BD2811F6ED2B6F04FF3895ACEED7BEF8DCD45EB121791BC194A0F806206BFFC3B9281C2B308B1A729CE008119DD3066E9378ACDCC50A98A82E20738800B6CDDBE5FE9694AD6D"}, 29 | {"H", "C06DD4261638C44AFCB186F0AF5DE20EA53AA63316FBB71728F874FF3DACEB0D", "1EED9CBA179A009EC2EC5508773DD305477CA117E6D569E66B5F64C6BC64801CE25A8424CE4A26D575B8A6FB10EAD3FD1992EDDDEEC2EBE7150DC98F63ADC3237EF57B91397AA8A7"}, 30 | {"H", "52CBC5DBE49B009663C43F079DD180E38A77533778062A72A29E864A58522922", "F13C972C52CB3CC4A4DF28C97F2DF11CE089B815466BE88863243EB318C2ADB1A417CB1041308598541720197B9B1CB5BA2318BD5574D1DF2174AF14884149BA9B2F446D609DF240CE335599957B8EC80876D9A085AE084907BC5961B20BF5F6CA58D5DAB38ADB"}, 31 | {"H", "3A8DFCFD1B362003DDFA17910727539E64B18021ABBA018B5F58D71F7A449733", "E35780EB9799AD4C77535D4DDB683CF33EF367715327CF4C4A58ED9CBDCDD486F669F80189D549A9364FA82A51A52654EC721BB3AAB95DCEB4A86A6AFA93826DB923517E928F33E3FBA850D45660EF83B9876ACCAFA2A9987A254B137C6E140A21691E1069413848"}, 32 | {"H", "BD6F5492582A7C1B116304DE28314DF9FFFE95B0DA11AF52FE9440A717A34859", "B771D5CEF5D1A41A93D15643D7181D2A2EF0A8E84D91812F20ED21F147BEF732BF3A60EF4067C3734B85BC8CD471780F10DC9E8291B58339A677B960218F71E793F2797AEA349406512829065D37BB55EA796FA4F56FD8896B49B2CD19B43215AD967C712B24E5032D065232E02C127409D2ED4146B9D75D763D52DB98D949D3B0FED6A8052FBB"}, 33 | {"H", "E717A7769448ABBE5FEF8187954A88AC56DED1D22E63940AB80D029585A21921", "B32D95B0B9AAD2A8816DE6D06D1F86008505BD8C14124F6E9A163B5A2ADE55F835D0EC3880EF50700D3B25E42CC0AF050CCD1BE5E555B23087E04D7BF9813622780C7313A1954F8740B6EE2D3F71F768DD417F520482BD3A08D4F222B4EE9DBD015447B33507DD50F3AB4247C5DE9A8ABD62A8DECEA01E3B87C8B927F5B08BEB37674C6F8E380C04"}, 34 | {"H", "344D129C228359463C40555D94213D015627E5871C04F106A0FEEF9361CDECB6", "EA40E83CB18B3A242C1ECC6CCD0B7853A439DAB2C569CFC6DC38A19F5C90ACBF76AEF9EA3742FF3B54EF7D36EB7CE4FF1C9AB3BC119CFF6BE93C03E208783335C0AB8137BE5B10CDC66FF3F89A1BDDC6A1EED74F504CBE7290690BB295A872B9E3FE2CEE9E6C67C41DB8EFD7D863CF10F840FE618E7936DA3DCA5CA6DF933F24F6954BA0801A1294CD8D7E66DFAFEC"}, 35 | {"H", "4CE7C2B935F21FC34C5E56D940A555C593872AEC2F896DE4E68F2A017060F535", "157D5B7E4507F66D9A267476D33831E7BB768D4D04CC3438DA12F9010263EA5FCAFBDE2579DB2F6B58F911D593D5F79FB05FE3596E3FA80FF2F761D1B0E57080055C118C53E53CDB63055261D7C9B2B39BD90ACC32520CBBDBDA2C4FD8856DBCEE173132A2679198DAF83007A9B5C51511AE49766C792A29520388444EBEFE28256FB33D4260439CBA73A9479EE00C63"}, 36 | // secp256k1 curve point public key vectors 37 | {"H", "72F15D6555488541650CE62C0BED7ABD61247635C1973EB38474A2516ED1D884", "836B35A026743E823A90A0EE3B91BF615C6A757E2B60B9E1DC1826FD0DD16106F7BC1E8179F665015F43C6C81F39062FC2086ED849625C06E04697698B21855E"}, 38 | {"H", "500625E5A55B726C0FC56C62C2D7CF95645D33006175B78989035C7C9061D3F9", "EFB99D9860F4DEC4CB548A5722C27E9EF58E37FBAB9719C5B33D55C216DB49311221A01F638CE5F255875B194E0ACAA58B19A89D2E56A864427298F826A7F887"}, 39 | {"H", "6F68D681DE0407D447C30E14DD4ECCD742D17887F50C27AEBB14D99BFD7571B6", "C5BC5C47FFA548D0F2B63D4F05FA7064D72FA3657C287F38CC87140A639C9465D4C9EDEC42F06B631C443311FD91585BCAB873136EAC50AF6DAA5363F0405544"}, 40 | }; 41 | 42 | for (String[] tc : CASES) { 43 | byte[] msg; 44 | switch (tc[0]) { 45 | case "A": msg = Utils.asciiToBytes(tc[2]); break; 46 | case "H": msg = Utils.hexToBytes(tc[2]); break; 47 | default: throw new AssertionError(); 48 | } 49 | assertArrayEquals(Utils.hexToBytes(tc[1]), Keccak256.getHash(msg)); 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /java/io/nayuki/bitcoin/crypto/Ripemd160.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | package io.nayuki.bitcoin.crypto; 10 | 11 | import static java.lang.Integer.rotateLeft; 12 | import java.util.Arrays; 13 | import java.util.Objects; 14 | 15 | 16 | /** 17 | * Computes the RIPEMD-160 hash of an array of bytes. Not instantiable. 18 | */ 19 | public final class Ripemd160 { 20 | 21 | private static final int BLOCK_LEN = 64; // In bytes 22 | 23 | 24 | 25 | /*---- Static functions ----*/ 26 | 27 | /** 28 | * Computes and returns a 20-byte (160-bit) hash of the specified binary message. 29 | * Each call will return a new byte array object instance. 30 | * @param msg the message to compute the hash of 31 | * @return a 20-byte array representing the message's RIPEMD-160 hash 32 | * @throws NullPointerException if the message is {@code null} 33 | */ 34 | public static byte[] getHash(byte[] msg) { 35 | // Compress whole message blocks 36 | Objects.requireNonNull(msg); 37 | int[] state = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0}; 38 | int off = msg.length / BLOCK_LEN * BLOCK_LEN; 39 | compress(state, msg, off); 40 | 41 | // Final blocks, padding, and length 42 | byte[] block = new byte[BLOCK_LEN]; 43 | System.arraycopy(msg, off, block, 0, msg.length - off); 44 | off = msg.length % block.length; 45 | block[off] = (byte)0x80; 46 | off++; 47 | if (off + 8 > block.length) { 48 | compress(state, block, block.length); 49 | Arrays.fill(block, (byte)0); 50 | } 51 | long len = (long)msg.length << 3; 52 | for (int i = 0; i < 8; i++) 53 | block[block.length - 8 + i] = (byte)(len >>> (i * 8)); 54 | compress(state, block, block.length); 55 | 56 | // Int32 array to bytes in little endian 57 | byte[] result = new byte[state.length * 4]; 58 | for (int i = 0; i < result.length; i++) 59 | result[i] = (byte)(state[i / 4] >>> (i % 4 * 8)); 60 | return result; 61 | } 62 | 63 | 64 | 65 | /*---- Private functions ----*/ 66 | 67 | private static void compress(int[] state, byte[] blocks, int len) { 68 | if (len % BLOCK_LEN != 0) 69 | throw new IllegalArgumentException(); 70 | for (int i = 0; i < len; i += BLOCK_LEN) { 71 | 72 | // Message schedule 73 | int[] schedule = new int[16]; 74 | for (int j = 0; j < BLOCK_LEN; j++) 75 | schedule[j / 4] |= (blocks[i + j] & 0xFF) << (j % 4 * 8); 76 | 77 | // The 80 rounds 78 | int al = state[0], ar = state[0]; 79 | int bl = state[1], br = state[1]; 80 | int cl = state[2], cr = state[2]; 81 | int dl = state[3], dr = state[3]; 82 | int el = state[4], er = state[4]; 83 | for (int j = 0; j < 80; j++) { 84 | int temp; 85 | temp = rotateLeft(al + f(j, bl, cl, dl) + schedule[RL[j]] + KL[j / 16], SL[j]) + el; 86 | al = el; 87 | el = dl; 88 | dl = rotateLeft(cl, 10); 89 | cl = bl; 90 | bl = temp; 91 | temp = rotateLeft(ar + f(79 - j, br, cr, dr) + schedule[RR[j]] + KR[j / 16], SR[j]) + er; 92 | ar = er; 93 | er = dr; 94 | dr = rotateLeft(cr, 10); 95 | cr = br; 96 | br = temp; 97 | } 98 | int temp = state[1] + cl + dr; 99 | state[1] = state[2] + dl + er; 100 | state[2] = state[3] + el + ar; 101 | state[3] = state[4] + al + br; 102 | state[4] = state[0] + bl + cr; 103 | state[0] = temp; 104 | } 105 | } 106 | 107 | 108 | private static int f(int i, int x, int y, int z) { 109 | assert 0 <= i && i < 80; 110 | if (i < 16) return x ^ y ^ z; 111 | if (i < 32) return (x & y) | (~x & z); 112 | if (i < 48) return (x | ~y) ^ z; 113 | if (i < 64) return (x & z) | (y & ~z); 114 | return x ^ (y | ~z); 115 | } 116 | 117 | 118 | /*---- Class constants ----*/ 119 | 120 | private static final int[] KL = {0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E}; // Round constants for left line 121 | private static final int[] KR = {0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000}; // Round constants for right line 122 | 123 | private static final int[] RL = { // Message schedule for left line 124 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 125 | 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, 126 | 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, 127 | 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, 128 | 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13}; 129 | 130 | private static final int[] RR = { // Message schedule for right line 131 | 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 132 | 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, 133 | 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, 134 | 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, 135 | 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11}; 136 | 137 | private static final int[] SL = { // Left-rotation for left line 138 | 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, 139 | 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, 140 | 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, 141 | 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, 142 | 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6}; 143 | 144 | private static final int[] SR = { // Left-rotation for right line 145 | 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, 146 | 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, 147 | 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, 148 | 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, 149 | 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11}; 150 | 151 | 152 | 153 | /*---- Miscellaneous ----*/ 154 | 155 | private Ripemd160() {} // Not instantiable 156 | 157 | } 158 | -------------------------------------------------------------------------------- /java/io/nayuki/bitcoin/crypto/Sha256.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | package io.nayuki.bitcoin.crypto; 10 | 11 | import static java.lang.Integer.rotateRight; 12 | import java.util.Arrays; 13 | import java.util.Objects; 14 | 15 | 16 | /** 17 | * Computes the SHA-256 hash of an array of bytes. Not instantiable. 18 | */ 19 | public final class Sha256 { 20 | 21 | private static final int BLOCK_LEN = 64; // In bytes 22 | 23 | 24 | 25 | /*---- Static functions ----*/ 26 | 27 | /** 28 | * Computes and returns the SHA-256 hash of the specified binary message. 29 | * @param msg the message to compute the hash of 30 | * @return an object representing the message's SHA-256 hash 31 | * @throws NullPointerException if the message is {@code null} 32 | */ 33 | public static Sha256Hash getHash(byte[] msg) { 34 | return getHash(msg, INITIAL_STATE.clone(), 0); 35 | } 36 | 37 | 38 | /** 39 | * Computes and returns the SHA-256 hash of the SHA-256 hash of the specified binary message. 40 | * @param msg the message to compute the double hash of 41 | * @return an object representing the message's double SHA-256 hash 42 | * @throws NullPointerException if the message is {@code null} 43 | */ 44 | public static Sha256Hash getDoubleHash(byte[] msg) { 45 | return getHash(getHash(msg).toBytes()); 46 | } 47 | 48 | 49 | /** 50 | * Computes and returns the HMAC-SHA-256 of the specified binary key and binary message. 51 | * @param key the key for the message authentication code 52 | * @param msg the message for the message authentication code 53 | * @return an object representing the HMAC-SHA-256 of the key and message 54 | * @throws NullPointerException if the key or message is {@code null} 55 | */ 56 | public static Sha256Hash getHmac(byte[] key, byte[] msg) { 57 | Objects.requireNonNull(key); 58 | Objects.requireNonNull(msg); 59 | 60 | // Preprocess key, creating a new byte array 61 | key = Arrays.copyOf(key.length <= BLOCK_LEN ? key : getHash(key).toBytes(), BLOCK_LEN); 62 | 63 | // Compute inner hash 64 | for (int i = 0; i < key.length; i++) 65 | key[i] ^= 0x36; 66 | int[] state = INITIAL_STATE.clone(); 67 | compress(state, key, key.length); 68 | Sha256Hash innerHash = getHash(msg, state, key.length); 69 | 70 | // Compute outer hash 71 | for (int i = 0; i < key.length; i++) 72 | key[i] ^= 0x36 ^ 0x5C; 73 | state = INITIAL_STATE.clone(); 74 | compress(state, key, key.length); 75 | return getHash(innerHash.toBytes(), state, key.length); 76 | } 77 | 78 | 79 | 80 | /*---- Private functions ----*/ 81 | 82 | // Note: The initState array will be modified. 83 | private static Sha256Hash getHash(byte[] msg, int[] initState, int prefixLen) { 84 | // Compress whole message blocks 85 | Objects.requireNonNull(msg); 86 | int[] state = initState; 87 | int off = msg.length / BLOCK_LEN * BLOCK_LEN; 88 | compress(state, msg, off); 89 | 90 | // Final blocks, padding, and length 91 | byte[] block = new byte[BLOCK_LEN]; 92 | System.arraycopy(msg, off, block, 0, msg.length - off); 93 | off = msg.length % block.length; 94 | block[off] = (byte)0x80; 95 | off++; 96 | if (off + 8 > block.length) { 97 | compress(state, block, block.length); 98 | Arrays.fill(block, (byte)0); 99 | } 100 | long len = ((long)msg.length + prefixLen) << 3; 101 | for (int i = 0; i < 8; i++) 102 | block[block.length - 1 - i] = (byte)(len >>> (i * 8)); 103 | compress(state, block, block.length); 104 | 105 | // Int32 array to bytes in big endian 106 | byte[] result = new byte[state.length * 4]; 107 | for (int i = 0; i < result.length; i++) 108 | result[i] = (byte)(state[i / 4] >>> ((3 - i % 4) * 8)); 109 | return new Sha256Hash(result); 110 | } 111 | 112 | 113 | private static void compress(int[] state, byte[] blocks, int len) { 114 | if (len < 0 || len % BLOCK_LEN != 0) 115 | throw new IllegalArgumentException(); 116 | for (int i = 0; i < len; i += BLOCK_LEN) { 117 | 118 | // Message schedule 119 | int[] schedule = new int[64]; 120 | for (int j = 0; j < BLOCK_LEN; j++) 121 | schedule[j / 4] |= (blocks[i + j] & 0xFF) << ((3 - j % 4) * 8); 122 | for (int j = 16; j < 64; j++) { 123 | schedule[j] = schedule[j-16] + schedule[j-7] 124 | + (rotateRight(schedule[j-15], 7) ^ rotateRight(schedule[j-15], 18) ^ (schedule[j-15] >>> 3)) 125 | + (rotateRight(schedule[j- 2], 17) ^ rotateRight(schedule[j- 2], 19) ^ (schedule[j- 2] >>> 10)); 126 | } 127 | 128 | // The 64 rounds 129 | int a = state[0]; 130 | int b = state[1]; 131 | int c = state[2]; 132 | int d = state[3]; 133 | int e = state[4]; 134 | int f = state[5]; 135 | int g = state[6]; 136 | int h = state[7]; 137 | for (int j = 0; j < 64; j++) { 138 | int t1 = h + (rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25)) + (g ^ (e & (f ^ g))) + ROUND_CONSTANTS[j] + schedule[j]; 139 | int t2 = (rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22)) + ((a & (b | c)) | (b & c)); 140 | h = g; 141 | g = f; 142 | f = e; 143 | e = d + t1; 144 | d = c; 145 | c = b; 146 | b = a; 147 | a = t1 + t2; 148 | } 149 | state[0] += a; 150 | state[1] += b; 151 | state[2] += c; 152 | state[3] += d; 153 | state[4] += e; 154 | state[5] += f; 155 | state[6] += g; 156 | state[7] += h; 157 | } 158 | } 159 | 160 | 161 | /*---- Class constants ----*/ 162 | 163 | private static final int[] INITIAL_STATE = { 164 | 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 165 | 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, 166 | }; 167 | 168 | 169 | private static final int[] ROUND_CONSTANTS = { 170 | 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 171 | 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, 172 | 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 173 | 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 174 | 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 175 | 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, 176 | 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 177 | 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, 178 | 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 179 | 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 180 | 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 181 | 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, 182 | 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 183 | 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, 184 | 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 185 | 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, 186 | }; 187 | 188 | 189 | 190 | /*---- Miscellaneous ----*/ 191 | 192 | private Sha256() {} // Not instantiable 193 | 194 | } 195 | -------------------------------------------------------------------------------- /java/io/nayuki/bitcoin/crypto/Sha256Hash.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | package io.nayuki.bitcoin.crypto; 10 | 11 | import java.util.Arrays; 12 | import java.util.Objects; 13 | 14 | 15 | /** 16 | * A 32-byte (256-bit) SHA-256 hash value. Immutable. 17 | *

Note that by Bitcoin convention, SHA-256 hash strings are serialized in byte-reversed order. 18 | * For example, these three lines all represent the same hash value:

19 | *
    20 | *
  • Bigint: 0x0102030405060708091011121314151617181920212223242526272829303132.
  • 21 | *
  • Byte array: {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x30,0x31,0x32}.
  • 22 | *
  • Hex string: "3231302928272625242322212019181716151413121110090807060504030201".
  • 23 | *
      24 | * @see Sha256 25 | */ 26 | public final class Sha256Hash implements Comparable { 27 | 28 | /*---- Constants ----*/ 29 | 30 | /** The number of bytes in each SHA-256 hash value. */ 31 | public static final int HASH_LENGTH = 32; 32 | 33 | 34 | 35 | /*---- Fields ----*/ 36 | 37 | private final byte[] hash; 38 | 39 | 40 | 41 | /*---- Constructors ----*/ 42 | 43 | /** 44 | * Constructs a SHA-256 hash object from the specified array of bytes. 45 | * The array must be 32 bytes long. All 2256 possible values are valid. 46 | * Constant-time with respect to the specified value. 47 | * @throws IllegalArgumentException if the array is not of length 32 48 | * @throws NullPointerException if the array is {@code null} 49 | */ 50 | public Sha256Hash(byte[] b) { 51 | Objects.requireNonNull(b); 52 | if (b.length != HASH_LENGTH) 53 | throw new IllegalArgumentException(); 54 | hash = b.clone(); 55 | } 56 | 57 | 58 | /** 59 | * Constructs a SHA-256 hash object from the specified hexadecimal string. 60 | * The string must be 64 characters long and entirely made up of hexadecimal digits. 61 | * All 2256 possible values are valid. Not constant-time. 62 | * @throws IllegalArgumentException if the string is not of length 64 or entirely hexadecimal digits 63 | * @throws NullPointerException if the string is {@code null} 64 | */ 65 | public Sha256Hash(String s) { 66 | Objects.requireNonNull(s); 67 | if (s.length() != HASH_LENGTH * 2 || !s.matches("[0-9a-fA-F]*")) 68 | throw new IllegalArgumentException("Invalid hash string"); 69 | hash = new byte[HASH_LENGTH]; 70 | for (int i = 0; i < hash.length; i++) 71 | hash[hash.length - 1 - i] = (byte)Integer.parseInt(s.substring(i * 2, (i + 1) * 2), 16); 72 | } 73 | 74 | 75 | 76 | /*---- Methods ----*/ 77 | 78 | /** 79 | * Returns a new 32-byte array representing this hash value. Constant-time with respect to this hash value. 80 | * @return a byte array representing this hash 81 | */ 82 | public byte[] toBytes() { 83 | return hash.clone(); 84 | } 85 | 86 | 87 | /** 88 | * Tests whether this hash is equal to the specified object. Returns {@code true} if and only if the 89 | * other object is a {@code Sha256Hash} object with the same byte array values. Not constant-time. 90 | * @param obj the object to test equality with 91 | * @return whether the other object is a {@code Sha256Hash} with the same hash value 92 | */ 93 | public boolean equals(Object obj) { 94 | if (obj == this) 95 | return true; 96 | else if (!(obj instanceof Sha256Hash)) 97 | return false; 98 | else 99 | return Arrays.equals(hash, ((Sha256Hash)obj).hash); 100 | } 101 | 102 | 103 | /** 104 | * Returns the hash code of this object. Constant-time with respect to this hash value. 105 | * @return the hash code of this object 106 | */ 107 | public int hashCode() { 108 | return (hash[0] & 0xFF) | (hash[1] & 0xFF) << 8 | (hash[2] & 0xFF) << 16 | hash[3] << 24; 109 | } 110 | 111 | 112 | /** 113 | * Compares whether this hash is less than, equal to, or greater than the specified hash object. Not constant-time. 114 | *

      The comparison is performed in byte-reversed order, which means the string representations are normally ordered. 115 | * This behavior corresponds to the comparison used in the proof-of-work check for block headers.

      116 | * @return a negative number if {@code this < other}, zero if {@code this == other}, or a positive number if {@code this > other} 117 | * @throws NullPointerException if the other object is {@code null} 118 | */ 119 | public int compareTo(Sha256Hash other) { 120 | Objects.requireNonNull(other); 121 | for (int i = hash.length - 1; i >= 0; i--) { 122 | int temp = (hash[i] & 0xFF) - (other.hash[i] & 0xFF); 123 | if (temp != 0) 124 | return temp; 125 | } 126 | return 0; 127 | } 128 | 129 | 130 | /** 131 | * Returns the hexadecimal string representation of this hash, in lowercase, 64 digits long. 132 | * Remember that the string is byte-reversed with respect to the byte array. Not constant-time. 133 | * @return a 64-digit hexadecimal string of this hash 134 | */ 135 | public String toString() { 136 | StringBuilder sb = new StringBuilder(); 137 | for (int i = hash.length - 1; i >= 0; i--) 138 | sb.append(String.format("%02x", hash[i])); 139 | return sb.toString(); 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /java/io/nayuki/bitcoin/crypto/Sha512.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | package io.nayuki.bitcoin.crypto; 10 | 11 | import static java.lang.Long.rotateRight; 12 | import java.util.Arrays; 13 | import java.util.Objects; 14 | 15 | 16 | /** 17 | * Computes the SHA-512 hash or HMAC of an array of bytes. Not instantiable. 18 | */ 19 | public final class Sha512 { 20 | 21 | private static final int BLOCK_LEN = 128; // In bytes 22 | 23 | 24 | 25 | /*---- Static functions ----*/ 26 | 27 | /** 28 | * Computes and returns a 64-byte (512-bit) hash of the specified binary message. 29 | * Each call will return a new byte array object instance. 30 | * @param msg the message to compute the hash of 31 | * @return a 64-byte array representing the message's SHA-512 hash 32 | * @throws NullPointerException if the message is {@code null} 33 | */ 34 | public static byte[] getHash(byte[] msg) { 35 | // Compress whole message blocks 36 | Objects.requireNonNull(msg); 37 | long[] state = { 38 | 0x6A09E667F3BCC908L, 0xBB67AE8584CAA73BL, 0x3C6EF372FE94F82BL, 0xA54FF53A5F1D36F1L, 39 | 0x510E527FADE682D1L, 0x9B05688C2B3E6C1FL, 0x1F83D9ABFB41BD6BL, 0x5BE0CD19137E2179L}; 40 | int off = msg.length / BLOCK_LEN * BLOCK_LEN; 41 | compress(state, msg, off); 42 | 43 | // Final blocks, padding, and length 44 | byte[] block = new byte[BLOCK_LEN]; 45 | System.arraycopy(msg, off, block, 0, msg.length - off); 46 | off = msg.length % block.length; 47 | block[off] = (byte)0x80; 48 | off++; 49 | if (off + 16 > block.length) { 50 | compress(state, block, block.length); 51 | Arrays.fill(block, (byte)0); 52 | } 53 | long len = (long)msg.length << 3; 54 | for (int i = 0; i < 8; i++) 55 | block[block.length - 1 - i] = (byte)(len >>> (i * 8)); 56 | compress(state, block, block.length); 57 | 58 | // Int64 array to bytes in big endian 59 | byte[] result = new byte[state.length * 8]; 60 | for (int i = 0; i < result.length; i++) 61 | result[i] = (byte)(state[i / 8] >>> ((7 - i % 8) * 8)); 62 | return result; 63 | } 64 | 65 | 66 | /** 67 | * Computes and returns a 64-byte (512-bit) message authentication code of the 68 | * specified message with the specified key, using the HMAC-SHA-512 algorithm. 69 | * Each call will return a new byte array object instance. 70 | * @param key the secret key 71 | * @param msg the message 72 | * @throws NullPointerException if the key or message is {@code null} 73 | * @return a 64-byte array representing the HMAC value 74 | */ 75 | public static byte[] getHmac(byte[] key, byte[] msg) { 76 | Objects.requireNonNull(key); 77 | Objects.requireNonNull(msg); 78 | if (key.length > BLOCK_LEN) 79 | key = getHash(key); 80 | if (key.length < BLOCK_LEN) // Note: Do not change to else-if 81 | key = Arrays.copyOf(key, BLOCK_LEN); 82 | if (key.length != BLOCK_LEN) 83 | throw new AssertionError(); 84 | 85 | byte[] innerMsg = new byte[BLOCK_LEN + msg.length]; 86 | for (int i = 0; i < key.length; i++) 87 | innerMsg[i] = (byte)(key[i] ^ 0x36); 88 | System.arraycopy(msg, 0, innerMsg, BLOCK_LEN, msg.length); 89 | byte[] innerHash = getHash(innerMsg); 90 | 91 | byte[] outerMsg = new byte[BLOCK_LEN + innerHash.length]; 92 | for (int i = 0; i < key.length; i++) 93 | outerMsg[i] = (byte)(key[i] ^ 0x5C); 94 | System.arraycopy(innerHash, 0, outerMsg, BLOCK_LEN, innerHash.length); 95 | return getHash(outerMsg); 96 | } 97 | 98 | 99 | 100 | /*---- Private functions ----*/ 101 | 102 | private static void compress(long[] state, byte[] blocks, int len) { 103 | if (len < 0 || len % BLOCK_LEN != 0) 104 | throw new IllegalArgumentException(); 105 | for (int i = 0; i < len; i += BLOCK_LEN) { 106 | 107 | // Message schedule 108 | long[] schedule = new long[80]; 109 | for (int j = 0; j < BLOCK_LEN; j++) 110 | schedule[j / 8] |= (blocks[i + j] & 0xFFL) << ((7 - j % 8) * 8); 111 | for (int j = 16; j < 80; j++) { 112 | schedule[j] = schedule[j-16] + schedule[j-7] 113 | + (rotateRight(schedule[j-15], 1) ^ rotateRight(schedule[j-15], 8) ^ (schedule[j-15] >>> 7)) 114 | + (rotateRight(schedule[j- 2], 19) ^ rotateRight(schedule[j- 2], 61) ^ (schedule[j- 2] >>> 6)); 115 | } 116 | 117 | // The 80 rounds 118 | long a = state[0]; 119 | long b = state[1]; 120 | long c = state[2]; 121 | long d = state[3]; 122 | long e = state[4]; 123 | long f = state[5]; 124 | long g = state[6]; 125 | long h = state[7]; 126 | for (int j = 0; j < 80; j++) { 127 | long t1 = h + (rotateRight(e, 14) ^ rotateRight(e, 18) ^ rotateRight(e, 41)) + (g ^ (e & (f ^ g))) + ROUND_CONSTANTS[j] + schedule[j]; 128 | long t2 = (rotateRight(a, 28) ^ rotateRight(a, 34) ^ rotateRight(a, 39)) + ((a & (b | c)) | (b & c)); 129 | h = g; 130 | g = f; 131 | f = e; 132 | e = d + t1; 133 | d = c; 134 | c = b; 135 | b = a; 136 | a = t1 + t2; 137 | } 138 | state[0] += a; 139 | state[1] += b; 140 | state[2] += c; 141 | state[3] += d; 142 | state[4] += e; 143 | state[5] += f; 144 | state[6] += g; 145 | state[7] += h; 146 | } 147 | } 148 | 149 | 150 | /*---- Class constants ----*/ 151 | 152 | private static final long[] ROUND_CONSTANTS = { 153 | 0x428A2F98D728AE22L, 0x7137449123EF65CDL, 0xB5C0FBCFEC4D3B2FL, 0xE9B5DBA58189DBBCL, 154 | 0x3956C25BF348B538L, 0x59F111F1B605D019L, 0x923F82A4AF194F9BL, 0xAB1C5ED5DA6D8118L, 155 | 0xD807AA98A3030242L, 0x12835B0145706FBEL, 0x243185BE4EE4B28CL, 0x550C7DC3D5FFB4E2L, 156 | 0x72BE5D74F27B896FL, 0x80DEB1FE3B1696B1L, 0x9BDC06A725C71235L, 0xC19BF174CF692694L, 157 | 0xE49B69C19EF14AD2L, 0xEFBE4786384F25E3L, 0x0FC19DC68B8CD5B5L, 0x240CA1CC77AC9C65L, 158 | 0x2DE92C6F592B0275L, 0x4A7484AA6EA6E483L, 0x5CB0A9DCBD41FBD4L, 0x76F988DA831153B5L, 159 | 0x983E5152EE66DFABL, 0xA831C66D2DB43210L, 0xB00327C898FB213FL, 0xBF597FC7BEEF0EE4L, 160 | 0xC6E00BF33DA88FC2L, 0xD5A79147930AA725L, 0x06CA6351E003826FL, 0x142929670A0E6E70L, 161 | 0x27B70A8546D22FFCL, 0x2E1B21385C26C926L, 0x4D2C6DFC5AC42AEDL, 0x53380D139D95B3DFL, 162 | 0x650A73548BAF63DEL, 0x766A0ABB3C77B2A8L, 0x81C2C92E47EDAEE6L, 0x92722C851482353BL, 163 | 0xA2BFE8A14CF10364L, 0xA81A664BBC423001L, 0xC24B8B70D0F89791L, 0xC76C51A30654BE30L, 164 | 0xD192E819D6EF5218L, 0xD69906245565A910L, 0xF40E35855771202AL, 0x106AA07032BBD1B8L, 165 | 0x19A4C116B8D2D0C8L, 0x1E376C085141AB53L, 0x2748774CDF8EEB99L, 0x34B0BCB5E19B48A8L, 166 | 0x391C0CB3C5C95A63L, 0x4ED8AA4AE3418ACBL, 0x5B9CCA4F7763E373L, 0x682E6FF3D6B2B8A3L, 167 | 0x748F82EE5DEFB2FCL, 0x78A5636F43172F60L, 0x84C87814A1F0AB72L, 0x8CC702081A6439ECL, 168 | 0x90BEFFFA23631E28L, 0xA4506CEBDE82BDE9L, 0xBEF9A3F7B2C67915L, 0xC67178F2E372532BL, 169 | 0xCA273ECEEA26619CL, 0xD186B8C721C0C207L, 0xEADA7DD6CDE0EB1EL, 0xF57D4F7FEE6ED178L, 170 | 0x06F067AA72176FBAL, 0x0A637DC5A2C898A6L, 0x113F9804BEF90DAEL, 0x1B710B35131C471BL, 171 | 0x28DB77F523047D84L, 0x32CAAB7B40C72493L, 0x3C9EBE0A15C9BEBCL, 0x431D67C49C100D4CL, 172 | 0x4CC5D4BECB3E42B6L, 0x597F299CFC657E2AL, 0x5FCB6FAB3AD6FAECL, 0x6C44198C4A475817L, 173 | }; 174 | 175 | 176 | 177 | /*---- Miscellaneous ----*/ 178 | 179 | private Sha512() {} // Not instantiable 180 | 181 | } 182 | -------------------------------------------------------------------------------- /java/io/nayuki/bitcoin/crypto/Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Bitcoin cryptography library 3 | * Copyright (c) Project Nayuki 4 | * 5 | * https://www.nayuki.io/page/bitcoin-cryptography-library 6 | * https://github.com/nayuki/Bitcoin-Cryptography-Library 7 | */ 8 | 9 | package io.nayuki.bitcoin.crypto; 10 | 11 | import java.io.UnsupportedEncodingException; 12 | 13 | 14 | // Miscellaneous utilities for the test suites. 15 | final class Utils { 16 | 17 | /*---- Static functions ----*/ 18 | 19 | // Converts a hex string to a new array of bytes. The string length 20 | // must be even. Hexadecimal letters can be uppercase or lowercase. 21 | public static byte[] hexToBytes(String s) { 22 | if (s.length() % 2 != 0) 23 | throw new IllegalArgumentException(); 24 | 25 | byte[] b = new byte[s.length() / 2]; 26 | for (int i = 0; i < s.length(); i += 2) { 27 | if (s.charAt(i) == '+' || s.charAt(i) == '-') 28 | throw new IllegalArgumentException(); 29 | b[i / 2] = (byte)Integer.parseInt(s.substring(i, i + 2), 16); 30 | } 31 | return b; 32 | } 33 | 34 | 35 | public static byte[] asciiToBytes(String s) { 36 | try { 37 | return s.getBytes("US-ASCII"); 38 | } catch (UnsupportedEncodingException e) { 39 | throw new AssertionError(e); 40 | } 41 | } 42 | 43 | 44 | 45 | /*---- Miscellaneous ----*/ 46 | 47 | private Utils() {} // Not instantiable 48 | 49 | } 50 | --------------------------------------------------------------------------------