Compare commits

...

96 Commits

Author SHA1 Message Date
NIIBE Yutaka
272875ee76 version 1.1.3 2014-04-16 13:26:47 +09:00
NIIBE Yutaka
85b2698bb3 Add curve25519 computation. 2014-04-15 10:28:17 +09:00
NIIBE Yutaka
4d6f59079a minor fixes. 2014-04-14 18:37:25 +09:00
NIIBE Yutaka
53aa3de9b4 cleanup mod_inv. 2014-04-08 10:57:46 +09:00
NIIBE Yutaka
afa0683495 EdDSA-sha512 means SHA512 implicitly. 2014-04-07 14:42:59 +09:00
NIIBE Yutaka
a7f3a3e260 now EdDSA works. 2014-04-03 16:06:42 +09:00
NIIBE Yutaka
9cd4a1a47f fix EdDSA 2014-04-03 16:02:56 +09:00
NIIBE Yutaka
f9ed79f644 gpg_do_write_prvkey for ed25519 2014-04-01 11:09:17 +09:00
NIIBE Yutaka
c7a6370b74 proc_key_import for ed25519 2014-03-31 17:12:07 +09:00
NIIBE Yutaka
dc4584a8a5 gpg_do_public_key for ed25519 2014-03-31 16:58:48 +09:00
NIIBE Yutaka
89f0af1496 Add attribute for ed25519 2014-03-31 16:54:29 +09:00
NIIBE Yutaka
28a5799cf7 eddsa_sign_25519 2014-03-31 16:46:40 +09:00
NIIBE Yutaka
07b960009a flash private key handling. 2014-03-31 15:23:37 +09:00
NIIBE Yutaka
b37a1e728e clean up. 2014-03-29 07:59:31 +09:00
NIIBE Yutaka
c5bdc370dd Change API of eddsa_25519 2014-03-28 16:04:00 +09:00
NIIBE Yutaka
9c5eb9ea4b Add implementation note 2014-03-27 15:12:21 +09:00
NIIBE Yutaka
356a9cc615 eddsa_25519: API change 2014-03-27 12:04:03 +09:00
NIIBE Yutaka
5882b37b58 simplify compute_kG_25519 2014-03-27 11:52:30 +09:00
NIIBE Yutaka
1920c5fc69 improve a bit 2014-03-26 18:37:38 +09:00
NIIBE Yutaka
fc53d507ce fix wrong comment 2014-03-25 16:24:31 +09:00
NIIBE Yutaka
da027eb67f add test code 2014-03-25 14:30:51 +09:00
NIIBE Yutaka
fcf6c60336 cleanup 2014-03-25 11:23:33 +09:00
NIIBE Yutaka
cbf896a61b Implemented EdDSA 2014-03-25 11:05:26 +09:00
NIIBE Yutaka
adbb67deb8 compute_kG_25519 2014-03-20 19:53:38 +09:00
NIIBE Yutaka
129d1b0d30 add precomputed tables. 2014-03-20 17:15:53 +09:00
NIIBE Yutaka
25e71cb29b use 64-bit for mul 2014-03-20 15:51:55 +09:00
NIIBE Yutaka
7d8696946a more bn fix 2014-03-20 15:42:32 +09:00
NIIBE Yutaka
2bb12e55c2 fix 2014-03-19 23:47:59 +09:00
NIIBE Yutaka
fa10e78344 fix bn.c 2014-03-19 23:47:19 +09:00
NIIBE Yutaka
116486affa Add ecc-edwards.c 2014-03-19 17:07:49 +09:00
NIIBE Yutaka
53bf87acf5 fix 2014-03-19 17:07:04 +09:00
NIIBE Yutaka
22bc67959e add comments 2014-03-19 11:12:36 +09:00
NIIBE Yutaka
971ee94d8f affine.h 2014-03-18 15:13:56 +09:00
NIIBE Yutaka
a3504e8510 mod25638 2014-03-18 14:18:39 +09:00
NIIBE Yutaka
bfe0466bd2 move fe25519 2014-03-14 13:07:51 +09:00
NIIBE Yutaka
fb8cb58c5c version 1.1.2 2014-03-07 15:43:05 +09:00
NIIBE Yutaka
db2187835c don't put OID for public key info. 2014-02-25 11:06:11 +09:00
NIIBE Yutaka
653868c00b fix configure for certdo 2014-02-25 09:25:49 +09:00
NIIBE Yutaka
ede98fbe7e bug fixes for secp256k1 2014-02-21 17:24:19 +09:00
NIIBE Yutaka
2accc339e2 fix modp256k1_shift 2014-02-21 11:36:15 +09:00
NIIBE Yutaka
9feeeb308b Add RSA_SIG (disable to use p256k1) 2014-02-20 12:02:44 +09:00
NIIBE Yutaka
01806c2e5e authentication with ecdsa p256r1 2014-02-20 10:58:51 +09:00
NIIBE Yutaka
a32f577dfa add call-ec_p256k1 2014-02-20 10:55:20 +09:00
NIIBE Yutaka
deaf340687 add ec_p256k1 2014-02-19 14:51:09 +09:00
NIIBE Yutaka
f5e8e94bf7 fix ec_p256r1 2014-02-19 11:36:27 +09:00
NIIBE Yutaka
df4e8c5481 Use CPP for jpc_p256[kr]1 2014-02-18 15:54:28 +09:00
NIIBE Yutaka
888eb2aa31 minor fix 2014-02-18 14:07:25 +09:00
NIIBE Yutaka
1436223320 sha256 bug fix 2014-02-18 14:01:57 +09:00
NIIBE Yutaka
13a52a0862 minor fixes 2014-02-18 14:01:34 +09:00
NIIBE Yutaka
ea73e1ee7e bugfic for modp256k1 2014-02-18 14:01:04 +09:00
NIIBE Yutaka
8ca0416be8 Add modp256k1.[ch] 2014-02-18 12:07:33 +09:00
NIIBE Yutaka
d42eba5cb0 Use P256R1 2014-02-18 11:00:28 +09:00
NIIBE Yutaka
60820f5a5f name change p256 -> p256r1 2014-02-17 13:49:35 +09:00
NIIBE Yutaka
2c8f1cb0ce sha improvement 2014-02-05 16:33:21 +09:00
NIIBE Yutaka
2e80472f1c Add sha512 2014-02-05 16:20:26 +09:00
NIIBE Yutaka
8f60b1568f fix sha256 2014-02-05 13:33:58 +09:00
NIIBE Yutaka
91ca2d9827 Assembler MUL/SQR 2014-01-28 11:31:52 +09:00
NIIBE Yutaka
6d2f9f8df1 bug fix for compute_kP 2014-01-28 09:59:26 +09:00
NIIBE Yutaka
42251eea8e Fix for constant time: compute_kP (for ECDH in future) 2014-01-27 16:27:51 +09:00
NIIBE Yutaka
fc5df5019f clean up 2014-01-27 11:26:58 +09:00
NIIBE Yutaka
e18df3af6b clean up 2014-01-27 11:17:10 +09:00
NIIBE Yutaka
4b65ed1a5b simplify compute_kP 2014-01-24 16:16:41 +09:00
NIIBE Yutaka
f4e10311c7 Fix for constant time (step 10): ECDSA done 2014-01-24 14:49:38 +09:00
NIIBE Yutaka
78ffb4179e Fix for constant time (step 9) 2014-01-24 11:05:49 +09:00
NIIBE Yutaka
36541838f9 bug fix 2014-01-23 14:59:55 +09:00
NIIBE Yutaka
29e76d0ba7 cosmetic change 2014-01-22 16:57:19 +09:00
NIIBE Yutaka
c29bd10555 bug fix 2014-01-22 15:53:13 +09:00
NIIBE Yutaka
5c01e92c20 bug fix for ecdsa 2014-01-22 14:34:46 +09:00
NIIBE Yutaka
94508ae5d9 Fix for constant time (step 8) 2014-01-22 14:33:40 +09:00
NIIBE Yutaka
251760d5da Fix for constant time (step 7) 2014-01-22 14:26:41 +09:00
NIIBE Yutaka
6a69c31c3b Fix for constant time (step 6) 2014-01-22 14:09:55 +09:00
NIIBE Yutaka
486f20bfd4 more fix on ecc 2014-01-22 10:02:08 +09:00
NIIBE Yutaka
8d05addc87 bug fix for inf check 2014-01-22 09:58:59 +09:00
NIIBE Yutaka
9f0e2eabd1 bug fix for mod.c change 2014-01-21 21:02:03 +09:00
NIIBE Yutaka
f21a89588c Fix for constant time (step 5) 2014-01-21 14:40:58 +09:00
NIIBE Yutaka
af66c5fa08 format 2014-01-21 14:26:31 +09:00
NIIBE Yutaka
0e7078bacb Fix for constant time (step 4) 2014-01-21 14:14:39 +09:00
NIIBE Yutaka
df8434db59 Fix for constant time (step 3) 2014-01-21 13:58:01 +09:00
NIIBE Yutaka
80d935d913 Fix for constant time (step 2) 2014-01-21 13:31:23 +09:00
NIIBE Yutaka
007eada502 Fix for constant time (step 1) 2014-01-21 13:25:30 +09:00
NIIBE Yutaka
3bb3c6e9d8 member name change 2014-01-21 13:07:20 +09:00
NIIBE Yutaka
4f154cc61d add fe25519 2014-01-20 16:14:10 +09:00
NIIBE Yutaka
38f8b91335 bn.c: constant time 2014-01-15 22:05:18 +09:00
NIIBE Yutaka
b35765d58b version 1.1.1 2013-12-25 13:05:43 +09:00
NIIBE Yutaka
932e6acd40 Support PyUSB 1.0, too 2013-12-25 11:33:00 +09:00
NIIBE Yutaka
62863d52b2 more minor change for bignum 2013-12-25 10:04:10 +09:00
NIIBE Yutaka
26db39b1b7 don't use r10 2013-12-24 21:21:44 +09:00
NIIBE Yutaka
1774563184 use r12 and more tweak 2013-12-24 20:50:21 +09:00
NIIBE Yutaka
a89ae40e89 improve a bit 2013-12-24 15:21:07 +09:00
NIIBE Yutaka
4427227284 more tweak 2013-12-24 13:46:22 +09:00
NIIBE Yutaka
141d345cfe more improvement of mpi_montsqr and multiply. 2013-12-24 12:22:54 +09:00
NIIBE Yutaka
cc7221e5cb merge 2013-12-23 17:55:46 +09:00
NIIBE Yutaka
34fe062548 more tweak of API 2013-12-23 17:51:04 +09:00
NIIBE Yutaka
72e67d81a3 more tweak of API 2013-12-23 16:42:53 +09:00
NIIBE Yutaka
e8896ecb4d mpi_exp_mod: Use stack instead of malloc 2013-12-23 16:17:20 +09:00
NIIBE Yutaka
cce282b3d7 more constant-time computation 2013-12-23 10:13:04 +09:00
65 changed files with 5085 additions and 1339 deletions

313
ChangeLog
View File

@@ -1,3 +1,316 @@
2014-04-16 Niibe Yutaka <gniibe@fsij.org>
* VERSION: 1.1.3.
2014-04-15 Niibe Yutaka <gniibe@fsij.org>
* src/ecc-mont.c: New.
* src/mod25638.c (p25519): Move from ecc-edwards.c.
(mod25519_reduce, add19): Likewise.
(mod25638_reduce) [!ASM_IMPLEMENTATION]: Use bn256_add_uint.
2014-04-14 Niibe Yutaka <gniibe@fsij.org>
* src/jpc.c (jpc_to_ac): Error check before mod_inv.
* src/mod.c (mod_inv): No return value (if N==0 returns ZERO).
* src/bn.c [BN256_NO_RANDOM]: Only include "random.h" if needed.
2014-04-08 Niibe Yutaka <gniibe@fsij.org>
* src/mod.c (mod_inv): Use MAX_GCD_STEPS_BN256.
Return failure or success.
* src/jpc.c (jpc_to_ac): Use mod_inv.
* src/modp256k1.c (modp256k1_inv): Remove.
* src/modp256r1.c (modp256r1_inv): Remove.
2014-04-07 Niibe Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (algorithm_attr_ed25519): It's OID only.
2014-04-03 Niibe Yutaka <gniibe@fsij.org>
* src/ecc-edwards.c (eddsa_sign_25519): Change type of OUT.
* src/openpgp.c (cmd_internal_authenticate): Have a buffer.
* src/flash.c (flash_init): Fix key address finder.
2014-04-02 Niibe Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (proc_key_import): Handle EdDSA.
(algorithm_attr_ed25519): Fix OID and add ID for SHA512.
2014-04-01 Niibe Yutaka <gniibe@fsij.org>
* src/ecc-edwards.c (eddsa_compute_public_25519): New.
* src/openpgp-do.c (algorithm_attr_ed25519): New.
(gpg_do_write_prvkey, proc_key_import, gpg_do_public_key): Add
EdDSA handling.
2014-03-31 Niibe Yutaka <gniibe@fsij.org>
* src/ecc-edwards.c (eddsa_sign_25519): Rename and API change.
* src/openpgp-do.c (gpg_do_load_prvkey, gpg_do_delete_prvkey)
(gpg_do_write_prvkey, gpg_do_public_key, gpg_do_keygen): Follow
the change of PRVKEY_DATA and KEY_DATA.
* src/flash.c (key_available_at): New.
(flash_init): Initilize KD.
* src/gnuk.h (struct prvkey_data): Remove member KEY_ADDR.
(struct key_data): Addd member KEY_ADDR.
* src/openpgp-do.c (gpg_do_keygen): Bug fix. Reset the signature
counter when new key is generated.
* src/flash.c (flash_key_alloc): Change API, supply KK.
2014-03-29 Niibe Yutaka <gniibe@fsij.org>
* src/ecc-edwards.c (point_double, point_add): Rename.
(mod25519_reduce): New.
2014-03-28 Niibe Yutaka <gniibe@fsij.org>
* misc/t-eddsa.c (main): Update for new API of eddsa_25519.
* src/ecc-edwards.c (compute_kG_25519): Tune for 252-bit.
(eddsa_25519): Public key should be provided by caller.
(eddsa_public_key_25519): New.
2014-03-27 Niibe Yutaka <gniibe@fsij.org>
* src/ecc-edwards.c (ed_add_25638): Remove the third argument.
(compute_kG_25519): The curve is complete, we don't need to avoid
identity element as NIST curve or secp256k1 curve.
(eddsa_25519): Change the API, with A and the seed.
2014-03-26 Niibe Yutaka <gniibe@fsij.org>
* src/mod25638.c (mod25638_reduce): New.
(mod25638_mul, mod25638_sqr): Use mod25638_reduce.
* src/ecc-edwards.c (ptc_to_ac_25519): No need to subtract p25519.
2014-03-25 Niibe Yutaka <gniibe@fsij.org>
* misc/t-eddsa.c: New.
* src/ecc-edwards.c (bnX_mul_C, mod_reduce_M): New.
(eddsa_25519): New.
2014-03-20 Niibe Yutaka <gniibe@fsij.org>
* src/ecc-edwards.c (ed_add_25638): Fix for X == A.
(main): Compute pre-computed tables.
(precomputed_KG, precomputed_2E_KG): Add.
(compute_kG_25519): New.
2014-03-19 Niibe Yutaka <gniibe@fsij.org>
* src/bn.c (bn256_add): Fix for X == B.
(bn256_sub): Likewise.
* src/ecc-edwards.c: New.
2014-03-18 Niibe Yutaka <gniibe@fsij.org>
* src/mod25638.c (mod25638_add, mod25638_sub, mod25638_sqr)
(mod25638_shift): New.
2014-03-13 Niibe Yutaka <gniibe@fsij.org>
* src/mod25638.c: Rename from fe25519.c.
* src/mod25638.h: Likewise.
2014-03-07 Niibe Yutaka <gniibe@fsij.org>
* VERSION: 1.1.2.
2014-02-25 Niibe Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (gpg_do_public_key): Don't put OID.
* src/configure [certdo] (gnuk.ld): Add TIM_SIZE and EXT_SIZE.
Thanks to Vasily Evseenko for the bug report.
2014-02-21 Niibe Yutaka <gniibe@fsij.org>
* src/ecc.c (compute_kG): Compute higer index at first.
(point_is_on_the_curve): Don't use coefficient_a if it's zero.
* src/jpc.c (jpc_double): Care coefficient A.
* src/ec_p256r1.c (COEFFICIENT_A_IS_MINUS_3): New.
* src/ec_p256k1.c (COEFFICIENT_A_IS_ZERO): New.
* src/jpc_p256r1.c (COEFFICIENT_A_IS_MINUS_3): Likewise.
* src/jpc_p256k1.c (COEFFICIENT_A_IS_MINUS_3): Likewise.
* src/modp256k1.c (modp256k1_shift): Bug fix.
2014-02-20 Niibe Yutaka <gniibe@fsij.org>
* src/Makefile.in (CSRC): Add files of p256k1.
* src/openpgp.c (cmd_pso): Support p256k1 for signature.
* src/openpgp-do.c (algorithm_attr_p256k1): New.
(gpg_do_write_prvkey): Support p256k1 for signature.
(proc_key_import, gpg_do_table, gpg_do_public_key): Likewise.
* src/Makefile.in (DEFS): Add -DRSA_SIG.
* src/openpgp-do.c (gpg_do_write_prvkey): Use _p256r1.
* src/openpgp.c (cmd_internal_authenticate): Likewise.
* src/call-ec_p256k1.c: New. Use call-ec.c.
* src/call-ec_p256r1.c: Use call-ec.c.
* src/call-ec.c: New.
(ecdsa_sign): Change the signature.
2014-02-19 Niibe Yutaka <gniibe@fsij.org>
* tool/calc_precompute_table_ecc.py: New.
* src/ec_p256k1.c: New. Use ecc.c.
* src/ec_p256k1.h: New.
* src/ec_p256r1.c: Use ecc.c.
* src/ecc.c: New.
2014-02-18 Niibe Yutaka <gniibe@fsij.org>
* src/jpc_p256k1.c: New. Use jpc.c.
* src/jpc_p256r1.c: Use jpc.c.
* src/jpc.c: New.
* src/sha256.c (memcpy_output_bswap32): Bug fix.
* src/modp256k1.h, src/modp256k1.c: New.
2014-02-17 Niibe Yutaka <gniibe@fsij.org>
* src/Makefile.in (CSRC): Follow the changes of filenames.
* src/modp256r1.c (modp256r1_add, modp256r1_sub, S3)
(modp256r1_mul, modp256r1_sqr, modp256r1_inv, modp256r1_shift):
Use new function names.
* src/jpc_p256r1.c (jpc_double_p256r1, jpc_add_ac_signed_p256r1)
(jpc_to_ac_p256r1): Likewise.
* src/ec_p256r1.c (point_is_on_the_curve)
(compute_kG_p256r1, compute_kP_p256r1): Likewise.
* src/call-ec_p256r1.c (ecdsa_sign): Likewise.
* src/modp256r1.h: Rename from modp256.h.
* src/jpc-ac_p256r1.h: Rename from jpc-ac.h.
* src/ec_p256r1.h: Rename from ec_p256.h.
* src/modp256r1.c: Rename from modp256.c.
* src/jpc_p256r1.c: Rename from jpc.c.
* src/ec_p256r1.c: Rename from ec_p256.c.
* src/call-ec_p256r1.c: Rename from call-ec_p256.c.
2014-02-05 NIIBE Yutaka <gniibe@fsij.org>
* src/sha512.h, src/sha512.c: New.
* src/sha256.c (initial_state): Don't export, it's internal.
(memcpy_output_bswap32): Rename and remove last argument.
2014-01-28 Niibe Yutaka <gniibe@fsij.org>
* src/muladd_256.h: New.
* src/bn.c (bn256_mul, bn256_sqr): Assembler implementation.
* src/ec_p256.c (get_vk_kP): Bug fix.
(compute_kP): Bug fix for index table.
2014-01-27 Niibe Yutaka <gniibe@fsij.org>
* src/ec_p256.c (get_vk_kP): New.
(naf4_257_set, naf4_257_get, compute_naf4_257): Remove.
(compute_kP): Change the argument, fixing for constant time.
2014-01-24 Niibe Yutaka <gniibe@fsij.org>
* src/ec_p256.c (get_vk): New.
(compute_kG): Fix for constant time.
(compute_kP): Simplify.
2014-01-23 Niibe Yutaka <gniibe@fsij.org>
* src/jpc.c (jpc_add_ac_signed): Fix for constant time.
* src/ec_p256.c (ecdsa): Bug fix for k selection.
2014-01-22 Niibe Yutaka <gniibe@fsij.org>
* src/modp256.c (modp256_inv): Fix for constant time.
* src/bn.c (bn256_sqr): Fix for constant time.
* src/mod.c (mod_inv): Fix for constant time.
* src/ec_p256.c (compute_kG): Simplify.
* src/jpc.c (jpc_double): Support calling with A = infinity.
2014-01-21 Niibe Yutaka <gniibe@fsij.org>
* src/jpc.c (jpc_add_ac_signed): Bug fix for A check.
* src/ec_p256.c (ecdsa): Fix for constant time.
* src/modp256.c (modp256_add, modp256_sub, modp256_reduce)
(modp256_shift): Fix for constant time.
(modp256_inv): Likewise (not fully constant time, yet).
* src/mod.c (mod_reduce): Fix for constant time.
(mod_inv): Likewise (not fully constant time, yet).
* src/bn.h (bn256, bn512): words -> word.
* src/ec_p256.h (naf4_257): Likewise.
2014-01-20 Niibe Yutaka <gniibe@fsij.org>
* src/fe25519.h, src/fe25519.c: New.
2014-01-15 Niibe Yutaka <gniibe@fsij.org>
* src/bn.c (bn256_is_zero, bn256_is_ge, bn256_cmp): Computation
should be constant time.
2013-12-25 Niibe Yutaka <gniibe@fsij.org>
* VERSION: 1.1.1.
* tool/gnuk_token.py (gnuk_token.__init__, regnual.__init__): Fix
the argument of setAltInterface.
* tool/gnuk_upgrade.py: Likewise.
* tool/dfuse.py (DFU_STM32.__init__): Likewise.
* tool/stlinkv2.py (stlinkv2.__init__): Likewise.
2013-12-24 Niibe Yutaka <gniibe@fsij.org>
* polarssl/include/polarssl/bn_mul.h (MULADDC_1024_CORE)
(MULADDC_1024_LOOP): Use younger number registers more for shorter
instructions and better performance.
* polarssl/library/bignum.c (mpi_montsqr): Likewise. Change loop
structure and conditional branch for better performance.
2013-12-23 Niibe Yutaka <gniibe@fsij.org>
* polarssl/library/bignum.c (mpi_montmul): Computation
time should not depends on input.
(mpi_montmul, mpi_montred, mpi_montsqr): Change the API.
(mpi_exp_mod): Follow the change of the API. Allocate memory on
stack instead of malloc.
* src/gnuk.ld.in (__process3_stack_size__): Increase stack size.
2013-12-20 Niibe Yutaka <gniibe@fsij.org>
* Version 1.1.0.

33
NEWS
View File

@@ -1,5 +1,38 @@
Gnuk NEWS - User visible changes
* Major changes in Gnuk 1.1.3
Released 2014-04-16, by NIIBE Yutaka
** Experimental EdDSA support.
After configure, you can edit the DEFS variable in src/Makefile, so
that Gnuk can support EdDSA with Ed25519 (for authentication). Note
that this is pretty much experimental, and subjects to change.
* Major changes in Gnuk 1.1.2
Released 2014-03-07, by NIIBE Yutaka
** Experimental ECC support for secp256k1.
After configure, you can edit the DEFS variable in src/Makefile, so
that Gnuk can support ECDSA with NIST P256 (for authentication), and
ECDSA with secp256k1 (for signature). Note that this is pretty much
experimental, and subjects to change.
* Major changes in Gnuk 1.1.1
Released 2013-12-25, by NIIBE Yutaka
** Tools and test suite now work with PyUSB 1.0, too.
It only worked with PyUSB 0.4.3, but it works with PyUSB 1.0 too.
** Improved RSA routine
Working memory for RSA computation is taken from stack instead of
malloc (mostly).
* Major changes in Gnuk 1.1.0
Released 2013-12-20, by NIIBE Yutaka

48
README
View File

@@ -1,18 +1,23 @@
Gnuk - An Implementation of USB Cryptographic Token for GnuPG
Version 1.1.0
2013-12-20
Version 1.1.3
2014-04-16
Niibe Yutaka
Free Software Initiative of Japan
Warning
=======
This is an experimental release of Gnuk 1.1.0, which has incompatible
changes to Gnuk 1.0.x. Specifically, it now supports overriding key
import, but importing keys (or generating keys) results password
reset. Please update your documentation for Gnuk Token, so that the
instruction of importing keys won't cause any confusion.
This is another experimental release of Gnuk, version 1.1.3, which has
incompatible changes to Gnuk 1.0.x. Specifically, it now supports
overriding key import, but importing keys (or generating keys) results
password reset. Please update your documentation for Gnuk Token, so
that the instruction of importing keys won't cause any confusion. It
has supports of ECDSA (with NIST P256 and secp256k1) and EdDSA with
EdDSA, but this feature is pretty much experimental, and it requires
development version of GnuPG with newest version of libgcrypt. You
will not able to keep using EdDSA keys, as the key format is subject
to change.
What's Gnuk?
@@ -52,7 +57,8 @@ A0: Good points of Gnuk are:
"for Free Software"; Gnuk supports GnuPG.
Q1: What kind of key algorithm is supported?
A1: Gnuk version 1 only supports 2048-bit RSA.
A1: Gnuk version 1.0 only supports 2048-bit RSA.
Development version of Gnuk (1.1.x) supports 256-bit ECDSA and EdDSA.
Q2: How long does it take for digital signing?
A2: It takes a second and a half or so.
@@ -122,11 +128,14 @@ Ac: ST-Link/V2 is cheap one. We have a tool/stlinkv2.py as flash ROM
Release notes
=============
This is an experimental release in version 1.1 series of Gnuk.
This is third experimental release in version 1.1 series of Gnuk.
While it is daily use for a year and a half, some newly introduced
features (including key generation and firmware upgrade) should be
considered experimental.
While it is daily use by its developer, some newly introduced features
(including ECDSA/EdDSA, key generation and firmware upgrade) should be
considered experimental. ECDSA/EdDSA is really experimental. The
feature even requires manual edit of Makefile after 'configure'.
More, EdDSA is much experimental. You won't be able to keep using
the EdDSA key, as it is subject to change.
Tested features are:
@@ -218,7 +227,7 @@ External source code
Gnuk is distributed with external source code.
* chopstx/ -- Chopstx 0.04
* chopstx/ -- Chopstx 0.03 (+ STBee support)
We use Chopstx as the kernel for Gnuk.
@@ -465,7 +474,7 @@ How to configure
================
You need python and pyscard (python-pyscard package in Debian) or
PyUSB (python-usb package in Debian).
PyUSB 0.4.3 (python-usb package in Debian).
(1) [pyscard] Stop scdaemon
[PyUSB] Stop the pcsc daemon.
@@ -581,10 +590,19 @@ Git Repositories
Please use: http://gitorious.org/gnuk
You can get it by:
$ git clone git://gitorious.org/gnuk/gnuk.git
It's also available at: www.gniibe.org
You can browse at: http://www.gniibe.org/gitweb?p=gnuk.git;a=summary
We migrated from ChibiOS/RT to Chopstix. If you have old code of
I put Chopstx as a submodule of Git. Please do this:
$ git submodule init
$ git submodule update
We have migrated from ChibiOS/RT to Chopstx. If you have old code of
ChibiOS/RT, you need:
Edit .git/config to remove chibios reference

1
THANKS
View File

@@ -19,4 +19,5 @@ NAGAMI Takeshi nagami-takeshi@aist.go.jp
Nguyễn Hồng Quân quannguyen@mbm.vn
Paul Bakker polarssl_maintainer@polarssl.org
Shane Coughlan scoughlan@openinventionnetwork.com
Vasily Evseenko
Werner Koch wk@gnupg.org

View File

@@ -1 +1 @@
release/1.1.0
release/1.1.3

View File

@@ -38,7 +38,7 @@ You need GNU toolchain and newlib for 'arm-none-eabi' target.
There is "gcc-arm-embedded" project. See:
https://launchpad.net/gcc-arm-embedded/
It is based on GCC 4.7 (as of October, 2013). We are using "-O3 -Os"
It is based on GCC 4.8 (as of December, 2013). We are using "-O3 -Os"
for compiler option.

View File

@@ -121,7 +121,7 @@ Then, GnuPG generate keys. It takes some time. ::
Not enough random bytes available. Please do some other work to give
the OS a chance to collect more entropy! (Need 15 more bytes)
...+++++
gpg: key 28C0CD7C marked as ultimately trusted
gpg: key 4CA7BABE marked as ultimately trusted
public and secret key created and signed.
gpg: checking the trustdb

View File

@@ -44,7 +44,6 @@ and type ``1`` to say it's signature key. ::
gpg> keytocard
Really move the primary key? (y/N) y
gpg: detected reader `FSIJ Gnuk (0.12-38FF6A06) 00 00'
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]

View File

@@ -56,7 +56,6 @@ and type ``1`` to say it's signature key. ::
gpg> keytocard
Really move the primary key? (y/N) y
gpg: detected reader `FSIJ Gnuk (0.12-38FF6A06) 00 00'
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]

View File

@@ -28,27 +28,38 @@ Set up PW1, PW3 and reset code
Invoke GnuPG with the option ``--card-edit``. ::
$ gpg --card-edit
gpg: detected reader `FSIJ Gnuk (0.12-34006E06) 00 00'
Application ID ...: D276000124010200F517000000010000
Version ..........: 2.0
Manufacturer .....: FSIJ
Serial number ....: 00000001
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Name of cardholder: Yutaka Niibe
Language prefs ...: ja
Sex ..............: male
URL of public key : http://www.gniibe.org/gniibe.asc
Login data .......: gniibe
Signature PIN ....: not forced
Key attributes ...: 2048R 2048R 2048R
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
Signature key ....: 1241 24BD 3B48 62AF 7A0A 42F1 00B4 5EBD 4CA7 BABE
created ....: 2010-10-15 06:46:33
Encryption key....: 42E1 E805 4E6F 1F30 26F2 DC79 79A7 9093 0842 39CF
created ....: 2010-10-15 06:46:33
Authentication key: B4D9 7142 C42D 6802 F5F7 4E70 9C33 B6BA 5BB0 65DC
created ....: 2010-10-22 06:06:36
General key info..:
pub 2048R/4CA7BABE 2010-10-15 NIIBE Yutaka <gniibe@fsij.org>
sec> 2048R/4CA7BABE created: 2010-10-15 expires: never
card-no: F517 00000001
ssb> 2048R/084239CF created: 2010-10-15 expires: never
card-no: F517 00000001
ssb> 2048R/5BB065DC created: 2010-10-22 expires: never
card-no: F517 00000001
It shows the status of the card (as same as the output of ``gpg --card-status``). It shows token's name and its USB serial string (0.12-34006E06) from PC/SC-lite.
gpg/card>
It shows the status of the card (as same as the output of ``gpg --card-status``).
Then, GnuPG enters its own command interaction mode. The prompt is ``gpg/card>``.
@@ -83,7 +94,12 @@ please change admin-password at first.
Then, the token works as same as OpenPGPcard specification
with regards to PW1 and PW3.)
Lastly, I setup reset code. This is optional. ::
Lastly, I setup reset code, entering admin mode.
Having reset code, you can unblock PIN when the token will be blocked
(by wrong attempt to entering PIN). This is optional step. ::
gpg/card> admin
Admin commands are allowed
gpg/card> passwd
gpg: OpenPGP card no. D276000124010200F517000000010000 detected

View File

@@ -9,11 +9,10 @@ Personalize your Gnuk Token
Invoke GnuPG with the option ``--card-edit``. ::
$ gpg --card-edit
gpg: detected reader `FSIJ Gnuk (0.12-34006E06) 00 00'
Application ID ...: D276000124010200F517000000010000
Application ID ...: D276000124010200FFFE330069060000
Version ..........: 2.0
Manufacturer .....: FSIJ
Serial number ....: 00000001
Manufacturer .....: unmanaged S/N range
Serial number ....: 33006906
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
@@ -29,7 +28,9 @@ Invoke GnuPG with the option ``--card-edit``. ::
Authentication key: [none]
General key info..: [none]
It shows the status of the card (as same as the output of ``gpg --card-status``). It shows token's name and its USB serial string (0.12-34006E06) from PC/SC-lite.
gpg/card>
It shows the status of the card (as same as the output of ``gpg --card-status``).
Then, GnuPG enters its own command interaction mode. The prompt is ``gpg/card>``.

View File

@@ -51,7 +51,7 @@ Host prerequisites for using Gnuk Token
* [Optional] PC/SC lite (pcscd, libccid)
* SSH: openssh
* [Optional] SSH: openssh
* [optional] Web: scute, firefox

View File

@@ -5,7 +5,7 @@ It is important to collect enough entropy. Perhaps, it would
be possible to get entropy from USB traffic (of other devices).
* RSA
* [Mostly DONE] RSA
It would be good not to use malloc.

View File

@@ -76,7 +76,6 @@ KEYPTR
----> [ P ][ Q ][ N ]
<---encrypted----><--- plain ---->
key_addr 4-byte
initial_vector (random) 16-byte
checksum_encrypted 16-byte
dek_encrypted_by_keystring_pw1 16-byte

View File

@@ -18,7 +18,6 @@ key reference (to the token) in ``.gnupg``.
To do that, invoke GnuPG with ``--card-edit`` option. ::
$ gpg --card-edit
gpg: detected reader `FSIJ Gnuk (0.12-37006A06) 00 00'
Application ID ...: D276000124010200F517000000010000
Version ..........: 2.0
Manufacturer .....: FSIJ

398
misc/t-eddsa.c Normal file
View File

@@ -0,0 +1,398 @@
/*
* t-eddsa.c - testing EdDSA
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* Run following commands. The file t-ed25519.inp is available in GNU
* libgcrypt source code under 'tests' directory.
gcc -Wall -c ecc-edwards.c
gcc -Wall -c -DBN256_NO_RANDOM -DBN256_C_IMPLEMENTATION bn.c
gcc -Wall -c mod.c
gcc -Wall -c -DBN256_C_IMPLEMENTATION mod25638.c
gcc -Wall -c sha512.c
gcc -Wall -c t-eddsa.c
gcc -o t-eddsa t-eddsa.o ecc-edwards.o bn.o mod.o mod25638.o sha512.o
./t-eddsa < ./t-ed25519.inp
*
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "bn.h"
#include "affine.h"
#include "sha512.h"
static void
print_le_bn256 (const bn256 *X)
{
int i;
const uint8_t *p = (const uint8_t *)X;
for (i = 0; i < 32; i++)
printf ("%02x", p[i]);
puts ("");
}
static void
print_be_bn256 (const bn256 *X)
{
int i;
for (i = 7; i >= 0; i--)
printf ("%08x", X->word[i]);
puts ("");
}
#define MAXLINE 4096
static int lineno;
static int test_no;
static bn256 sk[1];
static bn256 pk[1];
static unsigned char msg[MAXLINE];
static size_t msglen;
static bn512 sig[1];
static const char *
skip_white_space (const char *l)
{
while (*l != '\n' && isspace (*l))
l++;
return l;
}
static int
read_hex_4bit (char c)
{
int r;
if (c >= '0' && c <= '9')
r = c - '0';
else if (c >= 'a' && c <= 'f')
r = c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
r = c - 'A' + 10;
else
r = -1;
return r;
}
static int
read_hex_8bit (const char **l_p)
{
const char *l = *l_p;
int r, v;
r = read_hex_4bit (*l++);
if (r < 0)
return -1;
v = r*16;
r = read_hex_4bit (*l++);
if (r < 0)
return -1;
v += r;
*l_p = l;
return v;
}
static int
read_msg (unsigned char *msg, const char *l, int len)
{
int i, r;
for (i = 0; i < len; i++)
{
r = read_hex_8bit (&l);
if (r < 0)
return -1;
msg[i] = r;
}
return 0;
}
static int
read_le_bn256 (bn256 *sk, const char *l)
{
int i;
uint8_t *p = (uint8_t *)sk;
for (i = 0; i < sizeof (bn256); i++)
{
int r;
if (*l == '\n')
{
/* should support small input??? */
return -1;
}
r = read_hex_8bit (&l);
if (r < 0)
return -1;
p[i] = r;
}
return 0;
}
static int
read_be_bn256 (bn256 *sk, const char *l)
{
int i;
uint8_t *p = (uint8_t *)sk;
for (i = 0; i < sizeof (bn256); i++)
{
int r;
if (*l == '\n')
{
/* should support small input??? */
return -1;
}
r = read_hex_8bit (&l);
if (r < 0)
return -1;
p[31 - i] = r;
}
return 0;
}
static int
read_pk (bn256 *pk, const char *l, int len)
{
int r;
if (len == 64) /* 64 chars == 32-byte */
{ /* compressed form */
r = read_le_bn256 (pk, l);
if (r < 0)
return -1;
return 0;
}
else
{
bn256 x[1];
r = read_hex_8bit (&l);
if (r < 0)
return -1;
if (r != 4)
return -1;
r = read_be_bn256 (x, l);
if (r < 0)
return -1;
r = read_be_bn256 (pk, l+64);
if (r < 0)
return -1;
pk->word[7] ^= (x->word[0] & 1) * 0x80000000;
return 0;
}
}
static int
read_le_bn512 (bn512 *sig, const char *l)
{
int i;
uint8_t *p = (uint8_t *)sig;
for (i = 0; i < sizeof (bn512); i++)
{
int r;
if (*l == '\n')
{
/* should support small input??? */
return -1;
}
r = read_hex_8bit (&l);
if (r < 0)
return -1;
p[i] = r;
}
return 0;
}
static int
read_testcase (void)
{
ssize_t r;
size_t len = 0;
char *line = NULL;
int start = 0;
int err = 0;
test_no = 0;
memset (sk, 0, sizeof (bn256));
memset (pk, 0, sizeof (ac));
msglen = 0;
memset (sig, 0, sizeof (bn512));
while (1)
{
lineno++;
r = getline (&line, &len, stdin);
if (r < 0)
{
/* EOF */
if (!start)
err = -1;
break;
}
len = r; /* We don't need allocated size, but length. */
if (len >= MAXLINE)
{
fprintf (stderr, "Line too long: %d: >= %d\n", lineno, MAXLINE);
err = -1;
break;
}
if (r == 1 && *line == '\n')
{
if (start)
break; /* Done. */
else
continue; /* Ignore blank line before start. */
}
if (r > 0 && *line == '#') /* Ignore comment line. */
continue;
start = 1;
if (r > 4 && strncmp (line, "TST:", 4) == 0)
test_no = strtol (line+4, NULL, 10);
else if (r > 3 && strncmp (line, "SK:", 3) == 0)
{
const char *l = skip_white_space (line+3);
if (read_le_bn256 (sk, l) < 0)
{
fprintf (stderr, "read_le_bn256: %d\n", lineno);
err = -1;
break;
}
}
else if (r > 3 && strncmp (line, "PK:", 3) == 0)
{
const char *l = skip_white_space (line+3);
if (read_pk (pk, l, line+len-1-l) < 0)
{
fprintf (stderr, "read_pk: %d\n", lineno);
err = -1;
break;
}
}
else if (r > 4 && strncmp (line, "MSG:", 4) == 0)
{
const char *l = skip_white_space (line+4);
msglen = (line+len-1-l)/2;
if (read_msg (msg, l, msglen) < 0)
{
fprintf (stderr, "read_msg: %d\n", lineno);
err = -1;
break;
}
}
else if (r > 4 && strncmp (line, "SIG:", 4) == 0)
{
const char *l = skip_white_space (line+4);
if (read_le_bn512 (sig, l) < 0)
{
fprintf (stderr, "read_le_bn512: %d\n", lineno);
err = -1;
break;
}
}
else
{
fprintf (stderr, "Garbage line: %d", lineno);
err = -1;
break;
}
}
free (line);
return err;
}
int
main (int argc, char *argv[])
{
int all_good = 1;
int r;
bn256 pk_calculated[1];
uint8_t hash[64];
bn256 a[1];
bn256 *R, *S;
uint8_t out[64];
extern void eddsa_sign_25519 (const uint8_t *input, size_t ilen,
uint8_t *output,
const bn256 *a, const uint8_t *seed,
const bn256 *pk);
extern void eddsa_public_key_25519 (bn256 *pk, const bn256 *a);
R = (bn256 *)out;
S = (bn256 *)(out+32);
while (1)
{
r = read_testcase ();
if (r < 0)
break;
sha512 ((uint8_t *)sk, sizeof (bn256), hash);
hash[0] &= 248;
hash[31] &= 127;
hash[31] |= 64;
memcpy (a, hash, sizeof (bn256)); /* Lower half of hash */
eddsa_public_key_25519 (pk_calculated, a);
if (memcmp (pk, pk_calculated, sizeof (bn256)) != 0)
{
printf ("ERR PK: %d\n", test_no);
print_be_bn256 (sk);
print_be_bn256 (pk);
print_be_bn256 (pk_calculated);
all_good = 0;
continue;
}
eddsa_sign_25519 (msg, msglen, out, a, hash+32, pk);
if (memcmp (sig, R, sizeof (bn256)) != 0
|| memcmp (((const uint8_t *)sig)+32, S, sizeof (bn256)) != 0)
{
printf ("ERR SIG: %d\n", test_no);
print_le_bn256 (R);
print_le_bn256 (S);
print_le_bn256 ((const bn256 *)sig);
print_le_bn256 ((const bn256 *)(((const uint8_t *)sig)+32));
all_good = 0;
continue;
}
printf ("%d\n", test_no);
}
return all_good == 1?0:1;
}

View File

@@ -496,64 +496,64 @@
#if defined(__arm__)
#define MULADDC_1024_CORE \
"ldmia %0!, { r5, r6, r7 } \n\t" \
"ldmia %1, { r8, r9, r10 } \n\t" \
"adcs r8, r8, %2 \n\t" \
"umull r11, r12, r5, %4 \n\t" \
"adc %2, r12, #0 \n\t" \
"adds r8, r8, r11 \n\t" \
"adcs r9, r9, %2 \n\t" \
"umull r11, r12, r6, %4 \n\t" \
"adc %2, r12, #0 \n\t" \
"adds r9, r9, r11 \n\t" \
"adcs r10, r10, %2 \n\t" \
"umull r11, r12, r7, %4 \n\t" \
"adc %2, r12, #0 \n\t" \
"adds r10, r10, r11 \n\t" \
"stmia %1!, { r8, r9, r10 } \n\t"
"ldmia %[s]!, { r8, r9, r10 } \n\t" \
"ldmia %[d], { r5, r6, r7 } \n\t" \
"adcs r5, r5, %[c] \n\t" \
"umull r4, r8, r8, %[b] \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r5, r5, r4 \n\t" \
"adcs r6, r6, %[c] \n\t" \
"umull r4, r8, r9, %[b] \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r6, r6, r4 \n\t" \
"adcs r7, r7, %[c] \n\t" \
"umull r4, r8, r10, %[b] \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r7, r7, r4 \n\t" \
"stmia %[d]!, { r5, r6, r7 } \n\t"
#define MULADDC_1024_LOOP \
asm( "tst %3, #0xfe0 \n\t" \
"beq 0f \n" \
"1: sub %3, %3, #32 \n\t" \
"ldmia %0!, { r5, r6, r7 } \n\t" \
"ldmia %1, { r8, r9, r10 } \n\t" \
"adds r8, r8, %2 \n\t" \
"umull r11, r12, %4, r5 \n\t" \
"adc %2, r12, #0 \n\t" \
"adds r8, r8, r11 \n\t" \
"adcs r9, r9, %2 \n\t" \
"umull r11, r12, %4, r6 \n\t" \
"adc %2, r12, #0 \n\t" \
"adds r9, r9, r11 \n\t" \
"adcs r10, r10, %2 \n\t" \
"umull r11, r12, %4, r7 \n\t" \
"adc %2, r12, #0 \n\t" \
"adds r10, r10, r11 \n\t" \
"stmia %1!, { r8, r9, r10 } \n\t" \
asm( "tst %[i], #0xfe0 \n\t" \
"beq 0f \n" \
"1: ldmia %[s]!, { r8, r9, r10 } \n\t" \
"ldmia %[d], { r5, r6, r7 } \n\t" \
"sub %[i], %[i], #32 \n\t" \
"adds r5, r5, %[c] \n\t" \
"umull r4, r8, %[b], r8 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r5, r5, r4 \n\t" \
"adcs r6, r6, %[c] \n\t" \
"umull r4, r8, %[b], r9 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r6, r6, r4 \n\t" \
"adcs r7, r7, %[c] \n\t" \
"umull r4, r8, %[b], r10 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r7, r7, r4 \n\t" \
"stmia %[d]!, { r5, r6, r7 } \n\t" \
MULADDC_1024_CORE MULADDC_1024_CORE \
MULADDC_1024_CORE MULADDC_1024_CORE \
MULADDC_1024_CORE MULADDC_1024_CORE \
MULADDC_1024_CORE MULADDC_1024_CORE \
MULADDC_1024_CORE \
"ldmia %0!, { r5, r6 } \n\t" \
"ldmia %1, { r8, r9 } \n\t" \
"adcs r8, r8, %2 \n\t" \
"umull r11, r12, %4, r5 \n\t" \
"adc %2, r12, #0 \n\t" \
"adds r8, r8, r11 \n\t" \
"adcs r9, r9, %2 \n\t" \
"umull r11, r12, %4, r6 \n\t" \
"adc %2, r12, #0 \n\t" \
"adds r9, r9, r11 \n\t" \
"stmia %1!, { r8, r9 } \n\t" \
"adc %2, %2, #0 \n\t" \
"tst %3, #0xfe0 \n\t" \
"bne 1b \n" \
"ldmia %[s]!, { r8, r9 } \n\t" \
"ldmia %[d], { r5, r6 } \n\t" \
"adcs r5, r5, %[c] \n\t" \
"umull r4, r8, %[b], r8 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r5, r5, r4 \n\t" \
"adcs r6, r6, %[c] \n\t" \
"umull r4, r8, %[b], r9 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r6, r6, r4 \n\t" \
"adc %[c], %[c], #0 \n\t" \
"stmia %[d]!, { r5, r6 } \n\t" \
"tst %[i], #0xfe0 \n\t" \
"bne 1b \n" \
"0:" \
: "=r" (s), "=r" (d), "=r" (c), "=r" (i) \
: "r" (b), "0" (s), "1" (d), "2" (c), "3" (i) \
: "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "memory", "cc" );
: [s] "=r" (s), [d] "=r" (d), [c] "=r" (c), [i] "=r" (i) \
: [b] "r" (b), "[s]" (s), "[d]" (d), "[c]" (c), "[i]" (i) \
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", "memory", "cc" );
/* Just for reference (dead code) */
#define MULADDC_HUIT \

View File

@@ -1382,16 +1382,13 @@ static void mpi_montg_init( t_uint *mm, const mpi *N )
/*
* Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36)
* A is placed at the upper half of T.
* A is placed at the upper half of D.
*/
static void mpi_montmul( const mpi *B, const mpi *N, t_uint mm, mpi *T )
static void mpi_montmul( size_t n, const t_uint *np, t_uint mm, t_uint *d,
const t_uint *bp )
{
size_t i, n, m;
t_uint u0, u1, *d, c = 0;
d = T->p;
n = N->n;
m = ( B->n < n ) ? B->n : n;
size_t i;
t_uint u0, u1, c = 0;
for( i = 0; i < n; i++ )
{
@@ -1400,31 +1397,28 @@ static void mpi_montmul( const mpi *B, const mpi *N, t_uint mm, mpi *T )
*/
u0 = d[n];
d[n] = c;
u1 = ( d[0] + u0 * B->p[0] ) * mm;
u1 = ( d[0] + u0 * bp[0] ) * mm;
mpi_mul_hlp( m, B->p, d, u0 );
c = mpi_mul_hlp( n, N->p, d, u1 );
mpi_mul_hlp( n, bp, d, u0 );
c = mpi_mul_hlp( n, np, d, u1 );
d++;
}
/* prevent timing attacks */
if( ((mpi_cmp_abs_limbs ( n, d, N->p ) >= 0) | c) )
mpi_sub_hlp( n, N->p, d );
if( ((mpi_cmp_abs_limbs ( n, d, np ) >= 0) | c) )
mpi_sub_hlp( n, np, d );
else
mpi_sub_hlp( n, T->p, T->p);
mpi_sub_hlp( n, d - n, d - n);
}
/*
* Montgomery reduction: A = A * R^-1 mod N
* A is placed at the upper half of T.
* A is placed at the upper half of D.
*/
static void mpi_montred( const mpi *N, t_uint mm, mpi *T )
static void mpi_montred( size_t n, const t_uint *np, t_uint mm, t_uint *d )
{
size_t i, j, n;
t_uint u0, u1, *d, c = 0;
d = T->p;
n = N->n;
size_t i, j;
t_uint u0, u1, c = 0;
for( i = 0; i < n; i++ )
{
@@ -1442,116 +1436,106 @@ static void mpi_montred( const mpi *N, t_uint mm, mpi *T )
d[j] += c; c = ( d[j] < c );
}
c = mpi_mul_hlp( n, N->p, d, u1 );
c = mpi_mul_hlp( n, np, d, u1 );
d++;
}
/* prevent timing attacks */
if( ((mpi_cmp_abs_limbs ( n, d, N->p ) >= 0) | c) )
mpi_sub_hlp( n, N->p, d );
if( ((mpi_cmp_abs_limbs ( n, d, np ) >= 0) | c) )
mpi_sub_hlp( n, np, d );
else
mpi_sub_hlp( n, T->p, T->p);
mpi_sub_hlp( n, d - n, d - n);
}
/*
* Montgomery square: A = A * A * R^-1 mod N
* A is placed at the upper half of T.
* A is placed at the upper half of D.
*/
static void mpi_montsqr( const mpi *N, t_uint mm, mpi *T )
static void mpi_montsqr( size_t n, const t_uint *np, t_uint mm, t_uint *d )
{
size_t n, i;
t_uint c = 0, *d;
d = T->p;
n = N->n;
size_t i;
register t_uint c = 0;
for (i = 0; i < n; i++)
{
t_uint *wij = &d[i*2];
t_uint *xj = &d[i+n];
t_uint u, x_i;
t_uint x_i;
x_i = *xj;
*xj++ = c;
asm ("mov r8, #0\n\t" /* R8 := 0, the constant ZERO from here. */
/* (C,U,R9) := w_i_i + x_i*x_i; w_i_i := R9; */
"ldr r9, [%[wij]]\n\t" /* R9 := w_i_i; */
"mov %[c], r8\n\t"
"umull r11, r12, %[x_i], %[x_i]\n\t"
"adds r9, r9, r11\n\t"
"adc %[u], r8, r12\n\t"
"str r9, [%[wij]], #4\n\t"
asm (/* (C,R4,R5) := w_i_i + x_i*x_i; w_i_i := R5; */
"mov %[c], #0\n\t"
"ldr r5, [%[wij]]\n\t" /* R5 := w_i_i; */
"mov r4, %[c]\n\t"
"umlal r5, r4, %[x_i], %[x_i]\n\t"
"str r5, [%[wij]], #4\n\t"
"cmp %[xj], %[x_max1]\n\t"
"bhi 0f\n\t"
"mov r9, %[c]\n\t" /* R9 := 0, the constant ZERO from here. */
"beq 1f\n"
"2:\n\t"
"ldmia %[xj]!, { r7, r8 }\n\t"
"ldmia %[wij], { r5, r6 }\n\t"
/* (C,R4,R5) := (C,R4) + w_i_j + 2*x_i*x_j; */
"umull r7, r12, %[x_i], r7\n\t"
"adds r5, r5, r4\n\t"
"adc r4, %[c], r9\n\t"
"adds r5, r5, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], r9, r9\n\t"
"adds r5, r5, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], %[c], r9\n\t"
/* (C,R4,R6) := (C,R4) + w_i_j + 2*x_i*x_j; */
"adds r6, r6, r4\n\t"
"adc r4, %[c], r9\n\t"
"umull r7, r12, %[x_i], r8\n\t"
"adds r6, r6, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], r9, r9\n\t"
"adds r6, r6, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], %[c], r9\n\t"
/**/
"subs r9, %[xj_max], %[xj]\n\t"
"bls 1f\n\t"
/**/
"tst r9, #4\n\t"
"beq 0f\n\t"
/* (C,U,R9) := (C,U) + w_i_j + 2*x_i*x_j; */
"ldr r10, [%[xj]], #4\n\t"
"ldr r9, [%[wij]]\n\t"
"adds r9, r9, %[u]\n\t"
"adc %[u], %[c], r8\n\t"
"umull r11, r12, %[x_i], r10\n\t"
"adds r9, r9, r11\n\t"
"adcs %[u], %[u], r12\n\t"
"adc %[c], r8, r8\n\t"
"adds r9, r9, r11\n\t"
"adcs %[u], %[u], r12\n\t"
"adc %[c], %[c], r8\n\t"
"str r9, [%[wij]], #4\n\t"
/**/
"subs r9, %[xj_max], %[xj]\n\t"
"bls 1f\n"
"0:\n\t"
"ldmia %[xj]!, { r6, r7 }\n\t"
"ldmia %[wij], { r9, r10 }\n\t"
/* (C,U,R9) := (C,U) + w_i_j + 2*x_i*x_j; */
"umull r11, r12, %[x_i], r6\n\t"
"adds r9, r9, %[u]\n\t"
"adc %[u], %[c], r8\n\t"
"adds r9, r9, r11\n\t"
"adcs %[u], %[u], r12\n\t"
"adc %[c], r8, r8\n\t"
"adds r9, r9, r11\n\t"
"adcs %[u], %[u], r12\n\t"
"adc %[c], %[c], r8\n\t"
/* (C,U,R10) := (C,U) + w_i_j + 2*x_i*x_j; */
"adds r10, r10, %[u]\n\t"
"adc %[u], %[c], r8\n\t"
"umull r11, r12, %[x_i], r7\n\t"
"adds r10, r10, r11\n\t"
"adcs %[u], %[u], r12\n\t"
"adc %[c], r8, r8\n\t"
"adds r10, r10, r11\n\t"
"adcs %[u], %[u], r12\n\t"
"adc %[c], %[c], r8\n\t"
/**/
"stmia %[wij]!, { r9, r10 }\n\t"
/**/
"cmp %[xj], %[xj_max]\n\t"
"bcc 0b\n"
"stmia %[wij]!, { r5, r6 }\n\t"
"cmp %[xj], %[x_max1]\n\t"
"bcc 2b\n\t"
"bne 0f\n"
"1:\n\t"
"ldr r9, [%[wij]]\n\t"
"adds %[u], %[u], r9\n\t"
"adc %[c], %[c], r8\n\t"
"str %[u], [%[wij]]"
: [c] "=&r" (c), [u] "=&r" (u), [wij] "=r" (wij), [xj] "=r" (xj)
: [x_i] "r" (x_i), [xj_max] "r" (&d[n*2]),
/* (C,R4,R5) := (C,R4) + w_i_j + 2*x_i*x_j; */
"ldr r5, [%[wij]]\n\t"
"ldr r6, [%[xj]], #4\n\t"
"adds r5, r5, r4\n\t"
"adc r4, %[c], r9\n\t"
"umull r7, r12, %[x_i], r6\n\t"
"adds r5, r5, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], r9, r9\n\t"
"adds r5, r5, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], %[c], r9\n\t"
"str r5, [%[wij]], #4\n"
"0:\n\t"
"ldr r5, [%[wij]]\n\t"
"adds r4, r4, r5\n\t"
"adc %[c], %[c], #0\n\t"
"str r4, [%[wij]]"
: [c] "=&r" (c), [wij] "=r" (wij), [xj] "=r" (xj)
: [x_i] "r" (x_i), [x_max1] "r" (&d[n*2-1]),
"[wij]" (wij), "[xj]" (xj)
: "r6", "r7", "r8", "r9", "r10", "r11", "r12", "memory", "cc" );
: "r4", "r5", "r6", "r7", "r8", "r9", "r12", "memory", "cc");
u = d[i] * mm;
c += mpi_mul_hlp( n, N->p, &d[i], u );
c += mpi_mul_hlp( n, np, &d[i], d[i] * mm );
}
d = T->p + n;
d += n;
/* prevent timing attacks */
if( ((mpi_cmp_abs_limbs ( n, d, N->p ) >= 0) | c) )
mpi_sub_hlp( n, N->p, d );
if( ((mpi_cmp_abs_limbs ( n, d, np ) >= 0) | c) )
mpi_sub_hlp( n, np, d );
else
mpi_sub_hlp( n, T->p, T->p);
mpi_sub_hlp( n, d - n, d - n);
}
/*
@@ -1560,12 +1544,17 @@ static void mpi_montsqr( const mpi *N, t_uint mm, mpi *T )
int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
{
int ret;
size_t wbits, wsize, one = 1;
size_t i, j, nblimbs;
size_t i = mpi_msb( E );
size_t wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1;
size_t wbits, one = 1;
size_t nblimbs;
size_t bufsize, nbits;
t_uint ei, mm, state;
mpi RR, T, W[ 2 << POLARSSL_MPI_WINDOW_SIZE ], Apos;
int neg;
mpi RR;
t_uint d[N->n*2];
t_uint w1[N->n];
t_uint wn[(one << (wsize - 1))][N->n];
if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 )
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
@@ -1573,97 +1562,76 @@ int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
if( mpi_cmp_int( E, 0 ) < 0 )
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
if( A->s == -1 )
return( POLARSSL_ERR_MPI_BAD_INPUT_DATA );
/*
* Init temps and window size
*/
mpi_montg_init( &mm, N );
mpi_init( &RR ); mpi_init( &T );
memset( W, 0, sizeof( W ) );
i = mpi_msb( E );
wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1;
if( wsize > POLARSSL_MPI_WINDOW_SIZE )
wsize = POLARSSL_MPI_WINDOW_SIZE;
j = N->n;
MPI_CHK( mpi_grow( X, N->n ) );
MPI_CHK( mpi_grow( &W[1], N->n ) );
MPI_CHK( mpi_grow( &T, N->n * 2 ) ); /* T = 0 here. */
/*
* Compensate for negative A (and correct at the end)
*/
neg = ( A->s == -1 );
mpi_init( &Apos );
if( neg )
{
MPI_CHK( mpi_copy( &Apos, A ) );
Apos.s = 1;
A = &Apos;
}
/*
* If 1st call, pre-compute R^2 mod N
*/
if( _RR == NULL || _RR->p == NULL )
{
/* T->p is all zero here. */
mpi_sub_hlp( N->n, N->p, T.p + N->n);
mpi T;
mpi_init( &RR );
T.s = 1; T.n = N->n * 2; T.p = d;
memset (d, 0, 2 * N->n * ciL); /* Set D zero. */
mpi_sub_hlp( N->n, N->p, d + N->n);
MPI_CHK( mpi_mod_mpi( &RR, &T, N ) );
if( _RR != NULL )
memcpy( _RR, &RR, sizeof( mpi ) );
/* The condition of "the lower half of T is all zero" is kept. */
/* The condition of "the lower half of D is all zero" is kept. */
}
else
else {
memcpy( &RR, _RR, sizeof( mpi ) );
memset (d, 0, N->n * ciL); /* Set lower half of D zero. */
}
/*
* W[1] = A * R^2 * R^-1 mod N = A * R mod N
*/
if( mpi_cmp_mpi( A, N ) >= 0 )
mpi_mod_mpi( &W[1], A, N );
else mpi_copy( &W[1], A );
if( mpi_cmp_mpi( A, N ) >= 0 ) {
mpi W1;
W1.s = 1; W1.n = N->n; W1.p = d + N->n;
mpi_mod_mpi( &W1, A, N );
} else {
memset (d + N->n, 0, N->n * ciL);
memcpy (d + N->n, A->p, A->n * ciL);
}
memcpy ( T.p + N->n, W[1].p, N->n * ciL);
mpi_montmul( &RR, N, mm, &T );
memcpy ( W[1].p, T.p + N->n, N->n * ciL);
mpi_montmul( N->n, N->p, mm, d, RR.p );
memcpy (w1, d + N->n, N->n * ciL);
if( wsize > 1 )
{
/*
* W[1 << (wsize - 1)] = W[1] ^ ( 2 ^ (wsize - 1) )
*/
j = one << (wsize - 1);
MPI_CHK( mpi_grow( &W[j], N->n ) );
for( i = 0; i < wsize - 1; i++ )
mpi_montsqr( N, mm, &T );
memcpy ( W[j].p, T.p + N->n, N->n * ciL);
mpi_montsqr( N->n, N->p, mm, d );
memcpy (wn[0], d + N->n, N->n * ciL);
/*
* W[i] = W[i - 1] * W[1]
*/
for( i = j + 1; i < (one << wsize); i++ )
for( i = 1; i < (one << (wsize - 1)); i++ )
{
MPI_CHK( mpi_grow( &W[i], N->n ) );
mpi_montmul( &W[1], N, mm, &T );
memcpy ( W[i].p, T.p + N->n, N->n * ciL);
mpi_montmul( N->n, N->p, mm, d, w1 );
memcpy (wn[i], d + N->n, N->n * ciL);
}
}
/*
* X = R^2 * R^-1 mod N = R mod N
*/
memcpy ( T.p + N->n, RR.p, N->n * ciL);
mpi_montred( N, mm, &T );
memcpy (d + N->n, RR.p, N->n * ciL);
mpi_montred( N->n, N->p, mm, d );
nblimbs = E->n;
bufsize = 0;
@@ -1696,7 +1664,7 @@ int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
/*
* out of window, square X
*/
mpi_montsqr( N, mm, &T );
mpi_montsqr( N->n, N->p, mm, d );
continue;
}
@@ -1714,12 +1682,12 @@ int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
* X = X^wsize R^-1 mod N
*/
for( i = 0; i < wsize; i++ )
mpi_montsqr( N, mm, &T );
mpi_montsqr( N->n, N->p, mm, d );
/*
* X = X * W[wbits] R^-1 mod N
*/
mpi_montmul( &W[wbits], N, mm, &T );
mpi_montmul( N->n, N->p, mm, d, wn[wbits - (one << (wsize - 1))]);
state--;
nbits = 0;
@@ -1732,33 +1700,22 @@ int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR )
*/
for( i = 0; i < nbits; i++ )
{
mpi_montsqr( N, mm, &T );
mpi_montsqr( N->n, N->p, mm, d );
wbits <<= 1;
if( (wbits & (one << wsize)) != 0 )
mpi_montmul( &W[1], N, mm, &T );
mpi_montmul( N->n, N->p, mm, d, w1);
}
/*
* X = A^E * R * R^-1 mod N = A^E mod N
*/
mpi_montred( N, mm, &T );
memcpy ( X->p, T.p + N->n, N->n * ciL);
if( neg )
{
X->s = -1;
mpi_add_mpi( X, N, X );
}
mpi_montred( N->n, N->p, mm, d );
memcpy (X->p, d + N->n, N->n * ciL);
cleanup:
for( i = (one << (wsize - 1)); i < (one << wsize); i++ )
mpi_free( &W[i] );
mpi_free( &W[1] ); mpi_free( &T ); mpi_free( &Apos );
if( _RR == NULL )
mpi_free( &RR );

View File

@@ -12,7 +12,10 @@ CSRC = main.c usb_stm32f103.c adc_stm32f103.c \
usb_desc.c usb_ctrl.c \
call-rsa.c \
usb-icc.c openpgp.c ac.c openpgp-do.c flash.c \
bn.c modp256.c jpc.c mod.c ec_p256.c call-ec_p256.c \
bn.c mod.c \
modp256r1.c jpc_p256r1.c ec_p256r1.c call-ec_p256r1.c \
modp256k1.c jpc_p256k1.c ec_p256k1.c call-ec_p256k1.c \
mod25638.c ecc-edwards.c sha512.c \
random.c neug.c sha256.c sys.c
INCDIR =
@@ -52,7 +55,7 @@ OBJCOPY = $(CROSS)objcopy
MCU = cortex-m3
CWARN = -Wall -Wextra -Wstrict-prototypes
# DEFS: Add
DEFS = -DCHX_PRIO_MAIN=5 -DRSA_AUTH @KEYGEN_SUPPORT@ @HAVE_SYS_H@
DEFS = -DCHX_PRIO_MAIN=5 -DRSA_AUTH -DRSA_SIG @KEYGEN_SUPPORT@ @HAVE_SYS_H@
OPT = -O3 -Os -g
LIBS =

8
src/affine.h Normal file
View File

@@ -0,0 +1,8 @@
/**
* @brief Affine coordinates
*/
typedef struct
{
bn256 x[1];
bn256 y[1];
} ac;

213
src/bn.c
View File

@@ -1,7 +1,7 @@
/*
* bn.c -- 256-bit (and 512-bit) bignum calculation
*
* Copyright (C) 2011, 2013 Free Software Initiative of Japan
* Copyright (C) 2011, 2013, 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -22,28 +22,32 @@
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifndef BN256_NO_RANDOM
#include "random.h"
#endif
#include "bn.h"
uint32_t
bn256_add (bn256 *X, const bn256 *A, const bn256 *B)
{
int i;
uint32_t v;
uint32_t carry = 0;
uint32_t *px;
const uint32_t *pa, *pb;
px = X->words;
pa = A->words;
pb = B->words;
px = X->word;
pa = A->word;
pb = B->word;
for (i = 0; i < BN256_WORDS; i++)
{
v = *pb;
*px = *pa + carry;
carry = (*px < carry);
*px += *pb;
carry += (*px < *pb);
*px += v;
carry += (*px < v);
px++;
pa++;
pb++;
@@ -56,21 +60,23 @@ uint32_t
bn256_sub (bn256 *X, const bn256 *A, const bn256 *B)
{
int i;
uint32_t v;
uint32_t borrow = 0;
uint32_t *px;
const uint32_t *pa, *pb;
px = X->words;
pa = A->words;
pb = B->words;
px = X->word;
pa = A->word;
pb = B->word;
for (i = 0; i < BN256_WORDS; i++)
{
uint32_t borrow0 = (*pa < borrow);
v = *pb;
*px = *pa - borrow;
borrow = (*px < *pb) + borrow0;
*px -= *pb;
borrow = (*px < v) + borrow0;
*px -= v;
px++;
pa++;
pb++;
@@ -87,8 +93,8 @@ bn256_add_uint (bn256 *X, const bn256 *A, uint32_t w)
uint32_t *px;
const uint32_t *pa;
px = X->words;
pa = A->words;
px = X->word;
pa = A->word;
for (i = 0; i < BN256_WORDS; i++)
{
@@ -115,8 +121,8 @@ bn256_sub_uint (bn256 *X, const bn256 *A, uint32_t w)
uint32_t *px;
const uint32_t *pa;
px = X->words;
pa = A->words;
px = X->word;
pa = A->word;
for (i = 0; i < BN256_WORDS; i++)
{
@@ -138,9 +144,30 @@ bn256_sub_uint (bn256 *X, const bn256 *A, uint32_t w)
return borrow;
}
#ifndef BN256_C_IMPLEMENTATION
#define ASM_IMPLEMENTATION 1
#endif
void
bn256_mul (bn512 *X, const bn256 *A, const bn256 *B)
{
#if ASM_IMPLEMENTATION
#include "muladd_256.h"
const uint32_t *s;
uint32_t *d;
uint32_t w;
uint32_t c;
memset (X->word, 0, sizeof (uint32_t)*BN256_WORDS*2);
s = A->word; d = &X->word[0]; w = B->word[0]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[1]; w = B->word[1]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[2]; w = B->word[2]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[3]; w = B->word[3]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[4]; w = B->word[4]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[5]; w = B->word[5]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[6]; w = B->word[6]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[7]; w = B->word[7]; MULADD_256 (s, d, w, c);
#else
int i, j, k;
int i_beg, i_end;
uint32_t r0, r1, r2;
@@ -167,7 +194,7 @@ bn256_mul (bn512 *X, const bn256 *A, const bn256 *B)
j = k - i;
uv = ((uint64_t )A->words[i])*((uint64_t )B->words[j]);
uv = ((uint64_t )A->word[i])*((uint64_t )B->word[j]);
v = uv;
u = (uv >> 32);
r0 += v;
@@ -179,18 +206,96 @@ bn256_mul (bn512 *X, const bn256 *A, const bn256 *B)
r2 += carry;
}
X->words[k] = r0;
X->word[k] = r0;
r0 = r1;
r1 = r2;
r2 = 0;
}
X->words[k] = r0;
X->word[k] = r0;
#endif
}
void
bn256_sqr (bn512 *X, const bn256 *A)
{
#if ASM_IMPLEMENTATION
int i;
memset (X->word, 0, sizeof (bn512));
for (i = 0; i < BN256_WORDS; i++)
{
uint32_t *wij = &X->word[i*2];
const uint32_t *xj = &A->word[i];
uint32_t x_i = *xj++;
uint32_t c;
asm (/* (C,R4,R5) := w_i_i + x_i*x_i; w_i_i := R5; */
"mov %[c], #0\n\t"
"ldr r5, [%[wij]]\n\t" /* R5 := w_i_i; */
"mov r4, %[c]\n\t"
"umlal r5, r4, %[x_i], %[x_i]\n\t"
"str r5, [%[wij]], #4\n\t"
"cmp %[xj], %[x_max1]\n\t"
"bhi 0f\n\t"
"mov r9, %[c]\n\t" /* R9 := 0, the constant ZERO from here. */
"beq 1f\n"
"2:\n\t"
"ldmia %[xj]!, { r7, r8 }\n\t"
"ldmia %[wij], { r5, r6 }\n\t"
/* (C,R4,R5) := (C,R4) + w_i_j + 2*x_i*x_j; */
"umull r7, r12, %[x_i], r7\n\t"
"adds r5, r5, r4\n\t"
"adc r4, %[c], r9\n\t"
"adds r5, r5, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], r9, r9\n\t"
"adds r5, r5, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], %[c], r9\n\t"
/* (C,R4,R6) := (C,R4) + w_i_j + 2*x_i*x_j; */
"adds r6, r6, r4\n\t"
"adc r4, %[c], r9\n\t"
"umull r7, r12, %[x_i], r8\n\t"
"adds r6, r6, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], r9, r9\n\t"
"adds r6, r6, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], %[c], r9\n\t"
/**/
"stmia %[wij]!, { r5, r6 }\n\t"
"cmp %[xj], %[x_max1]\n\t"
"bcc 2b\n\t"
"bne 0f\n"
"1:\n\t"
/* (C,R4,R5) := (C,R4) + w_i_j + 2*x_i*x_j; */
"ldr r5, [%[wij]]\n\t"
"ldr r6, [%[xj]], #4\n\t"
"adds r5, r5, r4\n\t"
"adc r4, %[c], r9\n\t"
"umull r7, r12, %[x_i], r6\n\t"
"adds r5, r5, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], r9, r9\n\t"
"adds r5, r5, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], %[c], r9\n\t"
"str r5, [%[wij]], #4\n"
"0:\n\t"
"ldr r5, [%[wij]]\n\t"
"adds r4, r4, r5\n\t"
"adc %[c], %[c], #0\n\t"
"str r4, [%[wij]], #4"
: [c] "=&r" (c), [wij] "=r" (wij), [xj] "=r" (xj)
: [x_i] "r" (x_i), [x_max1] "r" (&A->word[BN256_WORDS-1]),
"[wij]" (wij), "[xj]" (xj)
: "r4", "r5", "r6", "r7", "r8", "r9", "r12", "memory", "cc");
if (i < BN256_WORDS - 1)
*wij = c;
}
#else
int i, j, k;
int i_beg, i_end;
uint32_t r0, r1, r2;
@@ -217,11 +322,10 @@ bn256_sqr (bn512 *X, const bn256 *A)
j = k - i;
uv = ((uint64_t )A->words[i])*((uint64_t )A->words[j]);
uv = ((uint64_t )A->word[i])*((uint64_t )A->word[j]);
if (i < j)
{
if ((uv >> 63) != 0)
r2++;
r2 += ((uv >> 63) != 0);
uv <<= 1;
}
v = uv;
@@ -235,13 +339,14 @@ bn256_sqr (bn512 *X, const bn256 *A)
r2 += carry;
}
X->words[k] = r0;
X->word[k] = r0;
r0 = r1;
r1 = r2;
r2 = 0;
}
X->words[k] = r0;
X->word[k] = r0;
#endif
}
uint32_t
@@ -254,8 +359,8 @@ bn256_shift (bn256 *X, const bn256 *A, int shift)
{
for (i = 0; i < BN256_WORDS; i++)
{
next_carry = A->words[i] >> (32 - shift);
X->words[i] = (A->words[i] << shift) | carry;
next_carry = A->word[i] >> (32 - shift);
X->word[i] = (A->word[i] << shift) | carry;
carry = next_carry;
}
}
@@ -265,8 +370,8 @@ bn256_shift (bn256 *X, const bn256 *A, int shift)
for (i = BN256_WORDS - 1; i >= 0; i--)
{
next_carry = A->words[i] & ((1 << shift) - 1);
X->words[i] = (A->words[i] >> shift) | (carry << (32 - shift));
next_carry = A->word[i] & ((1 << shift) - 1);
X->word[i] = (A->word[i] >> shift) | (carry << (32 - shift));
carry = next_carry;
}
}
@@ -278,63 +383,59 @@ int
bn256_is_zero (const bn256 *X)
{
int i;
int r = 1;
for (i = 0; i < BN256_WORDS; i++)
if (X->words[i] != 0)
return 0;
r &= (X->word[i] == 0);
return 1;
return r;
}
int
bn256_is_even (const bn256 *X)
{
return !(X->words[0] & 1);
return !(X->word[0] & 1);
}
int
bn256_is_ge (const bn256 *A, const bn256 *B)
{
int i;
uint32_t borrow;
bn256 tmp[1];
for (i = BN256_WORDS - 1; i >= 0; i--)
if (A->words[i] > B->words[i])
return 1;
else if (A->words[i] < B->words[i])
return 0;
return 1;
borrow = bn256_sub (tmp, A, B);
return borrow == 0;
}
int
bn256_cmp (const bn256 *A, const bn256 *B)
{
int i;
uint32_t borrow;
int is_zero;
bn256 tmp[1];
for (i = BN256_WORDS - 1; i >= 0; i--)
if (A->words[i] > B->words[i])
return 1;
else if (A->words[i] < B->words[i])
return -1;
return 0;
borrow = bn256_sub (tmp, A, B);
is_zero = bn256_is_zero (tmp);
return is_zero ? 0 : (borrow ? -1 : 1);
}
#ifndef BN256_NO_RANDOM
void
bn256_random (bn256 *X)
{
const uint8_t *rand = random_bytes_get ();
X->words[7] = ((uint32_t *)rand)[7];
X->words[6] = ((uint32_t *)rand)[6];
X->words[5] = ((uint32_t *)rand)[5];
X->words[4] = ((uint32_t *)rand)[4];
X->words[3] = ((uint32_t *)rand)[3];
X->words[2] = ((uint32_t *)rand)[2];
X->words[1] = ((uint32_t *)rand)[1];
X->words[0] = ((uint32_t *)rand)[0];
X->word[7] = ((uint32_t *)rand)[7];
X->word[6] = ((uint32_t *)rand)[6];
X->word[5] = ((uint32_t *)rand)[5];
X->word[4] = ((uint32_t *)rand)[4];
X->word[3] = ((uint32_t *)rand)[3];
X->word[2] = ((uint32_t *)rand)[2];
X->word[1] = ((uint32_t *)rand)[1];
X->word[0] = ((uint32_t *)rand)[0];
random_bytes_free (rand);
}
#endif

View File

@@ -1,11 +1,11 @@
#define BN256_WORDS 8
typedef struct bn256 {
uint32_t words[ BN256_WORDS ]; /* Little endian */
uint32_t word[ BN256_WORDS ]; /* Little endian */
} bn256;
#define BN512_WORDS 16
typedef struct bn512 {
uint32_t words[ BN512_WORDS ]; /* Little endian */
uint32_t word[ BN512_WORDS ]; /* Little endian */
} bn512;
uint32_t bn256_add (bn256 *X, const bn256 *A, const bn256 *B);

View File

@@ -1,5 +1,5 @@
/*
* call-ec_p256.c - interface between Gnuk and Elliptic curve over GF(p256)
* call-ec.c - interface between Gnuk and Elliptic curve over GF(prime)
*
* Copyright (C) 2013 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
@@ -21,24 +21,15 @@
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "bn.h"
#include "jpc-ac.h"
#include "ec_p256.h"
#include "config.h"
#include "gnuk.h"
#include "field-group-select.h"
/* We are little endian. */
#define ECDSA_BYTE_SIZE 32
int
ecdsa_sign (const uint8_t *hash, uint8_t *output,
const struct key_data *kd)
FUNC(ecdsa_sign) (const uint8_t *hash, uint8_t *output,
const uint8_t *key_data)
{
int i;
bn256 r[1], s[1], z[1], d[1];
@@ -46,13 +37,13 @@ ecdsa_sign (const uint8_t *hash, uint8_t *output,
p = (uint8_t *)d;
for (i = 0; i < ECDSA_BYTE_SIZE; i++)
p[ECDSA_BYTE_SIZE - i - 1] = kd->data[i];
p[ECDSA_BYTE_SIZE - i - 1] = key_data[i];
p = (uint8_t *)z;
for (i = 0; i < ECDSA_BYTE_SIZE; i++)
p[ECDSA_BYTE_SIZE - i - 1] = hash[i];
ecdsa (r, s, z, d);
FUNC(ecdsa) (r, s, z, d);
p = (uint8_t *)r;
for (i = 0; i < ECDSA_BYTE_SIZE; i++)
*output++ = p[ECDSA_BYTE_SIZE - i - 1];
@@ -63,7 +54,7 @@ ecdsa_sign (const uint8_t *hash, uint8_t *output,
}
uint8_t *
ecdsa_compute_public (const uint8_t *key_data)
FUNC(ecdsa_compute_public) (const uint8_t *key_data)
{
uint8_t *p0, *p, *p1;
ac q[1];
@@ -77,7 +68,7 @@ ecdsa_compute_public (const uint8_t *key_data)
p = (uint8_t *)k;
for (i = 0; i < ECDSA_BYTE_SIZE; i++)
p[ECDSA_BYTE_SIZE - i - 1] = key_data[i];
if (compute_kG (q, k) < 0)
if (FUNC(compute_kG) (q, k) < 0)
{
free (p0);
return NULL;

35
src/call-ec_p256k1.c Normal file
View File

@@ -0,0 +1,35 @@
/*
* call-ec_p256k1.c - interface between Gnuk and Elliptic curve over
* GF(p256k1)
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "bn.h"
#include "affine.h"
#include "jpc-ac_p256k1.h"
#include "ec_p256k1.h"
#define FIELD p256k1
#include "call-ec.c"

35
src/call-ec_p256r1.c Normal file
View File

@@ -0,0 +1,35 @@
/*
* call-ec_p256r1.c - interface between Gnuk and Elliptic curve over
* GF(p256r1)
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "bn.h"
#include "affine.h"
#include "jpc-ac_p256r1.h"
#include "ec_p256r1.h"
#define FIELD p256r1
#include "call-ec.c"

2
src/configure vendored
View File

@@ -321,6 +321,8 @@ if test "$certdo" = "yes"; then
-e "s/@MEMORY_SIZE@/$MEMORY_SIZE/" \
-e "s/@FLASH_PAGE_SIZE@/$FLASH_PAGE_SIZE/" \
-e "s/@MSC_SIZE@/$MSC_SIZE/" \
-e "s/@TIM_SIZE@/$TIM_SIZE/" \
-e "s/@EXT_SIZE@/$EXT_SIZE/" \
< gnuk.ld.in > gnuk.ld
else
sed -e "/^@CERTDO_SUPPORT_START@$/,/^@CERTDO_SUPPORT_END@$/ d" \

View File

@@ -1,12 +0,0 @@
/* Non-adjacent form */
typedef struct naf4_257 {
uint32_t words[ BN256_WORDS*4 ]; /* Little endian */
uint8_t last_nibble; /* most significant nibble */
} naf4_257;
void compute_naf4_257 (naf4_257 *NAF_K, const bn256 *K);
int compute_kP (ac *X, const naf4_257 *NAF_K, const ac *P);
int compute_kG (ac *X, const bn256 *K);
void ecdsa (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d);

225
src/ec_p256k1.c Normal file
View File

@@ -0,0 +1,225 @@
/* -*- coding: utf-8 -*-
* ec_p256k1.c - Elliptic curve over GF(p256k1)
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "modp256k1.h"
#include "affine.h"
#include "jpc-ac_p256k1.h"
#include "mod.h"
#include "ec_p256k1.h"
#define FIELD p256k1
#define COEFFICIENT_A_IS_ZERO 1
/*
* a = 0, b = 7
*/
static const bn256 coefficient_a[1] = {
{{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }}
};
static const bn256 coefficient_b[1] = {
{{ 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }}
};
static const ac precomputed_KG[15] = {
{
{{{ 0x16f81798, 0x59f2815b, 0x2dce28d9, 0x029bfcdb,
0xce870b07, 0x55a06295, 0xf9dcbbac, 0x79be667e }}},
{{{ 0xfb10d4b8, 0x9c47d08f, 0xa6855419, 0xfd17b448,
0x0e1108a8, 0x5da4fbfc, 0x26a3c465, 0x483ada77 }}}
}, {
{{{ 0x42d0e6bd, 0x13b7e0e7, 0xdb0f5e53, 0xf774d163,
0x104d6ecb, 0x82a2147c, 0x243c4e25, 0x3322d401 }}},
{{{ 0x6c28b2a0, 0x24f3a2e9, 0xa2873af6, 0x2805f63e,
0x4ddaf9b7, 0xbfb019bc, 0xe9664ef5, 0x56e70797 }}}
}, {
{{{ 0x829d122a, 0xdca81127, 0x67e99549, 0x8f17f314,
0x6a8a9e73, 0x9b889085, 0x846dd99d, 0x583fdfd9 }}},
{{{ 0x63c4eac4, 0xf3c7719e, 0xb734b37a, 0xb44685a3,
0x572a47a6, 0x9f92d2d6, 0x2ff57d81, 0xabc6232f }}}
}, {
{{{ 0x9ec4c0da, 0x1b7b444c, 0x723ea335, 0xe88c5678,
0x981f162e, 0x9239c1ad, 0xf63b5f33, 0x8f68b9d2 }}},
{{{ 0x501fff82, 0xf23cbf79, 0x95510bfd, 0xbbea2cfe,
0xb6be215d, 0xde1d90c2, 0xba063986, 0x662a9f2d }}}
}, {
{{{ 0x114cbf09, 0x63c5e885, 0x7be77e3e, 0x2f27ce93,
0xf54a3e33, 0xdaa6d12d, 0x3eff872c, 0x8b300e51 }}},
{{{ 0xb3b10a39, 0x26c6ff28, 0x9aaf7169, 0x08f6a7aa,
0x6b8238ea, 0x446f0d46, 0x7f43c0cc, 0x1cec3067 }}}
}, {
{{{ 0x075e9070, 0xba16ce6a, 0x9b5cfe37, 0xbc26893d,
0x9c510774, 0xe1ddadfe, 0xfe3ae2f4, 0x90922d88 }}},
{{{ 0x5c08824a, 0x653943cc, 0xfce8f4bc, 0x06d74475,
0x533c615d, 0x8d101fa7, 0x742108a9, 0x7b1903f6 }}}
}, {
{{{ 0x6ebdc96c, 0x1bcfa45c, 0x1c7584ba, 0xe400bc04,
0x74cf531f, 0x6395e20e, 0xc5131b30, 0x1edd0bb1 }}},
{{{ 0xe358cf9e, 0xa117161b, 0x2724d11c, 0xe490d6f0,
0xee6dd8c9, 0xf75062f6, 0xfba373e4, 0x31e03b2b }}}
}, {
{{{ 0x2120e2b3, 0x7f3b58fa, 0x7f47f9aa, 0x7a58fdce,
0x4ce6e521, 0xe7be4ae3, 0x1f51bdba, 0xeaa649f2 }}},
{{{ 0xba5ad93d, 0xd47a5305, 0xf13f7e59, 0x01a6b965,
0x9879aa5a, 0xc69a80f8, 0x5bbbb03a, 0xbe3279ed }}}
}, {
{{{ 0x27bb4d71, 0xcf291a33, 0x33524832, 0x6caf7d6b,
0x766584ee, 0x6e0ee131, 0xd064c589, 0x160cb0f6 }}},
{{{ 0x17136e8d, 0x9d5de554, 0x1aab720e, 0xe3f2d468,
0xccf75cc2, 0xd1378b49, 0xc4ff16e1, 0x6920c375 }}}
}, {
{{{ 0x1a9ee611, 0x3eef9e96, 0x9cc37faf, 0xfe4d7bf3,
0xb321d965, 0x462aa9b3, 0x208736c5, 0x1702da3e }}},
{{{ 0x3a545ceb, 0xfba57bbf, 0x7ea858f5, 0x6dbcd766,
0x680d92f1, 0x088e897c, 0xbc626c80, 0x468c1fd8 }}}
}, {
{{{ 0xb188660a, 0xb40f85c7, 0x99bc3c36, 0xc5873c19,
0x7f33b54c, 0x3c7b4541, 0x1f8c9bf8, 0x4cd3a93c }}},
{{{ 0x33099cb0, 0xf8dce380, 0x2edd2f33, 0x7a167dd6,
0x0ffe35b7, 0x576d8987, 0xc68ace5c, 0xd2de0386 }}}
}, {
{{{ 0x6658bb08, 0x9a9e0a72, 0xc589607b, 0xe23c5f2a,
0xf2bfb4c8, 0xa048ca14, 0xc62c2291, 0x4d9a0f89 }}},
{{{ 0x0f827294, 0x427b5f31, 0x9f2c35cd, 0x1ea7a8b5,
0x85a3c00f, 0x95442e56, 0x9b57975a, 0x8cb83121 }}}
}, {
{{{ 0x51f5cf67, 0x4333f0da, 0xf4f0d3cb, 0x6d3ea47c,
0xa05a831f, 0x442fda14, 0x016d3e81, 0x6a496013 }}},
{{{ 0xe52e0f48, 0xf647318c, 0x4a0d5ff1, 0x5ff3a66e,
0x61199ba8, 0x046ed81a, 0x3e79c23a, 0x578edf08 }}}
}, {
{{{ 0x3ea01ea7, 0xb8f996f8, 0x7497bb15, 0xc0045d33,
0x6205647c, 0xc4749dc9, 0x0efd22c9, 0xd8946054 }}},
{{{ 0x12774ad5, 0x062dcb09, 0x8be06e3a, 0xcb13f310,
0x235de1a9, 0xca281d35, 0x69c3645c, 0xaf8a7412 }}}
}, {
{{{ 0xbeb8b1e2, 0x8808ca5f, 0xea0dda76, 0x0262b204,
0xddeb356b, 0xb6fffffc, 0xfbb83870, 0x52de253a }}},
{{{ 0x8f8d21ea, 0x961f40c0, 0x002f03ed, 0x89686278,
0x38e421ea, 0x0ff834d7, 0xd36fb8db, 0x3a270d6f }}}
}
};
static const ac precomputed_2E_KG[15] = {
{
{{{ 0x39a48db0, 0xefd7835b, 0x9b3c03bf, 0x9f1215a2,
0x9b7bde45, 0x2791d0a0, 0x696e7167, 0x100f44da }}},
{{{ 0x2bc65a09, 0x0fbd5cd6, 0xff5195ac, 0xb7ff4a18,
0x0c090666, 0x2ec8f330, 0x92a00b77, 0xcdd9e131 }}}
}, {
{{{ 0x40fb27b6, 0x32427e28, 0xbe430576, 0xc76e3db2,
0x61686aa5, 0x10f238ad, 0xbe778b1b, 0xfea74e3d }}},
{{{ 0xf23cb96f, 0x701d3db7, 0x973f7b77, 0x126b596b,
0xccb6af93, 0x7cf674de, 0x9b0b1329, 0x6e0568db }}}
}, {
{{{ 0x2c8118bc, 0x6cac5154, 0x399ddd98, 0x19bd4b34,
0x2e9c8949, 0x47248a8d, 0x2cefa3b1, 0x734cb6a8 }}},
{{{ 0x1e410fd5, 0xf1b340ad, 0xc4873539, 0xa2982bee,
0xd4de4530, 0x7b5a3ea4, 0x42202574, 0xae46e10e }}}
}, {
{{{ 0xac1f98cd, 0xcbfc99c8, 0x4d7f0308, 0x52348905,
0x1cc66021, 0xfaed8a9c, 0x4a474870, 0x9c3919a8 }}},
{{{ 0xd4fc599d, 0xbe7e5e03, 0x6c64c8e6, 0x905326f7,
0xf260e641, 0x584f044b, 0x4a4ddd57, 0xddb84f0f }}}
}, {
{{{ 0xed7cebed, 0xc4aacaa8, 0x4fae424e, 0xb75d2dce,
0xba20735e, 0xa01585a2, 0xba122399, 0x3d75f24b }}},
{{{ 0xd5570dce, 0xcbe4606f, 0x2da192c2, 0x9d00bfd7,
0xa57b7265, 0x9c3ce86b, 0xec4edf5e, 0x987a22f1 }}}
}, {
{{{ 0x73ea0665, 0x211b9715, 0xf3a1abbb, 0x86f485d4,
0xcd076f0e, 0xabd242d8, 0x0ba5dc88, 0x862332ab }}},
{{{ 0x7b784911, 0x09af505c, 0xcaf4fae7, 0xc89544e8,
0xae9a32eb, 0x256625f6, 0x606d1a3f, 0xe2532b72 }}}
}, {
{{{ 0x0deaf885, 0x79e9f313, 0x46df21c9, 0x938ff76e,
0xa953bb2c, 0x1968f5fb, 0x29155f27, 0xdff538bf }}},
{{{ 0x31d5d020, 0xf7bae0b1, 0x1a676a8d, 0x5afdc787,
0xfa9d53ff, 0x11b4f032, 0xc5959167, 0x86ba433e }}}
}, {
{{{ 0x9475b7ba, 0x884fdff0, 0xe4918b3d, 0xe039e730,
0xf5018cdb, 0x3d3e57ed, 0x1943785c, 0x95939698 }}},
{{{ 0x7524f2fd, 0xe9b8abf8, 0xc8709385, 0x9c653f64,
0x4b9cd684, 0x8ba0386a, 0x88c331dd, 0x2e7e5528 }}}
}, {
{{{ 0xeefe79e5, 0x940bef53, 0xbe9b87f3, 0xc518d286,
0x7833042c, 0x9e0c7c76, 0x11fbe152, 0x104e2cb5 }}},
{{{ 0x50bbec83, 0xc0d35e0f, 0x4acd0fcc, 0xee4879be,
0x006085ee, 0xc8d80f5d, 0x72fe1ac1, 0x3c51bc1c }}}
}, {
{{{ 0xb2de976e, 0x06187f61, 0xf5e4b4b6, 0x52869e18,
0x38d332ca, 0x74d4facd, 0xb3a2f8d9, 0x5c1c90b4 }}},
{{{ 0xdaa37893, 0x98644d09, 0xabe39818, 0x682435a8,
0x469c53a0, 0x17e46617, 0x77dc2e64, 0x642f9632 }}}
}, {
{{{ 0x222f6c54, 0xad2101c5, 0xfa74785e, 0xb05c7a58,
0x489bcdaf, 0xce55fa79, 0xffe88d54, 0xc1f920fd }}},
{{{ 0x9065e490, 0x32553ab0, 0x35329f74, 0x7611b9af,
0xab7b24c0, 0x57df19ef, 0x6181c447, 0xb9a78749 }}}
}, {
{{{ 0xa80b7ea8, 0x392f156f, 0x8ae4a8bf, 0x57ab7ca0,
0x50c4b178, 0xac320747, 0x0e781feb, 0x146041b9 }}},
{{{ 0x845279b2, 0xd343f075, 0x7387afa5, 0x2d4fe757,
0xa72f3c39, 0x151e0948, 0x550da168, 0x41a6d54e }}}
}, {
{{{ 0x075a0010, 0xb3134ed3, 0x7ae93e23, 0x9fa76f4b,
0x7bb4daaa, 0xc0db256f, 0x464dd8a3, 0x7668dc27 }}},
{{{ 0x9f5da977, 0x150063f5, 0x05efce00, 0x3acac5c8,
0x884493fe, 0xc8e12ffc, 0x88f06bd2, 0x4ab936d8 }}}
}, {
{{{ 0x5d09ea98, 0x996fde77, 0x4145da58, 0x16ddf512,
0xdc2fb225, 0xa97a6ca8, 0xfbdcdf5a, 0xc7331f30 }}},
{{{ 0x86a86e52, 0x838f99e0, 0x77795edd, 0x68d39b29,
0x9f412aaa, 0xe4e4f97e, 0x30d25352, 0xe5cc2c0a }}}
}, {
{{{ 0x9c21ff71, 0xb3d68650, 0xddbe3884, 0x11e7589d,
0x423bac67, 0x7efd4055, 0x46957425, 0x587a7293 }}},
{{{ 0x8f5a8fc6, 0x360adc2e, 0xbd69f12e, 0x6f8bbafb,
0x0a3f3b4d, 0xf671f423, 0x59942dc3, 0xb49acb47 }}}
}
};
/*
* N: order of G
* 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
*/
static const bn256 N[1] = {
{{ 0xd0364141, 0xbfd25e8c, 0xaf48a03b, 0xbaaedce6,
0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff }}
};
/*
* MU = 2^512 / N
* MU = ( (1 << 256) | MU_lower )
*/
static const bn256 MU_lower[1] = {
{{ 0x2fc9bec0, 0x402da173, 0x50b75fc4, 0x45512319,
0x1, 0x0, 0x0, 0x0 }}
};
#include "ecc.c"

4
src/ec_p256k1.h Normal file
View File

@@ -0,0 +1,4 @@
int compute_kP_p256k1 (ac *X, const bn256 *K, const ac *P);
int compute_kG_p256k1 (ac *X, const bn256 *K);
void ecdsa_p256k1 (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d);

View File

@@ -1,7 +1,7 @@
/*
* ec_p256.c - Elliptic curve over GF(p256)
/* -*- coding: utf-8 -*-
* ec_p256r1.c - Elliptic curve over GF(p256r1)
*
* Copyright (C) 2011, 2013 Free Software Initiative of Japan
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -21,45 +21,20 @@
*
*/
/*
* References:
*
* [1] Suite B Implementer's Guide to FIPS 186-3 (ECDSA), February 3, 2010.
*
* [2] Michael Brown, Darrel Hankerson, Julio López, and Alfred Menezes,
* Software Implementation of the NIST Elliptic Curves Over Prime Fields,
* Proceedings of the 2001 Conference on Topics in Cryptology: The
* Cryptographer's Track at RSA
* Pages 250-265, Springer-Verlag London, UK, 2001
* ISBN:3-540-41898-9
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "modp256.h"
#include "jpc-ac.h"
#include "modp256r1.h"
#include "affine.h"
#include "jpc-ac_p256r1.h"
#include "mod.h"
#include "ec_p256.h"
#if TEST
/*
* Generator of Elliptic curve over GF(p256)
*/
const bn256 Gx[1] = {
{{ 0xd898c296, 0xf4a13945, 0x2deb33a0, 0x77037d81,
0x63a440f2, 0xf8bce6e5, 0xe12c4247, 0x6b17d1f2 }}
};
const bn256 Gy[1] = {
{{ 0x37bf51f5, 0xcbb64068, 0x6b315ece, 0x2bce3357,
0x7c0f9e16, 0x8ee7eb4a, 0xfe1a7f9b, 0x4fe342e2 }}
};
#endif
#include "ec_p256r1.h"
#define FIELD p256r1
#define COEFFICIENT_A_IS_MINUS_3 1
/*
* a = -3 mod p256
* a = -3 mod p256r1
*/
static const bn256 coefficient_a[1] = {
{{ 0xfffffffc, 0xffffffff, 0xffffffff, 0x00000000,
@@ -72,13 +47,6 @@ static const bn256 coefficient_b[1] = {
};
/*
* w = 4
* m = 256
* d = 64
* e = 32
*/
static const ac precomputed_KG[15] = {
{
{{{ 0xd898c296, 0xf4a13945, 0x2deb33a0, 0x77037d81,
@@ -237,271 +205,6 @@ static const ac precomputed_2E_KG[15] = {
}
};
/**
* @brief X = k * G
*
* @param K scalar k
*
* Return -1 on error.
* Return 0 on success.
*/
int
compute_kG (ac *X, const bn256 *K)
{
int i;
int q_is_infinite = 1;
jpc Q[1];
for (i = 31; i >= 0; i--)
{
int k_i, k_i_e;
if (!q_is_infinite)
jpc_double (Q, Q);
k_i = (((K->words[6] >> i) & 1) << 3)
| (((K->words[4] >> i) & 1) << 2)
| (((K->words[2] >> i) & 1) << 1)
| ((K->words[0] >> i) & 1);
k_i_e = (((K->words[7] >> i) & 1) << 3)
| (((K->words[5] >> i) & 1) << 2)
| (((K->words[3] >> i) & 1) << 1)
| ((K->words[1] >> i) & 1);
if (k_i)
{
if (q_is_infinite)
{
memcpy (Q->x, (&precomputed_KG[k_i - 1])->x, sizeof (bn256));
memcpy (Q->y, (&precomputed_KG[k_i - 1])->y, sizeof (bn256));
Q->z->words[0] = 1;
Q->z->words[1] = Q->z->words[2] = Q->z->words[3]
= Q->z->words[4] = Q->z->words[5] = Q->z->words[6]
= Q->z->words[7] = 0;
q_is_infinite = 0;
}
else
jpc_add_ac (Q, Q, &precomputed_KG[k_i - 1]);
}
if (k_i_e)
{
if (q_is_infinite)
{
memcpy (Q->x, (&precomputed_2E_KG[k_i_e - 1])->x, sizeof (bn256));
memcpy (Q->y, (&precomputed_2E_KG[k_i_e - 1])->y, sizeof (bn256));
memset (Q->z, 0, sizeof (bn256));
Q->z->words[0] = 1;
q_is_infinite = 0;
}
else
jpc_add_ac (Q, Q, &precomputed_2E_KG[k_i_e - 1]);
}
}
return jpc_to_ac (X, Q);
}
#define NAF_K_SIGN(k) (k&8)
#define NAF_K_INDEX(k) ((k&7)-1)
static void
naf4_257_set (naf4_257 *NAF_K, int i, int ki)
{
if (ki != 0)
{
if (ki > 0)
ki = (ki+1)/2;
else
ki = (1-ki)/2 | 8;
}
if (i == 256)
NAF_K->last_nibble = ki;
else
{
NAF_K->words[i/8] &= ~(0x0f << ((i & 0x07)*4));
NAF_K->words[i/8] |= (ki << ((i & 0x07)*4));
}
}
static int
naf4_257_get (const naf4_257 *NAF_K, int i)
{
int ki;
if (i == 256)
ki = NAF_K->last_nibble;
else
{
ki = NAF_K->words[i/8] >> ((i & 0x07)*4);
ki &= 0x0f;
}
return ki;
}
/*
* convert 256-bit bignum into non-adjacent form (NAF)
*/
void
compute_naf4_257 (naf4_257 *NAF_K, const bn256 *K)
{
int i = 0;
bn256 K_tmp[1];
uint32_t carry = 0;
memcpy (K_tmp, K, sizeof (bn256));
memset (NAF_K, 0, sizeof (naf4_257));
while (!bn256_is_zero (K_tmp))
{
if (bn256_is_even (K_tmp))
naf4_257_set (NAF_K, i, 0);
else
{
int ki = (K_tmp->words[0]) & 0x0f;
if ((ki & 0x08))
{
carry = bn256_add_uint (K_tmp, K_tmp, 16 - ki);
ki = ki - 16;
}
else
K_tmp->words[0] &= 0xfffffff0;
naf4_257_set (NAF_K, i, ki);
}
bn256_shift (K_tmp, K_tmp, -1);
if (carry)
{
K_tmp->words[7] |= 0x80000000;
carry = 0;
}
i++;
}
}
/**
* check if P is on the curve.
*
* Return -1 on error.
* Return 0 on success.
*/
static int
point_is_on_the_curve (const ac *P)
{
bn256 s[1], t[1];
/* Elliptic curve: y^2 = x^3 + a*x + b */
modp256_sqr (s, P->x);
modp256_mul (s, s, P->x);
modp256_mul (t, coefficient_a, P->x);
modp256_add (s, s, t);
modp256_add (s, s, coefficient_b);
modp256_sqr (t, P->y);
if (bn256_cmp (s, t) == 0)
return 0;
return -1;
}
/**
* @brief X = k * P
*
* @param NAF_K NAF representation of k
* @param P P in affine coordiate
*
* Return -1 on error.
* Return 0 on success.
*
* For the curve (cofactor is 1 and n is prime), possible error cases are:
*
* P is not on the curve.
* P = G, k = n
* Something wrong in the code.
*
* Mathmatically, k=1 and P=O is another possible case, but O cannot be
* represented by affine coordinate.
*/
int
compute_kP (ac *X, const naf4_257 *NAF_K, const ac *P)
{
int i;
int q_is_infinite = 1;
jpc Q[1];
ac P3[1], P5[1], P7[1];
const ac *p_Pi[4];
if (point_is_on_the_curve (P) < 0)
return -1;
p_Pi[0] = P;
p_Pi[1] = P3;
p_Pi[2] = P5;
p_Pi[3] = P7;
{
jpc Q1[1];
memcpy (Q->x, P->x, sizeof (bn256));
memcpy (Q->y, P->y, sizeof (bn256));
memset (Q->z, 0, sizeof (bn256));
Q->z->words[0] = 1;
jpc_double (Q, Q);
jpc_add_ac (Q1, Q, P);
if (jpc_to_ac (P3, Q1) < 0) /* Never occurs, except coding errors. */
return -1;
jpc_double (Q, Q);
jpc_add_ac (Q1, Q, P);
if (jpc_to_ac (P5, Q1) < 0) /* Never occurs, except coding errors. */
return -1;
memcpy (Q->x, P3->x, sizeof (bn256));
memcpy (Q->y, P3->y, sizeof (bn256));
memset (Q->z, 0, sizeof (bn256));
Q->z->words[0] = 1;
jpc_double (Q, Q);
jpc_add_ac (Q1, Q, P);
if (jpc_to_ac (P7, Q1) < 0) /* Never occurs, except coding errors. */
return -1;
}
for (i = 256; i >= 0; i--)
{
int k_i;
if (!q_is_infinite)
jpc_double (Q, Q);
k_i = naf4_257_get (NAF_K, i);
if (k_i)
{
if (q_is_infinite)
{
memcpy (Q->x, p_Pi[NAF_K_INDEX(k_i)]->x, sizeof (bn256));
if (NAF_K_SIGN (k_i))
bn256_sub (Q->y, P256, p_Pi[NAF_K_INDEX(k_i)]->y);
else
memcpy (Q->y, p_Pi[NAF_K_INDEX(k_i)]->y, sizeof (bn256));
memset (Q->z, 0, sizeof (bn256));
Q->z->words[0] = 1;
q_is_infinite = 0;
}
else
jpc_add_ac_signed (Q, Q, p_Pi[NAF_K_INDEX(k_i)], NAF_K_SIGN (k_i));
}
}
return jpc_to_ac (X, Q);
}
/*
* N: order of G
*/
@@ -520,46 +223,4 @@ static const bn256 MU_lower[1] = {
};
/**
* @brief Compute signature (r,s) of hash string z with secret key d
*/
void
ecdsa (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d)
{
bn256 k[1];
ac KG[1];
bn512 tmp[1];
bn256 k_inv[1];
uint32_t carry;
#define tmp_k k_inv
do
{
do
{
bn256_random (k);
if (bn256_sub (tmp_k, k, N) == 0) /* > N, it's too big. */
continue;
if (bn256_add_uint (tmp_k, tmp_k, 2)) /* > N - 2, still big. */
continue;
bn256_add_uint (k, k, 1);
compute_kG (KG, k);
if (bn256_is_ge (KG->x, N))
bn256_sub (r, KG->x, N);
else
memcpy (r, KG->x, sizeof (bn256));
}
while (bn256_is_zero (r));
mod_inv (k_inv, k, N);
bn256_mul (tmp, r, d);
mod_reduce (s, tmp, N, MU_lower);
carry = bn256_add (s, s, z);
if (carry)
bn256_sub (s, s, N);
bn256_mul (tmp, s, k_inv);
mod_reduce (s, tmp, N, MU_lower);
}
while (bn256_is_zero (s));
}
#include "ecc.c"

5
src/ec_p256r1.h Normal file
View File

@@ -0,0 +1,5 @@
int compute_kP_p256r1 (ac *X, const bn256 *K, const ac *P);
int compute_kG_p256r1 (ac *X, const bn256 *K);
void ecdsa_p256r1 (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d);

965
src/ecc-edwards.c Normal file
View File

@@ -0,0 +1,965 @@
/* -*- coding: utf-8 -*-
* ecc-edwards.c - Elliptic curve computation for
* the twisted Edwards curve: -x^2 + y^2 = 1 + d*x^2*y^2
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "bn.h"
#include "mod.h"
#include "mod25638.h"
#include "sha512.h"
/*
* References:
*
* [1] Daniel J. Bernstein, Niels Duif, Tanja Lange, Peter Schwabe, Bo-Yin Yang.
* High-speed high-security signatures.
* Journal of Cryptographic Engineering 2 (2012), 77--89.
* http://cr.yp.to/papers.html#ed25519
*
* [2] Daniel J. Bernstein, Peter Birkner, Marc Joye, Tanja Lange,
* Christiane Peters.
* Twisted Edwards curves.
* Pages 389--405 in Progress in cryptology---AFRICACRYPT 2008.
* http://cr.yp.to/papers.html#twisted
*/
/*
* IMPLEMENTATION NOTE
*
* (0) We assume that the processor has no cache, nor branch target
* prediction. Thus, we don't avoid indexing by secret value.
* We don't avoid conditional jump if both cases have same timing,
* either.
*
* (1) We use Radix-32 field arithmetic. It's a representation like
* 2^256-38, but it's more redundant. For example, "1" can be
* represented in three ways in 256-bit: 1, 2^255-18, and
* 2^256-37.
*
* (2) We use fixed base comb multiplication. Scalar is 252-bit.
* There are various possible choices for 252 = 2 * 2 * 3 * 3 * 7.
* Current choice of total size is 3KB. We use three tables, and
* a table has 16 points (3 * 1KB).
*
* Window size W = 4-bit, E = 21.
* <--21-bit-
* <---42-bit----------
* [ ][########][////////][ ][########][////////]
* <-------63-bit----------------
* <-----------84-bit----------------------
* <--------------105-bit----------------------------
*
* [ ][########][////////][ ][########][////////]
* <-126-bit-
* <-147-bit-
* <----168-bit--------
*
* <-------189-bit---------------
* <----------210-bit----------------------
* <-------------231-bit-----------------------------
*/
/*
* Identity element: (0,1)
* Negation: -(x,y) = (-x,y)
*
* d: -0x2DFC9311D490018C7338BF8688861767FF8FF5B2BEBE27548A14B235ECA6874A
* order:
* 0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED
* Gx: 0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A
* Gy: 0x6666666666666666666666666666666666666666666666666666666666666658
*/
/* d + 2^255 - 19 */
static const bn256 coefficient_d[1] = {
{{ 0x135978a3, 0x75eb4dca, 0x4141d8ab, 0x00700a4d,
0x7779e898, 0x8cc74079, 0x2b6ffe73, 0x52036cee }} };
/**
* @brief Projective Twisted Coordinates
*/
typedef struct
{
bn256 x[1];
bn256 y[1];
bn256 z[1];
} ptc;
#include "affine.h"
static int
mod25519_is_neg (const bn256 *a)
{
return (a->word[0] & 1);
}
/**
* @brief X = 2 * A
*
* Compute (X3 : Y3 : Z3) = 2 * (X1 : Y1 : Z1)
*/
static void
point_double (ptc *X, const ptc *A)
{
uint32_t borrow;
bn256 b[1], d[1], e[1];
/* Compute: B = (X1 + Y1)^2 */
mod25638_add (b, A->x, A->y);
mod25638_sqr (b, b);
/* Compute: C = X1^2 : E */
mod25638_sqr (e, A->x);
/* Compute: D = Y1^2 */
mod25638_sqr (d, A->y);
/* E = aC; where a = -1 */
/* Compute: E - D = -(C+D) : Y3_tmp */
mod25638_add (X->y, e, d);
/* Negation: it can result borrow, as it is in redundant representation. */
borrow = bn256_sub (X->y, n25638, X->y);
if (borrow)
bn256_add (X->y, X->y, n25638); /* carry ignored */
else
bn256_add (X->x, X->y, n25638); /* dummy calculation */
/* Compute: F = E + D = D - C; where a = -1 : E */
mod25638_sub (e, d, e);
/* Compute: H = Z1^2 : D */
mod25638_sqr (d, A->z);
/* Compute: J = F - 2*H : D */
mod25638_add (d, d, d);
mod25638_sub (d, e, d);
/* Compute: X3 = (B-C-D)*J = (B+Y3_tmp)*J */
mod25638_add (X->x, b, X->y);
mod25638_mul (X->x, X->x, d);
/* Compute: Y3 = F*(E-D) = F*Y3_tmp */
mod25638_mul (X->y, X->y, e);
/* Z3 = F*J */
mod25638_mul (X->z, e, d);
}
/**
* @brief X = A + B
*
* @param X Destination PTC
* @param A PTC
* @param B AC
*
* Compute: (X3 : Y3 : Z3) = (X1 : Y1 : Z1) + (X2 : Y2 : 1)
*/
static void
point_add (ptc *X, const ptc *A, const ac *B)
{
bn256 c[1], d[1], e[1], tmp[1];
/* Compute: C = X1 * X2 */
mod25638_mul (c, A->x, B->x);
/* Compute: D = Y1 * Y2 */
mod25638_mul (d, A->y, B->y);
/* Compute: E = d * C * D */
mod25638_mul (e, c, d);
mod25638_mul (e, coefficient_d, e);
/* Compute: C_1 = C + D */
mod25638_add (c, c, d);
/* Compute: D_1 = Z1^2 : B */
mod25638_sqr (d, A->z);
/* tmp = D_1 - E : F */
mod25638_sub (tmp, d, e);
/* D_2 = D_1 + E : G */
mod25638_add (d, d, e);
/* X3_final = Z1 * tmp * ((X1 + Y1) * (X2 + Y2) - C_1) */
mod25638_add (X->x, A->x, A->y);
mod25638_add (e, B->x, B->y);
mod25638_mul (e, X->x, e);
mod25638_sub (e, e, c);
mod25638_mul (e, tmp, e);
mod25638_mul (X->x, A->z, e);
/* Y3_final = Z1 * D_2 * C_1 */
mod25638_mul (c, d, c);
mod25638_mul (X->y, A->z, c);
/* Z3_final = tmp * D_2 */
mod25638_mul (X->z, tmp, d);
/* A = Z1 */
/* B = A^2 */
/* C = X1 * X2 */
/* D = Y1 * Y2 */
/* E = d * C * D */
/* F = B - E */
/* G = B + E */
/* X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D) */
/* Y3 = A * G * (D - aC); where a = -1 */
/* Z3 = F * G */
}
/**
* @brief X = convert A
*
* @param X Destination AC
* @param A PTC
*
* (X1:Y1:Z1) represents the affine point (x=X1/Z1, y=Y1/Z1)
*/
static void
point_ptc_to_ac (ac *X, const ptc *A)
{
bn256 z_inv[1];
/*
* A->z may be bigger than p25519, or two times bigger than p25519.
* But this is no problem for computation of mod_inv.
*/
mod_inv (z_inv, A->z, p25519);
mod25638_mul (X->x, A->x, z_inv);
mod25519_reduce (X->x);
mod25638_mul (X->y, A->y, z_inv);
mod25519_reduce (X->y);
}
static const ac precomputed_KG[16] = {
{ {{{ 0, 0, 0, 0, 0, 0, 0, 0 }}},
{{{ 1, 0, 0, 0, 0, 0, 0, 0 }}} },
{ {{{ 0x8f25d51a, 0xc9562d60, 0x9525a7b2, 0x692cc760,
0xfdd6dc5c, 0xc0a4e231, 0xcd6e53fe, 0x216936d3 }}},
{{{ 0x66666658, 0x66666666, 0x66666666, 0x66666666,
0x66666666, 0x66666666, 0x66666666, 0x66666666 }}} },
{ {{{ 0x3713af22, 0xac7137bd, 0xac634604, 0x25ed77a4,
0xa815e038, 0xce0d0064, 0xbca90151, 0x041c030f }}},
{{{ 0x0780f989, 0xe9b33fcf, 0x3d4445e7, 0xe4e97c2a,
0x655e5c16, 0xc67dc71c, 0xee43fb7a, 0x72467625 }}} },
{ {{{ 0x3ee99893, 0x76a19171, 0x7ba9b065, 0xe647edd9,
0x6aeae260, 0x31f39299, 0x5f4a9bb2, 0x6d9e4545 }}},
{{{ 0x94cae280, 0xc41433da, 0x79061211, 0x8e842de8,
0xa259dc8a, 0xaab95e0b, 0x99013cd0, 0x28bd5fc3 }}} },
{ {{{ 0x7d23ea24, 0x59e22c56, 0x0460850e, 0x1e745a88,
0xda13ef4b, 0x4583ff4c, 0x95083f85, 0x1f13202c }}},
{{{ 0x90275f48, 0xad42025c, 0xb55c4778, 0x0085087e,
0xfdfd7ffa, 0xf21109e7, 0x6c381b7e, 0x66336d35 }}} },
{ {{{ 0xd00851f2, 0xaa9476ab, 0x4a61600b, 0xe7838534,
0x1a52df87, 0x0de65625, 0xbd675870, 0x5f0dd494 }}},
{{{ 0xe23493ba, 0xf20aec1b, 0x3414b0a8, 0x8f7f2741,
0xa80e1eb6, 0x497e74bd, 0xe9365b15, 0x1648eaac }}} },
{ {{{ 0x04ac2b69, 0x5b78dcec, 0x32001a73, 0xecdb66ce,
0xb34cf697, 0xb75832f4, 0x3a2bce94, 0x7aaf57c5 }}},
{{{ 0x60fdfc6f, 0xb32ed2ce, 0x757924c6, 0x77bf20be,
0x48742dd1, 0xaebd15dd, 0x55d38439, 0x6311bb16 }}} },
{ {{{ 0x42ff5c97, 0x139cdd73, 0xdbd82964, 0xee4c359e,
0x70611a3f, 0x91c1cd94, 0x8075dbcb, 0x1d0c34f6 }}},
{{{ 0x5f931219, 0x43eaa549, 0xa23d35a6, 0x3737aba7,
0x46f167bb, 0x54b1992f, 0xb74a9944, 0x01a11f3c }}} },
{ {{{ 0xba46b161, 0x67a5310e, 0xd9d67f6c, 0x790f8527,
0x2f6cc814, 0x359c5b5f, 0x7786383d, 0x7b6a5565 }}},
{{{ 0x663ab0d3, 0xf1431b60, 0x09995826, 0x14a32d8f,
0xeddb8571, 0x61d526f6, 0x0eac739a, 0x0cb7acea }}} },
{ {{{ 0x4a2d009f, 0x5eb1a697, 0xd8df987a, 0xdacb43b4,
0x8397f958, 0x4870f214, 0x8a175fbb, 0x5aa0c67c }}},
{{{ 0x78887db3, 0x27dbbd4c, 0x64e322ab, 0xe327b707,
0x7cbe4e3b, 0x87e293fa, 0xbda72395, 0x17040799 }}} },
{ {{{ 0x99d1e696, 0xc833a5a2, 0x2d9d5877, 0x969bff8e,
0x2216fa67, 0x383a533a, 0x684d3925, 0x338bbe0a }}},
{{{ 0xd6cfb491, 0x35b5aae8, 0xaa12f3f8, 0x4a588279,
0x2e30380e, 0xa7c2e708, 0x9e4b3d62, 0x69f13e09 }}} },
{ {{{ 0x27f1cd56, 0xec0dc2ef, 0xdb11cc97, 0x1af11548,
0x9ebc7613, 0xb642f86a, 0xcb77c3b9, 0x5ce45e73 }}},
{{{ 0x3eddd6de, 0x5d128786, 0x4859eab7, 0x16f9a6b4,
0xd8782345, 0x55c53916, 0xdb7b202a, 0x6b1dfa87 }}} },
{ {{{ 0x19e30528, 0x2461a8ed, 0x665cfb1c, 0xaf756bf9,
0x3a6e8673, 0x0fcafd1d, 0x45d10f48, 0x0d264435 }}},
{{{ 0x5431db67, 0x543fd4c6, 0x60932432, 0xc153a5b3,
0xd2119aa4, 0x41d5b8eb, 0x8b09b6a5, 0x36bd9ab4 }}} },
{ {{{ 0x21e06738, 0x6d39f935, 0x3765dd86, 0x4e6a7c59,
0xa4730880, 0xefc0dd80, 0x4079fe2f, 0x40617e56 }}},
{{{ 0x921439b9, 0xbc83cdff, 0x98833c09, 0xd5cccc06,
0xda13cdcb, 0xe315c425, 0x67ff5370, 0x37bc6e84 }}} },
{ {{{ 0xf643b5f5, 0x65e7f028, 0x0ffbf5a8, 0x5b0d4831,
0xf4085f62, 0x0f540498, 0x0db7bd1b, 0x6f0bb035 }}},
{{{ 0x9733742c, 0x51f65571, 0xf513409f, 0x2fc047a0,
0x355facf6, 0x07f45010, 0x3a989a9c, 0x5cd416a9 }}} },
{ {{{ 0x748f2a67, 0x0bdd7208, 0x415b7f7f, 0x0cf0b80b,
0x57aa0119, 0x44afdd5f, 0x430dc946, 0x05d68802 }}},
{{{ 0x1a60eeb2, 0x420c46e5, 0x665024f5, 0xc60a9b33,
0x48c51347, 0x37520265, 0x00a21bfb, 0x6f4be0af }}} }
};
static const ac precomputed_2E_KG[16] = {
{ {{{ 0, 0, 0, 0, 0, 0, 0, 0 }}},
{{{ 1, 0, 0, 0, 0, 0, 0, 0 }}} },
{ {{{ 0x199c4f7d, 0xec314ac0, 0xb2ebaaf9, 0x66a39c16,
0xedd4d15f, 0xab1c92b8, 0x57d9eada, 0x482a4cdf }}},
{{{ 0x6e4eb04b, 0xbd513b11, 0x25e4fd6a, 0x3f115fa5,
0x14519298, 0x0b3c5fc6, 0x81c2f7a8, 0x7391de43 }}} },
{ {{{ 0x1254fe02, 0xa57dca18, 0x6da34368, 0xa56a2a14,
0x63e7328e, 0x44c6e34f, 0xca63ab3e, 0x3f748617 }}},
{{{ 0x7dc1641e, 0x5a13dc52, 0xee4e9ca1, 0x4cbb2899,
0x1ba9acee, 0x3938a289, 0x420fc47b, 0x0fed89e6 }}} },
{ {{{ 0x49cbad08, 0x3c193f32, 0x15e80ef5, 0xdda71ef1,
0x9d128c33, 0xda44186c, 0xbf98c24f, 0x54183ede }}},
{{{ 0x93d165c1, 0x2cb483f7, 0x177f44aa, 0x51762ace,
0xb4ab035d, 0xb3fe651b, 0xa0b0d4e5, 0x426c99c3 }}} },
{ {{{ 0xef3f3fb1, 0xb3fcf4d8, 0x065060a0, 0x7052292b,
0x24240b15, 0x18795ff8, 0x9989ffcc, 0x13aea184 }}},
{{{ 0xc2b81f44, 0x1930c101, 0x10600555, 0x672d6ca4,
0x1b25e570, 0xfbddbff2, 0x8ca12b70, 0x0884949c }}} },
{ {{{ 0x00564bbf, 0x9983a033, 0xde61b72d, 0x95587d25,
0xeb17ad71, 0xb6719dfb, 0xc0bc3517, 0x46871ad0 }}},
{{{ 0xe95a6693, 0xb034fb61, 0x76eabad9, 0x5b0d8d18,
0x884785dc, 0xad295dd0, 0x74a1276a, 0x359debad }}} },
{ {{{ 0xe89fb5ca, 0x2e5a2686, 0x5656c6c5, 0xd3d200ba,
0x9c969001, 0xef4c051e, 0x02cb45f4, 0x0d4ea946 }}},
{{{ 0x76d6e506, 0xa6f8a422, 0x63209e23, 0x454c768f,
0x2b372386, 0x5c12fd04, 0xdbfee11f, 0x1aedbd3e }}} },
{ {{{ 0x00dbf569, 0x700ab50f, 0xd335b313, 0x9553643c,
0xa17dc97e, 0xeea9bddf, 0x3350a2bd, 0x0d12fe3d }}},
{{{ 0xa16a3dee, 0xe5ac35fe, 0xf81950c3, 0x4ae4664a,
0x3dbbf921, 0x75c63df4, 0x2958a5a6, 0x545b109c }}} },
{ {{{ 0x0a61b29c, 0xd7a52a98, 0x65aca9ee, 0xe21e0acb,
0x5985dcbe, 0x57a69c0f, 0xeb87a534, 0x3c0c1e7b }}},
{{{ 0x6384bd2f, 0xf0a0b50d, 0xc6939e4b, 0xff349a34,
0x6e2f1973, 0x922c4554, 0xf1347631, 0x74e826b2 }}} },
{ {{{ 0xa655803c, 0xd7eaa066, 0x38292c5c, 0x09504e76,
0x2c874953, 0xe298a02e, 0x8932b73f, 0x225093ed }}},
{{{ 0xe69c3efd, 0xf93e2b4d, 0x8a87c799, 0xa2cbd5fc,
0x85dba986, 0xdf41da94, 0xccee8edc, 0x36fe85e7 }}} },
{ {{{ 0x7d742813, 0x78df7dc5, 0x4a193e64, 0x333bcc6d,
0x6a966d2d, 0x8242aa25, 0x4cd36d32, 0x03500a94 }}},
{{{ 0x580505d7, 0xd5d110fc, 0xfa11e1e9, 0xb2f47e16,
0x06eab6b4, 0xd0030f92, 0x62c91d46, 0x2dc80d5f }}} },
{ {{{ 0x2a75e492, 0x5788b01a, 0xbae31352, 0x992acf54,
0x8159db27, 0x4591b980, 0xd3d84740, 0x36c6533c }}},
{{{ 0x103883b5, 0xc44c7c00, 0x515d0820, 0x10329423,
0x71b9dc16, 0xbd306903, 0xf88f8d32, 0x7edd5a95 }}} },
{ {{{ 0x005523d7, 0xfd63b1ac, 0xad70dd21, 0x74482e0d,
0x02b56105, 0x67c9d9d0, 0x5971b456, 0x4d318012 }}},
{{{ 0x841106df, 0xdc9a6f6d, 0xa326987f, 0x7c52ed9d,
0x00607ea0, 0x4dbeaa6f, 0x6959e688, 0x115c221d }}} },
{ {{{ 0xc80f7c16, 0xf8718464, 0xe9930634, 0x05dc8f40,
0xc2e9d5f4, 0xefa699bb, 0x021da209, 0x2469e813 }}},
{{{ 0xc602a3c4, 0x75c02845, 0x0a200f9d, 0x49d1b2ce,
0x2fb3ec8f, 0xd21b75e4, 0xd72a7545, 0x10dd726a }}} },
{ {{{ 0x63ef1a6c, 0xeda58527, 0x051705e0, 0xb3fc0e72,
0x44f1161f, 0xbda6f3ee, 0xf339efe5, 0x7680aebf }}},
{{{ 0xb1b070a7, 0xe8d3fd01, 0xdbfbaaa0, 0xc3ff7dbf,
0xa320c916, 0xd81ef6f2, 0x62a3b54d, 0x3e22a1fb }}} },
{ {{{ 0xb1fa18c8, 0xcdbb9187, 0xcb483a17, 0x8ddb5f6b,
0xea49af98, 0xc0a880b9, 0xf2dfddd0, 0x53bf600b }}},
{{{ 0x9e25b164, 0x4217404c, 0xafb74aa7, 0xfabf06ee,
0x2b9f233c, 0xb17712ae, 0xd0eb909e, 0x71f0b344 }}} }
};
static const ac precomputed_4E_KG[16] = {
{ {{{ 0, 0, 0, 0, 0, 0, 0, 0 }}},
{{{ 1, 0, 0, 0, 0, 0, 0, 0 }}} },
{ {{{ 0xe388a820, 0xbb6ec091, 0x5182278a, 0xa928b283,
0xa9a6eb83, 0x2259174d, 0x45500054, 0x184b48cb }}},
{{{ 0x26e77c33, 0xfe324dba, 0x83faf453, 0x6679a5e3,
0x2380ef73, 0xdd60c268, 0x03dc33a9, 0x3ee0e07a }}} },
{ {{{ 0xce974493, 0x403aff28, 0x9bf6f5c4, 0x84076bf4,
0xecd898fb, 0xec57038c, 0xb663ed49, 0x2898ffaa }}},
{{{ 0xf335163d, 0xf4b3bc46, 0xfa4fb6c6, 0xe613a0f4,
0xb9934557, 0xe759d6bc, 0xab6c9477, 0x094f3b96 }}} },
{ {{{ 0x6afffe9e, 0x168bb5a0, 0xee748c29, 0x950f7ad7,
0xda17203d, 0xa4850a2b, 0x77289e0f, 0x0062f7a7 }}},
{{{ 0x4b3829fa, 0x6265d4e9, 0xbdfcd386, 0x4f155ada,
0x475795f6, 0x9f38bda4, 0xdece4a4c, 0x560ed4b3 }}} },
{ {{{ 0x141e648a, 0xdad4570a, 0x019b965c, 0x8bbf674c,
0xdb08fe30, 0xd7a8d50d, 0xa2851109, 0x7efb45d3 }}},
{{{ 0xd0c28cda, 0x52e818ac, 0xa321d436, 0x792257dd,
0x9d71f8b7, 0x867091c6, 0x11a1bf56, 0x0fe1198b }}} },
{ {{{ 0x06137ab1, 0x4e848339, 0x3e6674cc, 0x5673e864,
0x0140502b, 0xad882043, 0x6ea1e46a, 0x34b5c0cb }}},
{{{ 0x1d70aa7c, 0x29786814, 0x8cdbb8aa, 0x840ae3f9,
0xbd4801fb, 0x78b4d622, 0xcf18ae9a, 0x6cf4e146 }}} },
{ {{{ 0x36297168, 0x95c270ad, 0x942e7812, 0x2303ce80,
0x0205cf0e, 0x71908cc2, 0x32bcd754, 0x0cc15edd }}},
{{{ 0x2c7ded86, 0x1db94364, 0xf141b22c, 0xc694e39b,
0x5e5a9312, 0xf22f64ef, 0x3c5e6155, 0x649b8859 }}} },
{ {{{ 0xb6417945, 0x0d5611c6, 0xac306c97, 0x9643fdbf,
0x0df500ff, 0xe81faaa4, 0x6f50e615, 0x0792c79b }}},
{{{ 0xd2af8c8d, 0xb45bbc49, 0x84f51bfe, 0x16c615ab,
0xc1d02d32, 0xdc57c526, 0x3c8aaa55, 0x5fb9a9a6 }}} },
{ {{{ 0xdee40b98, 0x82faa8db, 0x6d520674, 0xff8a5208,
0x446ac562, 0x1f8c510f, 0x2cc6b66e, 0x4676d381 }}},
{{{ 0x2e7429f4, 0x8f1aa780, 0x8ed6bdf6, 0x2a95c1bf,
0x457fa0eb, 0x051450a0, 0x744c57b1, 0x7d89e2b7 }}} },
{ {{{ 0x3f95ea15, 0xb6bdacd2, 0x2f1a5d69, 0xc9a9d1b1,
0xf4d22d72, 0xd4c2f1a9, 0x4dc516b5, 0x73ecfdf1 }}},
{{{ 0x05391e08, 0xa1ce93cd, 0x7b8aac17, 0x98f1e99e,
0xa098cbb3, 0x9ba84f2e, 0xf9bdd37a, 0x1425aa8b }}} },
{ {{{ 0x966abfc0, 0x8a385bf4, 0xf081a640, 0x55e5e8bc,
0xee26f5ff, 0x835dff85, 0xe509e1ea, 0x4927e622 }}},
{{{ 0x352334b0, 0x164c8dbc, 0xa3fea31f, 0xcac1ad63,
0x682fd457, 0x9b87a676, 0x1a53145f, 0x75f382ff }}} },
{ {{{ 0xc3efcb46, 0x16b944f5, 0x68cb184c, 0x1fb55714,
0x9ccf2dc8, 0xf1c2b116, 0x808283d8, 0x7417e00f }}},
{{{ 0x930199ba, 0x1ea67a22, 0x718990d8, 0x9fbaf765,
0x8f3d5d57, 0x231fc664, 0xe5853194, 0x38141a19 }}} },
{ {{{ 0x2f81290d, 0xb9f00390, 0x04a9ca6c, 0x44877827,
0xe1dbdd65, 0x65d7f9b9, 0xf7c6698a, 0x7133424c }}},
{{{ 0xa7cd250f, 0x604cfb3c, 0x5acc18f3, 0x460c3c4b,
0xb518e3eb, 0xa53e50e0, 0x98a40196, 0x2b4b9267 }}} },
{ {{{ 0xc5dbd06c, 0x591b0672, 0xaa1eeb65, 0x10d43dca,
0xcd2517af, 0x420cdef8, 0x0b695a8a, 0x513a307e }}},
{{{ 0x66503215, 0xee9d6a7b, 0x088fd9a4, 0xdea58720,
0x973afe12, 0x8f3cbbea, 0x872f2538, 0x005c2350 }}} },
{ {{{ 0x35af3291, 0xe5024b70, 0x4f5e669a, 0x1d3eec2d,
0x6e79d539, 0xc1f6d766, 0x795b5248, 0x34ec043f }}},
{{{ 0x400960b6, 0xb2763511, 0x29e57df0, 0xff7a3d84,
0x1666c1f1, 0xaeac7792, 0x66084bc0, 0x72426e97 }}} },
{ {{{ 0x44f826ca, 0x5b1c3199, 0x790aa408, 0x68b00b73,
0x69e9b92b, 0xaf0984b4, 0x3ffe9093, 0x5fe6736f }}},
{{{ 0xffd49312, 0xd67f2889, 0x5cb9ed21, 0x3520d747,
0x3c65a606, 0x94f893b1, 0x2d65496f, 0x2fee5e8c }}} }
};
/**
* @brief X = k * G
*
* @param K scalar k
*
* Return -1 on error.
* Return 0 on success.
*/
static void
compute_kG_25519 (ac *X, const bn256 *K)
{
ptc Q[1];
int i;
/* identity element */
memset (Q, 0, sizeof (ptc));
Q->y->word[0] = 1;
Q->z->word[0] = 1;
for (i = 20; i >= 0; i--)
{
int k0, k1, k2;
k0 = ((K->word[0] >> i) & 1)
| (i < 1 ? ((K->word[1] >> 30) & 2)
: (((K->word[2] >> (i-1)) & 1) << 1))
| (i < 2 ? ((K->word[3] >> (i+28)) & 4)
: (((K->word[4] >> (i-2)) & 1) << 2))
| (i < 3 ? ((K->word[5] >> (i+26)) & 8)
: (((K->word[6] >> (i-3)) & 1) << 3));
k1 = (i < 11 ? ((K->word[0] >> (i+21)) & 1)
: ((K->word[1] >> (i-11)) & 1))
| (i < 12 ? ((K->word[2] >> (i+19)) & 2)
: (((K->word[3] >> (i-12)) & 1) << 1))
| (i < 13 ? ((K->word[4] >> (i+17)) & 4)
: (((K->word[5] >> (i-13)) & 1) << 2))
| (i < 14 ? ((K->word[6] >> (i+15)) & 8)
: (((K->word[7] >> (i-14)) & 1) << 3));
k2 = ((K->word[1] >> (i+10)) & 1)
| ((K->word[3] >> (i+8)) & 2)
| ((K->word[5] >> (i+6)) & 4)
| ((K->word[7] >> (i+4)) & 8);
point_double (Q, Q);
point_add (Q, Q, &precomputed_KG[k0]);
point_add (Q, Q, &precomputed_2E_KG[k1]);
point_add (Q, Q, &precomputed_4E_KG[k2]);
}
point_ptc_to_ac (X, Q);
}
#define BN416_WORDS 13
#define BN128_WORDS 4
/* M: The order of the generator G. */
static const bn256 M[1] = {
{{ 0x5CF5D3ED, 0x5812631A, 0xA2F79CD6, 0x14DEF9DE,
0x00000000, 0x00000000, 0x00000000, 0x10000000 }}
};
#define C ((const uint32_t *)M)
static void
bnX_mul_C (uint32_t *r, const uint32_t *q, int q_size)
{
int i, j, k;
int i_beg, i_end;
uint32_t r0, r1, r2;
r0 = r1 = r2 = 0;
for (k = 0; k <= q_size + BN128_WORDS - 2; k++)
{
if (q_size < BN128_WORDS)
if (k < q_size)
{
i_beg = 0;
i_end = k;
}
else
{
i_beg = k - q_size + 1;
i_end = k;
if (i_end > BN128_WORDS - 1)
i_end = BN128_WORDS - 1;
}
else
if (k < BN128_WORDS)
{
i_beg = 0;
i_end = k;
}
else
{
i_beg = k - BN128_WORDS + 1;
i_end = k;
if (i_end > q_size - 1)
i_end = q_size - 1;
}
for (i = i_beg; i <= i_end; i++)
{
uint64_t uv;
uint32_t u, v;
uint32_t carry;
j = k - i;
if (q_size < BN128_WORDS)
uv = ((uint64_t )q[j])*((uint64_t )C[i]);
else
uv = ((uint64_t )q[i])*((uint64_t )C[j]);
v = uv;
u = (uv >> 32);
r0 += v;
carry = (r0 < v);
r1 += carry;
carry = (r1 < carry);
r1 += u;
carry += (r1 < u);
r2 += carry;
}
r[k] = r0;
r0 = r1;
r1 = r2;
r2 = 0;
}
r[k] = r0;
}
/**
* @brief R = A mod M (using M=2^252+C) (Barret reduction)
*
* See HAC 14.47.
*/
static void
mod_reduce_M (bn256 *R, const bn512 *A)
{
uint32_t q[BN256_WORDS+1];
uint32_t tmp[BN416_WORDS];
bn256 r[1];
uint32_t carry, next_carry;
int i;
#define borrow carry
q[8] = A->word[15]>>28;
carry = A->word[15] & 0x0fffffff;
for (i = BN256_WORDS - 1; i >= 0; i--)
{
next_carry = A->word[i+7] & 0x0fffffff;
q[i] = (A->word[i+7] >> 28) | (carry << 4);
carry = next_carry;
}
memcpy (R, A, sizeof (bn256));
R->word[7] &= 0x0fffffff;
/* Q_size: 9 */
bnX_mul_C (tmp, q, 9); /* TMP = Q*C */
/* Q = tmp / 2^252 */
carry = tmp[12] & 0x0fffffff;
for (i = 4; i >= 0; i--)
{
next_carry = tmp[i+7] & 0x0fffffff;
q[i] = (tmp[i+7] >> 28) | (carry << 4);
carry = next_carry;
}
/* R' = tmp % 2^252 */
memcpy (r, tmp, sizeof (bn256));
r->word[7] &= 0x0fffffff;
/* R -= R' */
borrow = bn256_sub (R, R, r);
if (borrow)
bn256_add (R, R, M);
else
bn256_add ((bn256 *)tmp, R, M);
/* Q_size: 5 */
bnX_mul_C (tmp, q, 5); /* TMP = Q*C */
carry = tmp[8] & 0x0fffffff;
q[0] = (tmp[7] >> 28) | (carry << 4);
/* R' = tmp % 2^252 */
memcpy (r, tmp, sizeof (bn256));
r->word[7] &= 0x0fffffff;
/* R += R' */
bn256_add (R, R, r);
borrow = bn256_sub (R, R, M);
if (borrow)
bn256_add (R, R, M);
else
bn256_add ((bn256 *)tmp, R, M);
/* Q_size: 1 */
bnX_mul_C (tmp, q, 1); /* TMP = Q*C */
/* R' = tmp % 2^252 */
memset (((uint8_t *)r)+(sizeof (uint32_t)*5), 0, sizeof (uint32_t)*3);
memcpy (r, tmp, sizeof (uint32_t)*5);
/* R -= R' */
borrow = bn256_sub (R, R, r);
if (borrow)
bn256_add (R, R, M);
else
bn256_add ((bn256 *)tmp, R, M);
#undef borrow
}
void
eddsa_sign_25519 (const uint8_t *input, size_t ilen, uint32_t *out,
const bn256 *a, const uint8_t *seed, const bn256 *pk)
{
bn256 *r, *s;
sha512_context ctx;
uint8_t hash[64];
bn256 tmp[1];
ac R[1];
uint32_t carry, borrow;
r = (bn256 *)out;
s = (bn256 *)(out+(32/4));
sha512_start (&ctx);
sha512_update (&ctx, seed, sizeof (bn256)); /* It's upper half of the hash */
sha512_update (&ctx, input, ilen);
sha512_finish (&ctx, hash);
mod_reduce_M (r, (bn512 *)hash);
compute_kG_25519 (R, r);
/* EdDSA encoding. */
memcpy (tmp, R->y, sizeof (bn256));
tmp->word[7] ^= mod25519_is_neg (R->x) * 0x80000000;
sha512_start (&ctx);
sha512_update (&ctx, (uint8_t *)tmp, sizeof (bn256));
sha512_update (&ctx, (uint8_t *)pk, sizeof (bn256));
sha512_update (&ctx, input, ilen);
sha512_finish (&ctx, (uint8_t *)hash);
mod_reduce_M (s, (bn512 *)hash);
bn256_mul ((bn512 *)hash, s, a);
mod_reduce_M (s, (bn512 *)hash);
carry = bn256_add (s, s, r);
borrow = bn256_sub (s, s, M);
memcpy (r, tmp, sizeof (bn256));
if ((borrow && !carry))
bn256_add (s, s, M);
else
bn256_add (tmp, s, M);
}
void
eddsa_public_key_25519 (bn256 *pk, const bn256 *a)
{
ac R[1];
ptc X[1];
bn256 a0[1];
bn256_shift (a0, a, -3);
compute_kG_25519 (R, a0);
memcpy (X, R, sizeof (ac));
memset (X->z, 0, sizeof (bn256));
X->z->word[0] = 1;
point_double (X, X);
point_double (X, X);
point_double (X, X);
point_ptc_to_ac (R, X);
/* EdDSA encoding. */
memcpy (pk, R->y, sizeof (bn256));
pk->word[7] ^= mod25519_is_neg (R->x) * 0x80000000;
}
uint8_t *
eddsa_compute_public_25519 (const uint8_t *kd)
{
uint8_t *p0;
const bn256 *a = (const bn256 *)kd;
p0 = (uint8_t *)malloc (sizeof (bn256));
if (p0 == NULL)
return NULL;
eddsa_public_key_25519 ((bn256 *)p0, a);
return p0;
}
#if 0
/**
* check if P is on the curve.
*
* Return -1 on error.
* Return 0 on success.
*/
static int
point_is_on_the_curve (const ac *P)
{
bn256 s[1], t[1];
/* Twisted Edwards curve: a*x^2 + y^2 = 1 + d*x^2*y^2 */
}
int
compute_kP_25519 (ac *X, const bn256 *K, const ac *P);
#endif
#ifdef PRINT_OUT_TABLE
static const ptc G[1] = {{
{{{ 0x8f25d51a, 0xc9562d60, 0x9525a7b2, 0x692cc760,
0xfdd6dc5c, 0xc0a4e231, 0xcd6e53fe, 0x216936d3 }}},
{{{ 0x66666658, 0x66666666, 0x66666666, 0x66666666,
0x66666666, 0x66666666, 0x66666666, 0x66666666 }}},
{{{ 1, 0, 0, 0, 0, 0, 0, 0 }}},
}};
#include <stdio.h>
#ifdef TESTING_EDDSA
static void
print_bn256 (const bn256 *X)
{
int i;
for (i = 7; i >= 0; i--)
printf ("%08x", X->word[i]);
puts ("");
}
#endif
#if 0
static void
print_point (const ac *X)
{
int i;
#ifdef PRINT_OUT_TABLE_AS_C
fputs (" { {{{ ", stdout);
for (i = 0; i < 4; i++)
printf ("0x%08x, ", X->x->word[i]);
fputs ("\n ", stdout);
for (; i < 7; i++)
printf ("0x%08x, ", X->x->word[i]);
printf ("0x%08x }}},\n", X->x->word[i]);
fputs (" {{{ ", stdout);
for (i = 0; i < 4; i++)
printf ("0x%08x, ", X->y->word[i]);
fputs ("\n ", stdout);
for (; i < 7; i++)
printf ("0x%08x, ", X->y->word[i]);
printf ("0x%08x }}} },\n", X->y->word[i]);
#else
puts ("--");
for (i = 7; i >= 0; i--)
printf ("%08x", X->x->word[i]);
puts ("");
for (i = 7; i >= 0; i--)
printf ("%08x", X->y->word[i]);
puts ("");
puts ("--");
#endif
}
static void
print_point_ptc (const ptc *X)
{
int i;
puts ("---");
for (i = 7; i >= 0; i--)
printf ("%08x", X->x->word[i]);
puts ("");
for (i = 7; i >= 0; i--)
printf ("%08x", X->y->word[i]);
puts ("");
for (i = 7; i >= 0; i--)
printf ("%08x", X->z->word[i]);
puts ("");
puts ("---");
}
#endif
#ifndef TESTING_EDDSA
static void power_2 (ac *A, ptc *a, int N)
{
int i;
for (i = 0; i < N; i++)
ed_double_25638 (a, a);
ptc_to_ac_25519 (A, a);
}
static void print_table (ac *a0001, ac *a0010, ac *a0100, ac *a1000)
{
int i;
ptc a[1];
ac x[1];
for (i = 1; i < 16; i++)
{
/* A := Identity Element */
memset (a, 0, sizeof (ptc));
a->y->word[0] = 1;
a->z->word[0] = 1;
if ((i & 1))
ed_add_25638 (a, a, a0001);
if ((i & 2))
ed_add_25638 (a, a, a0010);
if ((i & 4))
ed_add_25638 (a, a, a0100);
if ((i & 8))
ed_add_25638 (a, a, a1000);
ptc_to_ac_25519 (x, a);
print_point (x);
}
fputs ("\n", stdout);
}
static void compute_and_print_table (ac *a0001, ac *a0010, ac *a0100, ac *a1000)
{
ptc a[1];
memcpy (a, a0001, sizeof (ac));
memset (a->z, 0, sizeof (bn256));
a->z->word[0] = 1;
power_2 (a0010, a, 63);
power_2 (a0100, a, 63);
power_2 (a1000, a, 63);
print_table (a0001, a0010, a0100, a1000);
}
#endif
int
main (int argc, char *argv[])
{
#ifdef TESTING_EDDSA
uint8_t hash[64];
bn256 a[1];
uint8_t r_s[64];
bn256 pk[1];
bn256 *r, *s;
const bn256 sk[1] = {
{{ 0x9db1619d, 0x605afdef, 0xf44a84ba, 0xc42cec92,
0x69c54944, 0x1969327b, 0x03ac3b70, 0x607fae1c }} };
const bn256 r_expected[1] = {
{{ 0x004356e5, 0x72ac60c3, 0xcce28690, 0x8a826e80,
0x1e7f8784, 0x74d9e5b8, 0x65e073d8, 0x55014922 }} };
const bn256 s_expected[1] = {
{{ 0x1582b85f, 0xac3ba390, 0x70391ec6, 0x6bb4f91c,
0xf0f55bd2, 0x24be5b59, 0x43415165, 0x0b107a8e }} };
r = (bn256 *)r_s;
s = (bn256 *)(r_s+32);
sha512 ((uint8_t *)sk, sizeof (bn256), hash);
hash[0] &= 248;
hash[31] &= 127;
hash[31] |= 64;
memcpy (a, hash, sizeof (bn256));
eddsa_public_key_25519 (pk, a);
eddsa_sign_25519 ((const uint8_t *)"", 0, r_s, a, hash+32, pk);
if (memcmp (r, r_expected, sizeof (bn256)) != 0
|| memcmp (s, s_expected, sizeof (bn256)) != 0)
{
print_bn256 (r);
print_bn256 (s);
return 1;
}
#else
ac a0001[1], a0010[1], a0100[1], a1000[1];
ptc a[1];
memcpy (a, G, sizeof (ptc));
ptc_to_ac_25519 (a0001, a);
compute_and_print_table (a0001, a0010, a0100, a1000);
memcpy (a, a0001, sizeof (ac));
memset (a->z, 0, sizeof (bn256));
a->z->word[0] = 1;
power_2 (a0001, a, 21);
compute_and_print_table (a0001, a0010, a0100, a1000);
memcpy (a, a0001, sizeof (ac));
memset (a->z, 0, sizeof (bn256));
a->z->word[0] = 1;
power_2 (a0001, a, 21);
compute_and_print_table (a0001, a0010, a0100, a1000);
#endif
return 0;
}
#endif

179
src/ecc-mont.c Normal file
View File

@@ -0,0 +1,179 @@
/* -*- coding: utf-8 -*-
* ecc-mont.c - Elliptic curve computation for
* the Montgomery curve: y^2 = x^3 + 486662*x^2 + x.
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "mod25638.h"
#include "mod.h"
/*
* References:
*
* [1] D. J. Bernstein. Curve25519: new Diffie-Hellman speed records.
* Proceedings of PKC 2006, to appear.
* http://cr.yp.to/papers.html#curve25519. Date: 2006.02.09.
*
* [2] D. J. Bernstein. Can we avoid tests for zero in fast
* elliptic-curve arithmetic?
* http://cr.yp.to/papers.html#curvezero. Date: 2006.07.26.
*
*/
/*
* IMPLEMENTATION NOTE
*
* (0) We assume that the processor has no cache, nor branch target
* prediction. Thus, we don't avoid indexing by secret value.
* We don't avoid conditional jump if both cases have same timing,
* either.
*
* (1) We use Radix-32 field arithmetic. It's a representation like
* 2^256-38, but it's more redundant. For example, "1" can be
* represented in three ways in 256-bit: 1, 2^255-18, and
* 2^256-37.
*
* (2) We use Montgomery double-and-add.
*
*/
/*
*
* 121665 = 0x1db41
* 1 1101 1011 0100 0001
*/
static void
mod25638_mul_121665 (bn256 *x, const bn256 *a)
{
uint32_t c;
bn256 m[1];
c = 0;
memcpy (x, a, sizeof (bn256)); /* X = A */
c += bn256_shift (m, a, 6); c += bn256_add (x, x, m); /* X += A << 6 */
c += bn256_shift (m, a, 8); c += bn256_add (x, x, m); /* X += A << 8 */
c += bn256_shift (m, a, 9); c += bn256_add (x, x, m); /* X += A << 9 */
c += bn256_shift (m, a, 11); c += bn256_add (x, x, m); /* X += A << 11 */
c += bn256_shift (m, a, 12); c += bn256_add (x, x, m); /* X += A << 12 */
c += bn256_shift (m, a, 14); c += bn256_add (x, x, m); /* X += A << 14 */
c += bn256_shift (m, a, 15); c += bn256_add (x, x, m); /* X += A << 15 */
c += bn256_shift (m, a, 16); c += bn256_add (x, x, m); /* X += A << 16 */
c *= 38;
c = bn256_add_uint (x, x, c);
x->word[0] += c * 38;
}
typedef struct
{
bn256 x[1];
bn256 z[1];
} pt;
/**
* @brief Process Montgomery double-and-add
*
* With Q0, Q1, DIF (= Q0 - Q1), compute PRD = 2Q0, SUM = Q0 + Q1
* Q0 and Q1 are clobbered.
*
*/
static void
mont_d_and_a (pt *prd, pt *sum, pt *q0, pt *q1, const bn256 *dif_x)
{
mod25638_add (sum->x, q1->x, q1->z);
mod25638_sub (q1->z, q1->x, q1->z);
mod25638_add (prd->x, q0->x, q0->z);
mod25638_sub (q0->z, q0->x, q0->z);
mod25638_mul (q1->x, q0->z, sum->x);
mod25638_mul (q1->z, prd->x, q1->z);
mod25638_sqr (q0->x, prd->x);
mod25638_sqr (q0->z, q0->z);
mod25638_add (sum->x, q1->x, q1->z);
mod25638_sub (q1->z, q1->x, q1->z);
mod25638_mul (prd->x, q0->x, q0->z);
mod25638_sub (q0->z, q0->x, q0->z);
mod25638_sqr (sum->x, sum->x);
mod25638_sqr (sum->z, q1->z);
mod25638_mul_121665 (prd->z, q0->z);
mod25638_mul (sum->z, sum->z, dif_x);
mod25638_add (prd->z, q0->x, prd->z);
mod25638_mul (prd->z, prd->z, q0->z);
}
/**
* @brief RES = x-coordinate of [n]Q
*
* @param N Scalar N (three least significant bits are 000)
* @param Q_X x-coordinate of Q
*
*/
void
compute_nQ (bn256 *res, const bn256 *n, const bn256 *q_x)
{
int i, j;
pt p0[1], p1[1], p0_[1], p1_[1];
/* P0 = O = (1:0) */
memset (p0->x, 0, sizeof (bn256));
p0->x->word[0] = 1;
memset (p0->z, 0, sizeof (bn256));
/* P1 = (X:1) */
memcpy (p1->x, q_x, sizeof (bn256));
memset (p1->z, 0, sizeof (bn256));
p1->z->word[0] = 1;
for (i = 0; i < 8; i++)
{
uint32_t u = n->word[7-i];
for (j = 0; j < 16; j++)
{
pt *q0, *q1;
pt *sum_n, *prd_n;
if ((u & 0x80000000))
q0 = p1, q1 = p0, sum_n = p0_, prd_n = p1_;
else
q0 = p0, q1 = p1, sum_n = p1_, prd_n = p0_;
mont_d_and_a (prd_n, sum_n, q0, q1, q_x);
if ((u & 0x40000000))
q0 = p1_, q1 = p0_, sum_n = p0, prd_n = p1;
else
q0 = p0_, q1 = p1_, sum_n = p1, prd_n = p0;
mont_d_and_a (prd_n, sum_n, q0, q1, q_x);
u <<= 2;
}
}
/* We know the LSB of N is always 0. Thus, result is always in P0. */
mod_inv (res, p0->z, p25519);
mod25638_mul (res, res, p0->x);
mod25519_reduce (res);
}

368
src/ecc.c Normal file
View File

@@ -0,0 +1,368 @@
/* -*- coding: utf-8 -*-
* ecc.c - Elliptic curve over GF(prime)
*
* Copyright (C) 2011, 2013, 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* References:
*
* [1] Suite B Implementer's Guide to FIPS 186-3 (ECDSA), February 3, 2010.
*
* [2] Michael Brown, Darrel Hankerson, Julio López, and Alfred Menezes,
* Software Implementation of the NIST Elliptic Curves Over Prime Fields,
* Proceedings of the 2001 Conference on Topics in Cryptology: The
* Cryptographer's Track at RSA
* Pages 250-265, Springer-Verlag London, UK, 2001
* ISBN:3-540-41898-9
*
* [3] Mustapha Hedabou, Pierre Pinel, Lucien Bénéteau,
* A comb method to render ECC resistant against Side Channel Attacks,
* 2004
*/
#include "field-group-select.h"
/*
* Coefficients
*/
/*
* static const bn256 *coefficient_a;
* static const bn256 *coefficient_b;
*/
/*
* N: order of G
*/
/*
* static const bn256 N[1];
*/
/*
* MU = 2^512 / N
* MU = ( (1 << 256) | MU_lower )
*/
/*
* static const bn256 MU_lower[1];
*/
/*
* w = 4
* m = 256
* d = 64
* e = 32
*/
/*
* static const ac precomputed_KG[15];
* static const ac precomputed_2E_KG[15];
*/
#if TEST
/*
* Generator of Elliptic curve over GF(p256)
*/
const ac *G = &precomputed_KG[0];
#endif
static int
get_vk (const bn256 *K, int i)
{
uint32_t w0, w1, w2, w3;
if (i < 32)
{
w3 = K->word[6]; w2 = K->word[4]; w1 = K->word[2]; w0 = K->word[0];
}
else
{
w3 = K->word[7]; w2 = K->word[5]; w1 = K->word[3]; w0 = K->word[1];
i -= 32;
}
w3 >>= i; w2 >>= i; w1 >>= i; w0 >>= i;
return ((w3 & 1) << 3) | ((w2 & 1) << 2) | ((w1 & 1) << 1) | (w0 & 1);
}
/**
* @brief X = k * G
*
* @param K scalar k
*
* Return -1 on error.
* Return 0 on success.
*/
int
FUNC(compute_kG) (ac *X, const bn256 *K)
{
uint8_t index[64]; /* Lower 4-bit for index absolute value, msb is
for sign (encoded as: 0 means 1, 1 means -1). */
bn256 K_dash[1];
jpc Q[1], tmp[1], *dst;
int i;
int vk;
uint32_t k_is_even = bn256_is_even (K);
bn256_sub_uint (K_dash, K, k_is_even);
/* It keeps the condition: 1 <= K' <= N - 2, and K' is odd. */
/* Fill index. */
vk = get_vk (K_dash, 0);
for (i = 1; i < 64; i++)
{
int vk_next, is_zero;
vk_next = get_vk (K_dash, i);
is_zero = (vk_next == 0);
index[i-1] = (vk - 1) | (is_zero << 7);
vk = (is_zero ? vk : vk_next);
}
index[63] = vk - 1;
memset (Q->z, 0, sizeof (bn256)); /* infinity */
for (i = 31; i >= 0; i--)
{
FUNC(jpc_double) (Q, Q);
FUNC(jpc_add_ac_signed) (Q, Q, &precomputed_2E_KG[index[i+32]&0x0f],
index[i+32] >> 7);
FUNC(jpc_add_ac_signed) (Q, Q, &precomputed_KG[index[i]&0x0f],
index[i] >> 7);
}
dst = k_is_even ? Q : tmp;
FUNC(jpc_add_ac) (dst, Q, &precomputed_KG[0]);
return FUNC(jpc_to_ac) (X, Q);
}
/**
* check if P is on the curve.
*
* Return -1 on error.
* Return 0 on success.
*/
static int
point_is_on_the_curve (const ac *P)
{
bn256 s[1], t[1];
/* Elliptic curve: y^2 = x^3 + a*x + b */
MFNC(sqr) (s, P->x);
MFNC(mul) (s, s, P->x);
#ifdef COEFFICIENT_A_IS_ZERO
MFNC(mul) (t, coefficient_a, P->x);
MFNC(add) (s, s, t);
#endif
MFNC(add) (s, s, coefficient_b);
MFNC(sqr) (t, P->y);
if (bn256_cmp (s, t) == 0)
return 0;
else
return -1;
}
static int
get_vk_kP (const bn256 *K, int i)
{
uint32_t w;
uint8_t blk = i/32;
uint8_t pos = i%32;
uint8_t col = 3*(pos % 11) + (pos >= 11) + (pos >= 22);
uint8_t word_index = (blk * 3) + (pos / 11);
w = ((K->word[word_index] >> col) & 7);
if (word_index < 7 && (pos == 10 || pos == 21))
{
uint8_t mask;
uint8_t shift;
word_index++;
if (pos == 10)
{
shift = 2;
mask = 4;
}
else
{
shift = 1;
mask = 6;
}
w |= ((K->word[word_index] << shift) & mask);
}
return w;
}
/**
* @brief X = k * P
*
* @param K scalar k
* @param P P in affine coordiate
*
* Return -1 on error.
* Return 0 on success.
*
* For the curve (cofactor is 1 and n is prime), possible error cases are:
*
* P is not on the curve.
* P = G, k = n
* Something wrong in the code.
*
* Mathmatically, k=1 and P=O is another possible case, but O cannot be
* represented by affine coordinate.
*/
int
FUNC(compute_kP) (ac *X, const bn256 *K, const ac *P)
{
uint8_t index[86]; /* Lower 2-bit for index absolute value, msb is
for sign (encoded as: 0 means 1, 1 means -1). */
bn256 K_dash[1];
uint32_t k_is_even = bn256_is_even (K);
jpc Q[1], tmp[1], *dst;
int i;
int vk;
ac P3[1], P5[1], P7[1];
const ac *p_Pi[4];
if (point_is_on_the_curve (P) < 0)
return -1;
if (bn256_sub (K_dash, K, N) == 0) /* >= N, it's too big. */
return -1;
bn256_sub_uint (K_dash, K, k_is_even);
/* It keeps the condition: 1 <= K' <= N - 2, and K' is odd. */
p_Pi[0] = P;
p_Pi[1] = P3;
p_Pi[2] = P5;
p_Pi[3] = P7;
{
jpc Q1[1];
memcpy (Q->x, P->x, sizeof (bn256));
memcpy (Q->y, P->y, sizeof (bn256));
memset (Q->z, 0, sizeof (bn256));
Q->z->word[0] = 1;
FUNC(jpc_double) (Q, Q);
FUNC(jpc_add_ac) (Q1, Q, P);
if (FUNC(jpc_to_ac) (P3, Q1) < 0) /* Never occurs, except coding errors. */
return -1;
FUNC(jpc_double) (Q, Q);
FUNC(jpc_add_ac) (Q1, Q, P);
if (FUNC(jpc_to_ac) (P5, Q1) < 0) /* Never occurs, except coding errors. */
return -1;
memcpy (Q->x, P3->x, sizeof (bn256));
memcpy (Q->y, P3->y, sizeof (bn256));
memset (Q->z, 0, sizeof (bn256));
Q->z->word[0] = 1;
FUNC(jpc_double) (Q, Q);
FUNC(jpc_add_ac) (Q1, Q, P);
if (FUNC(jpc_to_ac) (P7, Q1) < 0) /* Never occurs, except coding errors. */
return -1;
}
/* Fill index. */
vk = get_vk_kP (K_dash, 0);
for (i = 1; i < 86; i++)
{
int vk_next, is_even;
vk_next = get_vk_kP (K_dash, i);
is_even = ((vk_next & 1) == 0);
index[i-1] = (is_even << 7) | ((is_even?7-vk:vk-1) >> 1);
vk = vk_next + is_even;
}
index[85] = ((vk - 1) >> 1);
memset (Q->z, 0, sizeof (bn256)); /* infinity */
for (i = 85; i >= 0; i--)
{
FUNC(jpc_double) (Q, Q);
FUNC(jpc_double) (Q, Q);
FUNC(jpc_double) (Q, Q);
FUNC(jpc_add_ac_signed) (Q, Q, p_Pi[index[i]&0x03], index[i] >> 7);
}
dst = k_is_even ? Q : tmp;
FUNC(jpc_add_ac) (dst, Q, &precomputed_KG[0]);
return FUNC(jpc_to_ac) (X, Q);
}
/**
* @brief Compute signature (r,s) of hash string z with secret key d
*/
void
FUNC(ecdsa) (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d)
{
bn256 k[1];
ac KG[1];
bn512 tmp[1];
bn256 k_inv[1];
uint32_t carry;
#define borrow carry
#define tmp_k k_inv
do
{
do
{
bn256_random (k);
if (bn256_add_uint (k, k, 1))
continue;
if (bn256_sub (tmp_k, k, N) == 0) /* >= N, it's too big. */
continue;
/* 1 <= k <= N - 1 */
FUNC(compute_kG) (KG, k);
borrow = bn256_sub (r, KG->x, N);
if (borrow)
memcpy (r, KG->x, sizeof (bn256));
else
memcpy (KG->x, r, sizeof (bn256));
}
while (bn256_is_zero (r));
mod_inv (k_inv, k, N);
bn256_mul (tmp, r, d);
mod_reduce (s, tmp, N, MU_lower);
carry = bn256_add (s, s, z);
if (carry)
bn256_sub (s, s, N);
else
bn256_sub ((bn256 *)tmp, s, N);
bn256_mul (tmp, s, k_inv);
mod_reduce (s, tmp, N, MU_lower);
}
while (bn256_is_zero (s));
#undef tmp_k
#undef borrow
}

7
src/field-group-select.h Normal file
View File

@@ -0,0 +1,7 @@
#define CONCAT0(a,b) a##b
#define CONCAT1(a,b) CONCAT0(a,b)
#define CONCAT2(a,b,c) CONCAT1(a,b##c)
#define CONCAT3(a,b,c) CONCAT2(a,b,c)
#define FUNC(func) CONCAT1(func##_,FIELD)
#define MFNC(func) CONCAT3(mod,FIELD,_##func)

View File

@@ -63,7 +63,6 @@
#define FLASH_DATA_POOL_HEADER_SIZE 2
#define FLASH_DATA_POOL_SIZE (FLASH_PAGE_SIZE*2)
#define FLASH_KEYSTORE_SIZE (FLASH_PAGE_SIZE*3)
static const uint8_t *data_pool;
extern uint8_t _keystore_pool;
@@ -78,12 +77,33 @@ const uint8_t const flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
/* Linker set this symbol */
extern uint8_t _data_pool;
static int key_available_at (uint8_t *k)
{
int i;
for (i = 0; i < KEY_SIZE; i++)
if (k[i])
break;
if (i == KEY_SIZE) /* It's ZERO. Released key. */
return 0;
for (i = 0; i < KEY_SIZE; i++)
if (k[i] != 0xff)
break;
if (i == KEY_SIZE) /* It's FULL. Unused key. */
return 0;
return 1;
}
const uint8_t *
flash_init (void)
{
uint16_t gen0, gen1;
uint16_t *gen0_p = (uint16_t *)&_data_pool;
uint16_t *gen1_p = (uint16_t *)(&_data_pool + FLASH_PAGE_SIZE);
uint8_t *p;
int i;
/* Check data pool generation and choose the page */
gen0 = *gen0_p;
@@ -97,6 +117,23 @@ flash_init (void)
else
data_pool = &_data_pool;
/* For each key, find its address. */
p = &_keystore_pool;
for (i = 0; i < 3; i++)
{
uint8_t *k;
kd[i].key_addr = NULL;
for (k = p; k < p + FLASH_PAGE_SIZE; k += KEY_SIZE)
if (key_available_at (k))
{
kd[i].key_addr = k;
break;
}
p += FLASH_PAGE_SIZE;
}
return data_pool + FLASH_DATA_POOL_HEADER_SIZE;
}
@@ -270,14 +307,16 @@ flash_do_release (const uint8_t *do_data)
uint8_t *
flash_key_alloc (void)
flash_key_alloc (enum kind_of_key kk)
{
uint8_t *k;
uint8_t *k0, *k;
int i;
/* Seek empty keystore. */
k = &_keystore_pool;
while (k < &_keystore_pool + FLASH_KEYSTORE_SIZE)
/* There is a page for each KK. */
k0 = &_keystore_pool + (FLASH_PAGE_SIZE * kk);
/* Seek free space in the page. */
for (k = k0; k < k0 + FLASH_PAGE_SIZE; k += KEY_SIZE)
{
const uint32_t *p = (const uint32_t *)k;
@@ -287,11 +326,10 @@ flash_key_alloc (void)
if (i == KEY_SIZE/4) /* Yes, it's empty. */
return k;
k += KEY_SIZE;
}
/* Should not happen as we have enough space, but just in case. */
/* Should not happen as we have enough free space all time, but just
in case. */
return NULL;
}

View File

@@ -120,7 +120,7 @@ enum kind_of_key {
extern const uint8_t *flash_init (void);
extern void flash_do_release (const uint8_t *);
extern const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len);
extern uint8_t *flash_key_alloc (void);
extern uint8_t *flash_key_alloc (enum kind_of_key);
extern void flash_key_release (uint8_t *);
extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
const uint8_t *pubkey, int pubkey_len);
@@ -148,18 +148,20 @@ extern uint8_t random_bits_start;
#define INITIAL_VECTOR_SIZE 16
#define DATA_ENCRYPTION_KEY_SIZE 16
/* encrypted data content */
struct key_data {
uint8_t data[KEY_CONTENT_LEN]; /* p and q */
uint8_t *key_addr; /* Pointer to encrypted data, and public */
uint8_t data[KEY_CONTENT_LEN]; /* decrypted data content */
};
struct key_data_internal {
uint32_t data[KEY_CONTENT_LEN/4]; /* p and q */
uint32_t data[KEY_CONTENT_LEN/4]; /*
* Secret key data.
* RSA: p and q, ECDSA: d, EdDSA: a+seed
*/
uint32_t checksum[DATA_ENCRYPTION_KEY_SIZE/4];
};
struct prvkey_data {
const uint8_t *key_addr;
/*
* IV: Initial Vector
*/
@@ -246,9 +248,19 @@ extern int rsa_verify (const uint8_t *pubkey, const uint8_t *hash,
const uint8_t *signature);
extern uint8_t *rsa_genkey (void);
extern int ecdsa_sign (const uint8_t *hash, uint8_t *output,
const struct key_data *kd);
extern uint8_t *ecdsa_compute_public (const uint8_t *key_data);
extern int ecdsa_sign_p256r1 (const uint8_t *hash, uint8_t *output,
const uint8_t *key_data);
extern uint8_t *ecdsa_compute_public_p256r1 (const uint8_t *key_data);
extern int ecdsa_sign_p256k1 (const uint8_t *hash, uint8_t *output,
const uint8_t *key_data);
extern uint8_t *ecdsa_compute_public_p256k1 (const uint8_t *key_data);
extern int eddsa_sign_25519 (const uint8_t *input, size_t ilen,
uint32_t *output,
const uint8_t *sk_a, const uint8_t *seed,
const uint8_t *pk);
extern uint8_t *eddsa_compute_public_25519 (const uint8_t *a);
extern const uint8_t *gpg_do_read_simple (uint8_t);
extern void gpg_do_write_simple (uint8_t, const uint8_t *, int);

View File

@@ -5,7 +5,7 @@ __main_stack_size__ = 0x0100; /* Exception handlers */
__process0_stack_size__ = 0x0100; /* main */
__process1_stack_size__ = 0x0140; /* ccid */
__process2_stack_size__ = 0x0180; /* rng */
__process3_stack_size__ = 0x0b00; /* gpg */
__process3_stack_size__ = 0x1600; /* gpg */
__process4_stack_size__ = 0x0100; /* intr: usb */
__process5_stack_size__ = @MSC_SIZE@; /* msc */
__process6_stack_size__ = @TIM_SIZE@; /* intr: timer */

View File

@@ -1,23 +0,0 @@
/**
* @brief Jacobian projective coordinates
*/
typedef struct
{
bn256 x[1];
bn256 y[1];
bn256 z[1];
} jpc;
/**
* @brief Affin coordinates
*/
typedef struct
{
bn256 x[1];
bn256 y[1];
} ac;
void jpc_double (jpc *X, const jpc *A);
void jpc_add_ac (jpc *X, const jpc *A, const ac *B);
void jpc_add_ac_signed (jpc *X, const jpc *A, const ac *B, int minus);
int jpc_to_ac (ac *X, const jpc *A);

14
src/jpc-ac_p256k1.h Normal file
View File

@@ -0,0 +1,14 @@
/**
* @brief Jacobian projective coordinates
*/
typedef struct
{
bn256 x[1];
bn256 y[1];
bn256 z[1];
} jpc;
void jpc_double_p256k1 (jpc *X, const jpc *A);
void jpc_add_ac_p256k1 (jpc *X, const jpc *A, const ac *B);
void jpc_add_ac_signed_p256k1 (jpc *X, const jpc *A, const ac *B, int minus);
int jpc_to_ac_p256k1 (ac *X, const jpc *A);

14
src/jpc-ac_p256r1.h Normal file
View File

@@ -0,0 +1,14 @@
/**
* @brief Jacobian projective coordinates
*/
typedef struct
{
bn256 x[1];
bn256 y[1];
bn256 z[1];
} jpc;
void jpc_double_p256r1 (jpc *X, const jpc *A);
void jpc_add_ac_p256r1 (jpc *X, const jpc *A, const ac *B);
void jpc_add_ac_signed_p256r1 (jpc *X, const jpc *A, const ac *B, int minus);
int jpc_to_ac_p256r1 (ac *X, const jpc *A);

152
src/jpc.c
View File

@@ -1,5 +1,5 @@
/*
* jpc.c -- arithmetic on Jacobian projective coordinates and Affin coordinates
* jpc.c -- arithmetic on Jacobian projective coordinates.
*
* Copyright (C) 2011, 2013 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
@@ -21,11 +21,7 @@
*
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "modp256.h"
#include "jpc-ac.h"
#include "field-group-select.h"
/**
* @brief X = 2 * A
@@ -34,36 +30,48 @@
* @param A JPC
*/
void
jpc_double (jpc *X, const jpc *A)
FUNC(jpc_double) (jpc *X, const jpc *A)
{
bn256 a[1], b[1], c[1], tmp0[1];
bn256 *d = X->x;
bn256 *d;
modp256_sqr (a, A->y);
if (bn256_is_zero (A->z)) /* A is infinite */
return;
d = X->x;
MFNC(sqr) (a, A->y);
memcpy (b, a, sizeof (bn256));
modp256_mul (a, a, A->x);
modp256_shift (a, a, 2);
MFNC(mul) (a, a, A->x);
MFNC(shift) (a, a, 2);
modp256_sqr (b, b);
modp256_shift (b, b, 3);
MFNC(sqr) (b, b);
MFNC(shift) (b, b, 3);
modp256_sqr (tmp0, A->z);
modp256_sub (c, A->x, tmp0);
modp256_add (tmp0, tmp0, A->x);
modp256_mul (tmp0, tmp0, c);
modp256_shift (c, tmp0, 1);
modp256_add (c, c, tmp0);
#if defined(COEFFICIENT_A_IS_MINUS_3)
MFNC(sqr) (tmp0, A->z);
MFNC(sub) (c, A->x, tmp0);
MFNC(add) (tmp0, tmp0, A->x);
MFNC(mul) (tmp0, tmp0, c);
MFNC(shift) (c, tmp0, 1);
MFNC(add) (c, c, tmp0);
#elif defined (COEFFICIENT_A_IS_ZERO)
MFNC(sqr) (tmp0, A->x);
MFNC(shift) (c, tmp0, 1);
MFNC(add) (c, c, tmp0);
#else
#error "not supported."
#endif
modp256_sqr (d, c);
modp256_shift (tmp0, a, 1);
modp256_sub (d, d, tmp0);
MFNC(sqr) (d, c);
MFNC(shift) (tmp0, a, 1);
MFNC(sub) (d, d, tmp0);
modp256_mul (X->z, A->y, A->z);
modp256_shift (X->z, X->z, 1);
MFNC(mul) (X->z, A->y, A->z);
MFNC(shift) (X->z, X->z, 1);
modp256_sub (tmp0, a, d);
modp256_mul (tmp0, c, tmp0);
modp256_sub (X->y, tmp0, b);
MFNC(sub) (tmp0, a, d);
MFNC(mul) (tmp0, c, tmp0);
MFNC(sub) (X->y, tmp0, b);
}
/**
@@ -75,9 +83,9 @@ jpc_double (jpc *X, const jpc *A)
* @param MINUS if 1 subtraction, addition otherwise.
*/
void
jpc_add_ac_signed (jpc *X, const jpc *A, const ac *B, int minus)
FUNC(jpc_add_ac_signed) (jpc *X, const jpc *A, const ac *B, int minus)
{
bn256 a[1], b[1], c[1], d[1];
bn256 a[1], b[1], c[1], d[1], tmp[1];
#define minus_B_y c
#define c_sqr a
#define c_cube b
@@ -88,58 +96,66 @@ jpc_add_ac_signed (jpc *X, const jpc *A, const ac *B, int minus)
#define y3_tmp c
#define y1_c_cube a
if (A->z == 0) /* A is infinite */
if (bn256_is_zero (A->z)) /* A is infinite */
{
memcpy (X->x, B->x, sizeof (bn256));
if (minus)
bn256_sub (X->y, P256, B->y);
{
memcpy (tmp, B->y, sizeof (bn256));
bn256_sub (X->y, CONST_P256, B->y);
}
else
memcpy (X->y, B->y, sizeof (bn256));
{
memcpy (X->y, B->y, sizeof (bn256));
bn256_sub (tmp, CONST_P256, B->y);
}
memset (X->z, 0, sizeof (bn256));
X->z->words[0] = 1;
X->z->word[0] = 1;
return;
}
modp256_sqr (a, A->z);
MFNC(sqr) (a, A->z);
memcpy (b, a, sizeof (bn256));
modp256_mul (a, a, B->x);
MFNC(mul) (a, a, B->x);
modp256_mul (b, b, A->z);
MFNC(mul) (b, b, A->z);
if (minus)
{
bn256_sub (minus_B_y, P256, B->y);
modp256_mul (b, b, minus_B_y);
bn256_sub (minus_B_y, CONST_P256, B->y);
MFNC(mul) (b, b, minus_B_y);
}
else
modp256_mul (b, b, B->y);
{
bn256_sub (tmp, CONST_P256, B->y);
MFNC(mul) (b, b, B->y);
}
if (bn256_cmp (A->x, a) == 0)
if (bn256_cmp (A->y, b) == 0)
{
jpc_double (X, A);
return;
}
if (bn256_cmp (A->x, a) == 0 && bn256_cmp (A->y, b) == 0)
{
FUNC(jpc_double) (X, A);
return;
}
modp256_sub (c, a, A->x);
modp256_sub (d, b, A->y);
MFNC(sub) (c, a, A->x);
MFNC(sub) (d, b, A->y);
modp256_mul (X->z, A->z, c);
MFNC(mul) (X->z, A->z, c);
modp256_sqr (c_sqr, c);
modp256_mul (c_cube, c_sqr, c);
MFNC(sqr) (c_sqr, c);
MFNC(mul) (c_cube, c_sqr, c);
modp256_mul (x1_c_sqr, A->x, c_sqr);
MFNC(mul) (x1_c_sqr, A->x, c_sqr);
modp256_sqr (X->x, d);
MFNC(sqr) (X->x, d);
memcpy (x1_c_sqr_copy, x1_c_sqr, sizeof (bn256));
modp256_shift (x1_c_sqr_2, x1_c_sqr, 1);
modp256_add (c_cube_plus_x1_c_sqr_2, x1_c_sqr_2, c_cube);
modp256_sub (X->x, X->x, c_cube_plus_x1_c_sqr_2);
MFNC(shift) (x1_c_sqr_2, x1_c_sqr, 1);
MFNC(add) (c_cube_plus_x1_c_sqr_2, x1_c_sqr_2, c_cube);
MFNC(sub) (X->x, X->x, c_cube_plus_x1_c_sqr_2);
modp256_sub (y3_tmp, x1_c_sqr_copy, X->x);
modp256_mul (y3_tmp, y3_tmp, d);
modp256_mul (y1_c_cube, A->y, c_cube);
modp256_sub (X->y, y3_tmp, y1_c_cube);
MFNC(sub) (y3_tmp, x1_c_sqr_copy, X->x);
MFNC(mul) (y3_tmp, y3_tmp, d);
MFNC(mul) (y1_c_cube, A->y, c_cube);
MFNC(sub) (X->y, y3_tmp, y1_c_cube);
}
/**
@@ -150,9 +166,9 @@ jpc_add_ac_signed (jpc *X, const jpc *A, const ac *B, int minus)
* @param B AC
*/
void
jpc_add_ac (jpc *X, const jpc *A, const ac *B)
FUNC(jpc_add_ac) (jpc *X, const jpc *A, const ac *B)
{
jpc_add_ac_signed (X, A, B, 0);
FUNC(jpc_add_ac_signed) (X, A, B, 0);
}
/**
@@ -165,17 +181,19 @@ jpc_add_ac (jpc *X, const jpc *A, const ac *B)
* Return 0 on success.
*/
int
jpc_to_ac (ac *X, const jpc *A)
FUNC(jpc_to_ac) (ac *X, const jpc *A)
{
bn256 z_inv[1], z_inv_sqr[1];
if (modp256_inv (z_inv, A->z) < 0)
if (bn256_is_zero (A->z))
return -1;
modp256_sqr (z_inv_sqr, z_inv);
modp256_mul (z_inv, z_inv, z_inv_sqr);
mod_inv (z_inv, A->z, CONST_P256);
modp256_mul (X->x, A->x, z_inv_sqr);
modp256_mul (X->y, A->y, z_inv);
MFNC(sqr) (z_inv_sqr, z_inv);
MFNC(mul) (z_inv, z_inv, z_inv_sqr);
MFNC(mul) (X->x, A->x, z_inv_sqr);
MFNC(mul) (X->y, A->y, z_inv);
return 0;
}

36
src/jpc_p256k1.c Normal file
View File

@@ -0,0 +1,36 @@
/*
* jpc_p256k1.c -- arithmetic on Jacobian projective coordinates for p256k1.
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "mod.h"
#include "modp256k1.h"
#include "affine.h"
#include "jpc-ac_p256k1.h"
#define FIELD p256k1
#define CONST_P256 P256K1
#define COEFFICIENT_A_IS_ZERO 1
#include "jpc.c"

36
src/jpc_p256r1.c Normal file
View File

@@ -0,0 +1,36 @@
/*
* jpc_p256r1.c -- arithmetic on Jacobian projective coordinates for p256r1.
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "mod.h"
#include "modp256r1.h"
#include "affine.h"
#include "jpc-ac_p256r1.h"
#define FIELD p256r1
#define CONST_P256 P256R1
#define COEFFICIENT_A_IS_MINUS_3 1
#include "jpc.c"

367
src/mod.c
View File

@@ -1,7 +1,7 @@
/*
* mod.c -- modulo arithmetic
*
* Copyright (C) 2011 Free Software Initiative of Japan
* Copyright (C) 2011, 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -39,157 +39,316 @@ mod_reduce (bn256 *X, const bn512 *A, const bn256 *B, const bn256 *MU_lower)
uint32_t borrow_next;
memset (q, 0, sizeof (bn256));
q->words[0] = A->words[15];
q->word[0] = A->word[15];
bn256_mul (tmp, q, MU_lower);
tmp->words[8] += A->words[15];
carry = (tmp->words[8] < A->words[15]);
tmp->words[9] += carry;
tmp->word[8] += A->word[15];
carry = (tmp->word[8] < A->word[15]);
tmp->word[9] += carry;
q->words[7] = A->words[14];
q->words[6] = A->words[13];
q->words[5] = A->words[12];
q->words[4] = A->words[11];
q->words[3] = A->words[10];
q->words[2] = A->words[9];
q->words[1] = A->words[8];
q->words[0] = A->words[7];
q->word[7] = A->word[14];
q->word[6] = A->word[13];
q->word[5] = A->word[12];
q->word[4] = A->word[11];
q->word[3] = A->word[10];
q->word[2] = A->word[9];
q->word[1] = A->word[8];
q->word[0] = A->word[7];
bn256_mul (q_big, q, MU_lower);
bn256_add ((bn256 *)&q_big->words[8], (bn256 *)&q_big->words[8], q);
bn256_add ((bn256 *)&q_big->word[8], (bn256 *)&q_big->word[8], q);
q->words[0] = q_big->words[9] + tmp->words[1];
carry = (q->words[0] < tmp->words[1]);
q->word[0] = q_big->word[9] + tmp->word[1];
carry = (q->word[0] < tmp->word[1]);
q->words[1] = q_big->words[10] + carry;
carry = (q->words[1] < carry);
q->words[1] += tmp->words[2];
carry += (q->words[1] < tmp->words[2]);
q->word[1] = q_big->word[10] + carry;
carry = (q->word[1] < carry);
q->word[1] += tmp->word[2];
carry += (q->word[1] < tmp->word[2]);
q->words[2] = q_big->words[11] + carry;
carry = (q->words[2] < carry);
q->words[2] += tmp->words[3];
carry += (q->words[2] < tmp->words[3]);
q->word[2] = q_big->word[11] + carry;
carry = (q->word[2] < carry);
q->word[2] += tmp->word[3];
carry += (q->word[2] < tmp->word[3]);
q->words[3] = q_big->words[12] + carry;
carry = (q->words[3] < carry);
q->words[3] += tmp->words[4];
carry += (q->words[3] < tmp->words[4]);
q->word[3] = q_big->word[12] + carry;
carry = (q->word[3] < carry);
q->word[3] += tmp->word[4];
carry += (q->word[3] < tmp->word[4]);
q->words[4] = q_big->words[13] + carry;
carry = (q->words[4] < carry);
q->words[4] += tmp->words[5];
carry += (q->words[4] < tmp->words[5]);
q->word[4] = q_big->word[13] + carry;
carry = (q->word[4] < carry);
q->word[4] += tmp->word[5];
carry += (q->word[4] < tmp->word[5]);
q->words[5] = q_big->words[14] + carry;
carry = (q->words[5] < carry);
q->words[5] += tmp->words[6];
carry += (q->words[5] < tmp->words[6]);
q->word[5] = q_big->word[14] + carry;
carry = (q->word[5] < carry);
q->word[5] += tmp->word[6];
carry += (q->word[5] < tmp->word[6]);
q->words[6] = q_big->words[15] + carry;
carry = (q->words[6] < carry);
q->words[6] += tmp->words[7];
carry += (q->words[6] < tmp->words[7]);
q->word[6] = q_big->word[15] + carry;
carry = (q->word[6] < carry);
q->word[6] += tmp->word[7];
carry += (q->word[6] < tmp->word[7]);
q->words[7] = carry;
q->words[7] += tmp->words[8];
carry = (q->words[7] < tmp->words[8]);
q->word[7] = carry;
q->word[7] += tmp->word[8];
carry = (q->word[7] < tmp->word[8]);
memset (q_big, 0, sizeof (bn512));
q_big->words[8] = A->words[8];
q_big->words[7] = A->words[7];
q_big->words[6] = A->words[6];
q_big->words[5] = A->words[5];
q_big->words[4] = A->words[4];
q_big->words[3] = A->words[3];
q_big->words[2] = A->words[2];
q_big->words[1] = A->words[1];
q_big->words[0] = A->words[0];
q_big->word[8] = A->word[8];
q_big->word[7] = A->word[7];
q_big->word[6] = A->word[6];
q_big->word[5] = A->word[5];
q_big->word[4] = A->word[4];
q_big->word[3] = A->word[3];
q_big->word[2] = A->word[2];
q_big->word[1] = A->word[1];
q_big->word[0] = A->word[0];
bn256_mul (tmp, q, B);
tmp->word[8] += carry * B->word[0];
tmp->word[15] = tmp->word[14] = tmp->word[13] = tmp->word[12]
= tmp->word[11] = tmp->word[10] = tmp->word[9] = 0;
borrow = bn256_sub (X, (bn256 *)&q_big->word[0], (bn256 *)&tmp->word[0]);
borrow_next = (q_big->word[8] < borrow);
q_big->word[8] -= borrow;
borrow_next += (q_big->word[8] < tmp->word[8]);
q_big->word[8] -= tmp->word[8];
carry = q_big->word[8];
if (carry)
tmp->words[8] += B->words[0];
tmp->words[15] = tmp->words[14] = tmp->words[13] = tmp->words[12]
= tmp->words[11] = tmp->words[10] = tmp->words[9] = 0;
carry -= bn256_sub (X, X, B);
else
bn256_sub (q, X, B);
borrow = bn256_sub (X, (bn256 *)&q_big->words[0], (bn256 *)&tmp->words[0]);
borrow_next = (q_big->words[8] < borrow);
q_big->words[8] -= borrow;
borrow_next += (q_big->words[8] < tmp->words[8]);
q_big->words[8] -= tmp->words[8];
if (carry)
carry -= bn256_sub (X, X, B);
else
bn256_sub (q, X, B);
carry = q_big->words[8];
while (carry)
{
borrow_next = bn256_sub (X, X, B);
carry -= borrow_next;
}
if (bn256_is_ge (X, B))
bn256_sub (X, X, B);
borrow = bn256_sub (q, X, B);
if (borrow)
memcpy (q, X, sizeof (bn256));
else
memcpy (X, q, sizeof (bn256));
#undef borrow
}
/*
* Reference:
* Donald E. Knuth, The Art of Computer Programming, Vol. 2:
* Seminumerical Algorithms, 3rd ed. Reading, MA: Addison-Wesley, 1998
*
* Max loop: X=0x8000...0000 and N=0xffff...ffff
*/
#define MAX_GCD_STEPS_BN256 (3*256-2)
/**
* @brief C = X^(-1) mod N
*
* Assume X and N are co-prime (or N is prime).
* If N==0, return 0.
*
*/
void
mod_inv (bn256 *C, const bn256 *X, const bn256 *N)
{
bn256 u[1], v[1];
bn256 u[1], v[1], tmp[1];
bn256 A[1] = { { { 1, 0, 0, 0, 0, 0, 0, 0 } } };
uint32_t carry;
#define borrow carry
int n = MAX_GCD_STEPS_BN256;
memset (C, 0, sizeof (bn256));
memcpy (u, X, sizeof (bn256));
memcpy (v, N, sizeof (bn256));
while (!bn256_is_zero (u))
while (n--)
{
while (bn256_is_even (u))
int c = (bn256_is_even (u) << 1) + bn256_is_even (v);
switch (c)
{
case 3:
bn256_shift (u, u, -1);
if (bn256_is_even (A))
bn256_shift (A, A, -1);
else
{
int carry = bn256_add (A, A, N);
bn256_shift (A, A, -1);
if (carry)
A->words[7] |= 0x80000000;
bn256_add (tmp, A, N);
carry = 0;
}
}
else
carry = bn256_add (A, A, N);
bn256_shift (A, A, -1);
A->word[7] |= carry * 0x80000000;
while (bn256_is_even (v))
{
bn256_shift (v, v, -1);
if (bn256_is_even (C))
bn256_shift (C, C, -1);
{
bn256_add (tmp, C, N);
carry = 0;
}
else
carry = bn256_add (C, C, N);
bn256_shift (C, C, -1);
C->word[7] |= carry * 0x80000000;
if (bn256_is_ge (tmp, tmp))
{
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, A, N);
}
else
{
int carry = bn256_add (C, C, N);
bn256_shift (C, C, -1);
if (carry)
C->words[7] |= 0x80000000;
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, tmp, N);
}
}
break;
if (bn256_is_ge (u, v))
{
int borrow;
case 1:
bn256_shift (tmp, tmp, -1);
if (bn256_is_even (tmp))
{
bn256_add (tmp, tmp, N);
carry = 0;
}
else
carry = bn256_add (tmp, tmp, N);
bn256_sub (u, u, v);
borrow = bn256_sub (A, A, C);
if (borrow)
bn256_add (A, A, N);
}
else
{
int borrow;
bn256_shift (tmp, tmp, -1);
tmp->word[7] |= carry * 0x80000000;
bn256_sub (v, v, u);
borrow = bn256_sub (C, C, A);
if (borrow)
bn256_add (C, C, N);
bn256_shift (v, v, -1);
if (bn256_is_even (C))
{
bn256_add (tmp, C, N);
carry = 0;
}
else
carry = bn256_add (C, C, N);
bn256_shift (C, C, -1);
C->word[7] |= carry * 0x80000000;
if (bn256_is_ge (tmp, tmp))
{
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, A, N);
}
else
{
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, tmp, N);
}
break;
case 2:
bn256_shift (u, u, -1);
if (bn256_is_even (A))
{
bn256_add (tmp, A, N);
carry = 0;
}
else
carry = bn256_add (A, A, N);
bn256_shift (A, A, -1);
A->word[7] |= carry * 0x80000000;
bn256_shift (tmp, tmp, -1);
if (bn256_is_even (tmp))
{
bn256_add (tmp, tmp, N);
carry = 0;
}
else
carry = bn256_add (tmp, tmp, N);
bn256_shift (tmp, tmp, -1);
tmp->word[7] |= carry * 0x80000000;
if (bn256_is_ge (tmp, tmp))
{
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, A, N);
}
else
{
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, tmp, N);
}
break;
case 0:
bn256_shift (tmp, tmp, -1);
if (bn256_is_even (tmp))
{
bn256_add (tmp, tmp, N);
carry = 0;
}
else
carry = bn256_add (tmp, tmp, N);
bn256_shift (tmp, tmp, -1);
tmp->word[7] |= carry * 0x80000000;
bn256_shift (tmp, tmp, -1);
if (bn256_is_even (tmp))
{
bn256_add (tmp, tmp, N);
carry = 0;
}
else
carry = bn256_add (tmp, tmp, N);
bn256_shift (tmp, tmp, -1);
tmp->word[7] |= carry * 0x80000000;
if (bn256_is_ge (u, v))
{
bn256_sub (u, u, v);
borrow = bn256_sub (A, A, C);
if (borrow)
bn256_add (A, A, N);
else
bn256_add (tmp, A, N);
}
else
{
bn256_sub (v, v, u);
borrow = bn256_sub (C, C, A);
if (borrow)
bn256_add (C, C, N);
else
bn256_add (tmp, C, N);
}
break;
}
}
#undef borrow
}

312
src/mod25638.c Normal file
View File

@@ -0,0 +1,312 @@
/*
* mod25638.c -- modulo arithmetic of 2^256-38 for 2^255-19 field
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* The field is \Z/(2^255-19)
*
* We use radix-32. During computation, it's not reduced to 2^255-19,
* but it is represented in 256-bit (it is redundant representation),
* that is, something like 2^256-38.
*
* The idea is, keeping within 256-bit until it will be converted to
* affine coordinates.
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "mod25638.h"
#ifndef BN256_C_IMPLEMENTATION
#define ASM_IMPLEMENTATION 1
#endif
#if ASM_IMPLEMENTATION
#include "muladd_256.h"
#define ADDWORD_256(d_,w_,c_) \
asm ( "ldmia %[d], { r4, r5, r6, r7 } \n\t" \
"adds r4, r4, %[w] \n\t" \
"adcs r5, r5, #0 \n\t" \
"adcs r6, r6, #0 \n\t" \
"adcs r7, r7, #0 \n\t" \
"stmia %[d]!, { r4, r5, r6, r7 }\n\t" \
"ldmia %[d], { r4, r5, r6, r7 } \n\t" \
"adcs r4, r4, #0 \n\t" \
"adcs r5, r5, #0 \n\t" \
"adcs r6, r6, #0 \n\t" \
"adcs r7, r7, #0 \n\t" \
"stmia %[d]!, { r4, r5, r6, r7 }\n\t" \
"mov %[c], #0 \n\t" \
"adc %[c], %[c], #0" \
: [d] "=&r" (d_), [c] "=&r" (c_) \
: "[d]" (d_), [w] "r" (w_) \
: "r4", "r5", "r6", "r7", "memory", "cc" )
#endif
/*
256 224 192 160 128 96 64 32 0
2^256
1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 32
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffe0
2^256 - 32 - 4
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffdc
2^256 - 32 - 4 - 2
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffda
*/
const bn256 n25638[1] = {
{{0xffffffda, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }} };
const bn256 p25519[1] = {
{{ 0xffffffed, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff }} };
/*
* Implementation Note.
*
* It's not always modulo n25638. The representation is redundant
* during computation. For example, when we add the number - 1 and 1,
* it won't overflow to 2^256, and the result is represented within
* 256-bit.
*/
/**
* @brief X = (A + B) mod 2^256-38
*/
void
mod25638_add (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t carry;
bn256 tmp[1];
carry = bn256_add (X, A, B);
if (carry)
bn256_sub (X, X, n25638);
else
bn256_sub (tmp, X, n25638);
}
/**
* @brief X = (A - B) mod 2^256-38
*/
void
mod25638_sub (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t borrow;
bn256 tmp[1];
borrow = bn256_sub (X, A, B);
if (borrow)
bn256_add (X, X, n25638);
else
bn256_add (tmp, X, n25638);
}
/**
* @brief X = A mod 2^256-38
*
* Note that the second argument is not "const bn512 *".
* A is modified during the computation of modulo.
*
* It's not precisely modulo 2^256-38 for all cases,
* but result may be redundant.
*/
static void
mod25638_reduce (bn256 *X, bn512 *A)
{
const uint32_t *s;
uint32_t *d;
uint32_t w;
#if ASM_IMPLEMENTATION
uint32_t c, c0;
s = &A->word[8]; d = &A->word[0]; w = 38; MULADD_256 (s, d, w, c);
c0 = A->word[8] * 38;
s = &A->word[0];
ADDWORD_256 (s, c0, c);
A->word[0] += c * 38;
memcpy (X, A, sizeof (bn256));
#else
s = &A->word[8]; d = &A->word[0]; w = 38;
{
int i;
uint64_t r;
uint32_t carry;
r = 0;
for (i = 0; i < BN256_WORDS; i++)
{
uint64_t uv;
r += d[i];
carry = (r < d[i]);
uv = ((uint64_t)s[i])*w;
r += uv;
carry += (r < uv);
d[i] = (uint32_t)r;
r = ((r >> 32) | ((uint64_t)carry << 32));
}
d[i] = (uint32_t)r;
carry = bn256_add_uint ((bn256 *)A, (bn256 *)A, A->word[8] * 38);
A->word[0] += carry * 38;
}
memcpy (X, A, sizeof (bn256));
#endif
}
/**
* @brief X = (A * B) mod 2^256-38
*/
void
mod25638_mul (bn256 *X, const bn256 *A, const bn256 *B)
{
bn512 tmp[1];
bn256_mul (tmp, A, B);
mod25638_reduce (X, tmp);
}
/**
* @brief X = A * A mod 2^256-38
*/
void
mod25638_sqr (bn256 *X, const bn256 *A)
{
bn512 tmp[1];
bn256_sqr (tmp, A);
mod25638_reduce (X, tmp);
}
/**
* @brief X = (A << shift) mod 2^256-38
* @note shift < 32
*/
void
mod25638_shift (bn256 *X, const bn256 *A, int shift)
{
uint32_t carry;
bn256 tmp[1];
carry = bn256_shift (X, A, shift);
if (shift < 0)
return;
memset (tmp, 0, sizeof (bn256));
tmp->word[0] = (carry << 1);
/* tmp->word[1] = (carry >> 31); always zero. */
tmp->word[0] = tmp->word[0] + (carry << 2);
tmp->word[1] = (tmp->word[0] < (carry << 2)) + (carry >> 30);
tmp->word[0] = tmp->word[0] + (carry << 5);
tmp->word[1] = tmp->word[1] + (tmp->word[0] < (carry << 5)) + (carry >> 27);
mod25638_add (X, X, tmp);
}
static void
add19 (bn256 *r, bn256 *x)
{
uint32_t v;
int i;
v = 19;
for (i = 0; i < BN256_WORDS; i++)
{
r->word[i] = x->word[i] + v;
v = (r->word[i] < v);
}
}
/*
* @brief X = A mod 2^255-19
*
* It's precisely modulo 2^255-19 (unlike mod25638_reduce).
*/
void
mod25519_reduce (bn256 *X)
{
uint32_t q;
bn256 r0[1], r1[1];
int flag;
memcpy (r0, X, sizeof (bn256));
q = (r0->word[7] >> 31);
r0->word[7] &= 0x7fffffff;
if (q)
{
add19 (r0, r0);
q = (r0->word[7] >> 31);
r0->word[7] &= 0x7fffffff;
if (q)
{
add19 (r1, r0);
q = (r1->word[7] >> 31);
r1->word[7] &= 0x7fffffff;
flag = 0;
}
else
flag = 1;
}
else
{
add19 (r1, r0); /* dummy */
q = (r1->word[7] >> 31); /* dummy */
r1->word[7] &= 0x7fffffff; /* dummy */
if (q)
flag = 2;
else
flag = 3;
}
if (flag)
{
add19 (r1, r0);
q = (r1->word[7] >> 31);
r1->word[7] &= 0x7fffffff;
if (q)
memcpy (X, r1, sizeof (bn256));
else
memcpy (X, r0, sizeof (bn256));
}
else
{
if (q)
{
asm volatile ("" : : "r" (q) : "memory");
memcpy (X, r1, sizeof (bn256));
asm volatile ("" : : "r" (q) : "memory");
}
else
memcpy (X, r1, sizeof (bn256));
}
}

8
src/mod25638.h Normal file
View File

@@ -0,0 +1,8 @@
extern const bn256 n25638[1];
extern const bn256 p25519[1];
void mod25638_add (bn256 *X, const bn256 *A, const bn256 *B);
void mod25638_sub (bn256 *X, const bn256 *A, const bn256 *B);
void mod25638_mul (bn256 *X, const bn256 *A, const bn256 *B);
void mod25638_sqr (bn256 *X, const bn256 *A);
void mod25519_reduce (bn256 *X);

View File

@@ -1,305 +0,0 @@
/*
* modp256.c -- modulo P256 arithmetic
*
* Copyright (C) 2011, 2013 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* p256 = 2^256 - 2^224 + 2^192 + 2^96 - 1
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "modp256.h"
/*
256 224 192 160 128 96 64 32 0
2^256
1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 2^224
0 ffffffff 00000000 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 2^224 + 2^192
0 ffffffff 00000001 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 2^224 + 2^192 + 2^96
0 ffffffff 00000001 00000000 00000000 00000001 00000000 00000000 00000000
2^256 - 2^224 + 2^192 + 2^96 - 1
0 ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff
*/
const bn256 p256 = { {0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
0x00000000, 0x00000000, 0x00000001, 0xffffffff} };
/**
* @brief X = (A + B) mod p256
*/
void
modp256_add (bn256 *X, const bn256 *A, const bn256 *B)
{
int carry;
carry = bn256_add (X, A, B);
if (carry)
bn256_sub (X, X, P256);
}
/**
* @brief X = (A - B) mod p256
*/
void
modp256_sub (bn256 *X, const bn256 *A, const bn256 *B)
{
int borrow;
borrow = bn256_sub (X, A, B);
if (borrow)
bn256_add (X, X, P256);
}
/**
* @brief X = A mod p256
*/
void
modp256_reduce (bn256 *X, const bn512 *A)
{
bn256 tmp[1];
#define S1 X
#define S2 tmp
#define S3 tmp
#define S4 tmp
#define S5 tmp
#define S6 tmp
#define S7 tmp
#define S8 tmp
#define S9 tmp
S1->words[7] = A->words[7];
S1->words[6] = A->words[6];
S1->words[5] = A->words[5];
S1->words[4] = A->words[4];
S1->words[3] = A->words[3];
S1->words[2] = A->words[2];
S1->words[1] = A->words[1];
S1->words[0] = A->words[0];
/* X = S1 */
S2->words[7] = A->words[15];
S2->words[6] = A->words[14];
S2->words[5] = A->words[13];
S2->words[4] = A->words[12];
S2->words[3] = A->words[11];
S2->words[2] = S2->words[1] = S2->words[0] = 0;
/* X += 2 * S2 */
modp256_add (X, X, S2);
modp256_add (X, X, S2);
S3->words[7] = 0;
S3->words[6] = A->words[15];
S3->words[5] = A->words[14];
S3->words[4] = A->words[13];
S3->words[3] = A->words[12];
S3->words[2] = S3->words[1] = S3->words[0] = 0;
/* X += 2 * S3 */
modp256_add (X, X, S3);
modp256_add (X, X, S3);
S4->words[7] = A->words[15];
S4->words[6] = A->words[14];
S4->words[5] = S4->words[4] = S4->words[3] = 0;
S4->words[2] = A->words[10];
S4->words[1] = A->words[9];
S4->words[0] = A->words[8];
/* X += S4 */
modp256_add (X, X, S4);
S5->words[7] = A->words[8];
S5->words[6] = A->words[13];
S5->words[5] = A->words[15];
S5->words[4] = A->words[14];
S5->words[3] = A->words[13];
S5->words[2] = A->words[11];
S5->words[1] = A->words[10];
S5->words[0] = A->words[9];
/* X += S5 */
modp256_add (X, X, S5);
S6->words[7] = A->words[10];
S6->words[6] = A->words[8];
S6->words[5] = S6->words[4] = S6->words[3] = 0;
S6->words[2] = A->words[13];
S6->words[1] = A->words[12];
S6->words[0] = A->words[11];
/* X -= S6 */
modp256_sub (X, X, S6);
S7->words[7] = A->words[11];
S7->words[6] = A->words[9];
S7->words[5] = S7->words[4] = 0;
S7->words[3] = A->words[15];
S7->words[2] = A->words[14];
S7->words[1] = A->words[13];
S7->words[0] = A->words[12];
/* X -= S7 */
modp256_sub (X, X, S7);
S8->words[7] = A->words[12];
S8->words[6] = 0;
S8->words[5] = A->words[10];
S8->words[4] = A->words[9];
S8->words[3] = A->words[8];
S8->words[2] = A->words[15];
S8->words[1] = A->words[14];
S8->words[0] = A->words[13];
/* X -= S8 */
modp256_sub (X, X, S8);
S9->words[7] = A->words[13];
S9->words[6] = 0;
S9->words[5] = A->words[11];
S9->words[4] = A->words[10];
S9->words[3] = A->words[9];
S9->words[2] = 0;
S9->words[1] = A->words[15];
S9->words[0] = A->words[14];
/* X -= S9 */
modp256_sub (X, X, S9);
if (bn256_is_ge (X, P256))
bn256_sub (X, X, P256);
}
/**
* @brief X = (A * B) mod p256
*/
void
modp256_mul (bn256 *X, const bn256 *A, const bn256 *B)
{
bn512 AB[1];
bn256_mul (AB, A, B);
modp256_reduce (X, AB);
}
/**
* @brief X = A * A mod p256
*/
void
modp256_sqr (bn256 *X, const bn256 *A)
{
bn512 AA[1];
bn256_sqr (AA, A);
modp256_reduce (X, AA);
}
/**
* @brief C = (1 / a) mod p256
*
* Return -1 on error.
* Return 0 on success.
*/
int
modp256_inv (bn256 *C, const bn256 *a)
{
bn256 u[1], v[1];
bn256 A[1] = { { { 1, 0, 0, 0, 0, 0, 0, 0 } } };
if (bn256_is_zero (a))
return -1;
memset (C, 0, sizeof (bn256));
memcpy (u, a, sizeof (bn256));
memcpy (v, P256, sizeof (bn256));
while (!bn256_is_zero (u))
{
while (bn256_is_even (u))
{
bn256_shift (u, u, -1);
if (bn256_is_even (A))
bn256_shift (A, A, -1);
else
{
int carry = bn256_add (A, A, P256);
bn256_shift (A, A, -1);
if (carry)
A->words[7] |= 0x80000000;
}
}
while (bn256_is_even (v))
{
bn256_shift (v, v, -1);
if (bn256_is_even (C))
bn256_shift (C, C, -1);
else
{
int carry = bn256_add (C, C, P256);
bn256_shift (C, C, -1);
if (carry)
C->words[7] |= 0x80000000;
}
}
if (bn256_is_ge (u, v))
{
bn256_sub (u, u, v);
modp256_sub (A, A, C);
}
else
{
bn256_sub (v, v, u);
modp256_sub (C, C, A);
}
}
return 0;
}
/**
* @brief X = (A << shift) mod p256
* @note shift <= 32
*/
void
modp256_shift (bn256 *X, const bn256 *A, int shift)
{
uint32_t carry;
bn256 tmp[1];
carry = bn256_shift (X, A, shift);
if (shift < 0)
return;
memset (tmp, 0, sizeof (bn256));
tmp->words[7] = carry;
tmp->words[0] = carry;
modp256_add (X, X, tmp);
tmp->words[7] = 0;
tmp->words[0] = 0;
tmp->words[6] = carry;
tmp->words[3] = carry;
modp256_sub (X, X, tmp);
if (bn256_is_ge (X, P256))
bn256_sub (X, X, P256);
}

View File

@@ -1,10 +0,0 @@
extern const bn256 p256;
#define P256 (&p256)
void modp256_add (bn256 *X, const bn256 *A, const bn256 *B);
void modp256_sub (bn256 *X, const bn256 *A, const bn256 *B);
void modp256_reduce (bn256 *X, const bn512 *A);
void modp256_mul (bn256 *X, const bn256 *A, const bn256 *B);
void modp256_sqr (bn256 *X, const bn256 *A);
void modp256_shift (bn256 *X, const bn256 *A, int shift);
int modp256_inv (bn256 *C, const bn256 *a);

315
src/modp256k1.c Normal file
View File

@@ -0,0 +1,315 @@
/*
* modp256k1.c -- modulo arithmetic for p256k1
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* p256k1 = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "modp256k1.h"
/*
256 224 192 160 128 96 64 32 0
2^256
1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 2^32
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff 00000000
2^256 - 2^32 - 2^9
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffe00
2^256 - 2^32 - 2^9 - 2^8
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffd00
2^256 - 2^32 - 2^9 - 2^8 - 2^7
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc80
2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc40
2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc30
2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f
*/
const bn256 p256k1 = { {0xfffffc2f, 0xfffffffe, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } };
/*
* Implementation Note.
*
* It's not always modulo p256k1. The representation is redundant
* during computation. For example, when we add the prime - 1 and 1,
* it won't overflow to 2^256, and the result is represented within
* 256-bit.
*
* It is guaranteed that modp256k1_reduce reduces to modulo p256k1.
*/
/**
* @brief X = (A + B) mod p256k1
*/
void
modp256k1_add (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t carry;
bn256 tmp[1];
carry = bn256_add (X, A, B);
if (carry)
bn256_sub (X, X, P256K1);
else
bn256_sub (tmp, X, P256K1);
}
/**
* @brief X = (A - B) mod p256
*/
void
modp256k1_sub (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t borrow;
bn256 tmp[1];
borrow = bn256_sub (X, A, B);
if (borrow)
bn256_add (X, X, P256K1);
else
bn256_add (tmp, X, P256K1);
}
/**
* @brief X = A mod p256k1
*/
void
modp256k1_reduce (bn256 *X, const bn512 *A)
{
bn256 tmp[1];
uint32_t carry;
#define borrow carry
uint32_t s0, s1;
#define s00 tmp->word[0]
#define s01 tmp->word[1]
#define s02 tmp->word[2]
#define W0 X
#define W1 tmp
#define W2 tmp
#define W3 tmp
#define W4 tmp
#define W5 tmp
#define W6 tmp
#define W7 tmp
#define S tmp
/*
* Suppose: P256K1 = 2^256 - CONST
* Then, compute: W = A_low + A_high * CONST
* 256-bit W0 = W mod 2^256
* 64-bit (S1, S0) = W / 2^256
* where: CONST = 2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1
*/
/* W0 = A_low */
/* W7 = A_high */
/* W0 += W7 */
carry = bn256_add (W0, (const bn256 *)&A->word[8], (const bn256 *)A);
/* W6 = W7 << 4 */
/* W0 += W6 */
bn256_shift (W6, (const bn256 *)&A->word[8], 4);
carry += bn256_add (W0, W0, W6);
/* W5 = W6 << 2 */
/* W0 += W5 */
bn256_shift (W5, W6, 2);
carry += bn256_add (W0, W0, W5);
/* W4 = W5 << 1 */
/* W0 += W4 */
bn256_shift (W4, W5, 1);
carry += bn256_add (W0, W0, W4);
/* W3 = W4 << 1 */
/* W0 += W3 */
bn256_shift (W3, W4, 1);
carry += bn256_add (W0, W0, W3);
/* W2 = W3 << 1 */
/* W0 += W2 */
bn256_shift (W2, W3, 1);
carry += bn256_add (W0, W0, W2);
/* W1 = A_high << 32 */
/* W0 += W1 */
W1->word[7] = A->word[14];
W1->word[6] = A->word[13];
W1->word[5] = A->word[12];
W1->word[4] = A->word[11];
W1->word[3] = A->word[10];
W1->word[2] = A->word[9];
W1->word[1] = A->word[8];
W1->word[0] = 0;
carry += bn256_add (W0, W0, W1);
/* (S1, S0) = W / 2^256 */
s0 = A->word[15];
carry += (s0 >> 28) + (s0 >> 26) + (s0 >> 25) + (s0 >> 24) + (s0 >> 23);
carry += s0;
s1 = (carry < s0) ? 1 : 0;
s0 = carry;
/*
* Compute: S:=(S02, S01, S00), S = (S1,S0)*CONST
*/
S->word[7] = S->word[6] = S->word[5] = S->word[4] = S->word[3] = 0;
/* (S02, S01, S00) = (S1, S0) + (S1, S0)*2^32 */
s00 = s0;
s01 = s0 + s1;
s02 = s1 + ((s01 < s0)? 1 : 0);
/* (S02, S01, S00) += (S1, S0)*2^9 */
carry = (s0 >> 23) + s01;
s02 += (s1 >> 23) + ((carry < s01)? 1 : 0);
s01 = (s1 << 9) + carry;
s02 += ((s01 < carry)? 1 : 0);
s00 += (s0 << 9);
carry = ((s00 < (s0 << 9))? 1 : 0);
s01 += carry;
s02 += ((s01 < carry)? 1 : 0);
/* (S02, S01, S00) += (S1, S0)*2^8 */
carry = (s0 >> 24) + s01;
s02 += (s1 >> 24) + ((carry < s01)? 1 : 0);
s01 = (s1 << 8) + carry;
s02 += ((s01 < carry)? 1 : 0);
s00 += (s0 << 8);
carry = ((s00 < (s0 << 8))? 1 : 0);
s01 += carry;
s02 += ((s01 < carry)? 1 : 0);
/* (S02, S01, S00) += (S1, S0)*2^7 */
carry = (s0 >> 25) + s01;
s02 += (s1 >> 25) + ((carry < s01)? 1 : 0);
s01 = (s1 << 7) + carry;
s02 += ((s01 < carry)? 1 : 0);
s00 += (s0 << 7);
carry = ((s00 < (s0 << 7))? 1 : 0);
s01 += carry;
s02 += ((s01 < carry)? 1 : 0);
/* (S02, S01, S00) += (S1, S0)*2^6 */
carry = (s0 >> 26) + s01;
s02 += (s1 >> 26) + ((carry < s01)? 1 : 0);
s01 = (s1 << 6) + carry;
s02 += ((s01 < carry)? 1 : 0);
s00 += (s0 << 6);
carry = ((s00 < (s0 << 6))? 1 : 0);
s01 += carry;
s02 += ((s01 < carry)? 1 : 0);
/* (S02, S01, S00) += (S1, S0)*2^4 */
carry = (s0 >> 28) + s01;
s02 += (s1 >> 28) + ((carry < s01)? 1 : 0);
s01 = (s1 << 4) + carry;
s02 += ((s01 < carry)? 1 : 0);
s00 += (s0 << 4);
carry = ((s00 < (s0 << 4))? 1 : 0);
s01 += carry;
s02 += ((s01 < carry)? 1 : 0);
/* W0 += S */
modp256k1_add (W0, W0, S);
borrow = bn256_sub (tmp, W0, P256K1);
if (borrow)
memcpy (tmp, W0, sizeof (bn256));
else
memcpy (W0, tmp, sizeof (bn256));
#undef W0
#undef W1
#undef W2
#undef W3
#undef W4
#undef W5
#undef W6
#undef W7
#undef S
#undef s00
#undef s01
#undef s02
#undef borrow
}
/**
* @brief X = (A * B) mod p256k1
*/
void
modp256k1_mul (bn256 *X, const bn256 *A, const bn256 *B)
{
bn512 AB[1];
bn256_mul (AB, A, B);
modp256k1_reduce (X, AB);
}
/**
* @brief X = A * A mod p256k1
*/
void
modp256k1_sqr (bn256 *X, const bn256 *A)
{
bn512 AA[1];
bn256_sqr (AA, A);
modp256k1_reduce (X, AA);
}
/**
* @brief X = (A << shift) mod p256k1
* @note shift < 32
*/
void
modp256k1_shift (bn256 *X, const bn256 *A, int shift)
{
uint32_t carry;
bn256 tmp[1];
carry = bn256_shift (X, A, shift);
if (shift < 0)
return;
memset (tmp, 0, sizeof (bn256));
tmp->word[0] = carry + (carry << 9);
tmp->word[1] = carry + (tmp->word[0] < (carry << 9)) + (carry >> 23);
tmp->word[0] = tmp->word[0] + (carry << 8);
tmp->word[1] = tmp->word[1] + (tmp->word[0] < (carry << 8)) + (carry >> 24);
tmp->word[0] = tmp->word[0] + (carry << 7);
tmp->word[1] = tmp->word[1] + (tmp->word[0] < (carry << 7)) + (carry >> 25);
tmp->word[0] = tmp->word[0] + (carry << 6);
tmp->word[1] = tmp->word[1] + (tmp->word[0] < (carry << 6)) + (carry >> 26);
tmp->word[0] = tmp->word[0] + (carry << 4);
tmp->word[1] = tmp->word[1] + (tmp->word[0] < (carry << 4)) + (carry >> 28);
modp256k1_add (X, X, tmp);
}

9
src/modp256k1.h Normal file
View File

@@ -0,0 +1,9 @@
extern const bn256 p256k1;
#define P256K1 (&p256k1)
void modp256k1_add (bn256 *X, const bn256 *A, const bn256 *B);
void modp256k1_sub (bn256 *X, const bn256 *A, const bn256 *B);
void modp256k1_reduce (bn256 *X, const bn512 *A);
void modp256k1_mul (bn256 *X, const bn256 *A, const bn256 *B);
void modp256k1_sqr (bn256 *X, const bn256 *A);
void modp256k1_shift (bn256 *X, const bn256 *A, int shift);

276
src/modp256r1.c Normal file
View File

@@ -0,0 +1,276 @@
/*
* modp256r1.c -- modulo arithmetic for p256r1
*
* Copyright (C) 2011, 2013, 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* p256 = 2^256 - 2^224 + 2^192 + 2^96 - 1
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "modp256r1.h"
/*
256 224 192 160 128 96 64 32 0
2^256
1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 2^224
0 ffffffff 00000000 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 2^224 + 2^192
0 ffffffff 00000001 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 2^224 + 2^192 + 2^96
0 ffffffff 00000001 00000000 00000000 00000001 00000000 00000000 00000000
2^256 - 2^224 + 2^192 + 2^96 - 1
0 ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff
*/
const bn256 p256r1 = { {0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
0x00000000, 0x00000000, 0x00000001, 0xffffffff} };
/*
* Implementation Note.
*
* It's not always modulo p256r1. The representation is redundant
* during computation. For example, when we add the prime - 1 and 1,
* it won't overflow to 2^256, and the result is represented within
* 256-bit.
*
* It is guaranteed that modp256r1_reduce reduces to modulo p256r1.
*/
/**
* @brief X = (A + B) mod p256r1
*/
void
modp256r1_add (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t carry;
bn256 tmp[1];
carry = bn256_add (X, A, B);
if (carry)
bn256_sub (X, X, P256R1);
else
bn256_sub (tmp, X, P256R1);
}
/**
* @brief X = (A - B) mod p256r1
*/
void
modp256r1_sub (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t borrow;
bn256 tmp[1];
borrow = bn256_sub (X, A, B);
if (borrow)
bn256_add (X, X, P256R1);
else
bn256_add (tmp, X, P256R1);
}
/**
* @brief X = A mod p256r1
*/
void
modp256r1_reduce (bn256 *X, const bn512 *A)
{
bn256 tmp[1];
uint32_t borrow;
#define S1 X
#define S2 tmp
#define S3 tmp
#define S4 tmp
#define S5 tmp
#define S6 tmp
#define S7 tmp
#define S8 tmp
#define S9 tmp
S1->word[7] = A->word[7];
S1->word[6] = A->word[6];
S1->word[5] = A->word[5];
S1->word[4] = A->word[4];
S1->word[3] = A->word[3];
S1->word[2] = A->word[2];
S1->word[1] = A->word[1];
S1->word[0] = A->word[0];
/* X = S1 */
S2->word[7] = A->word[15];
S2->word[6] = A->word[14];
S2->word[5] = A->word[13];
S2->word[4] = A->word[12];
S2->word[3] = A->word[11];
S2->word[2] = S2->word[1] = S2->word[0] = 0;
/* X += 2 * S2 */
modp256r1_add (X, X, S2);
modp256r1_add (X, X, S2);
S3->word[7] = 0;
S3->word[6] = A->word[15];
S3->word[5] = A->word[14];
S3->word[4] = A->word[13];
S3->word[3] = A->word[12];
S3->word[2] = S3->word[1] = S3->word[0] = 0;
/* X += 2 * S3 */
modp256r1_add (X, X, S3);
modp256r1_add (X, X, S3);
S4->word[7] = A->word[15];
S4->word[6] = A->word[14];
S4->word[5] = S4->word[4] = S4->word[3] = 0;
S4->word[2] = A->word[10];
S4->word[1] = A->word[9];
S4->word[0] = A->word[8];
/* X += S4 */
modp256r1_add (X, X, S4);
S5->word[7] = A->word[8];
S5->word[6] = A->word[13];
S5->word[5] = A->word[15];
S5->word[4] = A->word[14];
S5->word[3] = A->word[13];
S5->word[2] = A->word[11];
S5->word[1] = A->word[10];
S5->word[0] = A->word[9];
/* X += S5 */
modp256r1_add (X, X, S5);
S6->word[7] = A->word[10];
S6->word[6] = A->word[8];
S6->word[5] = S6->word[4] = S6->word[3] = 0;
S6->word[2] = A->word[13];
S6->word[1] = A->word[12];
S6->word[0] = A->word[11];
/* X -= S6 */
modp256r1_sub (X, X, S6);
S7->word[7] = A->word[11];
S7->word[6] = A->word[9];
S7->word[5] = S7->word[4] = 0;
S7->word[3] = A->word[15];
S7->word[2] = A->word[14];
S7->word[1] = A->word[13];
S7->word[0] = A->word[12];
/* X -= S7 */
modp256r1_sub (X, X, S7);
S8->word[7] = A->word[12];
S8->word[6] = 0;
S8->word[5] = A->word[10];
S8->word[4] = A->word[9];
S8->word[3] = A->word[8];
S8->word[2] = A->word[15];
S8->word[1] = A->word[14];
S8->word[0] = A->word[13];
/* X -= S8 */
modp256r1_sub (X, X, S8);
S9->word[7] = A->word[13];
S9->word[6] = 0;
S9->word[5] = A->word[11];
S9->word[4] = A->word[10];
S9->word[3] = A->word[9];
S9->word[2] = 0;
S9->word[1] = A->word[15];
S9->word[0] = A->word[14];
/* X -= S9 */
modp256r1_sub (X, X, S9);
borrow = bn256_sub (tmp, X, P256R1);
if (borrow)
memcpy (tmp, X, sizeof (bn256));
else
memcpy (X, tmp, sizeof (bn256));
#undef S1
#undef S2
#undef S3
#undef S4
#undef S5
#undef S6
#undef S7
#undef S8
#undef S9
}
/**
* @brief X = (A * B) mod p256r1
*/
void
modp256r1_mul (bn256 *X, const bn256 *A, const bn256 *B)
{
bn512 AB[1];
bn256_mul (AB, A, B);
modp256r1_reduce (X, AB);
}
/**
* @brief X = A * A mod p256r1
*/
void
modp256r1_sqr (bn256 *X, const bn256 *A)
{
bn512 AA[1];
bn256_sqr (AA, A);
modp256r1_reduce (X, AA);
}
/**
* @brief X = (A << shift) mod p256r1
* @note shift < 32
*/
void
modp256r1_shift (bn256 *X, const bn256 *A, int shift)
{
uint32_t carry;
#define borrow carry
bn256 tmp[1];
carry = bn256_shift (X, A, shift);
if (shift < 0)
return;
memset (tmp, 0, sizeof (bn256));
tmp->word[7] = carry;
tmp->word[0] = carry;
modp256r1_add (X, X, tmp);
tmp->word[7] = 0;
tmp->word[0] = 0;
tmp->word[6] = carry;
tmp->word[3] = carry;
modp256r1_sub (X, X, tmp);
borrow = bn256_sub (tmp, X, P256R1);
if (borrow)
memcpy (tmp, X, sizeof (bn256));
else
memcpy (X, tmp, sizeof (bn256));
#undef borrow
}

9
src/modp256r1.h Normal file
View File

@@ -0,0 +1,9 @@
extern const bn256 p256r1;
#define P256R1 (&p256r1)
void modp256r1_add (bn256 *X, const bn256 *A, const bn256 *B);
void modp256r1_sub (bn256 *X, const bn256 *A, const bn256 *B);
void modp256r1_reduce (bn256 *X, const bn512 *A);
void modp256r1_mul (bn256 *X, const bn256 *A, const bn256 *B);
void modp256r1_sqr (bn256 *X, const bn256 *A);
void modp256r1_shift (bn256 *X, const bn256 *A, int shift);

47
src/muladd_256.h Normal file
View File

@@ -0,0 +1,47 @@
#define MULADD_256(s_,d_,w_,c_) do { \
asm ( "ldmia %[s]!, { r8, r9, r10 } \n\t" \
"ldmia %[d], { r5, r6, r7 } \n\t" \
"umull r4, r8, %[w], r8 \n\t" \
"adds r5, r5, r4 \n\t" \
"adcs r6, r6, r8 \n\t" \
"umull r4, r8, %[w], r9 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r6, r6, r4 \n\t" \
"adcs r7, r7, %[c] \n\t" \
"umull r4, r8, %[w], r10 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r7, r7, r4 \n\t" \
"stmia %[d]!, { r5, r6, r7 } \n\t" \
"ldmia %[s]!, { r8, r9, r10 } \n\t" \
"ldmia %[d], { r5, r6, r7 } \n\t" \
"adcs r5, r5, %[c] \n\t" \
"umull r4, r8, %[w], r8 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r5, r5, r4 \n\t" \
"adcs r6, r6, %[c] \n\t" \
"umull r4, r8, %[w], r9 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r6, r6, r4 \n\t" \
"adcs r7, r7, %[c] \n\t" \
"umull r4, r8, %[w], r10 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r7, r7, r4 \n\t" \
"stmia %[d]!, { r5, r6, r7 } \n\t" \
"ldmia %[s]!, { r8, r9 } \n\t" \
"ldmia %[d], { r5, r6 } \n\t" \
"adcs r5, r5, %[c] \n\t" \
"umull r4, r8, %[w], r8 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r5, r5, r4 \n\t" \
"adcs r6, r6, %[c] \n\t" \
"umull r4, r8, %[w], r9 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r6, r6, r4 \n\t" \
"adc %[c], %[c], #0 \n\t" \
"stmia %[d]!, { r5, r6 }" \
: [s] "=&r" (s_), [d] "=&r" (d_), [c] "=&r" (c_) \
: "[s]" (s_), "[d]" (d_), [w] "r" (w_) \
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", \
"memory", "cc" ); \
*d_ = c_; \
} while (0)

View File

@@ -1,7 +1,7 @@
/*
* openpgp-do.c -- OpenPGP card Data Objects (DO) handling
*
* Copyright (C) 2010, 2011, 2012, 2013
* Copyright (C) 2010, 2011, 2012, 2013, 2014
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -34,15 +34,7 @@
#include "random.h"
#include "polarssl/config.h"
#include "polarssl/aes.h"
/* Handles possible unaligned access. */
static uint32_t
fetch_four_bytes (const void *addr)
{
const uint8_t *p = (const uint8_t *)addr;
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}
#include "sha512.h"
#define PASSWORD_ERRORS_MAX 3 /* >= errors, it will be locked */
@@ -142,12 +134,26 @@ static const uint8_t algorithm_attr_rsa[] __attribute__ ((aligned (1))) = {
0x00 /* 0: p&q , 3: CRT with N (not yet supported) */
};
static const uint8_t algorithm_attr_ecdsa[] __attribute__ ((aligned (1))) = {
static const uint8_t algorithm_attr_p256r1[] __attribute__ ((aligned (1))) = {
9,
0x13, /* ECDSA */
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07 /* OID of NIST curve P-256 */
};
static const uint8_t algorithm_attr_p256k1[] __attribute__ ((aligned (1))) = {
6,
0x13, /* ECDSA */
0x2b, 0x81, 0x04, 0x00, 0x0a /* OID of curve secp256k1 */
};
static const uint8_t algorithm_attr_ed25519[] __attribute__ ((aligned (1))) = {
10,
0x69, /* EdDSA (experimental) */
/* OID of the curve Ed25519 */
0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01
};
/*
* Representation of PW1_LIFETIME:
* 0: PW1_LIEFTIME_P == NULL : PW1 is valid for single PSO:CDS command
@@ -618,7 +624,7 @@ encrypt (const uint8_t *key, const uint8_t *iv, uint8_t *data, int len)
aes_crypt_cfb128 (&aes, AES_ENCRYPT, len, &iv_offset, iv0, data, data);
}
/* Signing, Decryption, and Authentication */
/* For three keys: Signing, Decryption, and Authentication */
struct key_data kd[3];
static void
@@ -673,7 +679,7 @@ get_do_ptr_nr_for_kk (enum kind_of_key kk)
void
gpg_do_clear_prvkey (enum kind_of_key kk)
{
memset ((void *)&kd[kk], 0, sizeof (struct key_data));
memset (kd[kk].data, 0, KEY_CONTENT_LEN);
}
@@ -716,12 +722,12 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
if (do_data == NULL)
return 0;
key_addr = (const uint8_t *)fetch_four_bytes (&do_data[1]);
key_addr = kd[kk].key_addr;
memcpy (kdi.data, key_addr, KEY_CONTENT_LEN);
iv = do_data+5;
iv = &do_data[1];
memcpy (kdi.checksum, iv + INITIAL_VECTOR_SIZE, DATA_ENCRYPTION_KEY_SIZE);
memcpy (dek, do_data+5+16*(who+1), DATA_ENCRYPTION_KEY_SIZE);
memcpy (dek, iv+16*(who+1), DATA_ENCRYPTION_KEY_SIZE);
decrypt_dek (keystring, dek);
decrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal));
@@ -733,7 +739,7 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
}
memcpy (kd[kk].data, kdi.data, KEY_CONTENT_LEN);
DEBUG_BINARY (&kd[kk], KEY_CONTENT_LEN);
DEBUG_BINARY (kd[kk].data, KEY_CONTENT_LEN);
return 1;
}
@@ -750,10 +756,11 @@ gpg_do_delete_prvkey (enum kind_of_key kk)
if (do_data == NULL)
return;
key_addr = (uint8_t *)fetch_four_bytes (&do_data[1]);
flash_key_release (key_addr);
do_ptr[nr - NR_DO__FIRST__] = NULL;
flash_do_release (do_data);
key_addr = kd[kk].key_addr;
kd[kk].key_addr = NULL;
flash_key_release (key_addr);
if (admin_authorized == BY_ADMIN && kk == GPG_KEY_FOR_SIGNING)
{ /* Recover admin keystring DO. */
@@ -805,10 +812,22 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
/* Delete it first, if any. */
gpg_do_delete_prvkey (kk);
#ifdef RSA_AUTH
#if defined(RSA_AUTH) && defined(RSA_SIG)
if (key_len != KEY_CONTENT_LEN)
return -1;
#else /* ECDSA for authentication */
#elif defined(RSA_AUTH) && !defined(RSA_SIG)
/* ECDSA with p256k1 for signature */
if (kk != GPG_KEY_FOR_SIGNING && key_len != KEY_CONTENT_LEN)
return -1;
if (kk == GPG_KEY_FOR_SIGNING)
{
pubkey_len = key_len * 2;
if (key_len != 32)
return -1;
}
#elif !defined(RSA_AUTH) && defined(RSA_SIG)
#if defined(ECDSA_AUTH)
/* ECDSA with p256r1 for authentication */
if (kk != GPG_KEY_FOR_AUTHENTICATION && key_len != KEY_CONTENT_LEN)
return -1;
if (kk == GPG_KEY_FOR_AUTHENTICATION)
@@ -817,6 +836,19 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
if (key_len != 32)
return -1;
}
#else
/* EdDSA with Ed25519 for authentication */
if (kk != GPG_KEY_FOR_AUTHENTICATION && key_len != KEY_CONTENT_LEN)
return -1;
if (kk == GPG_KEY_FOR_AUTHENTICATION)
{
pubkey_len = key_len / 2;
if (key_len != 64)
return -1;
}
#endif
#else
#error "not supported."
#endif
pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data));
@@ -825,13 +857,30 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
if (pubkey == NULL)
{
#ifdef RSA_AUTH
#if defined(RSA_AUTH) && defined(RSA_SIG)
pubkey_allocated_here = modulus_calc (key_data, key_len);
#else /* ECDSA for authentication */
if (kk == GPG_KEY_FOR_AUTHENTICATION)
pubkey_allocated_here = ecdsa_compute_public (key_data);
#elif defined(RSA_AUTH) && !defined(RSA_SIG)
/* ECDSA with p256k1 for signature */
if (kk == GPG_KEY_FOR_SIGNING)
pubkey_allocated_here = ecdsa_compute_public_p256k1 (key_data);
else
pubkey_allocated_here = modulus_calc (key_data, key_len);
#elif !defined(RSA_AUTH) && defined(RSA_SIG)
#if defined(ECDSA_AUTH)
/* ECDSA with p256r1 for authentication */
if (kk == GPG_KEY_FOR_AUTHENTICATION)
pubkey_allocated_here = ecdsa_compute_public_p256r1 (key_data);
else
pubkey_allocated_here = modulus_calc (key_data, key_len);
#else
/* EdDSA with Ed25519 for authentication */
if (kk == GPG_KEY_FOR_AUTHENTICATION)
pubkey_allocated_here = eddsa_compute_public_25519 (key_data);
else
pubkey_allocated_here = modulus_calc (key_data, key_len);
#endif
#else
#error "not supported."
#endif
if (pubkey_allocated_here == NULL)
{
@@ -841,7 +890,7 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
}
DEBUG_INFO ("Getting keystore address...\r\n");
key_addr = flash_key_alloc ();
key_addr = flash_key_alloc (kk);
if (key_addr == NULL)
{
if (pubkey_allocated_here)
@@ -852,15 +901,27 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
free (pd);
return -1;
}
kd[kk].key_addr = key_addr;
num_prv_keys++;
DEBUG_INFO ("key_addr: ");
DEBUG_WORD ((uint32_t)key_addr);
#ifdef RSA_AUTH
#if defined(RSA_AUTH) && defined(RSA_SIG)
memcpy (kdi.data, key_data, KEY_CONTENT_LEN);
#else /* ECDSA for authentication */
#elif defined(RSA_AUTH) && !defined(RSA_SIG)
/* ECDSA with p256k1 for signature */
if (kk == GPG_KEY_FOR_SIGNING)
{
memcpy (kdi.data, key_data, key_len);
memset ((uint8_t *)kdi.data + key_len, 0, KEY_CONTENT_LEN - key_len);
}
else
memcpy (kdi.data, key_data, KEY_CONTENT_LEN);
#elif !defined(RSA_AUTH) && defined(RSA_SIG)
/* ECDSA with p256r1 for authentication */
/* EdDSA with Ed25519 for authentication */
if (kk == GPG_KEY_FOR_AUTHENTICATION)
{
memcpy (kdi.data, key_data, key_len);
@@ -868,6 +929,8 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
}
else
memcpy (kdi.data, key_data, KEY_CONTENT_LEN);
#else
#error "not supported."
#endif
compute_key_data_checksum (&kdi, 0);
@@ -910,7 +973,6 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
return r;
}
pd->key_addr = key_addr;
memcpy (pd->iv, iv, INITIAL_VECTOR_SIZE);
memcpy (pd->checksum_encrypted, kdi.checksum, DATA_ENCRYPTION_KEY_SIZE);
@@ -974,7 +1036,7 @@ gpg_do_chks_prvkey (enum kind_of_key kk,
memcpy (pd, &do_data[1], sizeof (struct prvkey_data));
dek_p = ((uint8_t *)pd) + 4 + INITIAL_VECTOR_SIZE
dek_p = ((uint8_t *)pd) + INITIAL_VECTOR_SIZE
+ DATA_ENCRYPTION_KEY_SIZE * who_old;
memcpy (dek, dek_p, DATA_ENCRYPTION_KEY_SIZE);
if (who_new == 0) /* Remove */
@@ -1016,24 +1078,39 @@ gpg_do_chks_prvkey (enum kind_of_key kk,
return 1;
}
static enum kind_of_key
kkb_to_kk (uint8_t kk_byte)
{
enum kind_of_key kk;
if (kk_byte == 0xb6)
kk = GPG_KEY_FOR_SIGNING;
else if (kk_byte == 0xb8)
kk = GPG_KEY_FOR_DECRYPTION;
else /* 0xa4 */
kk = GPG_KEY_FOR_AUTHENTICATION;
return kk;
}
/*
* RSA:
* 4d, xx, xx, xx: Extended Header List
* b6 00 (SIG) / b8 00 (DEC) / a4 00 (AUT)
* 7f48, xx: cardholder private key template
* 91 xx: length of E
* 92 xx xx: length of P
* 93 xx xx: length of Q
* 91 L<E>: L<E>: 91=tag of E, L<E>: length of E
* 92 Lh<P> Ll<P>: 92=tag of P, L<P>: length of P
* 93 Lh<Q> Ll<Q>: 93=tag of Q, L<Q>: length of Q
* 5f48, xx xx xx: cardholder private key
* <E: 4-byte>, <P: 128-byte>, <Q: 128-byte>
*
* ECDSA:
* ECDSA / EdDSA:
* 4d, xx: Extended Header List
* a4 00 (AUT)
* 7f48, xx: cardholder private key template
* 91 xx: length of d
* 9x LEN: 9x=tag of private key d, LEN=length of d
* 5f48, xx : cardholder private key
* <d>
* <d: 32-byte>
*/
static int
proc_key_import (const uint8_t *data, int len)
@@ -1061,35 +1138,48 @@ proc_key_import (const uint8_t *data, int len)
else
p += 1;
if (*p == 0xb6)
kk = kkb_to_kk (*p);
if (kk == GPG_KEY_FOR_SIGNING)
{
kk = GPG_KEY_FOR_SIGNING;
ac_reset_pso_cds ();
gpg_reset_digital_signature_counter ();
}
else
{
if (*p == 0xb8)
kk = GPG_KEY_FOR_DECRYPTION;
else /* 0xa4 */
kk = GPG_KEY_FOR_AUTHENTICATION;
ac_reset_other ();
}
ac_reset_other ();
#ifdef RSA_AUTH
#if defined(RSA_AUTH) && defined(RSA_SIG)
if (len <= 22)
#else /* ECDSA for authentication */
#elif defined(RSA_AUTH) && !defined(RSA_SIG)
/* ECDSA with p256k1 for signature */
if ((kk != GPG_KEY_FOR_SIGNING && len <= 22)
|| (kk == GPG_KEY_FOR_SIGNING && len <= 12))
#elif !defined(RSA_AUTH) && defined(RSA_SIG)
/* ECDSA with p256r1 for authentication */
if ((kk != GPG_KEY_FOR_AUTHENTICATION && len <= 22)
|| (kk == GPG_KEY_FOR_AUTHENTICATION && len <= 12))
#else
#error "not supported."
#endif
{ /* Deletion of the key */
gpg_do_delete_prvkey (kk);
return 1;
}
#ifdef RSA_AUTH
#if defined(RSA_AUTH) && defined(RSA_SIG)
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin, NULL);
#else /* ECDSA for authentication */
#elif defined(RSA_AUTH) && !defined(RSA_SIG)
/* ECDSA with p256k1 for signature */
if (kk != GPG_KEY_FOR_SIGNING)
{ /* RSA */
/* It should starts with 00 01 00 01 (E) */
/* Skip E, 4-byte */
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin, NULL);
}
else
r = gpg_do_write_prvkey (kk, &data[12], len - 12, keystring_admin, NULL);
#elif !defined(RSA_AUTH) && defined(RSA_SIG)
#if defined(ECDSA_AUTH)
/* ECDSA with p256r1 for authentication */
if (kk != GPG_KEY_FOR_AUTHENTICATION)
{ /* RSA */
/* It should starts with 00 01 00 01 (E) */
@@ -1098,6 +1188,30 @@ proc_key_import (const uint8_t *data, int len)
}
else
r = gpg_do_write_prvkey (kk, &data[12], len - 12, keystring_admin, NULL);
#else /* EdDSA */
/* EdDSA with Ed25519 for authentication */
if (kk != GPG_KEY_FOR_AUTHENTICATION)
{ /* RSA */
/* It should starts with 00 01 00 01 (E) */
/* Skip E, 4-byte */
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin, NULL);
}
else
{
uint8_t hash[64];
if (len - 12 != 32)
return 1; /* Error. */
sha512 (&data[12], 32, hash);
hash[0] &= 248;
hash[31] &= 127;
hash[31] |= 64;
r = gpg_do_write_prvkey (kk, hash, 64, keystring_admin, NULL);
}
#endif
#else
#error "not supported."
#endif
if (r < 0)
@@ -1161,12 +1275,20 @@ gpg_do_table[] = {
rw_pw_status },
/* Fixed data */
{ GPG_DO_EXTCAP, DO_FIXED, AC_ALWAYS, AC_NEVER, extended_capabilities },
#ifdef RSA_SIG
{ GPG_DO_ALG_SIG, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr_rsa },
{ GPG_DO_ALG_DEC, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr_rsa },
#ifdef RSA_AUTH
{ GPG_DO_ALG_AUT, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr_rsa },
#else
{ GPG_DO_ALG_AUT, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr_ecdsa },
{ GPG_DO_ALG_SIG, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr_p256k1 },
#endif
{ GPG_DO_ALG_DEC, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr_rsa },
#if defined(RSA_AUTH)
{ GPG_DO_ALG_AUT, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr_rsa },
#elif defined(ECDSA_AUTH)
{ GPG_DO_ALG_AUT, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr_p256r1 },
#elif defined(EDDSA_AUTH)
{ GPG_DO_ALG_AUT, DO_FIXED, AC_ALWAYS, AC_NEVER, algorithm_attr_ed25519 },
#else
#error "Not supported (AUTH)."
#endif
/* Compound data: Read access only */
{ GPG_DO_CH_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_ch_data },
@@ -1583,54 +1705,65 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len)
void
gpg_do_public_key (uint8_t kk_byte)
{
const uint8_t *do_data;
const uint8_t *key_addr;
enum kind_of_key kk;
DEBUG_INFO ("Public key\r\n");
DEBUG_BYTE (kk_byte);
if (kk_byte == 0xb6)
do_data = do_ptr[NR_DO_PRVKEY_SIG - NR_DO__FIRST__];
else if (kk_byte == 0xb8)
do_data = do_ptr[NR_DO_PRVKEY_DEC - NR_DO__FIRST__];
else /* 0xa4 */
do_data = do_ptr[NR_DO_PRVKEY_AUT - NR_DO__FIRST__];
if (do_data == NULL)
kk = kkb_to_kk (kk_byte);
key_addr = kd[kk].key_addr;
if (key_addr == NULL)
{
DEBUG_INFO ("none.\r\n");
GPG_NO_RECORD ();
return;
}
key_addr = (const uint8_t *)fetch_four_bytes (&do_data[1]);
res_p = res_APDU;
/* TAG */
*res_p++ = 0x7f; *res_p++ = 0x49;
#ifndef RSA_AUTH /* ECDSA for authentication */
#if defined(RSA_AUTH) && defined(RSA_SIG)
if (0)
#elif defined(RSA_AUTH) && !defined(RSA_SIG)
/* ECDSA with p256k1 for signature */
if (kk_byte == 0xb6)
#elif !defined(RSA_AUTH) && defined(RSA_SIG)
/* ECDSA with p256r1 for authentication */
/* EdDSA with Ed25519 for authentication */
if (kk_byte == 0xa4)
#else
#error "not supported."
#endif
#if defined(ECDSA_AUTH)
{ /* ECDSA */
/* LEN */
*res_p++ = 2 + 8 + 2 + 1 + 64;
*res_p++ = 2 + 1 + 64;
{
/*TAG*/ /* LEN = 8 */
*res_p++ = 0x06; *res_p++ = 0x08;
memcpy (res_p, algorithm_attr_ecdsa+2, 8);
res_p += 8;
/*TAG*/ /* LEN = 1+64 */
*res_p++ = 0x86; *res_p++ = 0x41;
*res_p++ = 0x04; /* No compression of EC point. */
/* 64-byte binary (big endian) */
/* 64-byte binary (big endian): X || Y */
memcpy (res_p, key_addr + KEY_CONTENT_LEN, 64);
res_p += 64;
}
}
else
#else /* EDDSA_AUTH */
{ /* EdDSA */
/* LEN */
*res_p++ = 2 + 32;
{
/*TAG*/ /* LEN = 32 */
*res_p++ = 0x86; *res_p++ = 0x20;
/* 32-byte binary (little endian): Y with parity */
memcpy (res_p, key_addr + KEY_CONTENT_LEN, 32);
res_p += 32;
}
}
#endif
else
{ /* RSA */
/* LEN = 9+256 */
*res_p++ = 0x82; *res_p++ = 0x01; *res_p++ = 0x09;
@@ -1704,13 +1837,7 @@ gpg_do_keygen (uint8_t kk_byte)
DEBUG_INFO ("Keygen\r\n");
DEBUG_BYTE (kk_byte);
if (kk_byte == 0xb6)
kk = GPG_KEY_FOR_SIGNING;
else if (kk_byte == 0xb8)
kk = GPG_KEY_FOR_DECRYPTION;
else /* 0xa4 */
kk = GPG_KEY_FOR_AUTHENTICATION;
kk = kkb_to_kk (kk_byte);
if (admin_authorized == BY_ADMIN)
keystring_admin = keystring_md_pw3;
else
@@ -1745,6 +1872,7 @@ gpg_do_keygen (uint8_t kk_byte)
/* GnuPG expects it's ready for signing. */
/* Don't call ac_reset_pso_cds here, but load the private key */
gpg_reset_digital_signature_counter ();
s2k (NULL, 0, pw, strlen (OPENPGP_CARD_INITIAL_PW1), keystring);
gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
}

View File

@@ -1,7 +1,7 @@
/*
* openpgp.c -- OpenPGP card protocol support
*
* Copyright (C) 2010, 2011, 2012, 2013
* Copyright (C) 2010, 2011, 2012, 2013, 2014
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -805,6 +805,12 @@ cmd_get_data (void)
gpg_do_get_data (tag, 0);
}
#define ECDSA_HASH_LEN 32
#define ECDSA_SIGNATURE_LENGTH 64
#define EDDSA_HASH_LEN_MAX 256
#define EDDSA_SIGNATURE_LENGTH 64
static void
cmd_pso (void)
{
@@ -824,6 +830,7 @@ cmd_pso (void)
return;
}
#ifdef RSA_SIG
/* Check size of digestInfo */
if (len != 34 /* MD5 */
&& len != 35 /* SHA1 / RIPEMD-160 */
@@ -839,7 +846,7 @@ cmd_pso (void)
else
{
DEBUG_SHORT (len);
DEBUG_BINARY (&kd[GPG_KEY_FOR_SIGNING], KEY_CONTENT_LEN);
DEBUG_BINARY (kd[GPG_KEY_FOR_SIGNING].data, KEY_CONTENT_LEN);
r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len,
&kd[GPG_KEY_FOR_SIGNING]);
@@ -852,11 +859,35 @@ cmd_pso (void)
/* Success */
gpg_increment_digital_signature_counter ();
}
#else
/* ECDSA with p256k1 for signature */
if (len != ECDSA_HASH_LEN)
{
DEBUG_INFO (" wrong length: ");
GPG_CONDITION_NOT_SATISFIED ();
}
else
{
DEBUG_SHORT (len);
res_APDU_size = ECDSA_SIGNATURE_LENGTH;
r = ecdsa_sign_p256k1 (apdu.cmd_apdu_data, res_APDU,
kd[GPG_KEY_FOR_SIGNING].data);
if (r < 0)
{
ac_reset_pso_cds ();
GPG_ERROR ();
}
else
/* Success */
gpg_increment_digital_signature_counter ();
}
#endif
}
else if (P1 (apdu) == 0x80 && P2 (apdu) == 0x86)
{
DEBUG_SHORT (len);
DEBUG_BINARY (&kd[GPG_KEY_FOR_DECRYPTION], KEY_CONTENT_LEN);
DEBUG_BINARY (kd[GPG_KEY_FOR_DECRYPTION].data, KEY_CONTENT_LEN);
if (!ac_check_status (AC_OTHER_AUTHORIZED))
{
@@ -890,7 +921,7 @@ cmd_pso (void)
}
#ifdef RSA_AUTH
#if defined(RSA_AUTH)
#define MAX_DIGEST_INFO_LEN 102 /* 40% */
static void
cmd_internal_authenticate (void)
@@ -934,10 +965,7 @@ cmd_internal_authenticate (void)
DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n");
}
#else
#define ECDSA_P256_HASH_LEN 32
#define ECDSA_SIGNATURE_LENGTH 64
#elif defined(ECDSA_AUTH)
static void
cmd_internal_authenticate (void)
{
@@ -957,7 +985,7 @@ cmd_internal_authenticate (void)
return;
}
if (len != ECDSA_P256_HASH_LEN)
if (len != ECDSA_HASH_LEN)
{
DEBUG_INFO ("wrong hash length.");
GPG_CONDITION_NOT_SATISFIED ();
@@ -965,8 +993,8 @@ cmd_internal_authenticate (void)
}
res_APDU_size = ECDSA_SIGNATURE_LENGTH;
r = ecdsa_sign (apdu.cmd_apdu_data, res_APDU,
&kd[GPG_KEY_FOR_AUTHENTICATION]);
r = ecdsa_sign_p256r1 (apdu.cmd_apdu_data, res_APDU,
kd[GPG_KEY_FOR_AUTHENTICATION].data);
if (r < 0)
GPG_ERROR ();
}
@@ -981,6 +1009,57 @@ cmd_internal_authenticate (void)
DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n");
}
#elif defined(EDDSA_AUTH)
static void
cmd_internal_authenticate (void)
{
int len = apdu.cmd_apdu_data_len;
int r;
DEBUG_INFO (" - INTERNAL AUTHENTICATE\r\n");
if (P1 (apdu) == 0x00 && P2 (apdu) == 0x00)
{
uint32_t output[64/4]; /* Require 4-byte alignment. */
DEBUG_SHORT (len);
if (!ac_check_status (AC_OTHER_AUTHORIZED))
{
DEBUG_INFO ("security error.");
GPG_SECURITY_FAILURE ();
return;
}
if (len > EDDSA_HASH_LEN_MAX)
{
DEBUG_INFO ("wrong hash length.");
GPG_CONDITION_NOT_SATISFIED ();
return;
}
res_APDU_size = EDDSA_SIGNATURE_LENGTH;
r = eddsa_sign_25519 (apdu.cmd_apdu_data, len, output,
kd[GPG_KEY_FOR_AUTHENTICATION].data,
kd[GPG_KEY_FOR_AUTHENTICATION].data+32,
kd[GPG_KEY_FOR_AUTHENTICATION].key_addr + KEY_CONTENT_LEN);
memcpy (res_APDU, output, EDDSA_SIGNATURE_LENGTH);
if (r < 0)
GPG_ERROR ();
}
else
{
DEBUG_INFO (" - ??");
DEBUG_BYTE (P1 (apdu));
DEBUG_INFO (" - ??");
DEBUG_BYTE (P2 (apdu));
GPG_ERROR ();
}
DEBUG_INFO ("INTERNAL AUTHENTICATE done.\r\n");
}
#else
#error "Authentication not defined."
#endif
#define MBD_OPRATION_WRITE 0

View File

@@ -52,13 +52,17 @@
#define SHA256_MASK (SHA256_BLOCK_SIZE - 1)
static void memcpy_bswap32 (void *dst, const uint32_t *p, int n)
static void memcpy_output_bswap32 (unsigned char *dst, const uint32_t *p)
{
uint32_t *q = (uint32_t *)dst;
int i;
uint32_t q = 0;
n >>= 2;
while (n--)
q[n] = __builtin_bswap32 (p[n]); /* bswap32 is GCC extention */
for (i = 0; i < 32; i++)
{
if ((i & 3) == 0)
q = __builtin_bswap32 (p[i >> 2]); /* bswap32 is GCC extention */
dst[i] = q >> ((i & 3) * 8);
}
}
#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n)))
@@ -193,11 +197,11 @@ sha256_finish (sha256_context *ctx, unsigned char output[32])
ctx->wbuf[15] = __builtin_bswap32 (ctx->total[0] << 3);
sha256_process (ctx);
memcpy_bswap32 (output, ctx->state, SHA256_DIGEST_SIZE);
memcpy_output_bswap32 (output, ctx->state);
memset (ctx, 0, sizeof (sha256_context));
}
const uint32_t initial_state[8] =
static const uint32_t initial_state[8] =
{
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19

216
src/sha512.c Normal file
View File

@@ -0,0 +1,216 @@
/*
* sha512.c -- Compute SHA-512 hash (for little endian architecture).
*
* This module is written by gniibe, following the API of sha256.c.
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Reference:
*
* [1] FIPS PUB 180-4: Secure hash Standard (SHS), March, 2012.
*
*/
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include "sha512.h"
#define SHA512_MASK (SHA512_BLOCK_SIZE - 1)
static void memcpy_output_bswap64 (unsigned char dst[64], const uint64_t *p)
{
int i;
uint64_t q = 0;
for (i = 0; i < 64; i++)
{
if ((i & 7) == 0)
q = __builtin_bswap64 (p[i >> 3]); /* bswap64 is GCC extention */
dst[i] = q >> ((i & 7) * 8);
}
}
#define rotr64(x,n) (((x) >> n) | ((x) << (64 - n)))
#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y))))
/* round transforms for SHA512 compression functions */
#define vf(n,i) v[(n - i) & 7]
#define hf(i) (p[i & 15] += \
g_1(p[(i + 14) & 15]) + p[(i + 9) & 15] + g_0(p[(i + 1) & 15]))
#define v_cycle0(i) \
p[i] = __builtin_bswap64 (p[i]); \
vf(7,i) += p[i] + k_0[i] \
+ s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \
vf(3,i) += vf(7,i); \
vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i))
#define v_cycle(i, j) \
vf(7,i) += hf(i) + k_0[i+j] \
+ s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \
vf(3,i) += vf(7,i); \
vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i))
#define s_0(x) (rotr64((x), 28) ^ rotr64((x), 34) ^ rotr64((x), 39))
#define s_1(x) (rotr64((x), 14) ^ rotr64((x), 18) ^ rotr64((x), 41))
#define g_0(x) (rotr64((x), 1) ^ rotr64((x), 8) ^ ((x) >> 7))
#define g_1(x) (rotr64((x), 19) ^ rotr64((x), 61) ^ ((x) >> 6))
#define k_0 k512
/* Taken from section 4.2.3 of [1]. */
static const uint64_t k512[80] = {
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
};
void
sha512_process (sha512_context *ctx)
{
uint32_t i;
uint64_t *p = ctx->wbuf;
uint64_t v[8];
memcpy (v, ctx->state, 8 * sizeof (uint64_t));
v_cycle0 ( 0); v_cycle0 ( 1); v_cycle0 ( 2); v_cycle0 ( 3);
v_cycle0 ( 4); v_cycle0 ( 5); v_cycle0 ( 6); v_cycle0 ( 7);
v_cycle0 ( 8); v_cycle0 ( 9); v_cycle0 (10); v_cycle0 (11);
v_cycle0 (12); v_cycle0 (13); v_cycle0 (14); v_cycle0 (15);
for (i = 16; i < 80; i += 16)
{
v_cycle ( 0, i); v_cycle ( 1, i); v_cycle ( 2, i); v_cycle ( 3, i);
v_cycle ( 4, i); v_cycle ( 5, i); v_cycle ( 6, i); v_cycle ( 7, i);
v_cycle ( 8, i); v_cycle ( 9, i); v_cycle (10, i); v_cycle (11, i);
v_cycle (12, i); v_cycle (13, i); v_cycle (14, i); v_cycle (15, i);
}
ctx->state[0] += v[0];
ctx->state[1] += v[1];
ctx->state[2] += v[2];
ctx->state[3] += v[3];
ctx->state[4] += v[4];
ctx->state[5] += v[5];
ctx->state[6] += v[6];
ctx->state[7] += v[7];
}
void
sha512_update (sha512_context *ctx, const unsigned char *input,
unsigned int ilen)
{
uint32_t left = (ctx->total[0] & SHA512_MASK);
uint32_t fill = SHA512_BLOCK_SIZE - left;
ctx->total[0] += ilen;
if (ctx->total[0] < ilen)
ctx->total[1]++;
while (ilen >= fill)
{
memcpy (((unsigned char*)ctx->wbuf) + left, input, fill);
sha512_process (ctx);
input += fill;
ilen -= fill;
left = 0;
fill = SHA512_BLOCK_SIZE;
}
memcpy (((unsigned char*)ctx->wbuf) + left, input, ilen);
}
void
sha512_finish (sha512_context *ctx, unsigned char output[64])
{
uint32_t last = (ctx->total[0] & SHA512_MASK);
ctx->wbuf[last >> 3] = __builtin_bswap64 (ctx->wbuf[last >> 3]);
ctx->wbuf[last >> 3] &= 0xffffffffffffff80LL << (8 * (~last & 7));
ctx->wbuf[last >> 3] |= 0x0000000000000080LL << (8 * (~last & 7));
ctx->wbuf[last >> 3] = __builtin_bswap64 (ctx->wbuf[last >> 3]);
if (last > SHA512_BLOCK_SIZE - 17)
{
if (last < 120)
ctx->wbuf[15] = 0;
sha512_process (ctx);
last = 0;
}
else
last = (last >> 3) + 1;
while (last < 14)
ctx->wbuf[last++] = 0;
ctx->wbuf[14] = __builtin_bswap64 ((ctx->total[0] >> 61) | (ctx->total[1] << 3));
ctx->wbuf[15] = __builtin_bswap64 (ctx->total[0] << 3);
sha512_process (ctx);
memcpy_output_bswap64 (output, ctx->state);
memset (ctx, 0, sizeof (sha512_context));
}
/* Taken from section 5.3.5 of [1]. */
static const uint64_t initial_state[8] = {
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179
};
void
sha512_start (sha512_context *ctx)
{
ctx->total[0] = ctx->total[1] = 0;
memcpy (ctx->state, initial_state, 8 * sizeof(uint64_t));
}
void
sha512 (const unsigned char *input, unsigned int ilen,
unsigned char output[64])
{
sha512_context ctx;
sha512_start (&ctx);
sha512_update (&ctx, input, ilen);
sha512_finish (&ctx, output);
}

17
src/sha512.h Normal file
View File

@@ -0,0 +1,17 @@
#define SHA512_DIGEST_SIZE 64
#define SHA512_BLOCK_SIZE 128
typedef struct
{
uint64_t total[2];
uint64_t state[8];
uint64_t wbuf[16];
} sha512_context;
void sha512 (const unsigned char *input, unsigned int ilen,
unsigned char output[64]);
void sha512_start (sha512_context *ctx);
void sha512_finish (sha512_context *ctx, unsigned char output[64]);
void sha512_update (sha512_context *ctx, const unsigned char *input,
unsigned int ilen);
void sha512_process (sha512_context *ctx);

View File

@@ -0,0 +1,28 @@
from ecdsa import curves, ecdsa
G = ecdsa.generator_secp256k1
# G = ecdsa.generator_256
def print_nG(n):
nG = n*G
nGx_str = "%064x" % nG.x()
nGy_str = "%064x" % nG.y()
print256(nGx_str)
print256(nGy_str)
print
def print256(s):
print("0x%s, 0x%s, 0x%s, 0x%s," % (s[56:64], s[48:56], s[40:48], s[32:40]))
print("0x%s, 0x%s, 0x%s, 0x%s" % (s[24:32], s[16:24], s[8:16], s[0:8]))
print
for i in range(1,16):
n = (i & 1) + (i & 2) * 0x8000000000000000L + (i & 4) * 0x40000000000000000000000000000000L + (i & 8) * 0x200000000000000000000000000000000000000000000000L
print "%064x" % n
print_nG(n)
for i in range(1,16):
n = (i & 1) + (i & 2) * 0x8000000000000000L + (i & 4) * 0x40000000000000000000000000000000L + (i & 8) * 0x200000000000000000000000000000000000000000000000L
n = n * 0x100000000L
print "%064x" % n
print_nG(n)

View File

@@ -111,7 +111,7 @@ class DFU_STM32(object):
self.__devhandle = device.open()
self.__devhandle.setConfiguration(configuration)
self.__devhandle.claimInterface(interface)
self.__devhandle.setAltInterface(interface)
self.__devhandle.setAltInterface(0)
self.__intf = interface.interfaceNumber
self.__alt = interface.alternateSetting

View File

@@ -73,7 +73,7 @@ class gnuk_token(object):
except:
pass
self.__devhandle.claimInterface(interface)
self.__devhandle.setAltInterface(interface)
self.__devhandle.setAltInterface(0)
self.__intf = interface.interfaceNumber
self.__alt = interface.alternateSetting
@@ -481,7 +481,7 @@ class regnual(object):
except:
pass
self.__devhandle.claimInterface(intf)
self.__devhandle.setAltInterface(intf)
self.__devhandle.setAltInterface(0)
def mem_info(self):
mem = self.__devhandle.controlMsg(requestType = 0xc0, request = 0,

View File

@@ -59,7 +59,7 @@ class regnual(object):
except:
pass
self.__devhandle.claimInterface(intf)
self.__devhandle.setAltInterface(intf)
self.__devhandle.setAltInterface(0)
def mem_info(self):
mem = self.__devhandle.controlMsg(requestType = 0xc0, request = 0,
@@ -172,7 +172,7 @@ class gnuk_token(object):
except:
pass
self.__devhandle.claimInterface(interface)
self.__devhandle.setAltInterface(interface)
self.__devhandle.setAltInterface(0)
self.__intf = interface.interfaceNumber
self.__alt = interface.alternateSetting

View File

@@ -146,7 +146,7 @@ class stlinkv2(object):
except:
pass
self.__devhandle.claimInterface(intf)
# self.__devhandle.setAltInterface(intf) # This is not good for libusb-win32
# self.__devhandle.setAltInterface(0) # This was not good for libusb-win32 with wrong arg intf, new correct value 0 would be OK
def shutdown(self):
self.__devhandle.releaseInterface()

View File

@@ -94,7 +94,6 @@ if __name__ == '__main__':
passwd = DEFAULT_PW3
keyno = 0
print sys.argv
while len(sys.argv) > 3:
option = sys.argv[1]
sys.argv.pop(1)