diff options
author | lundinc <lundinc@1d2547de-c912-0410-9cb9-b8ca96c0e9e2> | 2020-08-12 19:11:51 +0000 |
---|---|---|
committer | lundinc <lundinc@1d2547de-c912-0410-9cb9-b8ca96c0e9e2> | 2020-08-12 19:11:51 +0000 |
commit | 42255af1e27a3157d541f0812eaca447c569ca49 (patch) | |
tree | 5c8702c2f0dc1cb9be1a4d5ff285897d96b97dd2 /FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/ecc.c | |
parent | f5221dff43de249079c2da081723cb7a456f981f (diff) | |
download | freertos-master.tar.gz |
Author: Ming Yue <mingyue86010@gmail.com>
Date: Tue Aug 11 17:06:59 2020 -0700
Remove unused wolfSSL files. (#197)
* Remove unused wolfSSL files.
* Add back some removed ciphers.
* Update VS project file.
commit 0e0edd96e8236b2ea4a6e6018812807be828c77f
Author: RichardBarry <3073890+RichardBarry@users.noreply.github.com>
Date: Tue Aug 11 10:50:30 2020 -0700
Use new QEMU test project to improve stream/message buffer tests (#168)
* Add Eclipse/GCC project that targets the LM3S8962 QEMU model.
* Get the Cortex-M QEMU project working.
* Continue working on making stream buffer demo more robust and QEMU project.
* Rename directory CORTEX_LM3S8986_QEMU to CORTEX_LM3S6965_QEMU.
Work on making the Stream Buffer tests more robust.
Check in before adding in the trace recorder.
* Rename CORTEX_LM3S6969_QEMU to CORTEX_LM3S6969_GCC_QEMU.
* Make the StreamBufferDemo.c common demo file (test file) more robust to other test tasks running at an equally high priority.
* Work in progress checkin only - comments in main.c are incorrect.
* Correct comments at the top of FreeRTOS/Demo/CORTEX_LM3S6965_GCC_QEMU/main.c
Make the message buffer tests more robust in the case the a message buffer becomes full when prvSenderTask() has a higher priority than the reader task.
* Disable trace recorder in the LM3S6965 QEMU demo.
* I'm dropping FreeRTOS-Kernel reference update, since this seems to break the CMBC CI.
Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
commit 157a7fc39f19583ac8481e93fa3e1c91b1e1860c
Author: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com>
Date: Sun Aug 9 22:21:44 2020 -0700
Use chacheable RAM in IAR project for MPU_M7_NUCLEO_H743ZI2 project (#193)
This change updates the IAR project for Nucleo H743ZI2 to use the
cacheable DTC RAM and enables L1 cache. In order to ensure the correct
functioning of cache, the project sets configTEX_S_C_B_SRAM in
FreeRTOSConfig.h to not mark the RAM as shareable.
Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
commit f3e43556f90f01b82918ad533b0c616489331919
Author: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com>
Date: Sun Aug 9 16:23:53 2020 -0700
Add MPU demo projects for NUCLEO-H743ZI2 board (#155)
* Add MPU demo projects for NUCLEO-H743ZI2 board
It contains projects for Keil uVision, STM32CubeIDE and IAR EW. This
demo shows the use of newly added support for 16 MPU regions.
Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
* Delete not needed CMSIS files
Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
commit 94aa31c3cbae7c929b8a412768b74631f4a6b461
Author: TakayukiMatsuo <62984531+TakayukiMatsuo@users.noreply.github.com>
Date: Sat Aug 8 07:58:14 2020 +0900
Update wolfSSL to the latest version(v.4.4.0) (#186)
* deleted old version wolfSSL before updating
* updated wolfSSL to the latest version(v4.4.0)
* updated wolfSSL to the latest version(v4.4.0)
* added macros for timing resistance
Co-authored-by: RichardBarry <3073890+RichardBarry@users.noreply.github.com>
Co-authored-by: Ming Yue <mingyue86010@gmail.com>
commit 68518f5866aac58793c737d9a46dd07a6a816aaf
Author: RichardBarry <3073890+RichardBarry@users.noreply.github.com>
Date: Fri Aug 7 14:59:24 2020 -0700
Removed a 16MByte flash image file that was checked in by mistake (several years ago). (#173)
Remove the copies of lwIP that are no longer reference from demo projects.
Co-authored-by: Carl Lundin <53273776+lundinc2@users.noreply.github.com>
commit d4bf09480a2c77b1a25cce35b32293be61ab586f
Author: m17336 <45935231+m17336@users.noreply.github.com>
Date: Thu Aug 6 22:37:08 2020 +0300
Update previous AVR ATmega0 and AVR Dx projecs + addition of equivalent projects in MPLAB.X and IAR (#180)
* Updated indentation in AVR_ATMega4809_Atmel_Studio and AVR_Dx_Atmel_Studio projects, plus small fixes in their readme files.
* Added AVR_ATMega4809_IAR, AVR_ATMega4809_MPLAB.X, AVR_Dx_IAR and AVR_Dx_MPLAB.X demo projects.
* Removed build artefacts and added .gitignore files in AVR_ATMega4809_MPLAB.X and AVR_Dx_MPLAB.X projects.
Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
commit f32a0647c8228ddd066f5d69a85b2e49086e4c95
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Mon Aug 3 16:45:10 2020 -0700
Remove CBMC patch which is not used anymore (#187)
* Delete 0002-Change-FreeRTOS_IP_Private.h-union-to-struct.patch
* Delete 0002-Change-FreeRTOS_IP_Private.h-union-to-struct.patch
commit 08af68ef9049279b265c3d00e9c48fb9594129a8
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Sat Aug 1 16:38:23 2020 -0700
Remove dependency of CBMC on Patches (#181)
* Changes to DHCP
* CBMC DNS changes
* Changes for TCP_IP
* Changes to TCP_WIN
* Define away static to nothing
* Remove patches
* Changes after Mark's comments v1
* Update MakefileCommon.json
* Correction!
commit a7fec906a415363338449447daf10d7517b78848
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Wed Jul 29 17:39:36 2020 -0700
Misc changes (#183)
commit 07cf5e07e4a05d6775a2f9e753269f43f82cf6ba
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Wed Jul 29 16:15:38 2020 -0700
MISRA compliance changes for FreeRTOS+TCP headers (#165)
* misra changes
* Update FreeRTOS_IP_Private.h
* Update FreeRTOS_IP_Private.h
commit e903ac0fed7ce59916899e404f3e5ae5b08d1478
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Wed Jul 29 16:03:14 2020 -0700
UPD MISRA changes (#164)
Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
commit 97551bf44e7dc7dc1e4484a8fd30f699255e8569
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Wed Jul 29 15:52:00 2020 -0700
MISRA changes in FreeRTOS_TCP_WIN.c (#162)
commit f2611cc5e5999c4c87e040a8c2d2e6b5e77a16a6
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Wed Jul 29 15:38:37 2020 -0700
MISRA compliance changes in FreeRTOS_Sockets{.c/.h} (#161)
* MISRA changes Sockets
* add other changes
* Update FreeRTOSIPConfig.h
* Update FreeRTOSIPConfig.h
* Update FreeRTOSIPConfig.h
* Update FreeRTOSIPConfig.h
* correction
* Add 'U'
* Update FreeRTOS_Sockets.h
* Update FreeRTOS_Sockets.h
* Update FreeRTOS_Sockets.c
* Update FreeRTOS_Sockets.h
* Update after Gary's comments
* Correction reverted
commit ae4d4d38d9b2685bae159b4c87619cdb157c0bf7
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Wed Jul 29 13:56:57 2020 -0700
MISRA compliance changes for FreeRTOS_TCP_IP.c (#160)
* MISRA tcp-ip changes
* Changes after Hein's comments on original PR
* Update FreeRTOS_TCP_IP.c
Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
commit a457f43c66eb0f4be9d8f8678c0e3fb8d7ebd57b
Author: Carl Lundin <53273776+lundinc2@users.noreply.github.com>
Date: Tue Jul 28 13:01:38 2020 -0700
Add missing error state assignment. (#166)
commit 915af50524e15a78ceb6c62b3d33f6562621ee46
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Mon Jul 27 17:30:53 2020 -0700
Add Atmel Studio projects for ATMega4809 and AVR128DA48 (#159)
* Added explicit cast to allow roll over and avoid integer promotion during cycles counters comparison in recmutex.c.
* Fixed type mismatch between declaration and definition of function xAreSemaphoreTasksStillRunning( void ).
* Added Atmel Studio demo projects for ATMega4809 and AVR128DA48.
* Per https://www.freertos.org/upgrading-to-FreeRTOS-V8.html, I'm updating portBASE_TYPE to BaseType_t.
Signed-off-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
* Update register test for ATmega4809
- to cover r28, r29, r31.
- call public API taskYIELD() instead of portYIELD().
* Update ATmega4809 readme.md to include info for serial port setup, and minor wording fix.
Co-authored-by: Alexandru Niculae - M17336 <alexandru.niculae@microchip.com>
commit 4a7a48790d64127f85cc763721b575c51c452833
Author: Carl Lundin <53273776+lundinc2@users.noreply.github.com>
Date: Thu Jul 23 10:22:33 2020 -0700
Add Uncrustify file used for Kernel. (#163)
commit e0d62163b08769fd74f020709c398f994088ca96
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Wed Jul 22 18:06:23 2020 -0700
Sync with +TCP amazon-FreeRTOS (#158)
* DNS.c commit
* IP.c commit
* Add various source & header files
commit 8e36bee30eef2107e128edb58e83ee46e8241a91
Author: Nathan Chong <52972368+nchong-at-aws@users.noreply.github.com>
Date: Tue Jul 21 12:51:20 2020 -0400
Prove buffer lemmas (#124)
* Prove buffer lemmas
* Update queue proofs to latest kernel source
All changes were syntactic due to uncrustify code-formatting
* Strengthen prvCopyDataToQueue proof
* Add extract script for diff comparison
Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
commit c720c18ada40b502436ea811e8d03dca919726d8
Author: Hein Tibosch <hein_tibosch@yahoo.es>
Date: Tue Jul 14 05:35:44 2020 +0800
FreeRTOS+TCP Adding the combined driver for SAM4E and SAME70 v2 (#78)
* Adding a combined +TCP driver for SAM4E and SAME70
* Changes after review from Aniruddha
Co-authored-by: Hein Tibosch <hein@htibosch.net>
Co-authored-by: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
commit 4237049b12d9bb6b03694fecf6ea26a353e637c8
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Mon Jul 13 12:07:56 2020 -0700
Add changes from 2225-2227 amazon-FreeRTOS (#134)
commit 7caa32863458c4470d3c620945c30824199f524c
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Fri Jul 10 23:32:30 2020 -0700
Add Full TCP test suite - not using secure sockets (#131)
* Add Full-TCP suite
* delete unnecessary files
* Change after Joshua's comments
commit d7667a0034841f2968f9f9f805030cc608bfbce1
Author: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com>
Date: Fri Jul 3 15:45:44 2020 -0700
Remove unnecessary semicolon from the linker file (#121)
This was creating problem with the onboard LPCLink debug probe.
Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
commit 529c481c39506d0b331bfd0cdea35e5d1aeaaad0
Author: Nathan Chong <52972368+nchong-at-aws@users.noreply.github.com>
Date: Thu Jul 2 15:55:20 2020 -0400
Add VeriFast kernel queue proofs (#117)
commit d5fedeaa96b5b1d3c0f6b9b52a8064ab72ff2821
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Wed Jul 1 13:56:27 2020 -0700
Add checks in FreeRTOS_Socket.c (#104)
* Add fail-safes to FreeRTOS_Socket.c
* Use all 'pd' errors
* Correction after Hein's comments
* Correction after Hein's comments v2
* Changes after Hein's comments
* Update after Gary's comments
commit a9b2aac4e9fda2a259380156df9cc0af51384d2d
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Fri Jun 26 12:09:36 2020 -0700
Folder structure change + Fix broken Projects (#103)
* Update folder structure
* Correct project files
* Move test folder
* Some changes after Yuki's comments
commit 98bfc38bf3404414878dc68ea41753bea4e24c8e
Author: Hein Tibosch <hein_tibosch@yahoo.es>
Date: Thu Jun 25 13:01:45 2020 +0800
FreeRTOS+TCP : add memory statistics and dump packets, v3 (#83)
* FreeRTOS+TCP : add memory statistics and dump packets, v3
* Two changes as requested by Aniruddha
Co-authored-by: Hein Tibosch <hein@htibosch.net>
Co-authored-by: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
commit 072a173c9df31c75ff64bde440f3f316cedb9033
Author: S.Burch <8697966+wholl0p@users.noreply.github.com>
Date: Mon Jun 22 23:39:26 2020 +0200
Fixed Imports for Infineon XMC1100 Board (#88)
Co-authored-by: RichardBarry <3073890+RichardBarry@users.noreply.github.com>
commit 2df5eeef5763045c4c74ff0e2a4091b7d19bea89
Author: RichardBarry <3073890+RichardBarry@users.noreply.github.com>
Date: Mon Jun 8 14:22:46 2020 -0700
Feature/multiple direct to task notifications (#73)
* Add TaskNotifyArray.c with the single task tests updated to use the task notification array up to the point where the timer is created.
* Continue working on TaskNotifyArray.c to test the new task notification indexes. Next TaskNotifyArray.c will be refactored to break the tests up a bit.
* Refactor and update the comments in TaskNotifyArray.c - no functional changes.
* Change from the task notify "array" to task notification "indexed" nomenclature in the new task notification API functions that work on one particular task notification with the array of task notifications.
* Update the implementation of the taskNOTIFY_TAKE() and taskNOTIFY_WAIT() trace macros to take the array index of the task notification they are acting on.
Rename configNUMBER_OF_TASK_NOTIFICATIONS to configTASK_NOTIFICATION_ARRAY_ENTRIES.
Add FreeRTOS/Demo/Common/Minimal/TaskNotifyArray.c to the Visual Studio project - the file implements tests specific to the behaviour of the indexed task notification functions and should be used in addition to the tests already provided in FreeRTOS/Demo/Common/Minimal/TaskNotify.c.
commit b9e4ecfaf7286d8493d4a96a93fbb325534ad97b
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Fri Jun 5 11:10:58 2020 -0700
Remove Empty and Un-referenced folder from Demo (#86)
commit f11bcc8acc57a23fb03603762e758c25b9d0efb7
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Wed Jun 3 16:52:31 2020 -0700
Fix a Bug and corresponding CBMC patch (#84)
* Update remove-static-in-freertos-tcp-ip.patch
* Update FreeRTOS_TCP_IP.c
* Update remove-static-in-freertos-tcp-ip.patch
* Update remove-static-in-freertos-tcp-ip.patch
Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
commit bb9f92f771e5f6ea2b9b09c7e89130a75e562eb7
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Wed Jun 3 10:46:55 2020 -0700
Submodule FreeRTOS/Source 10bbbcf0b..6199b72fb (#82)
commit 6efc39f44be5b269168836e95aebbdb8ae77dce3
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Tue Jun 2 15:09:25 2020 -0700
Add Project for running integration tests v2 (#80)
* Project for integration tests
* relative paths in project files
* relative paths in project files-1
* relative paths in project files-2
* addressed comments
* addressed comments v2
Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
commit 0eb5909fb02bac9dc074ff1bc2fe338d77f73764
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Thu May 28 17:05:24 2020 -0700
readme.md for ATmega328PB Xplained Mini. (#76)
readme.md to get users jump started.
commit cb7edd2323a77f3dbea144c1f48f95582becc99e
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Thu May 28 10:11:58 2020 -0700
Sync with a:FR (#75)
* AFR sync
* AFR sync: CBMC
* AFR sync: CBMC: remove .bak files
* AFR sync: CBMC: more cleanup
* Corrected CBMC proofs
* Corrected CBMC patches
* Corrected CBMC patches-1
* Corrected CBMC patches-2
* remove .bak files (3)
Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
commit 6557291e5407ca7ec6beca53fced1aaa620c5c02
Author: alfred gedeon <alfred2g@hotmail.com>
Date: Wed May 27 14:44:33 2020 -0700
Test: Add Linux Networking support with demo application (#71)
* Test: Add Linux Networking support with demo application
* Test: revert files affected by uncrustify
* Test: revert files affected by uncrustify
Co-authored-by: Alfred Gedeon <gedeonag@amazon.com>
Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
commit 8b079bc394e7b205d72210ce9e052404d782938f
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Wed May 27 10:44:03 2020 -0700
ATmega328PB Xplained Mini -- demo project for ATmega port. (#70)
* Bootstrap a demo from START. No driver is added in this commit.
* Add FreeRTOS source code to project. Remove unnecessary folder nesting.
Heap_4 is used here.
* Copy over main.c, FreeRTOSConfig.h, and regtest.{c, h}.
This commit compiles, but will need some work on timer used.
* This port has 2KB RAM. We are using 1KB for heap.
Further decreasing minimum stack size, and also use stack overflow check 1 to save some stack space.
* Preserve EEPROM set to false.
* End of the line.
* Reduce register test stack size.
32 8-bit register + 10 bytes for stack frame cost. Round up to 50.
* Adding Queue test in Integer test.
- g3 to easy debugging.
- mainCHECK_PERIOD is set to 1000 ticks. Note that this port for now use WDT as tick timer, and period is set to 15ms.
- vErrorChecks, is of highest priority. So if this task gets run before other tasks, the very first check will fail.
* Avoid false alarm.
Since we don't know in which order the tasks are scheduled, clearing any error for the first entry of vErrorChecks.
Signed-off-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
* ParTest.c to init, set, toggle onboard user LED at PB5.
* Added a task to blink onboard user LED.
Need a magic number for stack size.
Signed-off-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
* Explicitly setting timing slicing to 0.
This is to avoid unecessary context switch when multiple tasks are of the same priority.
Signed-off-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
* Add taskYIELD() at the end of the loop in each register test task.
This is to give other tasks of the same priority a chance to run, regardless of scheduling algorithm.
Signed-off-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
* minor, update comment in main.c.
commit 95a3a02f95749fb7a600723076e291f9dee7426c
Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Fri May 22 16:26:59 2020 -0700
FreeRTOS-Plus: Unit testing Infrastructure and examples (#72)
* Added CMock as submodule
* Makefile added
* Removed TEMP from Makefile
* Added configuration files and header files
* Update Makefile
* Test runner working
* make clean
* Example added with README
* Update README.md
* Restored +TCP files
* Cleared +TCP changes
* removed comments from Makefile
* Update README.md
* Update README.md
* Update README.md
* Updated Test/Unit-test/readme.md
commit 5003d17feda25490e655c0f1c15d2b13e395c9f7
Author: Hein Tibosch <hein_tibosch@yahoo.es>
Date: Wed May 6 14:16:56 2020 -0400
FreeRTOS+TCP : renewing DHCP lease while network is down (#53)
Co-authored-by: Hein Tibosch <hein@htibosch.net>
Co-authored-by: Gary Wicker <14828980+gkwicker@users.noreply.github.com>
commit d95624c5d6ba95ec0474867d7165de2c28ed41b7
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Tue May 5 09:57:18 2020 -0700
Move CBMC proofs to FreeRTOS+ directory (#64)
* move CBMC proofs to FreeRTOS+ directory
* Failing proofs corrected
* ParseDNSReply proof added back
* removed queue_init.h from -Plus/Test
Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
commit 95ae7c65758a9473ea16ab08182f056f72331de2
Author: markrtuttle <tuttle@acm.org>
Date: Wed Apr 29 04:27:45 2020 +0000
Change cbmc-viewer invocation in CBMC makefile (#63)
* Exclude FreeRTOS/Demo from CBMC proof reports.
The script cbmc-viewer generates the CBMC proof reports. The script
searches source files for symbol definitions and annotates source
files with coverage information. This patch causes cbmc-viewer to
ignore the directory FreeRTOS/Demo containing 348M of data. The
script now terminates in a few seconds.
* Make report default target for CBMC Makefile.
Modify the Makefile for CBMC proofs to generate the report by default
(and not just property checking) and modify property checking to
ignore failures (due to property assertions failing) and terminating
report generation.
Co-authored-by: Mark R. Tuttle <mrtuttle@amazon.com>
commit d421ccc89f6f6473dfdd566a00567b0e1fd4cfc3
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Sat Apr 25 16:57:35 2020 -0700
Reword readme.md under ./Test. (#61)
commit 38412865985235b90dbd9da9708b68c4de5918f5
Author: Carl Lundin <53273776+lundinc2@users.noreply.github.com>
Date: Sat Apr 25 16:56:54 2020 -0700
Removed a:FR reference. (#60)
commit 4db195c916c7b13c82ab3a34a499fe606f266810
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Tue Apr 21 15:40:08 2020 -0700
Adding FreeRTOS+TCP CBMC proofs to FreeRTOS/FreeRTOS (#56)
ParseDNSReply is to be added in the next PR.
commit 40a31b6d35a866a3a6c551d95bf08dae855da5bd
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Mon Apr 13 13:58:33 2020 -0700
'uL' -> 'UL'
commit 5b3a289b69fc92089aa8bd4d1b44ab816f326f73
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Mon Apr 13 13:50:53 2020 -0700
Changes after Gary's comments
commit edf68637dd22470a8d4f59fecc15b51379bcfeda
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Fri Apr 10 16:26:03 2020 -0700
Update FreeRTOS_ARP.c
commit 35f3ac32a8899dd714a8a48952a4224fbcebc4aa
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Fri Apr 10 15:56:18 2020 -0700
correct debug output
commit 5e12a70db4b6a8e68a434489683306f040252efa
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Fri Apr 10 15:44:45 2020 -0700
Debugging flag check added
commit 4e8ac8de25ac4088b9c789b88a77cd39df4d9167
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Thu Apr 9 16:57:19 2020 -0700
Comment style consistency and Yuhui's suggestions
commit e43f7cd086096ad60491fedba69927a1e1a82f20
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Thu Apr 9 16:47:41 2020 -0700
Cleanup
commit ab3b51c7a0d880a6bf453ec63ae604e15050f310
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Thu Apr 9 16:33:03 2020 -0700
Update after Gary's comments
commit 97f7009699ffb972c0745dfdb526d1fa4e0faf84
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Wed Apr 8 14:30:15 2020 -0700
Update after richard's comments
commit a9fcafc074cec559dd67961ef44273df6180c2db
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Wed Apr 8 14:07:39 2020 -0700
Corrected the formatting
- visual studio had messed up the formatting
commit c381861014a8043ce30723fc5a8cf5107719c8df
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Wed Apr 8 13:01:12 2020 -0700
commit 2 after gary's comments
commit 75677a8d85fa802cca9058d6e23796d5043a0982
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Wed Apr 8 12:51:10 2020 -0700
Commit after Gary's comments
commit 666c0da366030109db2c0c5e7253cebb2f899db7
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Wed Apr 8 10:56:01 2020 -0700
Update after Yuhui's comments
- removed (void) from before memcpy, memset etc.
- corrected memcpy style as suggested by Yuhui
- Added logging for xNetworkInterfaceOutput. No need to configASSERT
commit 4a1148d15b6b8169d2412f8179f734683b179795
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Wed Apr 1 16:05:36 2020 -0700
Coverity + MISRA compliance
Modified code to conform to the MISRA directives more closely.
commit fa74f7dccf6b1a356993c6a894f8e1173b8c8157
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Thu Apr 2 20:26:10 2020 -0700
Removing writes to read-only PLIC interrupt pending registers.
Signed-off-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
commit 5b9777e11e16609648fb98d2f9a47553ab238950
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Tue Mar 31 10:45:23 2020 -0700
A readme file to introduce what ./Test directory is about.
commit 211bb4cbd9ae6dfa95e8d8501f37d272bde5ab26
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Tue Mar 24 15:14:24 2020 -0700
Ignore whitespace when working with patches.
commit 8156f64d1c45dd59ef12279f19a99f03e79e1f8a
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Tue Feb 25 18:04:23 2020 -0800
Copying CBMC proofs from aws/amazon-freertos repo ./tools/cbmc to this repo ./FreeRTOS/Test/CBMC as is.
The commit ID in aws/amazon-freertos is 0c8e0217f2a43bdeb364b58ae01c6c259e03ef1b.
commit 9f316c246baafa15c542a5aea81a94f26e3d6507
Author: David Vrabel <david.vrabel@cambridgeconsultants.com>
Date: Mon Mar 16 11:21:46 2020 +0000
Demo/Posix_GCC: add demo application for Posix port using GCC
This is largely a copy of the Windows demo application with a few key
changes:
- heap_3 (use malloc()/free()) so tools like valgrind "just work".
- printf() wrapped in a mutex to prevent deadlocks on the internal
pthread mutexes inside printf().
SCons (https://scons.org/) is used as the build system.
This will be built as a 64-bit application, but note that the memory
allocation trace points only record the lower 32-bits of the address.
commit f78f919b3e2f0d707531a301a8ca07cd02bc4778
Author: Markus Rinne <markus.ka.rinne@gmail.com>
Date: Thu Mar 19 21:00:24 2020 +0200
Fix function comments
commit 1cd2d38d960a3576addb224582c88489bade5141
Author: David Chalco <david@chalco.io>
Date: Fri Mar 20 10:29:05 2020 -0700
unix separators for path and remove .exe suffix from risc compiler (works on windows/mac)
commit 938b19419eded12817737ab0644e94ed2ba7e95d
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Thu Mar 19 18:23:09 2020 -0700
Removing ./FreeRTOS-Labs directory, since:
- IoT libraries are now in LTS branch.
- FAT/POSIX/Light-weight MQTT are in https://github.com/FreeRTOS/FreeRTOS-Labs.
commit 1a4abbc9e91b13fd6394464ade59d5e048320c7c
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Tue Mar 17 19:30:02 2020 -0700
Maintenance -- clean up readme.txt and add url to GitHub. (#38)
* Removing readme.txt, as now we have README.md in place.
The only information missing from README.md is about FAQ.
* Adding FAQ information in README.md.
* Adding a .url to root to redict user to FreeRTOS github home page.
commit 47bb466aa19395b7785bcb830e2e4dd35f6bafc5
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Tue Mar 17 13:07:44 2020 -0700
Update issue templates
Template maintenance.
- adding title prefix.
- adding examples to "additional context" section.
commit f506290041f56867765f8efa70ed2862125bdb7c
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Tue Mar 17 10:15:07 2020 -0700
Create SECURITY.md
Apply the recommended SECURITY.md from AWS to our repo.
commit 8982a2f80a80a2a0a47cf82de07b52101bd9d606
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Fri Mar 13 12:50:10 2020 -0700
Add ./lib directory to make sure Zynq project compiles.
commit ecf0f12aa14ad6fdafe1ef37257cbb4e03e2abd5
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Wed Mar 11 10:19:48 2020 -0700
Sync up with Amazon-freertos repo (10th March 2020) (#34)
* Sync up with amazon-freertos
* Sync up with amazon-freertos
* Sync up with amazon-freertos
commit 0acffef047973e2e61c2201fd69cd9bbd317f674
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Tue Mar 10 10:20:48 2020 -0700
GitHub PR template. (#29)
commit c40a6da2e4cb8042b56d1b174051cbbe9813781a
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Mon Mar 9 11:18:48 2020 -0700
pass payload length when calling UDP callback (#30)
* pass payload length when calling UDP callback
commit 12d580e93d4d9074b9a867632f0681a511b4ad12
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Fri Mar 6 18:16:51 2020 -0800
Update issue templates
Initial issue template. Created following https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser.
If change is needed, we could go another round.
commit 9debffb5e0e42ff716f58b2270b3af09652294af
Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Fri Mar 6 17:27:46 2020 -0800
Update README.md to remove dead link.
See the conversation https://github.com/FreeRTOS/FreeRTOS/commit/42c627b2b88cb3b487fea983d8b566a8bbae54fa#comments .
Linkage for both ```./FreeRTOS/Source``` and ```./FreeRTOS/Demo``` are removed, since it looks weird to only provide linkage to Demo.
commit 7e1a4bf563240501fc45167aee9d929c533939dd
Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com>
Date: Fri Mar 6 15:18:09 2020 -0800
Fix DHCP option Client-identifier (#28)
commit 42c627b2b88cb3b487fea983d8b566a8bbae54fa
Author: Yuhui.Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Fri Mar 6 09:15:11 2020 -0800
Update readme and revert relative URL. (#27)
* Reordering: bumping cloning instruction up.
* Rewording readme.md to be clear kernel code is a submodule of this repository.
* Reverting relative URL, since user cannot click through on GitHub page.
(With URL, user could still download the correct version of the code. Reverting simply due to UI issue.)
commit 5751ae9b60e248ebd0b4dd7c58df54364d2bb9d5
Author: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com>
Date: Fri Mar 6 09:11:42 2020 -0800
Update CORTEX_MPU_M33F_NXP_LPC55S69_MCUXpresso project (#26)
This commit updates the project for LPC55S69 so that it works with the
latest version of MCUXpresso and SDK.
Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
commit a9ffffe1f01f45f79e127c15727784984077932f
Author: Carl Lundin <53273776+lundinc2@users.noreply.github.com>
Date: Thu Mar 5 17:16:13 2020 -0800
Using Relative URL For Submoduling. (#24)
commit 52c82076b38fe73d1dc46c97abf74ae9b803696c
Author: Carl Lundin <53273776+lundinc2@users.noreply.github.com>
Date: Thu Mar 5 09:16:31 2020 -0800
use relative path to point to bundled toolchain instead (#25)
commit b877e4ec478de2c24d07ab46241070d7c66f375c
Author: lundinc2 <53273776+lundinc2@users.noreply.github.com>
Date: Tue Feb 25 13:18:38 2020 -0800
Moved vulnerability reporting and code of conduct to top of CONTRIBUTING.md (#20)
commit bef165d46799fb8faa58aaa224f80c16b6538e69
Author: Yuhui.Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Tue Feb 18 22:06:38 2020 -0800
Linking test source file from relative path. (#19)
commit 89e7bbe292afd3912d1f0b2402cc506878bad869
Author: Yuhui.Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Tue Feb 18 17:47:55 2020 -0800
A preliminary .gitignore file, to prevent us checking in files unnecessary. (#18)
https://github.com/github/gitignore.
commit c2a98127acb48c4562233230e66ca5c282688579
Author: RichardBarry <3073890+RichardBarry@users.noreply.github.com>
Date: Sun Feb 16 13:19:53 2020 -0800
Minor wording changes in the 'previous releases' section of the readme.me file. (#17)
commit 24c772d1439e5c291c0a29fce0a46996ca8afaa9
Author: Yuhui.Zheng <10982575+yuhui-zheng@users.noreply.github.com>
Date: Fri Feb 14 12:47:01 2020 -0800
Submodule kernel directory. (#16)
* Removing FreeRTOS/Source in readiness for submoduling.
* Submoduling kernel.
* README.md update due to submoduling.
When releasing, please follow these steps:
1. in local directory, clean directory and check "git status" shows "nothing to commit, working tree clean" for ALL subdirectories.
2. copy source code and instructions only to an empty folder. Git related should not be in this folder -- this covers .git, .gitignore, .github, .gitmodules, gitmessages, ......
3. zip the folder from step 2. (create both .zip and .7z)
4. attach .zip and .7z to the release. (e.g. attach these two in new release -- https://github.com/FreeRTOS/FreeRTOS/releases/new)
5. PLEASE download both, unzip, diff with your local git repo. (should not see any difference other than git related.) And, sanity check a couple of projects.
commit c3f8b91652392dc55e0d7067b90a40de5f5f0837
Author: Rashed Talukder <9218468+rashedtalukder@users.noreply.github.com>
Date: Thu Feb 13 17:47:14 2020 -0800
Update readme. Fixed typos and cli commands (#14)
commit 4723b825f2989213c1cdb2ebf4d6793e0292e363
Author: Julian Poidevin <julian-poidevin@users.noreply.github.com>
Date: Fri Feb 14 02:43:36 2020 +0100
Fixed wrong git clone SSH command (#13)
Replaced bad https URL with proper SSH URL
commit fc819b821715c42602819e58499846147a6394f5
Author: RichardBarry <3073890+RichardBarry@users.noreply.github.com>
Date: Thu Feb 13 17:42:22 2020 -0800
Correct the xTimerCreate() documentation which said NULL was returned if the timer period was passed into the function as 0, whereas that is not the case. (#15)
Add a note to the documentation for both the xTimerCreate() and xTimerCreateStatic() functions that the timer period must be greater than 0.
commit 1c711ab530b5f0dbd811d7d62e0a3763706ffff4
Author: Rashed Talukder <9218468+rashedtalukder@users.noreply.github.com>
Date: Wed Feb 12 23:00:18 2020 -0800
Updated contributions guidelines (#12)
commit 84fcc0d5317d96c6b086034093c8c1c83e050819
Author: Cobus van Eeden <35851496+cobusve@users.noreply.github.com>
Date: Wed Feb 12 15:05:06 2020 -0800
Updates to Markdown files and readme.txt (#11)
git-svn-id: http://svn.code.sf.net/p/freertos/code/trunk@2826 1d2547de-c912-0410-9cb9-b8ca96c0e9e2
Diffstat (limited to 'FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/ecc.c')
-rw-r--r-- | FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/ecc.c | 10389 |
1 files changed, 7982 insertions, 2407 deletions
diff --git a/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/ecc.c b/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/ecc.c index 897d46adf..22db7f167 100644 --- a/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/ecc.c +++ b/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/ecc.c @@ -1,8 +1,8 @@ /* ecc.c * - * Copyright (C) 2006-2015 wolfSSL Inc. + * Copyright (C) 2006-2020 wolfSSL Inc. * - * This file is part of wolfSSL. (formerly known as CyaSSL) + * This file is part of wolfSSL. * * wolfSSL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,10 +16,11 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -27,31 +28,149 @@ /* in case user set HAVE_ECC there */ #include <wolfssl/wolfcrypt/settings.h> +/* public ASN interface */ +#include <wolfssl/wolfcrypt/asn_public.h> + +/* +Possible ECC enable options: + * HAVE_ECC: Overall control of ECC default: on + * HAVE_ECC_ENCRYPT: ECC encrypt/decrypt w/AES and HKDF default: off + * HAVE_ECC_SIGN: ECC sign default: on + * HAVE_ECC_VERIFY: ECC verify default: on + * HAVE_ECC_DHE: ECC build shared secret default: on + * HAVE_ECC_CDH: ECC cofactor DH shared secret default: off + * HAVE_ECC_KEY_IMPORT: ECC Key import default: on + * HAVE_ECC_KEY_EXPORT: ECC Key export default: on + * ECC_SHAMIR: Enables Shamir calc method default: on + * HAVE_COMP_KEY: Enables compressed key default: off + * WOLFSSL_VALIDATE_ECC_IMPORT: Validate ECC key on import default: off + * WOLFSSL_VALIDATE_ECC_KEYGEN: Validate ECC key gen default: off + * WOLFSSL_CUSTOM_CURVES: Allow non-standard curves. default: off + * Includes the curve "a" variable in calculation + * ECC_DUMP_OID: Enables dump of OID encoding and sum default: off + * ECC_CACHE_CURVE: Enables cache of curve info to improve perofrmance + default: off + * FP_ECC: ECC Fixed Point Cache default: off + * USE_ECC_B_PARAM: Enable ECC curve B param default: off + (on for HAVE_COMP_KEY) + * WOLFSSL_ECC_CURVE_STATIC: default off (on for windows) + For the ECC curve paramaters `ecc_set_type` use fixed + array for hex string + */ + +/* +ECC Curve Types: + * NO_ECC_SECP Disables SECP curves default: off (not defined) + * HAVE_ECC_SECPR2 Enables SECP R2 curves default: off + * HAVE_ECC_SECPR3 Enables SECP R3 curves default: off + * HAVE_ECC_BRAINPOOL Enables Brainpool curves default: off + * HAVE_ECC_KOBLITZ Enables Koblitz curves default: off + */ + +/* +ECC Curve Sizes: + * ECC_USER_CURVES: Allows custom combination of key sizes below + * HAVE_ALL_CURVES: Enable all key sizes (on unless ECC_USER_CURVES is defined) + * HAVE_ECC112: 112 bit key + * HAVE_ECC128: 128 bit key + * HAVE_ECC160: 160 bit key + * HAVE_ECC192: 192 bit key + * HAVE_ECC224: 224 bit key + * HAVE_ECC239: 239 bit key + * NO_ECC256: Disables 256 bit key (on by default) + * HAVE_ECC320: 320 bit key + * HAVE_ECC384: 384 bit key + * HAVE_ECC512: 512 bit key + * HAVE_ECC521: 521 bit key + */ + + #ifdef HAVE_ECC +/* Make sure custom curves is enabled for Brainpool or Koblitz curve types */ +#if (defined(HAVE_ECC_BRAINPOOL) || defined(HAVE_ECC_KOBLITZ)) &&\ + !defined(WOLFSSL_CUSTOM_CURVES) + #error Brainpool and Koblitz curves requires WOLFSSL_CUSTOM_CURVES +#endif + +#if defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2) + /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */ + #define FIPS_NO_WRAPPERS + + #ifdef USE_WINDOWS_API + #pragma code_seg(".fipsA$f") + #pragma const_seg(".fipsB$f") + #endif +#endif + #include <wolfssl/wolfcrypt/ecc.h> #include <wolfssl/wolfcrypt/asn.h> #include <wolfssl/wolfcrypt/error-crypt.h> +#include <wolfssl/wolfcrypt/logging.h> +#include <wolfssl/wolfcrypt/types.h> + +#ifdef WOLFSSL_HAVE_SP_ECC +#include <wolfssl/wolfcrypt/sp.h> +#endif #ifdef HAVE_ECC_ENCRYPT #include <wolfssl/wolfcrypt/hmac.h> #include <wolfssl/wolfcrypt/aes.h> #endif +#ifdef HAVE_X963_KDF + #include <wolfssl/wolfcrypt/hash.h> +#endif + +#ifdef WOLF_CRYPTO_CB + #include <wolfssl/wolfcrypt/cryptocb.h> +#endif + #ifdef NO_INLINE #include <wolfssl/wolfcrypt/misc.h> #else + #define WOLFSSL_MISC_INCLUDED #include <wolfcrypt/src/misc.c> #endif -/* map +#if defined(FREESCALE_LTC_ECC) + #include <wolfssl/wolfcrypt/port/nxp/ksdk_port.h> +#endif - ptmul -> mulmod +#if defined(WOLFSSL_STM32_PKA) + #include <wolfssl/wolfcrypt/port/st/stm32.h> +#endif -*/ +#ifdef WOLFSSL_SP_MATH + #define GEN_MEM_ERR MP_MEM +#elif defined(USE_FAST_MATH) + #define GEN_MEM_ERR FP_MEM +#else + #define GEN_MEM_ERR MP_MEM +#endif + + +/* internal ECC states */ +enum { + ECC_STATE_NONE = 0, + + ECC_STATE_SHARED_SEC_GEN, + ECC_STATE_SHARED_SEC_RES, + + ECC_STATE_SIGN_DO, + ECC_STATE_SIGN_ENCODE, + ECC_STATE_VERIFY_DECODE, + ECC_STATE_VERIFY_DO, + ECC_STATE_VERIFY_RES, +}; + + +/* map + ptmul -> mulmod +*/ -/* p256 curve on by default whether user curves or not */ +/* 256-bit curve on by default whether user curves or not */ #if defined(HAVE_ECC112) || defined(HAVE_ALL_CURVES) #define ECC112 #endif @@ -67,939 +186,2334 @@ #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES) #define ECC224 #endif +#if defined(HAVE_ECC239) || defined(HAVE_ALL_CURVES) + #define ECC239 +#endif #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES) #define ECC256 #endif +#if defined(HAVE_ECC320) || defined(HAVE_ALL_CURVES) + #define ECC320 +#endif #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES) #define ECC384 #endif +#if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES) + #define ECC512 +#endif #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES) #define ECC521 #endif - - -/* This holds the key settings. ***MUST*** be organized by size from - smallest to largest. */ +/* The encoded OID's for ECC curves */ +#ifdef ECC112 + #ifndef NO_ECC_SECP + #ifdef HAVE_OID_ENCODING + #define CODED_SECP112R1 {1,3,132,0,6} + #define CODED_SECP112R1_SZ 5 + #else + #define CODED_SECP112R1 {0x2B,0x81,0x04,0x00,0x06} + #define CODED_SECP112R1_SZ 5 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_secp112r1[] = CODED_SECP112R1; + #else + #define ecc_oid_secp112r1 CODED_SECP112R1 + #endif + #define ecc_oid_secp112r1_sz CODED_SECP112R1_SZ + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_SECPR2 + #ifdef HAVE_OID_ENCODING + #define CODED_SECP112R2 {1,3,132,0,7} + #define CODED_SECP112R2_SZ 5 + #else + #define CODED_SECP112R2 {0x2B,0x81,0x04,0x00,0x07} + #define CODED_SECP112R2_SZ 5 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_secp112r2[] = CODED_SECP112R2; + #else + #define ecc_oid_secp112r2 CODED_SECP112R2 + #endif + #define ecc_oid_secp112r2_sz CODED_SECP112R2_SZ + #endif /* HAVE_ECC_SECPR2 */ +#endif /* ECC112 */ +#ifdef ECC128 + #ifndef NO_ECC_SECP + #ifdef HAVE_OID_ENCODING + #define CODED_SECP128R1 {1,3,132,0,28} + #define CODED_SECP128R1_SZ 5 + #else + #define CODED_SECP128R1 {0x2B,0x81,0x04,0x00,0x1C} + #define CODED_SECP128R1_SZ 5 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_secp128r1[] = CODED_SECP128R1; + #else + #define ecc_oid_secp128r1 CODED_SECP128R1 + #endif + #define ecc_oid_secp128r1_sz CODED_SECP128R1_SZ + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_SECPR2 + #ifdef HAVE_OID_ENCODING + #define CODED_SECP128R2 {1,3,132,0,29} + #define CODED_SECP128R2_SZ 5 + #else + #define CODED_SECP128R2 {0x2B,0x81,0x04,0x00,0x1D} + #define CODED_SECP128R2_SZ 5 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_secp128r2[] = CODED_SECP128R2; + #else + #define ecc_oid_secp128r2 CODED_SECP128R2 + #endif + #define ecc_oid_secp128r2_sz CODED_SECP128R2_SZ + #endif /* HAVE_ECC_SECPR2 */ +#endif /* ECC128 */ +#ifdef ECC160 + #ifndef NO_ECC_SECP + #ifdef HAVE_OID_ENCODING + #define CODED_SECP160R1 {1,3,132,0,8} + #define CODED_SECP160R1_SZ 5 + #else + #define CODED_SECP160R1 {0x2B,0x81,0x04,0x00,0x08} + #define CODED_SECP160R1_SZ 5 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_secp160r1[] = CODED_SECP160R1; + #else + #define ecc_oid_secp160r1 CODED_SECP160R1 + #endif + #define ecc_oid_secp160r1_sz CODED_SECP160R1_SZ + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_SECPR2 + #ifdef HAVE_OID_ENCODING + #define CODED_SECP160R2 {1,3,132,0,30} + #define CODED_SECP160R2_SZ 5 + #else + #define CODED_SECP160R2 {0x2B,0x81,0x04,0x00,0x1E} + #define CODED_SECP160R2_SZ 5 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_secp160r2[] = CODED_SECP160R2; + #else + #define ecc_oid_secp160r2 CODED_SECP160R2 + #endif + #define ecc_oid_secp160r2_sz CODED_SECP160R2_SZ + #endif /* HAVE_ECC_SECPR2 */ + #ifdef HAVE_ECC_KOBLITZ + #ifdef HAVE_OID_ENCODING + #define CODED_SECP160K1 {1,3,132,0,9} + #define CODED_SECP160K1_SZ 5 + #else + #define CODED_SECP160K1 {0x2B,0x81,0x04,0x00,0x09} + #define CODED_SECP160K1_SZ 5 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_secp160k1[] = CODED_SECP160K1; + #else + #define ecc_oid_secp160k1 CODED_SECP160K1 + #endif + #define ecc_oid_secp160k1_sz CODED_SECP160K1_SZ + #endif /* HAVE_ECC_KOBLITZ */ + #ifdef HAVE_ECC_BRAINPOOL + #ifdef HAVE_OID_ENCODING + #define CODED_BRAINPOOLP160R1 {1,3,36,3,3,2,8,1,1,1} + #define CODED_BRAINPOOLP160R1_SZ 10 + #else + #define CODED_BRAINPOOLP160R1 {0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x01} + #define CODED_BRAINPOOLP160R1_SZ 9 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_brainpoolp160r1[] = CODED_BRAINPOOLP160R1; + #else + #define ecc_oid_brainpoolp160r1 CODED_BRAINPOOLP160R1 + #endif + #define ecc_oid_brainpoolp160r1_sz CODED_BRAINPOOLP160R1_SZ + #endif /* HAVE_ECC_BRAINPOOL */ +#endif /* ECC160 */ +#ifdef ECC192 + #ifndef NO_ECC_SECP + #ifdef HAVE_OID_ENCODING + #define CODED_SECP192R1 {1,2,840,10045,3,1,1} + #define CODED_SECP192R1_SZ 7 + #else + #define CODED_SECP192R1 {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x01} + #define CODED_SECP192R1_SZ 8 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_secp192r1[] = CODED_SECP192R1; + #else + #define ecc_oid_secp192r1 CODED_SECP192R1 + #endif + #define ecc_oid_secp192r1_sz CODED_SECP192R1_SZ + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_SECPR2 + #ifdef HAVE_OID_ENCODING + #define CODED_PRIME192V2 {1,2,840,10045,3,1,2} + #define CODED_PRIME192V2_SZ 7 + #else + #define CODED_PRIME192V2 {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x02} + #define CODED_PRIME192V2_SZ 8 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_prime192v2[] = CODED_PRIME192V2; + #else + #define ecc_oid_prime192v2 CODED_PRIME192V2 + #endif + #define ecc_oid_prime192v2_sz CODED_PRIME192V2_SZ + #endif /* HAVE_ECC_SECPR2 */ + #ifdef HAVE_ECC_SECPR3 + #ifdef HAVE_OID_ENCODING + #define CODED_PRIME192V3 {1,2,840,10045,3,1,3} + #define CODED_PRIME192V3_SZ 7 + #else + #define CODED_PRIME192V3 {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x03} + #define CODED_PRIME192V3_SZ 8 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_prime192v3[] = CODED_PRIME192V3; + #else + #define ecc_oid_prime192v3 CODED_PRIME192V3 + #endif + #define ecc_oid_prime192v3_sz CODED_PRIME192V3_SZ + #endif /* HAVE_ECC_SECPR3 */ + #ifdef HAVE_ECC_KOBLITZ + #ifdef HAVE_OID_ENCODING + #define CODED_SECP192K1 {1,3,132,0,31} + #define CODED_SECP192K1_SZ 5 + #else + #define CODED_SECP192K1 {0x2B,0x81,0x04,0x00,0x1F} + #define CODED_SECP192K1_SZ 5 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_secp192k1[] = CODED_SECP192K1; + #else + #define ecc_oid_secp192k1 CODED_SECP192K1 + #endif + #define ecc_oid_secp192k1_sz CODED_SECP192K1_SZ + #endif /* HAVE_ECC_KOBLITZ */ + #ifdef HAVE_ECC_BRAINPOOL + #ifdef HAVE_OID_ENCODING + #define CODED_BRAINPOOLP192R1 {1,3,36,3,3,2,8,1,1,3} + #define CODED_BRAINPOOLP192R1_SZ 10 + #else + #define CODED_BRAINPOOLP192R1 {0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x03} + #define CODED_BRAINPOOLP192R1_SZ 9 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_brainpoolp192r1[] = CODED_BRAINPOOLP192R1; + #else + #define ecc_oid_brainpoolp192r1 CODED_BRAINPOOLP192R1 + #endif + #define ecc_oid_brainpoolp192r1_sz CODED_BRAINPOOLP192R1_SZ + #endif /* HAVE_ECC_BRAINPOOL */ +#endif /* ECC192 */ +#ifdef ECC224 + #ifndef NO_ECC_SECP + #ifdef HAVE_OID_ENCODING + #define CODED_SECP224R1 {1,3,132,0,33} + #define CODED_SECP224R1_SZ 5 + #else + #define CODED_SECP224R1 {0x2B,0x81,0x04,0x00,0x21} + #define CODED_SECP224R1_SZ 5 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_secp224r1[] = CODED_SECP224R1; + #else + #define ecc_oid_secp224r1 CODED_SECP224R1 + #endif + #define ecc_oid_secp224r1_sz CODED_SECP224R1_SZ + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_KOBLITZ + #ifdef HAVE_OID_ENCODING + #define CODED_SECP224K1 {1,3,132,0,32} + #define CODED_SECP224K1_SZ 5 + #else + #define CODED_SECP224K1 {0x2B,0x81,0x04,0x00,0x20} + #define CODED_SECP224K1_SZ 5 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_secp224k1[] = CODED_SECP224K1; + #else + #define ecc_oid_secp224k1 CODED_SECP224K1 + #endif + #define ecc_oid_secp224k1_sz CODED_SECP224K1_SZ + #endif /* HAVE_ECC_KOBLITZ */ + #ifdef HAVE_ECC_BRAINPOOL + #ifdef HAVE_OID_ENCODING + #define CODED_BRAINPOOLP224R1 {1,3,36,3,3,2,8,1,1,5} + #define CODED_BRAINPOOLP224R1_SZ 10 + #else + #define CODED_BRAINPOOLP224R1 {0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x05} + #define CODED_BRAINPOOLP224R1_SZ 9 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_brainpoolp224r1[] = CODED_BRAINPOOLP224R1; + #else + #define ecc_oid_brainpoolp224r1 CODED_BRAINPOOLP224R1 + #endif + #define ecc_oid_brainpoolp224r1_sz CODED_BRAINPOOLP224R1_SZ + #endif /* HAVE_ECC_BRAINPOOL */ +#endif /* ECC224 */ +#ifdef ECC239 + #ifndef NO_ECC_SECP + #ifdef HAVE_OID_ENCODING + #define CODED_PRIME239V1 {1,2,840,10045,3,1,4} + #define CODED_PRIME239V1_SZ 7 + #else + #define CODED_PRIME239V1 {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x04} + #define CODED_PRIME239V1_SZ 8 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_prime239v1[] = CODED_PRIME239V1; + #else + #define ecc_oid_prime239v1 CODED_PRIME239V1 + #endif + #define ecc_oid_prime239v1_sz CODED_PRIME239V1_SZ + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_SECPR2 + #ifdef HAVE_OID_ENCODING + #define CODED_PRIME239V2 {1,2,840,10045,3,1,5} + #define CODED_PRIME239V2_SZ 7 + #else + #define CODED_PRIME239V2 {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x05} + #define CODED_PRIME239V2_SZ 8 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_prime239v2[] = CODED_PRIME239V2; + #else + #define ecc_oid_prime239v2 CODED_PRIME239V2 + #endif + #define ecc_oid_prime239v2_sz CODED_PRIME239V2_SZ + #endif /* HAVE_ECC_SECPR2 */ + #ifdef HAVE_ECC_SECPR3 + #ifdef HAVE_OID_ENCODING + #define CODED_PRIME239V3 {1,2,840,10045,3,1,6} + #define CODED_PRIME239V3_SZ 7 + #else + #define CODED_PRIME239V3 {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x06} + #define CODED_PRIME239V3_SZ 8 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_prime239v3[] = CODED_PRIME239V3; + #else + #define ecc_oid_prime239v3 CODED_PRIME239V3 + #endif + #define ecc_oid_prime239v3_sz CODED_PRIME239V3_SZ + #endif /* HAVE_ECC_SECPR3 */ +#endif /* ECC239 */ +#ifdef ECC256 + #ifndef NO_ECC_SECP + #ifdef HAVE_OID_ENCODING + #define CODED_SECP256R1 {1,2,840,10045,3,1,7} + #define CODED_SECP256R1_SZ 7 + #else + #define CODED_SECP256R1 {0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07} + #define CODED_SECP256R1_SZ 8 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_secp256r1[] = CODED_SECP256R1; + #else + #define ecc_oid_secp256r1 CODED_SECP256R1 + #endif + #define ecc_oid_secp256r1_sz CODED_SECP256R1_SZ + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_KOBLITZ + #ifdef HAVE_OID_ENCODING + #define CODED_SECP256K1 {1,3,132,0,10} + #define CODED_SECP256K1_SZ 5 + #else + #define CODED_SECP256K1 {0x2B,0x81,0x04,0x00,0x0A} + #define CODED_SECP256K1_SZ 5 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_secp256k1[] = CODED_SECP256K1; + #else + #define ecc_oid_secp256k1 CODED_SECP256K1 + #endif + #define ecc_oid_secp256k1_sz CODED_SECP256K1_SZ + #endif /* HAVE_ECC_KOBLITZ */ + #ifdef HAVE_ECC_BRAINPOOL + #ifdef HAVE_OID_ENCODING + #define CODED_BRAINPOOLP256R1 {1,3,36,3,3,2,8,1,1,7} + #define CODED_BRAINPOOLP256R1_SZ 10 + #else + #define CODED_BRAINPOOLP256R1 {0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x07} + #define CODED_BRAINPOOLP256R1_SZ 9 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_brainpoolp256r1[] = CODED_BRAINPOOLP256R1; + #else + #define ecc_oid_brainpoolp256r1 CODED_BRAINPOOLP256R1 + #endif + #define ecc_oid_brainpoolp256r1_sz CODED_BRAINPOOLP256R1_SZ + #endif /* HAVE_ECC_BRAINPOOL */ +#endif /* ECC256 */ +#ifdef ECC320 + #ifdef HAVE_ECC_BRAINPOOL + #ifdef HAVE_OID_ENCODING + #define CODED_BRAINPOOLP320R1 {1,3,36,3,3,2,8,1,1,9} + #define CODED_BRAINPOOLP320R1_SZ 10 + #else + #define CODED_BRAINPOOLP320R1 {0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x09} + #define CODED_BRAINPOOLP320R1_SZ 9 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_brainpoolp320r1[] = CODED_BRAINPOOLP320R1; + #else + #define ecc_oid_brainpoolp320r1 CODED_BRAINPOOLP320R1 + #endif + #define ecc_oid_brainpoolp320r1_sz CODED_BRAINPOOLP320R1_SZ + #endif /* HAVE_ECC_BRAINPOOL */ +#endif /* ECC320 */ +#ifdef ECC384 + #ifndef NO_ECC_SECP + #ifdef HAVE_OID_ENCODING + #define CODED_SECP384R1 {1,3,132,0,34} + #define CODED_SECP384R1_SZ 5 + #else + #define CODED_SECP384R1 {0x2B,0x81,0x04,0x00,0x22} + #define CODED_SECP384R1_SZ 5 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_secp384r1[] = CODED_SECP384R1; + #define CODED_SECP384R1_OID ecc_oid_secp384r1 + #else + #define ecc_oid_secp384r1 CODED_SECP384R1 + #endif + #define ecc_oid_secp384r1_sz CODED_SECP384R1_SZ + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_BRAINPOOL + #ifdef HAVE_OID_ENCODING + #define CODED_BRAINPOOLP384R1 {1,3,36,3,3,2,8,1,1,11} + #define CODED_BRAINPOOLP384R1_SZ 10 + #else + #define CODED_BRAINPOOLP384R1 {0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0B} + #define CODED_BRAINPOOLP384R1_SZ 9 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_brainpoolp384r1[] = CODED_BRAINPOOLP384R1; + #else + #define ecc_oid_brainpoolp384r1 CODED_BRAINPOOLP384R1 + #endif + #define ecc_oid_brainpoolp384r1_sz CODED_BRAINPOOLP384R1_SZ + #endif /* HAVE_ECC_BRAINPOOL */ +#endif /* ECC384 */ +#ifdef ECC512 + #ifdef HAVE_ECC_BRAINPOOL + #ifdef HAVE_OID_ENCODING + #define CODED_BRAINPOOLP512R1 {1,3,36,3,3,2,8,1,1,13} + #define CODED_BRAINPOOLP512R1_SZ 10 + #else + #define CODED_BRAINPOOLP512R1 {0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0D} + #define CODED_BRAINPOOLP512R1_SZ 9 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_brainpoolp512r1[] = CODED_BRAINPOOLP512R1; + #else + #define ecc_oid_brainpoolp512r1 CODED_BRAINPOOLP512R1 + #endif + #define ecc_oid_brainpoolp512r1_sz CODED_BRAINPOOLP512R1_SZ + #endif /* HAVE_ECC_BRAINPOOL */ +#endif /* ECC512 */ +#ifdef ECC521 + #ifndef NO_ECC_SECP + #ifdef HAVE_OID_ENCODING + #define CODED_SECP521R1 {1,3,132,0,35} + #define CODED_SECP521R1_SZ 5 + #else + #define CODED_SECP521R1 {0x2B,0x81,0x04,0x00,0x23} + #define CODED_SECP521R1_SZ 5 + #endif + #ifndef WOLFSSL_ECC_CURVE_STATIC + static const ecc_oid_t ecc_oid_secp521r1[] = CODED_SECP521R1; + #else + #define ecc_oid_secp521r1 CODED_SECP521R1 + #endif + #define ecc_oid_secp521r1_sz CODED_SECP521R1_SZ + #endif /* !NO_ECC_SECP */ +#endif /* ECC521 */ + + +/* This holds the key settings. + ***MUST*** be organized by size from smallest to largest. */ const ecc_set_type ecc_sets[] = { #ifdef ECC112 -{ - 14, - "SECP112R1", - "DB7C2ABF62E35E668076BEAD208B", - "DB7C2ABF62E35E668076BEAD2088", - "659EF8BA043916EEDE8911702B22", - "DB7C2ABF62E35E7628DFAC6561C5", - "09487239995A5EE76B55F9C2F098", - "A89CE5AF8724C0A23E0E0FF77500" -}, -#endif + #ifndef NO_ECC_SECP + { + 14, /* size/bytes */ + ECC_SECP112R1, /* ID */ + "SECP112R1", /* curve name */ + "DB7C2ABF62E35E668076BEAD208B", /* prime */ + "DB7C2ABF62E35E668076BEAD2088", /* A */ + "659EF8BA043916EEDE8911702B22", /* B */ + "DB7C2ABF62E35E7628DFAC6561C5", /* order */ + "9487239995A5EE76B55F9C2F098", /* Gx */ + "A89CE5AF8724C0A23E0E0FF77500", /* Gy */ + ecc_oid_secp112r1, /* oid/oidSz */ + ecc_oid_secp112r1_sz, + ECC_SECP112R1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_SECPR2 + { + 14, /* size/bytes */ + ECC_SECP112R2, /* ID */ + "SECP112R2", /* curve name */ + "DB7C2ABF62E35E668076BEAD208B", /* prime */ + "6127C24C05F38A0AAAF65C0EF02C", /* A */ + "51DEF1815DB5ED74FCC34C85D709", /* B */ + "36DF0AAFD8B8D7597CA10520D04B", /* order */ + "4BA30AB5E892B4E1649DD0928643", /* Gx */ + "ADCD46F5882E3747DEF36E956E97", /* Gy */ + ecc_oid_secp112r2, /* oid/oidSz */ + ecc_oid_secp112r2_sz, + ECC_SECP112R2_OID, /* oid sum */ + 4, /* cofactor */ + }, + #endif /* HAVE_ECC_SECPR2 */ +#endif /* ECC112 */ #ifdef ECC128 -{ - 16, - "SECP128R1", - "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", - "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC", - "E87579C11079F43DD824993C2CEE5ED3", - "FFFFFFFE0000000075A30D1B9038A115", - "161FF7528B899B2D0C28607CA52C5B86", - "CF5AC8395BAFEB13C02DA292DDED7A83", -}, -#endif + #ifndef NO_ECC_SECP + { + 16, /* size/bytes */ + ECC_SECP128R1, /* ID */ + "SECP128R1", /* curve name */ + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", /* prime */ + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC", /* A */ + "E87579C11079F43DD824993C2CEE5ED3", /* B */ + "FFFFFFFE0000000075A30D1B9038A115", /* order */ + "161FF7528B899B2D0C28607CA52C5B86", /* Gx */ + "CF5AC8395BAFEB13C02DA292DDED7A83", /* Gy */ + ecc_oid_secp128r1, /* oid/oidSz */ + ecc_oid_secp128r1_sz, + ECC_SECP128R1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_SECPR2 + { + 16, /* size/bytes */ + ECC_SECP128R2, /* ID */ + "SECP128R2", /* curve name */ + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", /* prime */ + "D6031998D1B3BBFEBF59CC9BBFF9AEE1", /* A */ + "5EEEFCA380D02919DC2C6558BB6D8A5D", /* B */ + "3FFFFFFF7FFFFFFFBE0024720613B5A3", /* order */ + "7B6AA5D85E572983E6FB32A7CDEBC140", /* Gx */ + "27B6916A894D3AEE7106FE805FC34B44", /* Gy */ + ecc_oid_secp128r2, /* oid/oidSz */ + ecc_oid_secp128r2_sz, + ECC_SECP128R2_OID, /* oid sum */ + 4, /* cofactor */ + }, + #endif /* HAVE_ECC_SECPR2 */ +#endif /* ECC128 */ #ifdef ECC160 -{ - 20, - "SECP160R1", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC", - "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", - "0100000000000000000001F4C8F927AED3CA752257", - "4A96B5688EF573284664698968C38BB913CBFC82", - "23A628553168947D59DCC912042351377AC5FB32", -}, -#endif + #ifndef NO_ECC_SECP + { + 20, /* size/bytes */ + ECC_SECP160R1, /* ID */ + "SECP160R1", /* curve name */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", /* prime */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC", /* A */ + "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", /* B */ + "100000000000000000001F4C8F927AED3CA752257",/* order */ + "4A96B5688EF573284664698968C38BB913CBFC82", /* Gx */ + "23A628553168947D59DCC912042351377AC5FB32", /* Gy */ + ecc_oid_secp160r1, /* oid/oidSz */ + ecc_oid_secp160r1_sz, + ECC_SECP160R1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_SECPR2 + { + 20, /* size/bytes */ + ECC_SECP160R2, /* ID */ + "SECP160R2", /* curve name */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", /* prime */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70", /* A */ + "B4E134D3FB59EB8BAB57274904664D5AF50388BA", /* B */ + "100000000000000000000351EE786A818F3A1A16B",/* order */ + "52DCB034293A117E1F4FF11B30F7199D3144CE6D", /* Gx */ + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E", /* Gy */ + ecc_oid_secp160r2, /* oid/oidSz */ + ecc_oid_secp160r2_sz, + ECC_SECP160R2_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* HAVE_ECC_SECPR2 */ + #ifdef HAVE_ECC_KOBLITZ + { + 20, /* size/bytes */ + ECC_SECP160K1, /* ID */ + "SECP160K1", /* curve name */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", /* prime */ + "0000000000000000000000000000000000000000", /* A */ + "0000000000000000000000000000000000000007", /* B */ + "100000000000000000001B8FA16DFAB9ACA16B6B3",/* order */ + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB", /* Gx */ + "938CF935318FDCED6BC28286531733C3F03C4FEE", /* Gy */ + ecc_oid_secp160k1, /* oid/oidSz */ + ecc_oid_secp160k1_sz, + ECC_SECP160K1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* HAVE_ECC_KOBLITZ */ + #ifdef HAVE_ECC_BRAINPOOL + { + 20, /* size/bytes */ + ECC_BRAINPOOLP160R1, /* ID */ + "BRAINPOOLP160R1", /* curve name */ + "E95E4A5F737059DC60DFC7AD95B3D8139515620F", /* prime */ + "340E7BE2A280EB74E2BE61BADA745D97E8F7C300", /* A */ + "1E589A8595423412134FAA2DBDEC95C8D8675E58", /* B */ + "E95E4A5F737059DC60DF5991D45029409E60FC09", /* order */ + "BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3", /* Gx */ + "1667CB477A1A8EC338F94741669C976316DA6321", /* Gy */ + ecc_oid_brainpoolp160r1, /* oid/oidSz */ + ecc_oid_brainpoolp160r1_sz, + ECC_BRAINPOOLP160R1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* HAVE_ECC_BRAINPOOL */ +#endif /* ECC160 */ #ifdef ECC192 -{ - 24, - "ECC-192", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", - "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", - "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", - "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", - "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811", -}, -#endif + #ifndef NO_ECC_SECP + { + 24, /* size/bytes */ + ECC_SECP192R1, /* ID */ + "SECP192R1", /* curve name */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", /* prime */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", /* A */ + "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", /* B */ + "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", /* order */ + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", /* Gx */ + "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811", /* Gy */ + ecc_oid_secp192r1, /* oid/oidSz */ + ecc_oid_secp192r1_sz, + ECC_SECP192R1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_SECPR2 + { + 24, /* size/bytes */ + ECC_PRIME192V2, /* ID */ + "PRIME192V2", /* curve name */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", /* prime */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", /* A */ + "CC22D6DFB95C6B25E49C0D6364A4E5980C393AA21668D953", /* B */ + "FFFFFFFFFFFFFFFFFFFFFFFE5FB1A724DC80418648D8DD31", /* order */ + "EEA2BAE7E1497842F2DE7769CFE9C989C072AD696F48034A", /* Gx */ + "6574D11D69B6EC7A672BB82A083DF2F2B0847DE970B2DE15", /* Gy */ + ecc_oid_prime192v2, /* oid/oidSz */ + ecc_oid_prime192v2_sz, + ECC_PRIME192V2_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* HAVE_ECC_SECPR2 */ + #ifdef HAVE_ECC_SECPR3 + { + 24, /* size/bytes */ + ECC_PRIME192V3, /* ID */ + "PRIME192V3", /* curve name */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", /* prime */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", /* A */ + "22123DC2395A05CAA7423DAECCC94760A7D462256BD56916", /* B */ + "FFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13", /* order */ + "7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896", /* Gx */ + "38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0", /* Gy */ + ecc_oid_prime192v3, /* oid/oidSz */ + ecc_oid_prime192v3_sz, + ECC_PRIME192V3_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* HAVE_ECC_SECPR3 */ + #ifdef HAVE_ECC_KOBLITZ + { + 24, /* size/bytes */ + ECC_SECP192K1, /* ID */ + "SECP192K1", /* curve name */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", /* prime */ + "000000000000000000000000000000000000000000000000", /* A */ + "000000000000000000000000000000000000000000000003", /* B */ + "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", /* order */ + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D", /* Gx */ + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", /* Gy */ + ecc_oid_secp192k1, /* oid/oidSz */ + ecc_oid_secp192k1_sz, + ECC_SECP192K1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* HAVE_ECC_KOBLITZ */ + #ifdef HAVE_ECC_BRAINPOOL + { + 24, /* size/bytes */ + ECC_BRAINPOOLP192R1, /* ID */ + "BRAINPOOLP192R1", /* curve name */ + "C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", /* prime */ + "6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF", /* A */ + "469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9", /* B */ + "C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", /* order */ + "C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD6", /* Gx */ + "14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F", /* Gy */ + ecc_oid_brainpoolp192r1, /* oid/oidSz */ + ecc_oid_brainpoolp192r1_sz, + ECC_BRAINPOOLP192R1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* HAVE_ECC_BRAINPOOL */ +#endif /* ECC192 */ #ifdef ECC224 -{ - 28, - "ECC-224", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", - "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", - "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", - "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", -}, -#endif + #ifndef NO_ECC_SECP + { + 28, /* size/bytes */ + ECC_SECP224R1, /* ID */ + "SECP224R1", /* curve name */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", /* prime */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", /* A */ + "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", /* B */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", /* order */ + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", /* Gx */ + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", /* Gy */ + ecc_oid_secp224r1, /* oid/oidSz */ + ecc_oid_secp224r1_sz, + ECC_SECP224R1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_KOBLITZ + { + 28, /* size/bytes */ + ECC_SECP224K1, /* ID */ + "SECP224K1", /* curve name */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", /* prime */ + "00000000000000000000000000000000000000000000000000000000", /* A */ + "00000000000000000000000000000000000000000000000000000005", /* B */ + "10000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7",/* order */ + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", /* Gx */ + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", /* Gy */ + ecc_oid_secp224k1, /* oid/oidSz */ + ecc_oid_secp224k1_sz, + ECC_SECP224K1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* HAVE_ECC_KOBLITZ */ + #ifdef HAVE_ECC_BRAINPOOL + { + 28, /* size/bytes */ + ECC_BRAINPOOLP224R1, /* ID */ + "BRAINPOOLP224R1", /* curve name */ + "D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", /* prime */ + "68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43", /* A */ + "2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B", /* B */ + "D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", /* order */ + "0D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D", /* Gx */ + "58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD", /* Gy */ + ecc_oid_brainpoolp224r1, /* oid/oidSz */ + ecc_oid_brainpoolp224r1_sz, + ECC_BRAINPOOLP224R1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* HAVE_ECC_BRAINPOOL */ +#endif /* ECC224 */ +#ifdef ECC239 + #ifndef NO_ECC_SECP + { + 30, /* size/bytes */ + ECC_PRIME239V1, /* ID */ + "PRIME239V1", /* curve name */ + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", /* prime */ + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", /* A */ + "6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A", /* B */ + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E5E9A9F5D9071FBD1522688909D0B", /* order */ + "0FFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF", /* Gx */ + "7DEBE8E4E90A5DAE6E4054CA530BA04654B36818CE226B39FCCB7B02F1AE", /* Gy */ + ecc_oid_prime239v1, /* oid/oidSz */ + ecc_oid_prime239v1_sz, + ECC_PRIME239V1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_SECPR2 + { + 30, /* size/bytes */ + ECC_PRIME239V2, /* ID */ + "PRIME239V2", /* curve name */ + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", /* prime */ + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", /* A */ + "617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C", /* B */ + "7FFFFFFFFFFFFFFFFFFFFFFF800000CFA7E8594377D414C03821BC582063", /* order */ + "38AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7", /* Gx */ + "5B0125E4DBEA0EC7206DA0FC01D9B081329FB555DE6EF460237DFF8BE4BA", /* Gy */ + ecc_oid_prime239v2, /* oid/oidSz */ + ecc_oid_prime239v2_sz, + ECC_PRIME239V2_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* HAVE_ECC_SECPR2 */ + #ifdef HAVE_ECC_SECPR3 + { + 30, /* size/bytes */ + ECC_PRIME239V3, /* ID */ + "PRIME239V3", /* curve name */ + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", /* prime */ + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", /* A */ + "255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E", /* B */ + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF975DEB41B3A6057C3C432146526551", /* order */ + "6768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A", /* Gx */ + "1607E6898F390C06BC1D552BAD226F3B6FCFE48B6E818499AF18E3ED6CF3", /* Gy */ + ecc_oid_prime239v3, /* oid/oidSz */ + ecc_oid_prime239v3_sz, + ECC_PRIME239V3_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* HAVE_ECC_SECPR3 */ +#endif /* ECC239 */ #ifdef ECC256 -{ - 32, - "ECC-256", - "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", - "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", - "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", - "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", - "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", - "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", -}, -#endif + #ifndef NO_ECC_SECP + { + 32, /* size/bytes */ + ECC_SECP256R1, /* ID */ + "SECP256R1", /* curve name */ + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", /* prime */ + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", /* A */ + "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", /* B */ + "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", /* order */ + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", /* Gx */ + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", /* Gy */ + ecc_oid_secp256r1, /* oid/oidSz */ + ecc_oid_secp256r1_sz, + ECC_SECP256R1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_KOBLITZ + { + 32, /* size/bytes */ + ECC_SECP256K1, /* ID */ + "SECP256K1", /* curve name */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", /* prime */ + "0000000000000000000000000000000000000000000000000000000000000000", /* A */ + "0000000000000000000000000000000000000000000000000000000000000007", /* B */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", /* order */ + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", /* Gx */ + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", /* Gy */ + ecc_oid_secp256k1, /* oid/oidSz */ + ecc_oid_secp256k1_sz, + ECC_SECP256K1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* HAVE_ECC_KOBLITZ */ + #ifdef HAVE_ECC_BRAINPOOL + { + 32, /* size/bytes */ + ECC_BRAINPOOLP256R1, /* ID */ + "BRAINPOOLP256R1", /* curve name */ + "A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", /* prime */ + "7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", /* A */ + "26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", /* B */ + "A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", /* order */ + "8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262", /* Gx */ + "547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", /* Gy */ + ecc_oid_brainpoolp256r1, /* oid/oidSz */ + ecc_oid_brainpoolp256r1_sz, + ECC_BRAINPOOLP256R1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* HAVE_ECC_BRAINPOOL */ +#endif /* ECC256 */ +#ifdef ECC320 + #ifdef HAVE_ECC_BRAINPOOL + { + 40, /* size/bytes */ + ECC_BRAINPOOLP320R1, /* ID */ + "BRAINPOOLP320R1", /* curve name */ + "D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", /* prime */ + "3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4", /* A */ + "520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6", /* B */ + "D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", /* order */ + "43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E20611", /* Gx */ + "14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1", /* Gy */ + ecc_oid_brainpoolp320r1, ecc_oid_brainpoolp320r1_sz, /* oid/oidSz */ + ECC_BRAINPOOLP320R1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* HAVE_ECC_BRAINPOOL */ +#endif /* ECC320 */ #ifdef ECC384 -{ - 48, - "ECC-384", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", - "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", - "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", - "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", -}, -#endif + #ifndef NO_ECC_SECP + { + 48, /* size/bytes */ + ECC_SECP384R1, /* ID */ + "SECP384R1", /* curve name */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", /* prime */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", /* A */ + "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", /* B */ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", /* order */ + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", /* Gx */ + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", /* Gy */ + ecc_oid_secp384r1, ecc_oid_secp384r1_sz, /* oid/oidSz */ + ECC_SECP384R1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* !NO_ECC_SECP */ + #ifdef HAVE_ECC_BRAINPOOL + { + 48, /* size/bytes */ + ECC_BRAINPOOLP384R1, /* ID */ + "BRAINPOOLP384R1", /* curve name */ + "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", /* prime */ + "7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", /* A */ + "04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", /* B */ + "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", /* order */ + "1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E", /* Gx */ + "8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315", /* Gy */ + ecc_oid_brainpoolp384r1, ecc_oid_brainpoolp384r1_sz, /* oid/oidSz */ + ECC_BRAINPOOLP384R1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* HAVE_ECC_BRAINPOOL */ +#endif /* ECC384 */ +#ifdef ECC512 + #ifdef HAVE_ECC_BRAINPOOL + { + 64, /* size/bytes */ + ECC_BRAINPOOLP512R1, /* ID */ + "BRAINPOOLP512R1", /* curve name */ + "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", /* prime */ + "7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", /* A */ + "3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", /* B */ + "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", /* order */ + "81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822", /* Gx */ + "7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892", /* Gy */ + ecc_oid_brainpoolp512r1, ecc_oid_brainpoolp512r1_sz, /* oid/oidSz */ + ECC_BRAINPOOLP512R1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* HAVE_ECC_BRAINPOOL */ +#endif /* ECC512 */ #ifdef ECC521 -{ - 66, - "ECC-521", - "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", - "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", - "51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", - "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", - "C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66", - "11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", -}, + #ifndef NO_ECC_SECP + { + 66, /* size/bytes */ + ECC_SECP521R1, /* ID */ + "SECP521R1", /* curve name */ + "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", /* prime */ + "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", /* A */ + "51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", /* B */ + "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", /* order */ + "C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66", /* Gx */ + "11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", /* Gy */ + ecc_oid_secp521r1, ecc_oid_secp521r1_sz, /* oid/oidSz */ + ECC_SECP521R1_OID, /* oid sum */ + 1, /* cofactor */ + }, + #endif /* !NO_ECC_SECP */ +#endif /* ECC521 */ +#if defined(WOLFSSL_CUSTOM_CURVES) && defined(ECC_CACHE_CURVE) + /* place holder for custom curve index for cache */ + { + 1, /* non-zero */ + ECC_CURVE_CUSTOM, + #ifndef WOLFSSL_ECC_CURVE_STATIC + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + #else + {0},{0},{0},{0},{0},{0},{0},{0}, + #endif + 0, 0, 0 + }, #endif -{ - 0, - NULL, NULL, NULL, NULL, NULL, NULL, NULL -} + { + 0, + ECC_CURVE_INVALID, + #ifndef WOLFSSL_ECC_CURVE_STATIC + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + #else + {0},{0},{0},{0},{0},{0},{0},{0}, + #endif + 0, 0, 0 + } }; +#define ECC_SET_COUNT (sizeof(ecc_sets)/sizeof(ecc_set_type)) +const size_t ecc_sets_count = ECC_SET_COUNT - 1; -ecc_point* ecc_new_point(void); -void ecc_del_point(ecc_point* p); -int ecc_map(ecc_point*, mp_int*, mp_digit*); -int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R, - mp_int* modulus, mp_digit* mp); -int ecc_projective_dbl_point(ecc_point* P, ecc_point* R, mp_int* modulus, - mp_digit* mp); -static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, - int map); -static int ecc_check_pubkey_order(ecc_key* key, mp_int* prime, mp_int* order); -#ifdef ECC_SHAMIR -static int ecc_mul2add(ecc_point* A, mp_int* kA, ecc_point* B, mp_int* kB, - ecc_point* C, mp_int* modulus); +#ifdef HAVE_OID_ENCODING + /* encoded OID cache */ + typedef struct { + word32 oidSz; + byte oid[ECC_MAX_OID_LEN]; + } oid_cache_t; + static oid_cache_t ecc_oid_cache[ECC_SET_COUNT]; #endif -int mp_jacobi(mp_int* a, mp_int* p, int* c); -int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret); -int mp_submod(mp_int* a, mp_int* b, mp_int* c, mp_int* d); #ifdef HAVE_COMP_KEY static int wc_ecc_export_x963_compressed(ecc_key*, byte* out, word32* outLen); #endif -/* helper for either lib */ -static int get_digit_count(mp_int* a) + +#if (defined(WOLFSSL_VALIDATE_ECC_KEYGEN) || !defined(WOLFSSL_SP_MATH)) && \ + !defined(WOLFSSL_ATECC508A) +static int ecc_check_pubkey_order(ecc_key* key, ecc_point* pubkey, mp_int* a, + mp_int* prime, mp_int* order); +#endif + +int mp_jacobi(mp_int* a, mp_int* n, int* c); +int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret); + + +/* Curve Specs */ +typedef struct ecc_curve_spec { + const ecc_set_type* dp; + + mp_int* prime; + mp_int* Af; + #ifdef USE_ECC_B_PARAM + mp_int* Bf; + #endif + mp_int* order; + mp_int* Gx; + mp_int* Gy; + +#ifdef ECC_CACHE_CURVE + mp_int prime_lcl; + mp_int Af_lcl; + #ifdef USE_ECC_B_PARAM + mp_int Bf_lcl; + #endif + mp_int order_lcl; + mp_int Gx_lcl; + mp_int Gy_lcl; +#else + mp_int* spec_ints; + word32 spec_count; + word32 spec_use; +#endif + + byte load_mask; +} ecc_curve_spec; + +enum ecc_curve_load_mask { + ECC_CURVE_FIELD_NONE = 0x00, + ECC_CURVE_FIELD_PRIME = 0x01, + ECC_CURVE_FIELD_AF = 0x02, +#ifdef USE_ECC_B_PARAM + ECC_CURVE_FIELD_BF = 0x04, +#endif + ECC_CURVE_FIELD_ORDER = 0x08, + ECC_CURVE_FIELD_GX = 0x10, + ECC_CURVE_FIELD_GY = 0x20, +#ifdef USE_ECC_B_PARAM + ECC_CURVE_FIELD_ALL = 0x3F, + ECC_CURVE_FIELD_COUNT = 6, +#else + ECC_CURVE_FIELD_ALL = 0x3B, + ECC_CURVE_FIELD_COUNT = 5, +#endif +}; + +#ifdef ECC_CACHE_CURVE + /* cache (mp_int) of the curve parameters */ + static ecc_curve_spec* ecc_curve_spec_cache[ECC_SET_COUNT]; + #ifndef SINGLE_THREADED + static wolfSSL_Mutex ecc_curve_cache_mutex; + #endif + + #define DECLARE_CURVE_SPECS(curve, intcount) ecc_curve_spec* curve = NULL + #define ALLOC_CURVE_SPECS(intcount) + #define FREE_CURVE_SPECS() +#elif defined(WOLFSSL_SMALL_STACK) + #define DECLARE_CURVE_SPECS(curve, intcount) \ + mp_int* spec_ints = NULL; \ + ecc_curve_spec curve_lcl; \ + ecc_curve_spec* curve = &curve_lcl; \ + XMEMSET(curve, 0, sizeof(ecc_curve_spec)); \ + curve->spec_count = intcount + + #define ALLOC_CURVE_SPECS(intcount) \ + spec_ints = (mp_int*)XMALLOC(sizeof(mp_int) * (intcount), NULL, \ + DYNAMIC_TYPE_ECC); \ + if (spec_ints == NULL) \ + return MEMORY_E; \ + curve->spec_ints = spec_ints + #define FREE_CURVE_SPECS() \ + XFREE(spec_ints, NULL, DYNAMIC_TYPE_ECC) +#else + #define DECLARE_CURVE_SPECS(curve, intcount) \ + mp_int spec_ints[(intcount)]; \ + ecc_curve_spec curve_lcl; \ + ecc_curve_spec* curve = &curve_lcl; \ + XMEMSET(curve, 0, sizeof(ecc_curve_spec)); \ + curve->spec_ints = spec_ints; \ + curve->spec_count = intcount + #define ALLOC_CURVE_SPECS(intcount) + #define FREE_CURVE_SPECS() +#endif /* ECC_CACHE_CURVE */ + +static void _wc_ecc_curve_free(ecc_curve_spec* curve) { - if (a == NULL) - return 0; + if (curve == NULL) { + return; + } - return a->used; + if (curve->load_mask & ECC_CURVE_FIELD_PRIME) + mp_clear(curve->prime); + if (curve->load_mask & ECC_CURVE_FIELD_AF) + mp_clear(curve->Af); +#ifdef USE_ECC_B_PARAM + if (curve->load_mask & ECC_CURVE_FIELD_BF) + mp_clear(curve->Bf); +#endif + if (curve->load_mask & ECC_CURVE_FIELD_ORDER) + mp_clear(curve->order); + if (curve->load_mask & ECC_CURVE_FIELD_GX) + mp_clear(curve->Gx); + if (curve->load_mask & ECC_CURVE_FIELD_GY) + mp_clear(curve->Gy); + + curve->load_mask = 0; } -/* helper for either lib */ -static mp_digit get_digit(mp_int* a, int n) +static void wc_ecc_curve_free(ecc_curve_spec* curve) { - if (a == NULL) - return 0; - - return (n >= a->used || n < 0) ? 0 : a->dp[n]; + /* don't free cached curves */ +#ifndef ECC_CACHE_CURVE + _wc_ecc_curve_free(curve); +#endif + (void)curve; } +static int wc_ecc_curve_load_item(const char* src, mp_int** dst, + ecc_curve_spec* curve, byte mask) +{ + int err; -#if defined(USE_FAST_MATH) +#ifndef ECC_CACHE_CURVE + /* get mp_int from temp */ + if (curve->spec_use >= curve->spec_count) { + WOLFSSL_MSG("Invalid DECLARE_CURVE_SPECS count"); + return ECC_BAD_ARG_E; + } + *dst = &curve->spec_ints[curve->spec_use++]; +#endif -/* fast math accelerated version, but not for fp ecc yet */ + err = mp_init(*dst); + if (err == MP_OKAY) { + curve->load_mask |= mask; -/** - Add two ECC points - P The point to add - Q The point to add - R [out] The destination of the double - modulus The modulus of the field the ECC curve is in - mp The "b" value from montgomery_setup() - return MP_OKAY on success -*/ -int ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, - mp_int* modulus, mp_digit* mp) -{ - fp_int t1, t2, x, y, z; - int err; + err = mp_read_radix(*dst, src, MP_RADIX_HEX); - if (P == NULL || Q == NULL || R == NULL || modulus == NULL || mp == NULL) - return ECC_BAD_ARG_E; + #ifdef HAVE_WOLF_BIGINT + if (err == MP_OKAY) + err = wc_mp_to_bigint(*dst, &(*dst)->raw); + #endif + } + return err; +} - if ((err = mp_init_multi(&t1, &t2, &x, &y, &z, NULL)) != MP_OKAY) { - return err; - } +static int wc_ecc_curve_load(const ecc_set_type* dp, ecc_curve_spec** pCurve, + byte load_mask) +{ + int ret = 0, x; + ecc_curve_spec* curve; + byte load_items = 0; /* mask of items to load */ - /* should we dbl instead? */ - fp_sub(modulus, Q->y, &t1); - if ( (fp_cmp(P->x, Q->x) == FP_EQ) && - (get_digit_count(Q->z) && fp_cmp(P->z, Q->z) == FP_EQ) && - (fp_cmp(P->y, Q->y) == FP_EQ || fp_cmp(P->y, &t1) == FP_EQ)) { - return ecc_projective_dbl_point(P, R, modulus, mp); - } + if (dp == NULL || pCurve == NULL) + return BAD_FUNC_ARG; - fp_copy(P->x, &x); - fp_copy(P->y, &y); - fp_copy(P->z, &z); +#ifdef ECC_CACHE_CURVE + x = wc_ecc_get_curve_idx(dp->id); + if (x == ECC_CURVE_INVALID) + return ECC_BAD_ARG_E; - /* if Z is one then these are no-operations */ - if (get_digit_count(Q->z)) { - /* T1 = Z' * Z' */ - fp_sqr(Q->z, &t1); - fp_montgomery_reduce(&t1, modulus, *mp); - /* X = X * T1 */ - fp_mul(&t1, &x, &x); - fp_montgomery_reduce(&x, modulus, *mp); - /* T1 = Z' * T1 */ - fp_mul(Q->z, &t1, &t1); - fp_montgomery_reduce(&t1, modulus, *mp); - /* Y = Y * T1 */ - fp_mul(&t1, &y, &y); - fp_montgomery_reduce(&y, modulus, *mp); - } +#if !defined(SINGLE_THREADED) + ret = wc_LockMutex(&ecc_curve_cache_mutex); + if (ret != 0) { + return ret; + } +#endif - /* T1 = Z*Z */ - fp_sqr(&z, &t1); - fp_montgomery_reduce(&t1, modulus, *mp); - /* T2 = X' * T1 */ - fp_mul(Q->x, &t1, &t2); - fp_montgomery_reduce(&t2, modulus, *mp); - /* T1 = Z * T1 */ - fp_mul(&z, &t1, &t1); - fp_montgomery_reduce(&t1, modulus, *mp); - /* T1 = Y' * T1 */ - fp_mul(Q->y, &t1, &t1); - fp_montgomery_reduce(&t1, modulus, *mp); + /* make sure cache has been allocated */ + if (ecc_curve_spec_cache[x] == NULL) { + ecc_curve_spec_cache[x] = (ecc_curve_spec*)XMALLOC( + sizeof(ecc_curve_spec), NULL, DYNAMIC_TYPE_ECC); + if (ecc_curve_spec_cache[x] == NULL) { + #if defined(ECC_CACHE_CURVE) && !defined(SINGLE_THREADED) + wc_UnLockMutex(&ecc_curve_cache_mutex); + #endif + return MEMORY_E; + } + XMEMSET(ecc_curve_spec_cache[x], 0, sizeof(ecc_curve_spec)); + } - /* Y = Y - T1 */ - fp_sub(&y, &t1, &y); - if (fp_cmp_d(&y, 0) == FP_LT) { - fp_add(&y, modulus, &y); - } - /* T1 = 2T1 */ - fp_add(&t1, &t1, &t1); - if (fp_cmp(&t1, modulus) != FP_LT) { - fp_sub(&t1, modulus, &t1); - } - /* T1 = Y + T1 */ - fp_add(&t1, &y, &t1); - if (fp_cmp(&t1, modulus) != FP_LT) { - fp_sub(&t1, modulus, &t1); - } - /* X = X - T2 */ - fp_sub(&x, &t2, &x); - if (fp_cmp_d(&x, 0) == FP_LT) { - fp_add(&x, modulus, &x); - } - /* T2 = 2T2 */ - fp_add(&t2, &t2, &t2); - if (fp_cmp(&t2, modulus) != FP_LT) { - fp_sub(&t2, modulus, &t2); - } - /* T2 = X + T2 */ - fp_add(&t2, &x, &t2); - if (fp_cmp(&t2, modulus) != FP_LT) { - fp_sub(&t2, modulus, &t2); - } + /* set curve pointer to cache */ + *pCurve = ecc_curve_spec_cache[x]; + +#endif /* ECC_CACHE_CURVE */ + curve = *pCurve; + + /* make sure the curve is initialized */ + if (curve->dp != dp) { + curve->load_mask = 0; + + #ifdef ECC_CACHE_CURVE + curve->prime = &curve->prime_lcl; + curve->Af = &curve->Af_lcl; + #ifdef USE_ECC_B_PARAM + curve->Bf = &curve->Bf_lcl; + #endif + curve->order = &curve->order_lcl; + curve->Gx = &curve->Gx_lcl; + curve->Gy = &curve->Gy_lcl; + #endif + } + curve->dp = dp; /* set dp info */ + + /* determine items to load */ + load_items = (((byte)~(word32)curve->load_mask) & load_mask); + curve->load_mask |= load_items; + + /* load items */ + x = 0; + if (load_items & ECC_CURVE_FIELD_PRIME) + x += wc_ecc_curve_load_item(dp->prime, &curve->prime, curve, + ECC_CURVE_FIELD_PRIME); + if (load_items & ECC_CURVE_FIELD_AF) + x += wc_ecc_curve_load_item(dp->Af, &curve->Af, curve, + ECC_CURVE_FIELD_AF); +#ifdef USE_ECC_B_PARAM + if (load_items & ECC_CURVE_FIELD_BF) + x += wc_ecc_curve_load_item(dp->Bf, &curve->Bf, curve, + ECC_CURVE_FIELD_BF); +#endif + if (load_items & ECC_CURVE_FIELD_ORDER) + x += wc_ecc_curve_load_item(dp->order, &curve->order, curve, + ECC_CURVE_FIELD_ORDER); + if (load_items & ECC_CURVE_FIELD_GX) + x += wc_ecc_curve_load_item(dp->Gx, &curve->Gx, curve, + ECC_CURVE_FIELD_GX); + if (load_items & ECC_CURVE_FIELD_GY) + x += wc_ecc_curve_load_item(dp->Gy, &curve->Gy, curve, + ECC_CURVE_FIELD_GY); + + /* check for error */ + if (x != 0) { + wc_ecc_curve_free(curve); + ret = MP_READ_E; + } - /* if Z' != 1 */ - if (get_digit_count(Q->z)) { - /* Z = Z * Z' */ - fp_mul(&z, Q->z, &z); - fp_montgomery_reduce(&z, modulus, *mp); - } +#if defined(ECC_CACHE_CURVE) && !defined(SINGLE_THREADED) + wc_UnLockMutex(&ecc_curve_cache_mutex); +#endif - /* Z = Z * X */ - fp_mul(&z, &x, &z); - fp_montgomery_reduce(&z, modulus, *mp); + return ret; +} - /* T1 = T1 * X */ - fp_mul(&t1, &x, &t1); - fp_montgomery_reduce(&t1, modulus, *mp); - /* X = X * X */ - fp_sqr(&x, &x); - fp_montgomery_reduce(&x, modulus, *mp); - /* T2 = T2 * x */ - fp_mul(&t2, &x, &t2); - fp_montgomery_reduce(&t2, modulus, *mp); - /* T1 = T1 * X */ - fp_mul(&t1, &x, &t1); - fp_montgomery_reduce(&t1, modulus, *mp); - - /* X = Y*Y */ - fp_sqr(&y, &x); - fp_montgomery_reduce(&x, modulus, *mp); - /* X = X - T2 */ - fp_sub(&x, &t2, &x); - if (fp_cmp_d(&x, 0) == FP_LT) { - fp_add(&x, modulus, &x); - } +#ifdef ECC_CACHE_CURVE +int wc_ecc_curve_cache_init(void) +{ + int ret = 0; +#if defined(ECC_CACHE_CURVE) && !defined(SINGLE_THREADED) + ret = wc_InitMutex(&ecc_curve_cache_mutex); +#endif + return ret; +} - /* T2 = T2 - X */ - fp_sub(&t2, &x, &t2); - if (fp_cmp_d(&t2, 0) == FP_LT) { - fp_add(&t2, modulus, &t2); - } - /* T2 = T2 - X */ - fp_sub(&t2, &x, &t2); - if (fp_cmp_d(&t2, 0) == FP_LT) { - fp_add(&t2, modulus, &t2); - } - /* T2 = T2 * Y */ - fp_mul(&t2, &y, &t2); - fp_montgomery_reduce(&t2, modulus, *mp); - /* Y = T2 - T1 */ - fp_sub(&t2, &t1, &y); - if (fp_cmp_d(&y, 0) == FP_LT) { - fp_add(&y, modulus, &y); - } - /* Y = Y/2 */ - if (fp_isodd(&y)) { - fp_add(&y, modulus, &y); - } - fp_div_2(&y, &y); +void wc_ecc_curve_cache_free(void) +{ + int x; + + /* free all ECC curve caches */ + for (x = 0; x < (int)ECC_SET_COUNT; x++) { + if (ecc_curve_spec_cache[x]) { + _wc_ecc_curve_free(ecc_curve_spec_cache[x]); + XFREE(ecc_curve_spec_cache[x], NULL, DYNAMIC_TYPE_ECC); + ecc_curve_spec_cache[x] = NULL; + } + } - fp_copy(&x, R->x); - fp_copy(&y, R->y); - fp_copy(&z, R->z); - - return MP_OKAY; +#if defined(ECC_CACHE_CURVE) && !defined(SINGLE_THREADED) + wc_FreeMutex(&ecc_curve_cache_mutex); +#endif } +#endif /* ECC_CACHE_CURVE */ -/** - Double an ECC point - P The point to double - R [out] The destination of the double - modulus The modulus of the field the ECC curve is in - mp The "b" value from montgomery_setup() - return MP_OKAY on success -*/ -int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* modulus, - mp_digit* mp) +/* Retrieve the curve name for the ECC curve id. + * + * curve_id The id of the curve. + * returns the name stored from the curve if available, otherwise NULL. + */ +const char* wc_ecc_get_name(int curve_id) { - fp_int t1, t2; - int err; + int curve_idx = wc_ecc_get_curve_idx(curve_id); + if (curve_idx == ECC_CURVE_INVALID) + return NULL; + return ecc_sets[curve_idx].name; +} - if (P == NULL || R == NULL || modulus == NULL || mp == NULL) - return ECC_BAD_ARG_E; +int wc_ecc_set_curve(ecc_key* key, int keysize, int curve_id) +{ + if (keysize <= 0 && curve_id < 0) { + return BAD_FUNC_ARG; + } - if (P != R) { - fp_copy(P->x, R->x); - fp_copy(P->y, R->y); - fp_copy(P->z, R->z); - } + if (keysize > ECC_MAXSIZE) { + return ECC_BAD_ARG_E; + } - if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) { - return err; - } + /* handle custom case */ + if (key->idx != ECC_CUSTOM_IDX) { + int x; - /* t1 = Z * Z */ - fp_sqr(R->z, &t1); - fp_montgomery_reduce(&t1, modulus, *mp); - /* Z = Y * Z */ - fp_mul(R->z, R->y, R->z); - fp_montgomery_reduce(R->z, modulus, *mp); - /* Z = 2Z */ - fp_add(R->z, R->z, R->z); - if (fp_cmp(R->z, modulus) != FP_LT) { - fp_sub(R->z, modulus, R->z); - } - - /* &t2 = X - T1 */ - fp_sub(R->x, &t1, &t2); - if (fp_cmp_d(&t2, 0) == FP_LT) { - fp_add(&t2, modulus, &t2); - } - /* T1 = X + T1 */ - fp_add(&t1, R->x, &t1); - if (fp_cmp(&t1, modulus) != FP_LT) { - fp_sub(&t1, modulus, &t1); - } - /* T2 = T1 * T2 */ - fp_mul(&t1, &t2, &t2); - fp_montgomery_reduce(&t2, modulus, *mp); - /* T1 = 2T2 */ - fp_add(&t2, &t2, &t1); - if (fp_cmp(&t1, modulus) != FP_LT) { - fp_sub(&t1, modulus, &t1); - } - /* T1 = T1 + T2 */ - fp_add(&t1, &t2, &t1); - if (fp_cmp(&t1, modulus) != FP_LT) { - fp_sub(&t1, modulus, &t1); - } + /* default values */ + key->idx = 0; + key->dp = NULL; - /* Y = 2Y */ - fp_add(R->y, R->y, R->y); - if (fp_cmp(R->y, modulus) != FP_LT) { - fp_sub(R->y, modulus, R->y); - } - /* Y = Y * Y */ - fp_sqr(R->y, R->y); - fp_montgomery_reduce(R->y, modulus, *mp); - /* T2 = Y * Y */ - fp_sqr(R->y, &t2); - fp_montgomery_reduce(&t2, modulus, *mp); - /* T2 = T2/2 */ - if (fp_isodd(&t2)) { - fp_add(&t2, modulus, &t2); - } - fp_div_2(&t2, &t2); - /* Y = Y * X */ - fp_mul(R->y, R->x, R->y); - fp_montgomery_reduce(R->y, modulus, *mp); + /* find ecc_set based on curve_id or key size */ + for (x = 0; ecc_sets[x].size != 0; x++) { + if (curve_id > ECC_CURVE_DEF) { + if (curve_id == ecc_sets[x].id) + break; + } + else if (keysize <= ecc_sets[x].size) { + break; + } + } + if (ecc_sets[x].size == 0) { + WOLFSSL_MSG("ECC Curve not found"); + return ECC_CURVE_OID_E; + } - /* X = T1 * T1 */ - fp_sqr(&t1, R->x); - fp_montgomery_reduce(R->x, modulus, *mp); - /* X = X - Y */ - fp_sub(R->x, R->y, R->x); - if (fp_cmp_d(R->x, 0) == FP_LT) { - fp_add(R->x, modulus, R->x); - } - /* X = X - Y */ - fp_sub(R->x, R->y, R->x); - if (fp_cmp_d(R->x, 0) == FP_LT) { - fp_add(R->x, modulus, R->x); - } + key->idx = x; + key->dp = &ecc_sets[x]; + } - /* Y = Y - X */ - fp_sub(R->y, R->x, R->y); - if (fp_cmp_d(R->y, 0) == FP_LT) { - fp_add(R->y, modulus, R->y); - } - /* Y = Y * T1 */ - fp_mul(R->y, &t1, R->y); - fp_montgomery_reduce(R->y, modulus, *mp); - /* Y = Y - T2 */ - fp_sub(R->y, &t2, R->y); - if (fp_cmp_d(R->y, 0) == FP_LT) { - fp_add(R->y, modulus, R->y); - } - - return MP_OKAY; + return 0; } -#else /* USE_FAST_MATH */ + +#ifdef ALT_ECC_SIZE +static void alt_fp_init(mp_int* a) +{ + a->size = FP_SIZE_ECC; + mp_zero(a); +} +#endif /* ALT_ECC_SIZE */ + + +#ifndef WOLFSSL_ATECC508A + +#if !defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_PUBLIC_ECC_ADD_DBL) /** Add two ECC points P The point to add Q The point to add R [out] The destination of the double + a ECC curve parameter a modulus The modulus of the field the ECC curve is in mp The "b" value from montgomery_setup() return MP_OKAY on success */ int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R, - mp_int* modulus, mp_digit* mp) + mp_int* a, mp_int* modulus, mp_digit mp) { - mp_int t1; - mp_int t2; - mp_int x; - mp_int y; - mp_int z; - int err; +#ifndef WOLFSSL_SP_MATH +#ifdef WOLFSSL_SMALL_STACK + mp_int* t1 = NULL; + mp_int* t2 = NULL; +#ifdef ALT_ECC_SIZE + mp_int* rx = NULL; + mp_int* ry = NULL; + mp_int* rz = NULL; +#endif +#else + mp_int t1[1], t2[1]; +#ifdef ALT_ECC_SIZE + mp_int rx[1], ry[1], rz[1]; +#endif +#endif + mp_int *x, *y, *z; + int err; - if (P == NULL || Q == NULL || R == NULL || modulus == NULL || mp == NULL) + if (P == NULL || Q == NULL || R == NULL || modulus == NULL) { return ECC_BAD_ARG_E; + } + + /* if Q == R then swap P and Q, so we don't require a local x,y,z */ + if (Q == R) { + ecc_point* tPt = P; + P = Q; + Q = tPt; + } - if ((err = mp_init_multi(&t1, &t2, &x, &y, &z, NULL)) != MP_OKAY) { +#ifdef WOLFSSL_SMALL_STACK +#ifdef WOLFSSL_SMALL_STACK_CACHE + if (R->key != NULL) { + t1 = R->key->t1; + t2 = R->key->t2; +#ifdef ALT_ECC_SIZE + rx = R->key->x; + ry = R->key->y; + rz = R->key->z; +#endif + } + else +#endif /* WOLFSSL_SMALL_STACK_CACHE */ + { + t1 = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + t2 = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + if (t1 == NULL || t2 == NULL) { + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); + XFREE(t2, NULL, DYNAMIC_TYPE_ECC); + return MEMORY_E; + } +#ifdef ALT_ECC_SIZE + rx = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + ry = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + rz = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + if (rx == NULL || ry == NULL || rz == NULL) { + XFREE(rz, NULL, DYNAMIC_TYPE_ECC); + XFREE(ry, NULL, DYNAMIC_TYPE_ECC); + XFREE(rx, NULL, DYNAMIC_TYPE_ECC); + XFREE(t2, NULL, DYNAMIC_TYPE_ECC); + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); + return MEMORY_E; + } +#endif + } +#endif /* WOLFSSL_SMALL_STACK */ + + if ((err = mp_init_multi(t1, t2, NULL, NULL, NULL, NULL)) != MP_OKAY) { +#ifdef WOLFSSL_SMALL_STACK + #ifdef WOLFSSL_SMALL_STACK_CACHE + if (R->key == NULL) + #endif + { + #ifdef ALT_ECC_SIZE + XFREE(rz, NULL, DYNAMIC_TYPE_ECC); + XFREE(ry, NULL, DYNAMIC_TYPE_ECC); + XFREE(rx, NULL, DYNAMIC_TYPE_ECC); + #endif + XFREE(t2, NULL, DYNAMIC_TYPE_ECC); + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); + } +#endif return err; } - - /* should we dbl instead? */ - err = mp_sub(modulus, Q->y, &t1); + /* should we dbl instead? */ + if (err == MP_OKAY) + err = mp_sub(modulus, Q->y, t1); if (err == MP_OKAY) { - if ( (mp_cmp(P->x, Q->x) == MP_EQ) && + if ( (mp_cmp(P->x, Q->x) == MP_EQ) && (get_digit_count(Q->z) && mp_cmp(P->z, Q->z) == MP_EQ) && - (mp_cmp(P->y, Q->y) == MP_EQ || mp_cmp(P->y, &t1) == MP_EQ)) { - mp_clear(&t1); - mp_clear(&t2); - mp_clear(&x); - mp_clear(&y); - mp_clear(&z); - - return ecc_projective_dbl_point(P, R, modulus, mp); + (mp_cmp(P->y, Q->y) == MP_EQ || mp_cmp(P->y, t1) == MP_EQ)) { + mp_clear(t1); + mp_clear(t2); + #ifdef WOLFSSL_SMALL_STACK + #ifdef WOLFSSL_SMALL_STACK_CACHE + if (R->key == NULL) + #endif + { + #ifdef ALT_ECC_SIZE + XFREE(rz, NULL, DYNAMIC_TYPE_ECC); + XFREE(ry, NULL, DYNAMIC_TYPE_ECC); + XFREE(rx, NULL, DYNAMIC_TYPE_ECC); + #endif + XFREE(t2, NULL, DYNAMIC_TYPE_ECC); + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); + } + #endif + return ecc_projective_dbl_point(P, R, a, modulus, mp); } } + if (err != MP_OKAY) { + goto done; + } + +/* If use ALT_ECC_SIZE we need to use local stack variable since + ecc_point x,y,z is reduced size */ +#ifdef ALT_ECC_SIZE + /* Use local stack variable */ + x = rx; + y = ry; + z = rz; + + if ((err = mp_init_multi(x, y, z, NULL, NULL, NULL)) != MP_OKAY) { + goto done; + } +#else + /* Use destination directly */ + x = R->x; + y = R->y; + z = R->z; +#endif + if (err == MP_OKAY) - err = mp_copy(P->x, &x); + err = mp_copy(P->x, x); if (err == MP_OKAY) - err = mp_copy(P->y, &y); + err = mp_copy(P->y, y); if (err == MP_OKAY) - err = mp_copy(P->z, &z); + err = mp_copy(P->z, z); /* if Z is one then these are no-operations */ if (err == MP_OKAY) { - if (get_digit_count(Q->z)) { + if (!mp_iszero(Q->z)) { /* T1 = Z' * Z' */ - err = mp_sqr(Q->z, &t1); + err = mp_sqr(Q->z, t1); if (err == MP_OKAY) - err = mp_montgomery_reduce(&t1, modulus, *mp); + err = mp_montgomery_reduce(t1, modulus, mp); /* X = X * T1 */ if (err == MP_OKAY) - err = mp_mul(&t1, &x, &x); + err = mp_mul(t1, x, x); if (err == MP_OKAY) - err = mp_montgomery_reduce(&x, modulus, *mp); + err = mp_montgomery_reduce(x, modulus, mp); /* T1 = Z' * T1 */ if (err == MP_OKAY) - err = mp_mul(Q->z, &t1, &t1); + err = mp_mul(Q->z, t1, t1); if (err == MP_OKAY) - err = mp_montgomery_reduce(&t1, modulus, *mp); + err = mp_montgomery_reduce(t1, modulus, mp); /* Y = Y * T1 */ if (err == MP_OKAY) - err = mp_mul(&t1, &y, &y); + err = mp_mul(t1, y, y); if (err == MP_OKAY) - err = mp_montgomery_reduce(&y, modulus, *mp); + err = mp_montgomery_reduce(y, modulus, mp); } } /* T1 = Z*Z */ if (err == MP_OKAY) - err = mp_sqr(&z, &t1); + err = mp_sqr(z, t1); if (err == MP_OKAY) - err = mp_montgomery_reduce(&t1, modulus, *mp); + err = mp_montgomery_reduce(t1, modulus, mp); /* T2 = X' * T1 */ if (err == MP_OKAY) - err = mp_mul(Q->x, &t1, &t2); + err = mp_mul(Q->x, t1, t2); if (err == MP_OKAY) - err = mp_montgomery_reduce(&t2, modulus, *mp); + err = mp_montgomery_reduce(t2, modulus, mp); /* T1 = Z * T1 */ if (err == MP_OKAY) - err = mp_mul(&z, &t1, &t1); + err = mp_mul(z, t1, t1); if (err == MP_OKAY) - err = mp_montgomery_reduce(&t1, modulus, *mp); + err = mp_montgomery_reduce(t1, modulus, mp); /* T1 = Y' * T1 */ if (err == MP_OKAY) - err = mp_mul(Q->y, &t1, &t1); + err = mp_mul(Q->y, t1, t1); if (err == MP_OKAY) - err = mp_montgomery_reduce(&t1, modulus, *mp); + err = mp_montgomery_reduce(t1, modulus, mp); /* Y = Y - T1 */ if (err == MP_OKAY) - err = mp_sub(&y, &t1, &y); + err = mp_sub(y, t1, y); if (err == MP_OKAY) { - if (mp_cmp_d(&y, 0) == MP_LT) - err = mp_add(&y, modulus, &y); + if (mp_isneg(y)) + err = mp_add(y, modulus, y); } /* T1 = 2T1 */ if (err == MP_OKAY) - err = mp_add(&t1, &t1, &t1); + err = mp_add(t1, t1, t1); if (err == MP_OKAY) { - if (mp_cmp(&t1, modulus) != MP_LT) - err = mp_sub(&t1, modulus, &t1); + if (mp_cmp(t1, modulus) != MP_LT) + err = mp_sub(t1, modulus, t1); } /* T1 = Y + T1 */ if (err == MP_OKAY) - err = mp_add(&t1, &y, &t1); + err = mp_add(t1, y, t1); if (err == MP_OKAY) { - if (mp_cmp(&t1, modulus) != MP_LT) - err = mp_sub(&t1, modulus, &t1); + if (mp_cmp(t1, modulus) != MP_LT) + err = mp_sub(t1, modulus, t1); } /* X = X - T2 */ if (err == MP_OKAY) - err = mp_sub(&x, &t2, &x); + err = mp_sub(x, t2, x); if (err == MP_OKAY) { - if (mp_cmp_d(&x, 0) == MP_LT) - err = mp_add(&x, modulus, &x); + if (mp_isneg(x)) + err = mp_add(x, modulus, x); } /* T2 = 2T2 */ if (err == MP_OKAY) - err = mp_add(&t2, &t2, &t2); + err = mp_add(t2, t2, t2); if (err == MP_OKAY) { - if (mp_cmp(&t2, modulus) != MP_LT) - err = mp_sub(&t2, modulus, &t2); + if (mp_cmp(t2, modulus) != MP_LT) + err = mp_sub(t2, modulus, t2); } /* T2 = X + T2 */ if (err == MP_OKAY) - err = mp_add(&t2, &x, &t2); + err = mp_add(t2, x, t2); if (err == MP_OKAY) { - if (mp_cmp(&t2, modulus) != MP_LT) - err = mp_sub(&t2, modulus, &t2); + if (mp_cmp(t2, modulus) != MP_LT) + err = mp_sub(t2, modulus, t2); } if (err == MP_OKAY) { - if (get_digit_count(Q->z)) { + if (!mp_iszero(Q->z)) { /* Z = Z * Z' */ - err = mp_mul(&z, Q->z, &z); + err = mp_mul(z, Q->z, z); if (err == MP_OKAY) - err = mp_montgomery_reduce(&z, modulus, *mp); + err = mp_montgomery_reduce(z, modulus, mp); } } /* Z = Z * X */ if (err == MP_OKAY) - err = mp_mul(&z, &x, &z); + err = mp_mul(z, x, z); if (err == MP_OKAY) - err = mp_montgomery_reduce(&z, modulus, *mp); + err = mp_montgomery_reduce(z, modulus, mp); /* T1 = T1 * X */ if (err == MP_OKAY) - err = mp_mul(&t1, &x, &t1); + err = mp_mul(t1, x, t1); if (err == MP_OKAY) - err = mp_montgomery_reduce(&t1, modulus, *mp); + err = mp_montgomery_reduce(t1, modulus, mp); /* X = X * X */ if (err == MP_OKAY) - err = mp_sqr(&x, &x); + err = mp_sqr(x, x); if (err == MP_OKAY) - err = mp_montgomery_reduce(&x, modulus, *mp); - + err = mp_montgomery_reduce(x, modulus, mp); + /* T2 = T2 * x */ if (err == MP_OKAY) - err = mp_mul(&t2, &x, &t2); + err = mp_mul(t2, x, t2); if (err == MP_OKAY) - err = mp_montgomery_reduce(&t2, modulus, *mp); + err = mp_montgomery_reduce(t2, modulus, mp); /* T1 = T1 * X */ if (err == MP_OKAY) - err = mp_mul(&t1, &x, &t1); + err = mp_mul(t1, x, t1); if (err == MP_OKAY) - err = mp_montgomery_reduce(&t1, modulus, *mp); - + err = mp_montgomery_reduce(t1, modulus, mp); + /* X = Y*Y */ if (err == MP_OKAY) - err = mp_sqr(&y, &x); + err = mp_sqr(y, x); if (err == MP_OKAY) - err = mp_montgomery_reduce(&x, modulus, *mp); + err = mp_montgomery_reduce(x, modulus, mp); /* X = X - T2 */ if (err == MP_OKAY) - err = mp_sub(&x, &t2, &x); + err = mp_sub(x, t2, x); if (err == MP_OKAY) { - if (mp_cmp_d(&x, 0) == MP_LT) - err = mp_add(&x, modulus, &x); + if (mp_isneg(x)) + err = mp_add(x, modulus, x); } /* T2 = T2 - X */ if (err == MP_OKAY) - err = mp_sub(&t2, &x, &t2); + err = mp_sub(t2, x, t2); if (err == MP_OKAY) { - if (mp_cmp_d(&t2, 0) == MP_LT) - err = mp_add(&t2, modulus, &t2); - } + if (mp_isneg(t2)) + err = mp_add(t2, modulus, t2); + } /* T2 = T2 - X */ if (err == MP_OKAY) - err = mp_sub(&t2, &x, &t2); + err = mp_sub(t2, x, t2); if (err == MP_OKAY) { - if (mp_cmp_d(&t2, 0) == MP_LT) - err = mp_add(&t2, modulus, &t2); + if (mp_isneg(t2)) + err = mp_add(t2, modulus, t2); } /* T2 = T2 * Y */ if (err == MP_OKAY) - err = mp_mul(&t2, &y, &t2); + err = mp_mul(t2, y, t2); if (err == MP_OKAY) - err = mp_montgomery_reduce(&t2, modulus, *mp); + err = mp_montgomery_reduce(t2, modulus, mp); /* Y = T2 - T1 */ if (err == MP_OKAY) - err = mp_sub(&t2, &t1, &y); + err = mp_sub(t2, t1, y); if (err == MP_OKAY) { - if (mp_cmp_d(&y, 0) == MP_LT) - err = mp_add(&y, modulus, &y); + if (mp_isneg(y)) + err = mp_add(y, modulus, y); } /* Y = Y/2 */ if (err == MP_OKAY) { - if (mp_isodd(&y)) - err = mp_add(&y, modulus, &y); + if (mp_isodd(y) == MP_YES) + err = mp_add(y, modulus, y); } if (err == MP_OKAY) - err = mp_div_2(&y, &y); + err = mp_div_2(y, y); +#ifdef ALT_ECC_SIZE if (err == MP_OKAY) - err = mp_copy(&x, R->x); + err = mp_copy(x, R->x); if (err == MP_OKAY) - err = mp_copy(&y, R->y); + err = mp_copy(y, R->y); if (err == MP_OKAY) - err = mp_copy(&z, R->z); + err = mp_copy(z, R->z); +#endif + +done: /* clean up */ - mp_clear(&t1); - mp_clear(&t2); - mp_clear(&x); - mp_clear(&y); - mp_clear(&z); + mp_clear(t1); + mp_clear(t2); +#ifdef WOLFSSL_SMALL_STACK +#ifdef WOLFSSL_SMALL_STACK_CACHE + if (R->key == NULL) +#endif + { + #ifdef ALT_ECC_SIZE + XFREE(rz, NULL, DYNAMIC_TYPE_ECC); + XFREE(ry, NULL, DYNAMIC_TYPE_ECC); + XFREE(rx, NULL, DYNAMIC_TYPE_ECC); + #endif + XFREE(t2, NULL, DYNAMIC_TYPE_ECC); + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); + } +#endif return err; +#else + if (P == NULL || Q == NULL || R == NULL || modulus == NULL) { + return ECC_BAD_ARG_E; + } + + (void)a; + (void)mp; + +#ifndef WOLFSSL_SP_NO_256 + if (mp_count_bits(modulus) == 256) { + return sp_ecc_proj_add_point_256(P->x, P->y, P->z, Q->x, Q->y, Q->z, + R->x, R->y, R->z); + } +#endif +#ifdef WOLFSSL_SP_384 + if (mp_count_bits(modulus) == 384) { + return sp_ecc_proj_add_point_384(P->x, P->y, P->z, Q->x, Q->y, Q->z, + R->x, R->y, R->z); + } +#endif + return ECC_BAD_ARG_E; +#endif } +/* ### Point doubling in Jacobian coordinate system ### + * + * let us have a curve: y^2 = x^3 + a*x + b + * in Jacobian coordinates it becomes: y^2 = x^3 + a*x*z^4 + b*z^6 + * + * The doubling of P = (Xp, Yp, Zp) is given by R = (Xr, Yr, Zr) where: + * Xr = M^2 - 2*S + * Yr = M * (S - Xr) - 8*T + * Zr = 2 * Yp * Zp + * + * M = 3 * Xp^2 + a*Zp^4 + * T = Yp^4 + * S = 4 * Xp * Yp^2 + * + * SPECIAL CASE: when a == 3 we can compute M as + * M = 3 * (Xp^2 - Zp^4) = 3 * (Xp + Zp^2) * (Xp - Zp^2) + */ /** Double an ECC point P The point to double R [out] The destination of the double + a ECC curve parameter a modulus The modulus of the field the ECC curve is in mp The "b" value from montgomery_setup() return MP_OKAY on success */ -int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* modulus, - mp_digit* mp) +int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* a, + mp_int* modulus, mp_digit mp) { - mp_int t1; - mp_int t2; +#ifndef WOLFSSL_SP_MATH +#ifdef WOLFSSL_SMALL_STACK + mp_int* t1 = NULL; + mp_int* t2 = NULL; +#ifdef ALT_ECC_SIZE + mp_int* rx = NULL; + mp_int* ry = NULL; + mp_int* rz = NULL; +#endif +#else + mp_int t1[1], t2[1]; +#ifdef ALT_ECC_SIZE + mp_int rx[1], ry[1], rz[1]; +#endif +#endif + mp_int *x, *y, *z; int err; - if (P == NULL || R == NULL || modulus == NULL || mp == NULL) + if (P == NULL || R == NULL || modulus == NULL) return ECC_BAD_ARG_E; - if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) { +#ifdef WOLFSSL_SMALL_STACK +#ifdef WOLFSSL_SMALL_STACK_CACHE + if (R->key != NULL) { + t1 = R->key->t1; + t2 = R->key->t2; + #ifdef ALT_ECC_SIZE + rx = R->key->x; + ry = R->key->y; + rz = R->key->z; + #endif + } + else +#endif /* WOLFSSL_SMALL_STACK_CACHE */ + { + t1 = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + t2 = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + if (t1 == NULL || t2 == NULL) { + XFREE(t2, NULL, DYNAMIC_TYPE_ECC); + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); + return MEMORY_E; + } + #ifdef ALT_ECC_SIZE + rx = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + ry = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + rz = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + if (rx == NULL || ry == NULL || rz == NULL) { + XFREE(rz, NULL, DYNAMIC_TYPE_ECC); + XFREE(ry, NULL, DYNAMIC_TYPE_ECC); + XFREE(rx, NULL, DYNAMIC_TYPE_ECC); + XFREE(t2, NULL, DYNAMIC_TYPE_ECC); + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); + return MEMORY_E; + } + #endif + } +#endif + + if ((err = mp_init_multi(t1, t2, NULL, NULL, NULL, NULL)) != MP_OKAY) { +#ifdef WOLFSSL_SMALL_STACK +#ifdef WOLFSSL_SMALL_STACK_CACHE + if (R->key == NULL) +#endif + { + #ifdef ALT_ECC_SIZE + XFREE(rz, NULL, DYNAMIC_TYPE_ECC); + XFREE(ry, NULL, DYNAMIC_TYPE_ECC); + XFREE(rx, NULL, DYNAMIC_TYPE_ECC); + #endif + XFREE(t2, NULL, DYNAMIC_TYPE_ECC); + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); + } +#endif return err; } - if (P != R) { - err = mp_copy(P->x, R->x); - if (err == MP_OKAY) - err = mp_copy(P->y, R->y); - if (err == MP_OKAY) - err = mp_copy(P->z, R->z); +/* If use ALT_ECC_SIZE we need to use local stack variable since + ecc_point x,y,z is reduced size */ +#ifdef ALT_ECC_SIZE + /* Use local stack variable */ + x = rx; + y = ry; + z = rz; + + if ((err = mp_init_multi(x, y, z, NULL, NULL, NULL)) != MP_OKAY) { + mp_clear(t1); + mp_clear(t2); + #ifdef WOLFSSL_SMALL_STACK + #ifdef WOLFSSL_SMALL_STACK_CACHE + if (R->key == NULL) + #endif + { + #ifdef ALT_ECC_SIZE + XFREE(rz, NULL, DYNAMIC_TYPE_ECC); + XFREE(ry, NULL, DYNAMIC_TYPE_ECC); + XFREE(rx, NULL, DYNAMIC_TYPE_ECC); + #endif + XFREE(t2, NULL, DYNAMIC_TYPE_ECC); + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); + } + #endif + return err; } +#else + /* Use destination directly */ + x = R->x; + y = R->y; + z = R->z; +#endif - /* t1 = Z * Z */ if (err == MP_OKAY) - err = mp_sqr(R->z, &t1); + err = mp_copy(P->x, x); + if (err == MP_OKAY) + err = mp_copy(P->y, y); if (err == MP_OKAY) - err = mp_montgomery_reduce(&t1, modulus, *mp); + err = mp_copy(P->z, z); + + /* T1 = Z * Z */ + if (err == MP_OKAY) + err = mp_sqr(z, t1); + if (err == MP_OKAY) + err = mp_montgomery_reduce(t1, modulus, mp); /* Z = Y * Z */ if (err == MP_OKAY) - err = mp_mul(R->z, R->y, R->z); + err = mp_mul(z, y, z); if (err == MP_OKAY) - err = mp_montgomery_reduce(R->z, modulus, *mp); + err = mp_montgomery_reduce(z, modulus, mp); /* Z = 2Z */ if (err == MP_OKAY) - err = mp_add(R->z, R->z, R->z); + err = mp_add(z, z, z); if (err == MP_OKAY) { - if (mp_cmp(R->z, modulus) != MP_LT) - err = mp_sub(R->z, modulus, R->z); + if (mp_cmp(z, modulus) != MP_LT) + err = mp_sub(z, modulus, z); } - /* T2 = X - T1 */ - if (err == MP_OKAY) - err = mp_sub(R->x, &t1, &t2); - if (err == MP_OKAY) { - if (mp_cmp_d(&t2, 0) == MP_LT) - err = mp_add(&t2, modulus, &t2); - } - /* T1 = X + T1 */ - if (err == MP_OKAY) - err = mp_add(&t1, R->x, &t1); + /* Determine if curve "a" should be used in calc */ +#ifdef WOLFSSL_CUSTOM_CURVES if (err == MP_OKAY) { - if (mp_cmp(&t1, modulus) != MP_LT) - err = mp_sub(&t1, modulus, &t1); + /* Use a and prime to determine if a == 3 */ + err = mp_submod(modulus, a, modulus, t2); } - /* T2 = T1 * T2 */ - if (err == MP_OKAY) - err = mp_mul(&t1, &t2, &t2); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&t2, modulus, *mp); + if (err == MP_OKAY && mp_cmp_d(t2, 3) != MP_EQ) { + /* use "a" in calc */ - /* T1 = 2T2 */ - if (err == MP_OKAY) - err = mp_add(&t2, &t2, &t1); - if (err == MP_OKAY) { - if (mp_cmp(&t1, modulus) != MP_LT) - err = mp_sub(&t1, modulus, &t1); + /* T2 = T1 * T1 */ + if (err == MP_OKAY) + err = mp_sqr(t1, t2); + if (err == MP_OKAY) + err = mp_montgomery_reduce(t2, modulus, mp); + /* T1 = T2 * a */ + if (err == MP_OKAY) + err = mp_mulmod(t2, a, modulus, t1); + /* T2 = X * X */ + if (err == MP_OKAY) + err = mp_sqr(x, t2); + if (err == MP_OKAY) + err = mp_montgomery_reduce(t2, modulus, mp); + /* T1 = T2 + T1 */ + if (err == MP_OKAY) + err = mp_add(t1, t2, t1); + if (err == MP_OKAY) { + if (mp_cmp(t1, modulus) != MP_LT) + err = mp_sub(t1, modulus, t1); + } + /* T1 = T2 + T1 */ + if (err == MP_OKAY) + err = mp_add(t1, t2, t1); + if (err == MP_OKAY) { + if (mp_cmp(t1, modulus) != MP_LT) + err = mp_sub(t1, modulus, t1); + } + /* T1 = T2 + T1 */ + if (err == MP_OKAY) + err = mp_add(t1, t2, t1); + if (err == MP_OKAY) { + if (mp_cmp(t1, modulus) != MP_LT) + err = mp_sub(t1, modulus, t1); + } } - /* T1 = T1 + T2 */ - if (err == MP_OKAY) - err = mp_add(&t1, &t2, &t1); - if (err == MP_OKAY) { - if (mp_cmp(&t1, modulus) != MP_LT) - err = mp_sub(&t1, modulus, &t1); + else +#endif /* WOLFSSL_CUSTOM_CURVES */ + { + /* assumes "a" == 3 */ + (void)a; + + /* T2 = X - T1 */ + if (err == MP_OKAY) + err = mp_sub(x, t1, t2); + if (err == MP_OKAY) { + if (mp_isneg(t2)) + err = mp_add(t2, modulus, t2); + } + /* T1 = X + T1 */ + if (err == MP_OKAY) + err = mp_add(t1, x, t1); + if (err == MP_OKAY) { + if (mp_cmp(t1, modulus) != MP_LT) + err = mp_sub(t1, modulus, t1); + } + /* T2 = T1 * T2 */ + if (err == MP_OKAY) + err = mp_mul(t1, t2, t2); + if (err == MP_OKAY) + err = mp_montgomery_reduce(t2, modulus, mp); + + /* T1 = 2T2 */ + if (err == MP_OKAY) + err = mp_add(t2, t2, t1); + if (err == MP_OKAY) { + if (mp_cmp(t1, modulus) != MP_LT) + err = mp_sub(t1, modulus, t1); + } + /* T1 = T1 + T2 */ + if (err == MP_OKAY) + err = mp_add(t1, t2, t1); + if (err == MP_OKAY) { + if (mp_cmp(t1, modulus) != MP_LT) + err = mp_sub(t1, modulus, t1); + } } + /* Y = 2Y */ if (err == MP_OKAY) - err = mp_add(R->y, R->y, R->y); + err = mp_add(y, y, y); if (err == MP_OKAY) { - if (mp_cmp(R->y, modulus) != MP_LT) - err = mp_sub(R->y, modulus, R->y); + if (mp_cmp(y, modulus) != MP_LT) + err = mp_sub(y, modulus, y); } /* Y = Y * Y */ if (err == MP_OKAY) - err = mp_sqr(R->y, R->y); + err = mp_sqr(y, y); if (err == MP_OKAY) - err = mp_montgomery_reduce(R->y, modulus, *mp); - + err = mp_montgomery_reduce(y, modulus, mp); + /* T2 = Y * Y */ if (err == MP_OKAY) - err = mp_sqr(R->y, &t2); + err = mp_sqr(y, t2); if (err == MP_OKAY) - err = mp_montgomery_reduce(&t2, modulus, *mp); + err = mp_montgomery_reduce(t2, modulus, mp); /* T2 = T2/2 */ if (err == MP_OKAY) { - if (mp_isodd(&t2)) - err = mp_add(&t2, modulus, &t2); + if (mp_isodd(t2) == MP_YES) + err = mp_add(t2, modulus, t2); } if (err == MP_OKAY) - err = mp_div_2(&t2, &t2); - + err = mp_div_2(t2, t2); + /* Y = Y * X */ if (err == MP_OKAY) - err = mp_mul(R->y, R->x, R->y); + err = mp_mul(y, x, y); if (err == MP_OKAY) - err = mp_montgomery_reduce(R->y, modulus, *mp); + err = mp_montgomery_reduce(y, modulus, mp); - /* X = T1 * T1 */ + /* X = T1 * T1 */ if (err == MP_OKAY) - err = mp_sqr(&t1, R->x); + err = mp_sqr(t1, x); if (err == MP_OKAY) - err = mp_montgomery_reduce(R->x, modulus, *mp); + err = mp_montgomery_reduce(x, modulus, mp); /* X = X - Y */ if (err == MP_OKAY) - err = mp_sub(R->x, R->y, R->x); + err = mp_sub(x, y, x); if (err == MP_OKAY) { - if (mp_cmp_d(R->x, 0) == MP_LT) - err = mp_add(R->x, modulus, R->x); + if (mp_isneg(x)) + err = mp_add(x, modulus, x); } /* X = X - Y */ if (err == MP_OKAY) - err = mp_sub(R->x, R->y, R->x); + err = mp_sub(x, y, x); if (err == MP_OKAY) { - if (mp_cmp_d(R->x, 0) == MP_LT) - err = mp_add(R->x, modulus, R->x); + if (mp_isneg(x)) + err = mp_add(x, modulus, x); } - /* Y = Y - X */ + + /* Y = Y - X */ if (err == MP_OKAY) - err = mp_sub(R->y, R->x, R->y); + err = mp_sub(y, x, y); if (err == MP_OKAY) { - if (mp_cmp_d(R->y, 0) == MP_LT) - err = mp_add(R->y, modulus, R->y); + if (mp_isneg(y)) + err = mp_add(y, modulus, y); } /* Y = Y * T1 */ if (err == MP_OKAY) - err = mp_mul(R->y, &t1, R->y); + err = mp_mul(y, t1, y); if (err == MP_OKAY) - err = mp_montgomery_reduce(R->y, modulus, *mp); + err = mp_montgomery_reduce(y, modulus, mp); /* Y = Y - T2 */ if (err == MP_OKAY) - err = mp_sub(R->y, &t2, R->y); + err = mp_sub(y, t2, y); if (err == MP_OKAY) { - if (mp_cmp_d(R->y, 0) == MP_LT) - err = mp_add(R->y, modulus, R->y); + if (mp_isneg(y)) + err = mp_add(y, modulus, y); } - /* clean up */ - mp_clear(&t1); - mp_clear(&t2); +#ifdef ALT_ECC_SIZE + if (err == MP_OKAY) + err = mp_copy(x, R->x); + if (err == MP_OKAY) + err = mp_copy(y, R->y); + if (err == MP_OKAY) + err = mp_copy(z, R->z); +#endif + + /* clean up */ + mp_clear(t1); + mp_clear(t2); + +#ifdef WOLFSSL_SMALL_STACK +#ifdef WOLFSSL_SMALL_STACK_CACHE + if (R->key == NULL) +#endif + { + #ifdef ALT_ECC_SIZE + XFREE(rz, NULL, DYNAMIC_TYPE_ECC); + XFREE(ry, NULL, DYNAMIC_TYPE_ECC); + XFREE(rx, NULL, DYNAMIC_TYPE_ECC); + #endif + XFREE(t2, NULL, DYNAMIC_TYPE_ECC); + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); + } +#endif return err; +#else + if (P == NULL || R == NULL || modulus == NULL) + return ECC_BAD_ARG_E; + + (void)a; + (void)mp; + +#ifndef WOLFSSL_SP_NO_256 + if (mp_count_bits(modulus) == 256) { + return sp_ecc_proj_dbl_point_256(P->x, P->y, P->z, R->x, R->y, R->z); + } +#endif +#ifdef WOLFSSL_SP_384 + if (mp_count_bits(modulus) == 384) { + return sp_ecc_proj_dbl_point_384(P->x, P->y, P->z, R->x, R->y, R->z); + } +#endif + return ECC_BAD_ARG_E; +#endif } -#endif /* USE_FAST_MATH */ /** - Map a projective jacbobian point back to affine space + Map a projective Jacobian point back to affine space P [in/out] The point to map modulus The modulus of the field the ECC curve is in mp The "b" value from montgomery_setup() + ct Operation should be constant time. return MP_OKAY on success */ -int ecc_map(ecc_point* P, mp_int* modulus, mp_digit* mp) +int ecc_map_ex(ecc_point* P, mp_int* modulus, mp_digit mp, int ct) { - mp_int t1; - mp_int t2; +#ifndef WOLFSSL_SP_MATH +#ifdef WOLFSSL_SMALL_STACK + mp_int* t1 = NULL; + mp_int* t2 = NULL; +#ifdef ALT_ECC_SIZE + mp_int* rx = NULL; + mp_int* ry = NULL; + mp_int* rz = NULL; +#endif +#else + mp_int t1[1], t2[1]; +#ifdef ALT_ECC_SIZE + mp_int rx[1], ry[1], rz[1]; +#endif +#endif /* WOLFSSL_SMALL_STACK */ + mp_int *x, *y, *z; int err; - if (P == NULL || mp == NULL || modulus == NULL) + (void)ct; + + if (P == NULL || modulus == NULL) return ECC_BAD_ARG_E; /* special case for point at infinity */ if (mp_cmp_d(P->z, 0) == MP_EQ) { - mp_set(P->x, 0); - mp_set(P->y, 0); - mp_set(P->z, 1); - return MP_OKAY; + err = mp_set(P->x, 0); + if (err == MP_OKAY) + err = mp_set(P->y, 0); + if (err == MP_OKAY) + err = mp_set(P->z, 1); + return err; + } + +#ifdef WOLFSSL_SMALL_STACK +#ifdef WOLFSSL_SMALL_STACK_CACHE + if (P->key != NULL) { + t1 = P->key->t1; + t2 = P->key->t2; + #ifdef ALT_ECC_SIZE + rx = P->key->x; + ry = P->key->y; + rz = P->key->z; + #endif + } + else +#endif /* WOLFSSL_SMALL_STACK_CACHE */ + { + t1 = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + t2 = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + if (t1 == NULL || t2 == NULL) { + XFREE(t2, NULL, DYNAMIC_TYPE_ECC); + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); + return MEMORY_E; + } +#ifdef ALT_ECC_SIZE + rx = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + ry = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + rz = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + if (rx == NULL || ry == NULL || rz == NULL) { + XFREE(rz, NULL, DYNAMIC_TYPE_ECC); + XFREE(ry, NULL, DYNAMIC_TYPE_ECC); + XFREE(rx, NULL, DYNAMIC_TYPE_ECC); + XFREE(t2, NULL, DYNAMIC_TYPE_ECC); + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); + return MEMORY_E; + } +#endif } +#endif /* WOLFSSL_SMALL_STACK */ - if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) { + if ((err = mp_init_multi(t1, t2, NULL, NULL, NULL, NULL)) != MP_OKAY) { +#ifdef WOLFSSL_SMALL_STACK +#ifdef WOLFSSL_SMALL_STACK_CACHE + if (P->key == NULL) +#endif + { + #ifdef ALT_ECC_SIZE + XFREE(rz, NULL, DYNAMIC_TYPE_ECC); + XFREE(ry, NULL, DYNAMIC_TYPE_ECC); + XFREE(rx, NULL, DYNAMIC_TYPE_ECC); + #endif + XFREE(t2, NULL, DYNAMIC_TYPE_ECC); + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); + } +#endif return MEMORY_E; } - /* first map z back to normal */ - err = mp_montgomery_reduce(P->z, modulus, *mp); +#ifdef ALT_ECC_SIZE + /* Use local stack variable */ + x = rx; + y = ry; + z = rz; - /* get 1/z */ + if ((err = mp_init_multi(x, y, z, NULL, NULL, NULL)) != MP_OKAY) { + goto done; + } + + if (err == MP_OKAY) + err = mp_copy(P->x, x); + if (err == MP_OKAY) + err = mp_copy(P->y, y); if (err == MP_OKAY) - err = mp_invmod(P->z, modulus, &t1); - + err = mp_copy(P->z, z); + + if (err != MP_OKAY) { + goto done; + } +#else + /* Use destination directly */ + x = P->x; + y = P->y; + z = P->z; +#endif + + /* get 1/z */ + if (err == MP_OKAY) { +#if defined(ECC_TIMING_RESISTANT) && defined(USE_FAST_MATH) + if (ct) { + err = mp_invmod_mont_ct(z, modulus, t1, mp); + if (err == MP_OKAY) + err = mp_montgomery_reduce(t1, modulus, mp); + } + else +#endif + { + /* first map z back to normal */ + err = mp_montgomery_reduce(z, modulus, mp); + if (err == MP_OKAY) + err = mp_invmod(z, modulus, t1); + } + } + /* get 1/z^2 and 1/z^3 */ if (err == MP_OKAY) - err = mp_sqr(&t1, &t2); + err = mp_sqr(t1, t2); if (err == MP_OKAY) - err = mp_mod(&t2, modulus, &t2); + err = mp_mod(t2, modulus, t2); if (err == MP_OKAY) - err = mp_mul(&t1, &t2, &t1); + err = mp_mul(t1, t2, t1); if (err == MP_OKAY) - err = mp_mod(&t1, modulus, &t1); + err = mp_mod(t1, modulus, t1); /* multiply against x/y */ if (err == MP_OKAY) - err = mp_mul(P->x, &t2, P->x); + err = mp_mul(x, t2, x); + if (err == MP_OKAY) + err = mp_montgomery_reduce(x, modulus, mp); + if (err == MP_OKAY) + err = mp_mul(y, t1, y); + if (err == MP_OKAY) + err = mp_montgomery_reduce(y, modulus, mp); + if (err == MP_OKAY) - err = mp_montgomery_reduce(P->x, modulus, *mp); + err = mp_set(z, 1); + +#ifdef ALT_ECC_SIZE + /* return result */ if (err == MP_OKAY) - err = mp_mul(P->y, &t1, P->y); + err = mp_copy(x, P->x); if (err == MP_OKAY) - err = mp_montgomery_reduce(P->y, modulus, *mp); - + err = mp_copy(y, P->y); if (err == MP_OKAY) - mp_set(P->z, 1); + err = mp_copy(z, P->z); + +done: +#endif /* clean up */ - mp_clear(&t1); - mp_clear(&t2); + mp_clear(t1); + mp_clear(t2); + +#ifdef WOLFSSL_SMALL_STACK +#ifdef WOLFSSL_SMALL_STACK_CACHE + if (P->key == NULL) +#endif + { + #ifdef ALT_ECC_SIZE + XFREE(rz, NULL, DYNAMIC_TYPE_ECC); + XFREE(ry, NULL, DYNAMIC_TYPE_ECC); + XFREE(rx, NULL, DYNAMIC_TYPE_ECC); + #endif + XFREE(t2, NULL, DYNAMIC_TYPE_ECC); + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); + } +#endif return err; -} +#else + if (P == NULL || modulus == NULL) + return ECC_BAD_ARG_E; + (void)mp; -#ifndef ECC_TIMING_RESISTANT +#ifndef WOLFSSL_SP_NO_256 + if (mp_count_bits(modulus) == 256) { + return sp_ecc_map_256(P->x, P->y, P->z); + } +#endif +#ifdef WOLFSSL_SP_384 + if (mp_count_bits(modulus) == 384) { + return sp_ecc_map_384(P->x, P->y, P->z); + } +#endif + return ECC_BAD_ARG_E; +#endif +} + +int ecc_map(ecc_point* P, mp_int* modulus, mp_digit mp) +{ + return ecc_map_ex(P, modulus, mp, 0); +} +#endif /* !WOLFSSL_SP_MATH || WOLFSSL_PUBLIC_ECC_ADD_DBL */ -/* size of sliding window, don't change this! */ -#define WINSIZE 4 +#if !defined(FREESCALE_LTC_ECC) && !defined(WOLFSSL_STM32_PKA) +#if !defined(FP_ECC) || !defined(WOLFSSL_SP_MATH) /** - Perform a point multiplication + Perform a point multiplication k The scalar to multiply by G The base point R [out] Destination for kG + a ECC curve parameter a modulus The modulus of the field the ECC curve is in map Boolean whether to map back to affine or not (1==map, 0 == leave in projective) @@ -1007,83 +2521,182 @@ int ecc_map(ecc_point* P, mp_int* modulus, mp_digit* mp) */ #ifdef FP_ECC static int normal_ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, - mp_int* modulus, int map) + mp_int* a, mp_int* modulus, int map, + void* heap) #else -static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, - int map) +int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, + mp_int* a, mp_int* modulus, int map, + void* heap) #endif { - ecc_point *tG, *M[8]; - int i, j, err; - mp_int mu; +#ifndef WOLFSSL_SP_MATH +#ifndef ECC_TIMING_RESISTANT + /* size of sliding window, don't change this! */ + #define WINSIZE 4 + #define M_POINTS 8 + int first = 1, bitbuf = 0, bitcpy = 0, j; +#elif defined(WC_NO_CACHE_RESISTANT) + #define M_POINTS 4 +#else + #define M_POINTS 5 +#endif + + ecc_point *tG, *M[M_POINTS]; + int i, err; +#ifdef WOLFSSL_SMALL_STACK_CACHE + ecc_key key; +#endif +#ifdef WOLFSSL_SMALL_STACK + mp_int* mu = NULL; +#else + mp_int mu[1]; +#endif mp_digit mp; mp_digit buf; - int first = 1, bitbuf = 0, bitcpy = 0, bitcnt = 0, mode = 0, - digidx = 0; + int bitcnt = 0, mode = 0, digidx = 0; - if (k == NULL || G == NULL || R == NULL || modulus == NULL) + if (k == NULL || G == NULL || R == NULL || modulus == NULL) { return ECC_BAD_ARG_E; + } + + /* init variables */ + tG = NULL; + XMEMSET(M, 0, sizeof(M)); +#ifdef WOLFSSL_SMALL_STACK + mu = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); + if (mu == NULL) + return MEMORY_E; +#endif +#ifdef WOLFSSL_SMALL_STACK_CACHE + key.t1 = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); + key.t2 = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); +#ifdef ALT_ECC_SIZE + key.x = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); + key.y = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); + key.z = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); +#endif + if (key.t1 == NULL || key.t2 == NULL +#ifdef ALT_ECC_SIZE + || key.x == NULL || key.y == NULL || key.z == NULL +#endif + ) { +#ifdef ALT_ECC_SIZE + XFREE(key.z, heap, DYNAMIC_TYPE_ECC); + XFREE(key.y, heap, DYNAMIC_TYPE_ECC); + XFREE(key.x, heap, DYNAMIC_TYPE_ECC); +#endif + XFREE(key.t2, heap, DYNAMIC_TYPE_ECC); + XFREE(key.t1, heap, DYNAMIC_TYPE_ECC); + XFREE(mu, heap, DYNAMIC_TYPE_ECC); + return MEMORY_E; + } +#endif /* WOLFSSL_SMALL_STACK_CACHE */ /* init montgomery reduction */ if ((err = mp_montgomery_setup(modulus, &mp)) != MP_OKAY) { - return err; +#ifdef WOLFSSL_SMALL_STACK_CACHE +#ifdef ALT_ECC_SIZE + XFREE(key.z, heap, DYNAMIC_TYPE_ECC); + XFREE(key.y, heap, DYNAMIC_TYPE_ECC); + XFREE(key.x, heap, DYNAMIC_TYPE_ECC); +#endif + XFREE(key.t2, heap, DYNAMIC_TYPE_ECC); + XFREE(key.t1, heap, DYNAMIC_TYPE_ECC); +#endif /* WOLFSSL_SMALL_STACK_CACHE */ +#ifdef WOLFSSL_SMALL_STACK + XFREE(mu, heap, DYNAMIC_TYPE_ECC); +#endif + return err; } - if ((err = mp_init(&mu)) != MP_OKAY) { - return err; + + if ((err = mp_init(mu)) != MP_OKAY) { +#ifdef WOLFSSL_SMALL_STACK_CACHE +#ifdef ALT_ECC_SIZE + XFREE(key.z, heap, DYNAMIC_TYPE_ECC); + XFREE(key.y, heap, DYNAMIC_TYPE_ECC); + XFREE(key.x, heap, DYNAMIC_TYPE_ECC); +#endif + XFREE(key.t2, heap, DYNAMIC_TYPE_ECC); + XFREE(key.t1, heap, DYNAMIC_TYPE_ECC); +#endif /* WOLFSSL_SMALL_STACK_CACHE */ +#ifdef WOLFSSL_SMALL_STACK + XFREE(mu, heap, DYNAMIC_TYPE_ECC); +#endif + return err; } - if ((err = mp_montgomery_calc_normalization(&mu, modulus)) != MP_OKAY) { - mp_clear(&mu); - return err; + if ((err = mp_montgomery_calc_normalization(mu, modulus)) != MP_OKAY) { + mp_clear(mu); +#ifdef WOLFSSL_SMALL_STACK_CACHE +#ifdef ALT_ECC_SIZE + XFREE(key.z, heap, DYNAMIC_TYPE_ECC); + XFREE(key.y, heap, DYNAMIC_TYPE_ECC); + XFREE(key.x, heap, DYNAMIC_TYPE_ECC); +#endif + XFREE(key.t2, heap, DYNAMIC_TYPE_ECC); + XFREE(key.t1, heap, DYNAMIC_TYPE_ECC); +#endif /* WOLFSSL_SMALL_STACK_CACHE */ +#ifdef WOLFSSL_SMALL_STACK + XFREE(mu, heap, DYNAMIC_TYPE_ECC); +#endif + return err; } - + /* alloc ram for window temps */ - for (i = 0; i < 8; i++) { - M[i] = ecc_new_point(); + for (i = 0; i < M_POINTS; i++) { + M[i] = wc_ecc_new_point_h(heap); if (M[i] == NULL) { - for (j = 0; j < i; j++) { - ecc_del_point(M[j]); - } - mp_clear(&mu); - return MEMORY_E; + mp_clear(mu); + err = MEMORY_E; goto exit; } +#ifdef WOLFSSL_SMALL_STACK_CACHE + M[i]->key = &key; +#endif } - /* make a copy of G incase R==G */ - tG = ecc_new_point(); + /* make a copy of G in case R==G */ + tG = wc_ecc_new_point_h(heap); if (tG == NULL) err = MEMORY_E; /* tG = G and convert to montgomery */ if (err == MP_OKAY) { - if (mp_cmp_d(&mu, 1) == MP_EQ) { + if (mp_cmp_d(mu, 1) == MP_EQ) { err = mp_copy(G->x, tG->x); if (err == MP_OKAY) err = mp_copy(G->y, tG->y); if (err == MP_OKAY) err = mp_copy(G->z, tG->z); } else { - err = mp_mulmod(G->x, &mu, modulus, tG->x); + err = mp_mulmod(G->x, mu, modulus, tG->x); if (err == MP_OKAY) - err = mp_mulmod(G->y, &mu, modulus, tG->y); + err = mp_mulmod(G->y, mu, modulus, tG->y); if (err == MP_OKAY) - err = mp_mulmod(G->z, &mu, modulus, tG->z); + err = mp_mulmod(G->z, mu, modulus, tG->z); } } - mp_clear(&mu); - + + /* done with mu */ + mp_clear(mu); + +#ifdef WOLFSSL_SMALL_STACK_CACHE + R->key = &key; +#endif +#ifndef ECC_TIMING_RESISTANT + /* calc the M tab, which holds kG for k==8..15 */ /* M[0] == 8G */ if (err == MP_OKAY) - err = ecc_projective_dbl_point(tG, M[0], modulus, &mp); + err = ecc_projective_dbl_point(tG, M[0], a, modulus, mp); if (err == MP_OKAY) - err = ecc_projective_dbl_point(M[0], M[0], modulus, &mp); + err = ecc_projective_dbl_point(M[0], M[0], a, modulus, mp); if (err == MP_OKAY) - err = ecc_projective_dbl_point(M[0], M[0], modulus, &mp); + err = ecc_projective_dbl_point(M[0], M[0], a, modulus, mp); /* now find (8+k)G for k=1..7 */ if (err == MP_OKAY) for (j = 9; j < 16; j++) { - err = ecc_projective_add_point(M[j-9], tG, M[j-8], modulus, &mp); + err = ecc_projective_add_point(M[j-9], tG, M[j-M_POINTS], a, modulus, + mp); if (err != MP_OKAY) break; } @@ -1104,7 +2717,7 @@ static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, break; } buf = get_digit(k, digidx); - bitcnt = (int) DIGIT_BIT; + bitcnt = (int) DIGIT_BIT; --digidx; } @@ -1118,7 +2731,7 @@ static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, /* if the bit is zero and mode == 1 then we double */ if (mode == 1 && i == 0) { - err = ecc_projective_dbl_point(R, R, modulus, &mp); + err = ecc_projective_dbl_point(R, R, a, modulus, mp); if (err != MP_OKAY) break; continue; } @@ -1131,26 +2744,27 @@ static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, /* if this is the first window we do a simple copy */ if (first == 1) { /* R = kG [k = first window] */ - err = mp_copy(M[bitbuf-8]->x, R->x); + err = mp_copy(M[bitbuf-M_POINTS]->x, R->x); if (err != MP_OKAY) break; - err = mp_copy(M[bitbuf-8]->y, R->y); + err = mp_copy(M[bitbuf-M_POINTS]->y, R->y); if (err != MP_OKAY) break; - err = mp_copy(M[bitbuf-8]->z, R->z); + err = mp_copy(M[bitbuf-M_POINTS]->z, R->z); first = 0; } else { /* normal window */ /* ok window is filled so double as required and add */ /* double first */ for (j = 0; j < WINSIZE; j++) { - err = ecc_projective_dbl_point(R, R, modulus, &mp); + err = ecc_projective_dbl_point(R, R, a, modulus, mp); if (err != MP_OKAY) break; } if (err != MP_OKAY) break; /* out of first for(;;) */ - /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranted */ - err = ecc_projective_add_point(R,M[bitbuf-8],R,modulus,&mp); + /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranteed */ + err = ecc_projective_add_point(R, M[bitbuf-M_POINTS], R, a, + modulus, mp); } if (err != MP_OKAY) break; /* empty window and reset */ @@ -1167,7 +2781,7 @@ static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, for (j = 0; j < bitcpy; j++) { /* only double if we have had at least one add first */ if (first == 0) { - err = ecc_projective_dbl_point(R, R, modulus, &mp); + err = ecc_projective_dbl_point(R, R, a, modulus, mp); if (err != MP_OKAY) break; } @@ -1186,7 +2800,7 @@ static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, first = 0; } else { /* then add */ - err = ecc_projective_add_point(R, tG, R, modulus, &mp); + err = ecc_projective_add_point(R, tG, R, a, modulus, mp); if (err != MP_OKAY) break; } } @@ -1194,89 +2808,10 @@ static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, } } - /* map R back from projective space */ - if (err == MP_OKAY && map) - err = ecc_map(R, modulus, &mp); - - mp_clear(&mu); - ecc_del_point(tG); - for (i = 0; i < 8; i++) { - ecc_del_point(M[i]); - } - return err; -} - -#undef WINSIZE + #undef WINSIZE #else /* ECC_TIMING_RESISTANT */ -/** - Perform a point multiplication (timing resistant) - k The scalar to multiply by - G The base point - R [out] Destination for kG - modulus The modulus of the field the ECC curve is in - map Boolean whether to map back to affine or not - (1==map, 0 == leave in projective) - return MP_OKAY on success -*/ -#ifdef FP_ECC -static int normal_ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, - mp_int* modulus, int map) -#else -static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, - int map) -#endif -{ - ecc_point *tG, *M[3]; - int i, j, err; - mp_int mu; - mp_digit mp; - mp_digit buf; - int bitcnt = 0, mode = 0, digidx = 0; - - if (k == NULL || G == NULL || R == NULL || modulus == NULL) - return ECC_BAD_ARG_E; - - /* init montgomery reduction */ - if ((err = mp_montgomery_setup(modulus, &mp)) != MP_OKAY) { - return err; - } - if ((err = mp_init(&mu)) != MP_OKAY) { - return err; - } - if ((err = mp_montgomery_calc_normalization(&mu, modulus)) != MP_OKAY) { - mp_clear(&mu); - return err; - } - - /* alloc ram for window temps */ - for (i = 0; i < 3; i++) { - M[i] = ecc_new_point(); - if (M[i] == NULL) { - for (j = 0; j < i; j++) { - ecc_del_point(M[j]); - } - mp_clear(&mu); - return MEMORY_E; - } - } - - /* make a copy of G incase R==G */ - tG = ecc_new_point(); - if (tG == NULL) - err = MEMORY_E; - - /* tG = G and convert to montgomery */ - if (err == MP_OKAY) { - err = mp_mulmod(G->x, &mu, modulus, tG->x); - if (err == MP_OKAY) - err = mp_mulmod(G->y, &mu, modulus, tG->y); - if (err == MP_OKAY) - err = mp_mulmod(G->z, &mu, modulus, tG->z); - } - mp_clear(&mu); - /* calc the M tab */ /* M[0] == G */ if (err == MP_OKAY) @@ -1288,13 +2823,24 @@ static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, /* M[1] == 2G */ if (err == MP_OKAY) - err = ecc_projective_dbl_point(tG, M[1], modulus, &mp); + err = ecc_projective_dbl_point(tG, M[1], a, modulus, mp); +#ifdef WC_NO_CACHE_RESISTANT + if (err == MP_OKAY) + err = wc_ecc_copy_point(M[0], M[2]); +#else + if (err == MP_OKAY) + err = wc_ecc_copy_point(M[0], M[3]); + if (err == MP_OKAY) + err = wc_ecc_copy_point(M[1], M[4]); +#endif /* setup sliding window */ mode = 0; bitcnt = 1; buf = 0; - digidx = get_digit_count(k) - 1; + digidx = get_digit_count(modulus) - 1; + /* The order MAY be 1 bit longer than the modulus. */ + digidx += (modulus->dp[digidx] >> (DIGIT_BIT-1)); /* perform ops */ if (err == MP_OKAY) { @@ -1305,43 +2851,92 @@ static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, break; } buf = get_digit(k, digidx); - bitcnt = (int) DIGIT_BIT; + bitcnt = (int)DIGIT_BIT; --digidx; } - /* grab the next msb from the ltiplicand */ + /* grab the next msb from the multiplicand */ i = (buf >> (DIGIT_BIT - 1)) & 1; buf <<= 1; - if (mode == 0 && i == 0) { - /* dummy operations */ - if (err == MP_OKAY) - err = ecc_projective_add_point(M[0], M[1], M[2], modulus, - &mp); +#ifdef WC_NO_CACHE_RESISTANT + if (mode == 0) { + /* timing resistant - dummy operations */ if (err == MP_OKAY) - err = ecc_projective_dbl_point(M[1], M[2], modulus, &mp); + err = ecc_projective_add_point(M[1], M[2], M[2], a, modulus, + mp); if (err == MP_OKAY) - continue; + err = ecc_projective_dbl_point(M[2], M[3], a, modulus, mp); } - - if (mode == 0 && i == 1) { - mode = 1; - /* dummy operations */ - if (err == MP_OKAY) - err = ecc_projective_add_point(M[0], M[1], M[2], modulus, - &mp); + else { if (err == MP_OKAY) - err = ecc_projective_dbl_point(M[1], M[2], modulus, &mp); + err = ecc_projective_add_point(M[0], M[1], M[i^1], a, + modulus, mp); if (err == MP_OKAY) - continue; + err = ecc_projective_dbl_point(M[i], M[i], a, modulus, mp); } +#else + if (err == MP_OKAY) + err = ecc_projective_add_point(M[0], M[1], M[2], a, modulus, mp); + if (err == MP_OKAY) + err = mp_cond_copy(M[2]->x, i, M[0]->x); + if (err == MP_OKAY) + err = mp_cond_copy(M[2]->y, i, M[0]->y); + if (err == MP_OKAY) + err = mp_cond_copy(M[2]->z, i, M[0]->z); + if (err == MP_OKAY) + err = mp_cond_copy(M[2]->x, i ^ 1, M[1]->x); + if (err == MP_OKAY) + err = mp_cond_copy(M[2]->y, i ^ 1, M[1]->y); + if (err == MP_OKAY) + err = mp_cond_copy(M[2]->z, i ^ 1, M[1]->z); + + if (err == MP_OKAY) + err = mp_cond_copy(M[0]->x, i ^ 1, M[2]->x); + if (err == MP_OKAY) + err = mp_cond_copy(M[0]->y, i ^ 1, M[2]->y); + if (err == MP_OKAY) + err = mp_cond_copy(M[0]->z, i ^ 1, M[2]->z); + if (err == MP_OKAY) + err = mp_cond_copy(M[1]->x, i, M[2]->x); + if (err == MP_OKAY) + err = mp_cond_copy(M[1]->y, i, M[2]->y); + if (err == MP_OKAY) + err = mp_cond_copy(M[1]->z, i, M[2]->z); + + if (err == MP_OKAY) + err = ecc_projective_dbl_point(M[2], M[2], a, modulus, mp); + if (err == MP_OKAY) + err = mp_cond_copy(M[2]->x, i ^ 1, M[0]->x); + if (err == MP_OKAY) + err = mp_cond_copy(M[2]->y, i ^ 1, M[0]->y); + if (err == MP_OKAY) + err = mp_cond_copy(M[2]->z, i ^ 1, M[0]->z); + if (err == MP_OKAY) + err = mp_cond_copy(M[2]->x, i, M[1]->x); + if (err == MP_OKAY) + err = mp_cond_copy(M[2]->y, i, M[1]->y); + if (err == MP_OKAY) + err = mp_cond_copy(M[2]->z, i, M[1]->z); if (err == MP_OKAY) - err = ecc_projective_add_point(M[0], M[1], M[i^1], modulus, &mp); + err = mp_cond_copy(M[3]->x, (mode ^ 1) & i, M[0]->x); if (err == MP_OKAY) - err = ecc_projective_dbl_point(M[i], M[i], modulus, &mp); + err = mp_cond_copy(M[3]->y, (mode ^ 1) & i, M[0]->y); + if (err == MP_OKAY) + err = mp_cond_copy(M[3]->z, (mode ^ 1) & i, M[0]->z); + if (err == MP_OKAY) + err = mp_cond_copy(M[4]->x, (mode ^ 1) & i, M[1]->x); + if (err == MP_OKAY) + err = mp_cond_copy(M[4]->y, (mode ^ 1) & i, M[1]->y); + if (err == MP_OKAY) + err = mp_cond_copy(M[4]->z, (mode ^ 1) & i, M[1]->z); +#endif /* WC_NO_CACHE_RESISTANT */ + if (err != MP_OKAY) break; + + mode |= i; } /* end for */ } @@ -1353,56 +2948,96 @@ static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, if (err == MP_OKAY) err = mp_copy(M[0]->z, R->z); +#endif /* ECC_TIMING_RESISTANT */ + /* map R back from projective space */ if (err == MP_OKAY && map) - err = ecc_map(R, modulus, &mp); + err = ecc_map(R, modulus, mp); + +exit: /* done */ - mp_clear(&mu); - ecc_del_point(tG); - for (i = 0; i < 3; i++) { - ecc_del_point(M[i]); + wc_ecc_del_point_h(tG, heap); + for (i = 0; i < M_POINTS; i++) { + wc_ecc_del_point_h(M[i], heap); } +#ifdef WOLFSSL_SMALL_STACK_CACHE + R->key = NULL; +#ifdef ALT_ECC_SIZE + XFREE(key.z, heap, DYNAMIC_TYPE_ECC); + XFREE(key.y, heap, DYNAMIC_TYPE_ECC); + XFREE(key.x, heap, DYNAMIC_TYPE_ECC); +#endif + XFREE(key.t2, heap, DYNAMIC_TYPE_ECC); + XFREE(key.t1, heap, DYNAMIC_TYPE_ECC); +#endif /* WOLFSSL_SMALL_STACK_CACHE */ +#ifdef WOLFSSL_SMALL_STACK + XFREE(mu, heap, DYNAMIC_TYPE_ECC); +#endif + return err; -} +#else + if (k == NULL || G == NULL || R == NULL || modulus == NULL) { + return ECC_BAD_ARG_E; + } -#endif /* ECC_TIMING_RESISTANT */ + (void)a; +#ifndef WOLFSSL_SP_NO_256 + if (mp_count_bits(modulus) == 256) { + return sp_ecc_mulmod_256(k, G, R, map, heap); + } +#endif +#ifdef WOLFSSL_SP_384 + if (mp_count_bits(modulus) == 384) { + return sp_ecc_mulmod_384(k, G, R, map, heap); + } +#endif + return ECC_BAD_ARG_E; +#endif +} -#ifdef ALT_ECC_SIZE +#endif /* !FP_ECC || !WOLFSSL_SP_MATH */ + +#endif /* !FREESCALE_LTC_ECC && !WOLFSSL_STM32_PKA */ -static void alt_fp_init(fp_int* a) +/** ECC Fixed Point mulmod global + k The multiplicand + G Base point to multiply + R [out] Destination of product + a ECC curve parameter a + modulus The modulus for the curve + map [boolean] If non-zero maps the point back to affine coordinates, + otherwise it's left in jacobian-montgomery form + return MP_OKAY if successful +*/ +int wc_ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, + mp_int* modulus, int map) { - a->size = FP_SIZE_ECC; - fp_zero(a); + return wc_ecc_mulmod_ex(k, G, R, a, modulus, map, NULL); } -#endif /* ALT_ECC_SIZE */ - +#endif /* !WOLFSSL_ATECC508A */ /** - Allocate a new ECC point - return A newly allocated point or NULL on error -*/ -ecc_point* ecc_new_point(void) + * use a heap hint when creating new ecc_point + * return an allocated point on success or NULL on failure + */ +ecc_point* wc_ecc_new_point_h(void* heap) { ecc_point* p; - p = (ecc_point*)XMALLOC(sizeof(ecc_point), 0, DYNAMIC_TYPE_ECC); + (void)heap; + + p = (ecc_point*)XMALLOC(sizeof(ecc_point), heap, DYNAMIC_TYPE_ECC); if (p == NULL) { return NULL; } XMEMSET(p, 0, sizeof(ecc_point)); -#ifndef USE_FAST_MATH - p->x->dp = NULL; - p->y->dp = NULL; - p->z->dp = NULL; -#endif - #ifndef ALT_ECC_SIZE if (mp_init_multi(p->x, p->y, p->z, NULL, NULL, NULL) != MP_OKAY) { - XFREE(p, 0, DYNAMIC_TYPE_ECC); + XFREE(p, heap, DYNAMIC_TYPE_ECC); return NULL; } #else @@ -1417,26 +3052,97 @@ ecc_point* ecc_new_point(void) return p; } -/** Free an ECC point from memory - p The point to free + +/** + Allocate a new ECC point + return A newly allocated point or NULL on error */ -void ecc_del_point(ecc_point* p) +ecc_point* wc_ecc_new_point(void) +{ + return wc_ecc_new_point_h(NULL); +} + + +void wc_ecc_del_point_h(ecc_point* p, void* heap) { /* prevents free'ing null arguments */ if (p != NULL) { mp_clear(p->x); mp_clear(p->y); mp_clear(p->z); - XFREE(p, 0, DYNAMIC_TYPE_ECC); + XFREE(p, heap, DYNAMIC_TYPE_ECC); } + (void)heap; +} + + +/** Free an ECC point from memory + p The point to free +*/ +void wc_ecc_del_point(ecc_point* p) +{ + wc_ecc_del_point_h(p, NULL); +} + + +/** Copy the value of a point to an other one + p The point to copy + r The created point +*/ +int wc_ecc_copy_point(ecc_point* p, ecc_point *r) +{ + int ret; + + /* prevents null arguments */ + if (p == NULL || r == NULL) + return ECC_BAD_ARG_E; + + ret = mp_copy(p->x, r->x); + if (ret != MP_OKAY) + return ret; + ret = mp_copy(p->y, r->y); + if (ret != MP_OKAY) + return ret; + ret = mp_copy(p->z, r->z); + if (ret != MP_OKAY) + return ret; + + return MP_OKAY; +} + +/** Compare the value of a point with an other one + a The point to compare + b The other point to compare + + return MP_EQ if equal, MP_LT/MP_GT if not, < 0 in case of error + */ +int wc_ecc_cmp_point(ecc_point* a, ecc_point *b) +{ + int ret; + + /* prevents null arguments */ + if (a == NULL || b == NULL) + return BAD_FUNC_ARG; + + ret = mp_cmp(a->x, b->x); + if (ret != MP_EQ) + return ret; + ret = mp_cmp(a->y, b->y); + if (ret != MP_EQ) + return ret; + ret = mp_cmp(a->z, b->z); + if (ret != MP_EQ) + return ret; + + return MP_EQ; } /** Returns whether an ECC idx is valid or not n The idx number to check return 1 if valid, 0 if not -*/ -static int ecc_is_valid_idx(int n) +*/ +int wc_ecc_is_valid_idx(int n) { int x; @@ -1444,84 +3150,741 @@ static int ecc_is_valid_idx(int n) ; /* -1 is a valid index --- indicating that the domain params were supplied by the user */ - if ((n >= -1) && (n < x)) { + if ((n >= ECC_CUSTOM_IDX) && (n < x)) { return 1; } + + return 0; +} + +int wc_ecc_get_curve_idx(int curve_id) +{ + int curve_idx; + for (curve_idx = 0; ecc_sets[curve_idx].size != 0; curve_idx++) { + if (curve_id == ecc_sets[curve_idx].id) + break; + } + if (ecc_sets[curve_idx].size == 0) { + return ECC_CURVE_INVALID; + } + return curve_idx; +} + +int wc_ecc_get_curve_id(int curve_idx) +{ + if (wc_ecc_is_valid_idx(curve_idx)) { + return ecc_sets[curve_idx].id; + } + return ECC_CURVE_INVALID; +} + +/* Returns the curve size that corresponds to a given ecc_curve_id identifier + * + * id curve id, from ecc_curve_id enum in ecc.h + * return curve size, from ecc_sets[] on success, negative on error + */ +int wc_ecc_get_curve_size_from_id(int curve_id) +{ + int curve_idx = wc_ecc_get_curve_idx(curve_id); + if (curve_idx == ECC_CURVE_INVALID) + return ECC_BAD_ARG_E; + return ecc_sets[curve_idx].size; +} + +/* Returns the curve index that corresponds to a given curve name in + * ecc_sets[] of ecc.c + * + * name curve name, from ecc_sets[].name in ecc.c + * return curve index in ecc_sets[] on success, negative on error + */ +int wc_ecc_get_curve_idx_from_name(const char* curveName) +{ + int curve_idx; + word32 len; + + if (curveName == NULL) + return BAD_FUNC_ARG; + + len = (word32)XSTRLEN(curveName); + + for (curve_idx = 0; ecc_sets[curve_idx].size != 0; curve_idx++) { + if ( + #ifndef WOLFSSL_ECC_CURVE_STATIC + ecc_sets[curve_idx].name && + #endif + XSTRNCASECMP(ecc_sets[curve_idx].name, curveName, len) == 0) { + break; + } + } + if (ecc_sets[curve_idx].size == 0) { + WOLFSSL_MSG("ecc_set curve name not found"); + return ECC_CURVE_INVALID; + } + return curve_idx; +} + +/* Returns the curve size that corresponds to a given curve name, + * as listed in ecc_sets[] of ecc.c. + * + * name curve name, from ecc_sets[].name in ecc.c + * return curve size, from ecc_sets[] on success, negative on error + */ +int wc_ecc_get_curve_size_from_name(const char* curveName) +{ + int curve_idx; + + if (curveName == NULL) + return BAD_FUNC_ARG; + + curve_idx = wc_ecc_get_curve_idx_from_name(curveName); + if (curve_idx < 0) + return curve_idx; + + return ecc_sets[curve_idx].size; +} + +/* Returns the curve id that corresponds to a given curve name, + * as listed in ecc_sets[] of ecc.c. + * + * name curve name, from ecc_sets[].name in ecc.c + * return curve id, from ecc_sets[] on success, negative on error + */ +int wc_ecc_get_curve_id_from_name(const char* curveName) +{ + int curve_idx; + + if (curveName == NULL) + return BAD_FUNC_ARG; + + curve_idx = wc_ecc_get_curve_idx_from_name(curveName); + if (curve_idx < 0) + return curve_idx; + + return ecc_sets[curve_idx].id; +} + +/* Compares a curve parameter (hex, from ecc_sets[]) to given input + * parameter for equality. + * encType is WC_TYPE_UNSIGNED_BIN or WC_TYPE_HEX_STR + * Returns MP_EQ on success, negative on error */ +static int wc_ecc_cmp_param(const char* curveParam, + const byte* param, word32 paramSz, int encType) +{ + int err = MP_OKAY; +#ifdef WOLFSSL_SMALL_STACK + mp_int* a = NULL; + mp_int* b = NULL; +#else + mp_int a[1], b[1]; +#endif + + if (param == NULL || curveParam == NULL) + return BAD_FUNC_ARG; + + if (encType == WC_TYPE_HEX_STR) + return XSTRNCMP(curveParam, (char*) param, paramSz); + +#ifdef WOLFSSL_SMALL_STACK + a = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + if (a == NULL) + return MEMORY_E; + b = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + if (b == NULL) { + XFREE(a, NULL, DYNAMIC_TYPE_ECC); + return MEMORY_E; + } +#endif + + if ((err = mp_init_multi(a, b, NULL, NULL, NULL, NULL)) != MP_OKAY) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(a, NULL, DYNAMIC_TYPE_ECC); + XFREE(b, NULL, DYNAMIC_TYPE_ECC); + #endif + return err; + } + + if (err == MP_OKAY) { + err = mp_read_unsigned_bin(a, param, paramSz); + } + if (err == MP_OKAY) + err = mp_read_radix(b, curveParam, MP_RADIX_HEX); + + if (err == MP_OKAY) { + if (mp_cmp(a, b) != MP_EQ) { + err = -1; + } else { + err = MP_EQ; + } + } + + mp_clear(a); + mp_clear(b); +#ifdef WOLFSSL_SMALL_STACK + XFREE(b, NULL, DYNAMIC_TYPE_ECC); + XFREE(a, NULL, DYNAMIC_TYPE_ECC); +#endif + + return err; +} + +/* Returns the curve id in ecc_sets[] that corresponds to a given set of + * curve parameters. + * + * fieldSize the field size in bits + * prime prime of the finite field + * primeSz size of prime in octets + * Af first coefficient a of the curve + * AfSz size of Af in octets + * Bf second coefficient b of the curve + * BfSz size of Bf in octets + * order curve order + * orderSz size of curve in octets + * Gx affine x coordinate of base point + * GxSz size of Gx in octets + * Gy affine y coordinate of base point + * GySz size of Gy in octets + * cofactor curve cofactor + * + * return curve id, from ecc_sets[] on success, negative on error + */ +int wc_ecc_get_curve_id_from_params(int fieldSize, + const byte* prime, word32 primeSz, const byte* Af, word32 AfSz, + const byte* Bf, word32 BfSz, const byte* order, word32 orderSz, + const byte* Gx, word32 GxSz, const byte* Gy, word32 GySz, int cofactor) +{ + int idx; + int curveSz; + + if (prime == NULL || Af == NULL || Bf == NULL || order == NULL || + Gx == NULL || Gy == NULL) + return BAD_FUNC_ARG; + + curveSz = (fieldSize + 1) / 8; /* round up */ + + for (idx = 0; ecc_sets[idx].size != 0; idx++) { + if (curveSz == ecc_sets[idx].size) { + if ((wc_ecc_cmp_param(ecc_sets[idx].prime, prime, + primeSz, WC_TYPE_UNSIGNED_BIN) == MP_EQ) && + (wc_ecc_cmp_param(ecc_sets[idx].Af, Af, AfSz, + WC_TYPE_UNSIGNED_BIN) == MP_EQ) && + (wc_ecc_cmp_param(ecc_sets[idx].Bf, Bf, BfSz, + WC_TYPE_UNSIGNED_BIN) == MP_EQ) && + (wc_ecc_cmp_param(ecc_sets[idx].order, order, + orderSz, WC_TYPE_UNSIGNED_BIN) == MP_EQ) && + (wc_ecc_cmp_param(ecc_sets[idx].Gx, Gx, GxSz, + WC_TYPE_UNSIGNED_BIN) == MP_EQ) && + (wc_ecc_cmp_param(ecc_sets[idx].Gy, Gy, GySz, + WC_TYPE_UNSIGNED_BIN) == MP_EQ) && + (cofactor == ecc_sets[idx].cofactor)) { + break; + } + } + } + + if (ecc_sets[idx].size == 0) + return ECC_CURVE_INVALID; + + return ecc_sets[idx].id; +} + +/* Returns the curve id in ecc_sets[] that corresponds + * to a given domain parameters pointer. + * + * dp domain parameters pointer + * + * return curve id, from ecc_sets[] on success, negative on error + */ +int wc_ecc_get_curve_id_from_dp_params(const ecc_set_type* dp) +{ + int idx; + + if (dp == NULL + #ifndef WOLFSSL_ECC_CURVE_STATIC + || dp->prime == NULL || dp->Af == NULL || + dp->Bf == NULL || dp->order == NULL || dp->Gx == NULL || dp->Gy == NULL + #endif + ) { + return BAD_FUNC_ARG; + } + + for (idx = 0; ecc_sets[idx].size != 0; idx++) { + if (dp->size == ecc_sets[idx].size) { + if ((wc_ecc_cmp_param(ecc_sets[idx].prime, (const byte*)dp->prime, + (word32)XSTRLEN(dp->prime), WC_TYPE_HEX_STR) == MP_EQ) && + (wc_ecc_cmp_param(ecc_sets[idx].Af, (const byte*)dp->Af, + (word32)XSTRLEN(dp->Af),WC_TYPE_HEX_STR) == MP_EQ) && + (wc_ecc_cmp_param(ecc_sets[idx].Bf, (const byte*)dp->Bf, + (word32)XSTRLEN(dp->Bf),WC_TYPE_HEX_STR) == MP_EQ) && + (wc_ecc_cmp_param(ecc_sets[idx].order, (const byte*)dp->order, + (word32)XSTRLEN(dp->order),WC_TYPE_HEX_STR) == MP_EQ) && + (wc_ecc_cmp_param(ecc_sets[idx].Gx, (const byte*)dp->Gx, + (word32)XSTRLEN(dp->Gx),WC_TYPE_HEX_STR) == MP_EQ) && + (wc_ecc_cmp_param(ecc_sets[idx].Gy, (const byte*)dp->Gy, + (word32)XSTRLEN(dp->Gy),WC_TYPE_HEX_STR) == MP_EQ) && + (dp->cofactor == ecc_sets[idx].cofactor)) { + break; + } + } + } + + if (ecc_sets[idx].size == 0) + return ECC_CURVE_INVALID; + + return ecc_sets[idx].id; +} + +/* Returns the curve id that corresponds to a given OID, + * as listed in ecc_sets[] of ecc.c. + * + * oid OID, from ecc_sets[].name in ecc.c + * len OID len, from ecc_sets[].name in ecc.c + * return curve id, from ecc_sets[] on success, negative on error + */ +int wc_ecc_get_curve_id_from_oid(const byte* oid, word32 len) +{ + int curve_idx; + + if (oid == NULL) + return BAD_FUNC_ARG; + + for (curve_idx = 0; ecc_sets[curve_idx].size != 0; curve_idx++) { + if ( + #ifndef WOLFSSL_ECC_CURVE_STATIC + ecc_sets[curve_idx].oid && + #endif + ecc_sets[curve_idx].oidSz == len && + XMEMCMP(ecc_sets[curve_idx].oid, oid, len) == 0) { + break; + } + } + if (ecc_sets[curve_idx].size == 0) { + WOLFSSL_MSG("ecc_set curve name not found"); + return ECC_CURVE_INVALID; + } + + return ecc_sets[curve_idx].id; +} + +/* Get curve parameters using curve index */ +const ecc_set_type* wc_ecc_get_curve_params(int curve_idx) +{ + const ecc_set_type* ecc_set = NULL; + + if (curve_idx >= 0 && curve_idx < (int)ECC_SET_COUNT) { + ecc_set = &ecc_sets[curve_idx]; + } + return ecc_set; +} + + +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) +static WC_INLINE int wc_ecc_alloc_mpint(ecc_key* key, mp_int** mp) +{ + if (key == NULL || mp == NULL) + return BAD_FUNC_ARG; + if (*mp == NULL) { + *mp = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_BIGINT); + if (*mp == NULL) { + return MEMORY_E; + } + XMEMSET(*mp, 0, sizeof(mp_int)); + } return 0; } +static WC_INLINE void wc_ecc_free_mpint(ecc_key* key, mp_int** mp) +{ + if (key && mp && *mp) { + mp_clear(*mp); + XFREE(*mp, key->heap, DYNAMIC_TYPE_BIGINT); + *mp = NULL; + } +} + +static int wc_ecc_alloc_async(ecc_key* key) +{ + int err = wc_ecc_alloc_mpint(key, &key->r); + if (err == 0) + err = wc_ecc_alloc_mpint(key, &key->s); + return err; +} + +static void wc_ecc_free_async(ecc_key* key) +{ + wc_ecc_free_mpint(key, &key->r); + wc_ecc_free_mpint(key, &key->s); +#ifdef HAVE_CAVIUM_V + wc_ecc_free_mpint(key, &key->e); + wc_ecc_free_mpint(key, &key->signK); +#endif /* HAVE_CAVIUM_V */ +} +#endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_ECC */ +#ifdef HAVE_ECC_DHE /** Create an ECC shared secret between two keys - private_key The private ECC key + private_key The private ECC key (heap hint based off of private key) public_key The public key out [out] Destination of the shared secret - Conforms to EC-DH from ANSI X9.63 + Conforms to EC-DH from ANSI X9.63 outlen [in/out] The max size and resulting size of the shared secret return MP_OKAY if successful */ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, word32* outlen) { - word32 x = 0; - ecc_point* result; - mp_int prime; - int err; - + int err; +#if defined(WOLFSSL_CRYPTOCELL) && !defined(WOLFSSL_ATECC508A) + CRYS_ECDH_TempData_t tempBuff; +#endif if (private_key == NULL || public_key == NULL || out == NULL || - outlen == NULL) + outlen == NULL) { return BAD_FUNC_ARG; + } + +#ifdef WOLF_CRYPTO_CB + if (private_key->devId != INVALID_DEVID) { + err = wc_CryptoCb_Ecdh(private_key, public_key, out, outlen); + if (err != CRYPTOCB_UNAVAILABLE) + return err; + /* fall-through when unavailable */ + } +#endif /* type valid? */ - if (private_key->type != ECC_PRIVATEKEY) { + if (private_key->type != ECC_PRIVATEKEY && + private_key->type != ECC_PRIVATEKEY_ONLY) { return ECC_BAD_ARG_E; } - if (ecc_is_valid_idx(private_key->idx) == 0 || - ecc_is_valid_idx(public_key->idx) == 0) + /* Verify domain params supplied */ + if (wc_ecc_is_valid_idx(private_key->idx) == 0 || + wc_ecc_is_valid_idx(public_key->idx) == 0) { return ECC_BAD_ARG_E; + } - if (XSTRNCMP(private_key->dp->name, public_key->dp->name, ECC_MAXNAME) != 0) + /* Verify curve id matches */ + if (private_key->dp->id != public_key->dp->id) { return ECC_BAD_ARG_E; - - /* make new point */ - result = ecc_new_point(); - if (result == NULL) { - return MEMORY_E; } - if ((err = mp_init(&prime)) != MP_OKAY) { - ecc_del_point(result); - return err; +#ifdef WOLFSSL_ATECC508A + /* For SECP256R1 use hardware */ + if (private_key->dp->id == ECC_SECP256R1) { + err = atmel_ecc_create_pms(private_key->slot, public_key->pubkey_raw, out); + *outlen = private_key->dp->size; + } + else { + err = NOT_COMPILED_IN; } +#elif defined(WOLFSSL_CRYPTOCELL) - err = mp_read_radix(&prime, (char *)private_key->dp->prime, 16); + /* generate a secret*/ + err = CRYS_ECDH_SVDP_DH(&public_key->ctx.pubKey, + &private_key->ctx.privKey, + out, + outlen, + &tempBuff); - if (err == MP_OKAY) - err = ecc_mulmod(&private_key->k, &public_key->pubkey, result, &prime,1); + if (err != SA_SILIB_RET_OK){ + WOLFSSL_MSG("CRYS_ECDH_SVDP_DH for secret failed"); + return err; + } - if (err == MP_OKAY) { - x = mp_unsigned_bin_size(&prime); - if (*outlen < x) - err = BUFFER_E; - } +#else + err = wc_ecc_shared_secret_ex(private_key, &public_key->pubkey, out, outlen); +#endif /* WOLFSSL_ATECC508A */ - if (err == MP_OKAY) { - XMEMSET(out, 0, x); - err = mp_to_unsigned_bin(result->x,out + (x - - mp_unsigned_bin_size(result->x))); - *outlen = x; - } + return err; +} - mp_clear(&prime); - ecc_del_point(result); - return err; +#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_CRYPTOCELL) + +static int wc_ecc_shared_secret_gen_sync(ecc_key* private_key, ecc_point* point, + byte* out, word32* outlen, ecc_curve_spec* curve) +{ + int err; +#ifndef WOLFSSL_SP_MATH + ecc_point* result = NULL; + word32 x = 0; +#endif + mp_int* k = &private_key->k; +#ifdef HAVE_ECC_CDH + mp_int k_lcl; + + /* if cofactor flag has been set */ + if (private_key->flags & WC_ECC_FLAG_COFACTOR) { + mp_digit cofactor = (mp_digit)private_key->dp->cofactor; + /* only perform cofactor calc if not equal to 1 */ + if (cofactor != 1) { + k = &k_lcl; + if (mp_init(k) != MP_OKAY) + return MEMORY_E; + /* multiply cofactor times private key "k" */ + err = mp_mul_d(&private_key->k, cofactor, k); + if (err != MP_OKAY) { + mp_clear(k); + return err; + } + } + } +#endif + +#ifdef WOLFSSL_HAVE_SP_ECC +#ifndef WOLFSSL_SP_NO_256 + if (private_key->idx != ECC_CUSTOM_IDX && + ecc_sets[private_key->idx].id == ECC_SECP256R1) { + err = sp_ecc_secret_gen_256(k, point, out, outlen, private_key->heap); + } + else +#endif +#ifdef WOLFSSL_SP_384 + if (private_key->idx != ECC_CUSTOM_IDX && + ecc_sets[private_key->idx].id == ECC_SECP384R1) { + err = sp_ecc_secret_gen_384(k, point, out, outlen, private_key->heap); + } + else +#endif +#endif +#ifdef WOLFSSL_SP_MATH + { + err = WC_KEY_SIZE_E; + + (void)curve; + } +#else + { + mp_digit mp = 0; + + /* make new point */ + result = wc_ecc_new_point_h(private_key->heap); + if (result == NULL) { +#ifdef HAVE_ECC_CDH + if (k == &k_lcl) + mp_clear(k); +#endif + return MEMORY_E; + } + + /* Map in a separate call as this should be constant time */ + err = wc_ecc_mulmod_ex(k, point, result, curve->Af, curve->prime, 0, + private_key->heap); + if (err == MP_OKAY) { + err = mp_montgomery_setup(curve->prime, &mp); + } + if (err == MP_OKAY) { + /* Use constant time map if compiled in */ + err = ecc_map_ex(result, curve->prime, mp, 1); + } + if (err == MP_OKAY) { + x = mp_unsigned_bin_size(curve->prime); + if (*outlen < x || (int)x < mp_unsigned_bin_size(result->x)) { + err = BUFFER_E; + } + } + + if (err == MP_OKAY) { + XMEMSET(out, 0, x); + err = mp_to_unsigned_bin(result->x,out + + (x - mp_unsigned_bin_size(result->x))); + } + *outlen = x; + + wc_ecc_del_point_h(result, private_key->heap); + } +#endif +#ifdef HAVE_ECC_CDH + if (k == &k_lcl) + mp_clear(k); +#endif + + return err; +} + +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) +static int wc_ecc_shared_secret_gen_async(ecc_key* private_key, + ecc_point* point, byte* out, word32 *outlen, + ecc_curve_spec* curve) +{ + int err; + +#if defined(HAVE_CAVIUM_V) || defined(HAVE_INTEL_QA) +#ifdef HAVE_CAVIUM_V + /* verify the curve is supported by hardware */ + if (NitroxEccIsCurveSupported(private_key)) +#endif + { + word32 keySz = private_key->dp->size; + + /* sync public key x/y */ + err = wc_mp_to_bigint_sz(&private_key->k, &private_key->k.raw, keySz); + if (err == MP_OKAY) + err = wc_mp_to_bigint_sz(point->x, &point->x->raw, keySz); + if (err == MP_OKAY) + err = wc_mp_to_bigint_sz(point->y, &point->y->raw, keySz); + #ifdef HAVE_CAVIUM_V + /* allocate buffer for output */ + if (err == MP_OKAY) + err = wc_ecc_alloc_mpint(private_key, &private_key->e); + if (err == MP_OKAY) + err = wc_bigint_alloc(&private_key->e->raw, + NitroxEccGetSize(private_key)*2); + if (err == MP_OKAY) + err = NitroxEcdh(private_key, + &private_key->k.raw, &point->x->raw, &point->y->raw, + private_key->e->raw.buf, &private_key->e->raw.len, + &curve->prime->raw); + #else + if (err == MP_OKAY) + err = wc_ecc_curve_load(private_key->dp, &curve, ECC_CURVE_FIELD_BF); + if (err == MP_OKAY) + err = IntelQaEcdh(&private_key->asyncDev, + &private_key->k.raw, &point->x->raw, &point->y->raw, + out, outlen, + &curve->Af->raw, &curve->Bf->raw, &curve->prime->raw, + private_key->dp->cofactor); + #endif + return err; + } +#elif defined(WOLFSSL_ASYNC_CRYPT_TEST) + if (wc_AsyncTestInit(&private_key->asyncDev, ASYNC_TEST_ECC_SHARED_SEC)) { + WC_ASYNC_TEST* testDev = &private_key->asyncDev.test; + testDev->eccSharedSec.private_key = private_key; + testDev->eccSharedSec.public_point = point; + testDev->eccSharedSec.out = out; + testDev->eccSharedSec.outLen = outlen; + return WC_PENDING_E; + } +#endif + + /* use sync in other cases */ + err = wc_ecc_shared_secret_gen_sync(private_key, point, out, outlen, curve); + + return err; +} +#endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_ECC */ + +int wc_ecc_shared_secret_gen(ecc_key* private_key, ecc_point* point, + byte* out, word32 *outlen) +{ + int err; + DECLARE_CURVE_SPECS(curve, 2); + + if (private_key == NULL || point == NULL || out == NULL || + outlen == NULL) { + return BAD_FUNC_ARG; + } + + /* load curve info */ + ALLOC_CURVE_SPECS(2); + err = wc_ecc_curve_load(private_key->dp, &curve, + (ECC_CURVE_FIELD_PRIME | ECC_CURVE_FIELD_AF)); + if (err != MP_OKAY) { + FREE_CURVE_SPECS(); + return err; + } + +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + if (private_key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_ECC) { + err = wc_ecc_shared_secret_gen_async(private_key, point, + out, outlen, curve); + } + else +#endif + { + err = wc_ecc_shared_secret_gen_sync(private_key, point, + out, outlen, curve); + } + + wc_ecc_curve_free(curve); + FREE_CURVE_SPECS(); + + return err; +} + +/** + Create an ECC shared secret between private key and public point + private_key The private ECC key (heap hint based on private key) + point The point to use (public key) + out [out] Destination of the shared secret + Conforms to EC-DH from ANSI X9.63 + outlen [in/out] The max size and resulting size of the shared secret + return MP_OKAY if successful +*/ +int wc_ecc_shared_secret_ex(ecc_key* private_key, ecc_point* point, + byte* out, word32 *outlen) +{ + int err; + + if (private_key == NULL || point == NULL || out == NULL || + outlen == NULL) { + return BAD_FUNC_ARG; + } + + /* type valid? */ + if (private_key->type != ECC_PRIVATEKEY && + private_key->type != ECC_PRIVATEKEY_ONLY) { + return ECC_BAD_ARG_E; + } + + /* Verify domain params supplied */ + if (wc_ecc_is_valid_idx(private_key->idx) == 0) + return ECC_BAD_ARG_E; + + switch(private_key->state) { + case ECC_STATE_NONE: + case ECC_STATE_SHARED_SEC_GEN: + private_key->state = ECC_STATE_SHARED_SEC_GEN; + + err = wc_ecc_shared_secret_gen(private_key, point, out, outlen); + if (err < 0) { + break; + } + FALL_THROUGH; + + case ECC_STATE_SHARED_SEC_RES: + private_key->state = ECC_STATE_SHARED_SEC_RES; + #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + if (private_key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_ECC) { + #ifdef HAVE_CAVIUM_V + /* verify the curve is supported by hardware */ + if (NitroxEccIsCurveSupported(private_key)) { + /* copy output */ + *outlen = private_key->dp->size; + XMEMCPY(out, private_key->e->raw.buf, *outlen); + } + #endif /* HAVE_CAVIUM_V */ + } + #endif /* WOLFSSL_ASYNC_CRYPT */ + err = 0; + break; + + default: + err = BAD_STATE_E; + } /* switch */ + + /* if async pending then return and skip done cleanup below */ + if (err == WC_PENDING_E) { + private_key->state++; + return err; + } + + /* cleanup */ +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + wc_ecc_free_async(private_key); +#endif + private_key->state = ECC_STATE_NONE; + + return err; } +#endif /* !WOLFSSL_ATECC508A && !WOLFSSL_CRYPTOCELL */ +#endif /* HAVE_ECC_DHE */ +#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_CRYPTOCELL) /* return 1 if point is at infinity, 0 if not, < 0 on error */ -static int ecc_point_is_at_infinity(ecc_point* p) +int wc_ecc_point_is_at_infinity(ecc_point* p) { if (p == NULL) return BAD_FUNC_ARG; @@ -1532,317 +3895,1461 @@ static int ecc_point_is_at_infinity(ecc_point* p) return 0; } +/* generate random and ensure its greater than 0 and less than order */ +int wc_ecc_gen_k(WC_RNG* rng, int size, mp_int* k, mp_int* order) +{ +#ifndef WC_NO_RNG + int err; + byte buf[ECC_MAXSIZE_GEN]; -int wc_ecc_make_key_ex(RNG* rng, ecc_key* key, const ecc_set_type* dp); + /*generate 8 extra bytes to mitigate bias from the modulo operation below*/ + /*see section A.1.2 in 'Suite B Implementor's Guide to FIPS 186-3 (ECDSA)'*/ + size += 8; -/** - Make a new ECC key - rng An active RNG state - keysize The keysize for the new key (in octets from 20 to 65 bytes) - key [out] Destination of the newly created key - return MP_OKAY if successful, - upon error all allocated memory will be freed -*/ -int wc_ecc_make_key(RNG* rng, int keysize, ecc_key* key) -{ - int x, err; + /* make up random string */ + err = wc_RNG_GenerateBlock(rng, buf, size); - if (key == NULL || rng == NULL) - return ECC_BAD_ARG_E; + /* load random buffer data into k */ + if (err == 0) + err = mp_read_unsigned_bin(k, (byte*)buf, size); - /* find key size */ - for (x = 0; (keysize > ecc_sets[x].size) && (ecc_sets[x].size != 0); x++) - ; - keysize = ecc_sets[x].size; + /* the key should be smaller than the order of base point */ + if (err == MP_OKAY) { + if (mp_cmp(k, order) != MP_LT) { + err = mp_mod(k, order, k); + } + } - if (keysize > ECC_MAXSIZE || ecc_sets[x].size == 0) { - return BAD_FUNC_ARG; - } - err = wc_ecc_make_key_ex(rng, key, &ecc_sets[x]); - key->idx = x; + /* quick sanity check to make sure we're not dealing with a 0 key */ + if (err == MP_OKAY) { + if (mp_iszero(k) == MP_YES) + err = MP_ZERO_E; + } - return err; + ForceZero(buf, ECC_MAXSIZE); + + return err; +#else + (void)rng; + (void)size; + (void)k; + (void)order; + return NOT_COMPILED_IN; +#endif /* !WC_NO_RNG */ } +#endif /* !WOLFSSL_ATECC508A && !WOLFSSL_CRYPTOCELL */ -int wc_ecc_make_key_ex(RNG* rng, ecc_key* key, const ecc_set_type* dp) +static WC_INLINE void wc_ecc_reset(ecc_key* key) { - int err; - ecc_point* base; - mp_int prime; - mp_int order; -#ifdef WOLFSSL_SMALL_STACK - byte* buf; -#else - byte buf[ECC_MAXSIZE]; -#endif - int keysize; - int po_init = 0; /* prime order Init flag for clear */ + /* make sure required key variables are reset */ + key->state = ECC_STATE_NONE; +} - if (key == NULL || rng == NULL || dp == NULL) - return ECC_BAD_ARG_E; -#ifdef WOLFSSL_SMALL_STACK - buf = (byte*)XMALLOC(ECC_MAXSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (buf == NULL) - return MEMORY_E; +/* create the public ECC key from a private key + * + * key an initialized private key to generate public part from + * curveIn [in]curve for key, can be NULL + * pubOut [out]ecc_point holding the public key, if NULL then public key part + * is cached in key instead. + * + * Note this function is local to the file because of the argument type + * ecc_curve_spec. Having this argument allows for not having to load the + * curve type multiple times when generating a key with wc_ecc_make_key(). + * + * returns MP_OKAY on success + */ +static int wc_ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn, + ecc_point* pubOut) +{ + int err = MP_OKAY; +#ifndef WOLFSSL_ATECC508A +#ifndef WOLFSSL_SP_MATH + ecc_point* base = NULL; #endif + ecc_point* pub; + DECLARE_CURVE_SPECS(curve, ECC_CURVE_FIELD_COUNT); +#endif /* !WOLFSSL_ATECC508A */ + + if (key == NULL) { + return BAD_FUNC_ARG; + } + +#ifndef WOLFSSL_ATECC508A + + /* if ecc_point passed in then use it as output for public key point */ + if (pubOut != NULL) { + pub = pubOut; + } + else { + /* caching public key making it a ECC_PRIVATEKEY instead of + ECC_PRIVATEKEY_ONLY */ + pub = &key->pubkey; + key->type = ECC_PRIVATEKEY_ONLY; + } - key->idx = -1; - key->dp = dp; - keysize = dp->size; + /* avoid loading the curve unless it is not passed in */ + if (curveIn != NULL) { + curve = curveIn; + } + else { + /* load curve info */ + if (err == MP_OKAY) { + ALLOC_CURVE_SPECS(ECC_CURVE_FIELD_COUNT); + err = wc_ecc_curve_load(key->dp, &curve, ECC_CURVE_FIELD_ALL); + } + } - /* allocate ram */ - base = NULL; + if (err == MP_OKAY) { + #ifndef ALT_ECC_SIZE + err = mp_init_multi(pub->x, pub->y, pub->z, NULL, NULL, NULL); + #else + pub->x = (mp_int*)&pub->xyz[0]; + pub->y = (mp_int*)&pub->xyz[1]; + pub->z = (mp_int*)&pub->xyz[2]; + alt_fp_init(pub->x); + alt_fp_init(pub->y); + alt_fp_init(pub->z); + #endif + } - /* make up random string */ - err = wc_RNG_GenerateBlock(rng, buf, keysize); - if (err == 0) - buf[0] |= 0x0c; - /* setup the key variables */ - if (err == 0) { -#ifndef ALT_ECC_SIZE - err = mp_init_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, - &key->k, &prime, &order); -#else - key->pubkey.x = (mp_int*)&key->pubkey.xyz[0]; - key->pubkey.y = (mp_int*)&key->pubkey.xyz[1]; - key->pubkey.z = (mp_int*)&key->pubkey.xyz[2]; - alt_fp_init(key->pubkey.x); - alt_fp_init(key->pubkey.y); - alt_fp_init(key->pubkey.z); - err = mp_init_multi(&key->k, &prime, &order, NULL, NULL, NULL); + if (err != MP_OKAY) { + } + else +#ifdef WOLFSSL_HAVE_SP_ECC +#ifndef WOLFSSL_SP_NO_256 + if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP256R1) { + err = sp_ecc_mulmod_base_256(&key->k, pub, 1, key->heap); + } + else #endif - if (err != MP_OKAY) - err = MEMORY_E; - else - po_init = 1; - } +#ifdef WOLFSSL_SP_384 + if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP384R1) { + err = sp_ecc_mulmod_base_384(&key->k, pub, 1, key->heap); + } + else +#endif +#endif +#ifdef WOLFSSL_SP_MATH + err = WC_KEY_SIZE_E; +#else + { + mp_digit mp; - if (err == MP_OKAY) { - base = ecc_new_point(); - if (base == NULL) - err = MEMORY_E; - } + base = wc_ecc_new_point_h(key->heap); + if (base == NULL) + err = MEMORY_E; + /* read in the x/y for this key */ + if (err == MP_OKAY) + err = mp_copy(curve->Gx, base->x); + if (err == MP_OKAY) + err = mp_copy(curve->Gy, base->y); + if (err == MP_OKAY) + err = mp_set(base->z, 1); - /* read in the specs for this key */ - if (err == MP_OKAY) - err = mp_read_radix(&prime, (char *)key->dp->prime, 16); - if (err == MP_OKAY) - err = mp_read_radix(&order, (char *)key->dp->order, 16); - if (err == MP_OKAY) - err = mp_read_radix(base->x, (char *)key->dp->Gx, 16); - if (err == MP_OKAY) - err = mp_read_radix(base->y, (char *)key->dp->Gy, 16); - - if (err == MP_OKAY) - mp_set(base->z, 1); - if (err == MP_OKAY) - err = mp_read_unsigned_bin(&key->k, (byte*)buf, keysize); - - /* the key should be smaller than the order of base point */ - if (err == MP_OKAY) { - if (mp_cmp(&key->k, &order) != MP_LT) - err = mp_mod(&key->k, &order, &key->k); - } - /* make the public key */ - if (err == MP_OKAY) - err = ecc_mulmod(&key->k, base, &key->pubkey, &prime, 1); + /* make the public key */ + if (err == MP_OKAY) { + /* Map in a separate call as this should be constant time */ + err = wc_ecc_mulmod_ex(&key->k, base, pub, curve->Af, curve->prime, + 0, key->heap); + if (err == MP_MEM) { + err = MEMORY_E; + } + } + if (err == MP_OKAY) { + err = mp_montgomery_setup(curve->prime, &mp); + } + if (err == MP_OKAY) { + /* Use constant time map if compiled in */ + err = ecc_map_ex(pub, curve->prime, mp, 1); + } + + wc_ecc_del_point_h(base, key->heap); + } +#endif #ifdef WOLFSSL_VALIDATE_ECC_KEYGEN - /* validate the public key, order * pubkey = point at infinity */ - if (err == MP_OKAY) - err = ecc_check_pubkey_order(key, &prime, &order); + /* validate the public key, order * pubkey = point at infinity */ + if (err == MP_OKAY) + err = ecc_check_pubkey_order(key, pub, curve->Af, curve->prime, + curve->order); #endif /* WOLFSSL_VALIDATE_KEYGEN */ - if (err == MP_OKAY) - key->type = ECC_PRIVATEKEY; + if (err != MP_OKAY) { + /* clean up if failed */ + #ifndef ALT_ECC_SIZE + mp_clear(pub->x); + mp_clear(pub->y); + mp_clear(pub->z); + #endif + } - if (err != MP_OKAY) { - /* clean up */ - mp_clear(key->pubkey.x); - mp_clear(key->pubkey.y); - mp_clear(key->pubkey.z); - mp_clear(&key->k); + /* free up local curve */ + if (curveIn == NULL) { + wc_ecc_curve_free(curve); + FREE_CURVE_SPECS(); + } + +#else + (void)curveIn; + err = NOT_COMPILED_IN; +#endif /* WOLFSSL_ATECC508A */ + + /* change key state if public part is cached */ + if (key->type == ECC_PRIVATEKEY_ONLY && pubOut == NULL) { + key->type = ECC_PRIVATEKEY; + } + + return err; +} + + +/* create the public ECC key from a private key + * + * key an initialized private key to generate public part from + * pubOut [out]ecc_point holding the public key, if NULL then public key part + * is cached in key instead. + * + * + * returns MP_OKAY on success + */ +int wc_ecc_make_pub(ecc_key* key, ecc_point* pubOut) +{ + WOLFSSL_ENTER("wc_ecc_make_pub"); + + return wc_ecc_make_pub_ex(key, NULL, pubOut); +} + + +WOLFSSL_ABI +int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) +{ + int err; +#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_CRYPTOCELL) +#ifndef WOLFSSL_SP_MATH + DECLARE_CURVE_SPECS(curve, ECC_CURVE_FIELD_COUNT); +#endif +#endif /* !WOLFSSL_ATECC508A */ +#if defined(WOLFSSL_CRYPTOCELL) && !defined(WOLFSSL_ATECC508A) + const CRYS_ECPKI_Domain_t* pDomain; + CRYS_ECPKI_KG_TempData_t tempBuff; + CRYS_ECPKI_KG_FipsContext_t fipsCtx; + byte ucompressed_key[ECC_MAX_CRYPTO_HW_SIZE*2 + 1]; + word32 raw_size = 0; +#endif + if (key == NULL || rng == NULL) { + return BAD_FUNC_ARG; + } + + /* make sure required variables are reset */ + wc_ecc_reset(key); + + err = wc_ecc_set_curve(key, keysize, curve_id); + if (err != 0) { + return err; + } + +#ifdef WOLF_CRYPTO_CB + if (key->devId != INVALID_DEVID) { + err = wc_CryptoCb_MakeEccKey(rng, keysize, key, curve_id); + if (err != CRYPTOCB_UNAVAILABLE) + return err; + /* fall-through when unavailable */ + } +#endif + +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_ECC) { + #ifdef HAVE_CAVIUM + /* TODO: Not implemented */ + #elif defined(HAVE_INTEL_QA) + /* TODO: Not implemented */ + #else + if (wc_AsyncTestInit(&key->asyncDev, ASYNC_TEST_ECC_MAKE)) { + WC_ASYNC_TEST* testDev = &key->asyncDev.test; + testDev->eccMake.rng = rng; + testDev->eccMake.key = key; + testDev->eccMake.size = keysize; + testDev->eccMake.curve_id = curve_id; + return WC_PENDING_E; + } + #endif + } +#endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_ECC */ + +#ifdef WOLFSSL_ATECC508A + if (key->dp->id == ECC_SECP256R1) { + key->type = ECC_PRIVATEKEY; + key->slot = atmel_ecc_alloc(ATMEL_SLOT_ECDHE); + err = atmel_ecc_create_key(key->slot, key->pubkey_raw); + + /* populate key->pubkey */ + if (err == 0 + #ifdef ALT_ECC_SIZE + && key->pubkey.x + #endif + ) { + err = mp_read_unsigned_bin(key->pubkey.x, key->pubkey_raw, + ECC_MAX_CRYPTO_HW_SIZE); + } + if (err == 0 + #ifdef ALT_ECC_SIZE + && key->pubkey.y + #endif + ) { + err = mp_read_unsigned_bin(key->pubkey.y, + key->pubkey_raw + ECC_MAX_CRYPTO_HW_SIZE, + ECC_MAX_CRYPTO_HW_SIZE); + } } - ecc_del_point(base); - if (po_init) { - mp_clear(&prime); - mp_clear(&order); + else { + err = NOT_COMPILED_IN; } +#elif defined(WOLFSSL_CRYPTOCELL) - ForceZero(buf, ECC_MAXSIZE); -#ifdef WOLFSSL_SMALL_STACK - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + pDomain = CRYS_ECPKI_GetEcDomain(cc310_mapCurve(curve_id)); + raw_size = (word32)(key->dp->size)*2 + 1; + + /* generate first key pair */ + err = CRYS_ECPKI_GenKeyPair(&wc_rndState, + wc_rndGenVectFunc, + pDomain, + &key->ctx.privKey, + &key->ctx.pubKey, + &tempBuff, + &fipsCtx); + + if (err != SA_SILIB_RET_OK){ + WOLFSSL_MSG("CRYS_ECPKI_GenKeyPair for key pair failed"); + return err; + } + key->type = ECC_PRIVATEKEY; + + err = CRYS_ECPKI_ExportPublKey(&key->ctx.pubKey, + CRYS_EC_PointUncompressed, + &ucompressed_key[0], + &raw_size); + + if (err == SA_SILIB_RET_OK && key->pubkey.x && key->pubkey.y) { + err = mp_read_unsigned_bin(key->pubkey.x, + &ucompressed_key[1], key->dp->size); + if (err == MP_OKAY) { + err = mp_read_unsigned_bin(key->pubkey.y, + &ucompressed_key[1+key->dp->size],key->dp->size); + } + } + raw_size = key->dp->size; + if (err == MP_OKAY) { + err = CRYS_ECPKI_ExportPrivKey(&key->ctx.privKey, + ucompressed_key, + &raw_size); + } + + if (err == SA_SILIB_RET_OK) { + err = mp_read_unsigned_bin(&key->k, ucompressed_key, raw_size); + } + +#else + +#ifdef WOLFSSL_HAVE_SP_ECC +#ifndef WOLFSSL_SP_NO_256 + if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP256R1) { + err = sp_ecc_make_key_256(rng, &key->k, &key->pubkey, key->heap); + if (err == MP_OKAY) { + key->type = ECC_PRIVATEKEY; + } + } + else +#endif +#ifdef WOLFSSL_SP_384 + if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP384R1) { + err = sp_ecc_make_key_384(rng, &key->k, &key->pubkey, key->heap); + if (err == MP_OKAY) { + key->type = ECC_PRIVATEKEY; + } + } + else #endif +#endif /* WOLFSSL_HAVE_SP_ECC */ - return err; + { /* software key gen */ +#ifdef WOLFSSL_SP_MATH + err = WC_KEY_SIZE_E; +#else + + /* setup the key variables */ + err = mp_init(&key->k); + + /* load curve info */ + if (err == MP_OKAY) { + ALLOC_CURVE_SPECS(ECC_CURVE_FIELD_COUNT); + err = wc_ecc_curve_load(key->dp, &curve, ECC_CURVE_FIELD_ALL); + } + + /* generate k */ + if (err == MP_OKAY) + err = wc_ecc_gen_k(rng, key->dp->size, &key->k, curve->order); + + /* generate public key from k */ + if (err == MP_OKAY) + err = wc_ecc_make_pub_ex(key, curve, NULL); + + if (err == MP_OKAY) + key->type = ECC_PRIVATEKEY; + + /* cleanup these on failure case only */ + if (err != MP_OKAY) { + /* clean up */ + mp_forcezero(&key->k); + } + + /* cleanup allocations */ + wc_ecc_curve_free(curve); + FREE_CURVE_SPECS(); +#endif /* WOLFSSL_SP_MATH */ + } + +#ifdef HAVE_WOLF_BIGINT + if (err == MP_OKAY) + err = wc_mp_to_bigint(&key->k, &key->k.raw); + if (err == MP_OKAY) + err = wc_mp_to_bigint(key->pubkey.x, &key->pubkey.x->raw); + if (err == MP_OKAY) + err = wc_mp_to_bigint(key->pubkey.y, &key->pubkey.y->raw); + if (err == MP_OKAY) + err = wc_mp_to_bigint(key->pubkey.z, &key->pubkey.z->raw); +#endif + +#endif /* WOLFSSL_ATECC508A */ + + return err; } +#ifdef ECC_DUMP_OID +/* Optional dump of encoded OID for adding new curves */ +static int mOidDumpDone; +static void wc_ecc_dump_oids(void) +{ + int x; -/* Setup dynamic pointers is using normal math for proper freeing */ -int wc_ecc_init(ecc_key* key) + if (mOidDumpDone) { + return; + } + + /* find matching OID sum (based on encoded value) */ + for (x = 0; ecc_sets[x].size != 0; x++) { + int i; + byte* oid; + word32 oidSz, sum = 0; + + printf("ECC %s (%d):\n", ecc_sets[x].name, x); + + #ifdef HAVE_OID_ENCODING + byte oidEnc[ECC_MAX_OID_LEN]; + + oid = oidEnc; + oidSz = ECC_MAX_OID_LEN; + + printf("OID: "); + for (i = 0; i < (int)ecc_sets[x].oidSz; i++) { + printf("%d.", ecc_sets[x].oid[i]); + } + printf("\n"); + + EncodeObjectId(ecc_sets[x].oid, ecc_sets[x].oidSz, oidEnc, &oidSz); + #else + oid = (byte*)ecc_sets[x].oid; + oidSz = ecc_sets[x].oidSz; + #endif + + printf("OID Encoded: "); + for (i = 0; i < (int)oidSz; i++) { + printf("0x%02X,", oid[i]); + } + printf("\n"); + + for (i = 0; i < (int)oidSz; i++) { + sum += oid[i]; + } + printf("Sum: %d\n", sum); + + /* validate sum */ + if (ecc_sets[x].oidSum != sum) { + printf(" Sum %d Not Valid!\n", ecc_sets[x].oidSum); + } + } + mOidDumpDone = 1; +} +#endif /* ECC_DUMP_OID */ + + +WOLFSSL_ABI +ecc_key* wc_ecc_key_new(void* heap) +{ + ecc_key* key; + + key = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, DYNAMIC_TYPE_ECC); + if (key) { + if (wc_ecc_init_ex(key, heap, INVALID_DEVID) != 0) { + XFREE(key, heap, DYNAMIC_TYPE_ECC); + key = NULL; + } + } + + return key; +} + + +WOLFSSL_ABI +void wc_ecc_key_free(ecc_key* key) +{ + if (key) { + void* heap = key->heap; + + wc_ecc_free(key); + ForceZero(key, sizeof(ecc_key)); + XFREE(key, heap, DYNAMIC_TYPE_ECC); + (void)heap; + } +} + + +/** + Make a new ECC key + rng An active RNG state + keysize The keysize for the new key (in octets from 20 to 65 bytes) + key [out] Destination of the newly created key + return MP_OKAY if successful, + upon error all allocated memory will be freed + */ +int wc_ecc_make_key(WC_RNG* rng, int keysize, ecc_key* key) +{ + return wc_ecc_make_key_ex(rng, keysize, key, ECC_CURVE_DEF); +} + +/* Setup dynamic pointers if using normal math for proper freeing */ +WOLFSSL_ABI +int wc_ecc_init_ex(ecc_key* key, void* heap, int devId) { - (void)key; + int ret = 0; -#ifndef USE_FAST_MATH - key->pubkey.x->dp = NULL; - key->pubkey.y->dp = NULL; - key->pubkey.z->dp = NULL; + if (key == NULL) { + return BAD_FUNC_ARG; + } - key->k.dp = NULL; +#ifdef ECC_DUMP_OID + wc_ecc_dump_oids(); #endif -#ifdef ALT_ECC_SIZE - if (mp_init(&key->k) != MP_OKAY) - return MEMORY_E; + XMEMSET(key, 0, sizeof(ecc_key)); + key->state = ECC_STATE_NONE; +#if defined(PLUTON_CRYPTO_ECC) || defined(WOLF_CRYPTO_CB) + key->devId = devId; +#else + (void)devId; +#endif + +#ifdef WOLFSSL_ATECC508A + key->slot = ATECC_INVALID_SLOT; +#else +#ifdef ALT_ECC_SIZE key->pubkey.x = (mp_int*)&key->pubkey.xyz[0]; key->pubkey.y = (mp_int*)&key->pubkey.xyz[1]; key->pubkey.z = (mp_int*)&key->pubkey.xyz[2]; alt_fp_init(key->pubkey.x); alt_fp_init(key->pubkey.y); alt_fp_init(key->pubkey.z); + ret = mp_init(&key->k); + if (ret != MP_OKAY) { + return MEMORY_E; + } +#else + ret = mp_init_multi(&key->k, key->pubkey.x, key->pubkey.y, key->pubkey.z, + NULL, NULL); + if (ret != MP_OKAY) { + return MEMORY_E; + } +#endif /* ALT_ECC_SIZE */ +#endif /* WOLFSSL_ATECC508A */ + +#ifdef WOLFSSL_HEAP_TEST + key->heap = (void*)WOLFSSL_HEAP_TEST; +#else + key->heap = heap; +#endif + +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + /* handle as async */ + ret = wolfAsync_DevCtxInit(&key->asyncDev, WOLFSSL_ASYNC_MARKER_ECC, + key->heap, devId); +#endif + +#if defined(WOLFSSL_DSP) + key->handle = -1; +#endif + return ret; +} + +int wc_ecc_init(ecc_key* key) +{ + return wc_ecc_init_ex(key, NULL, INVALID_DEVID); +} + +#ifdef HAVE_PKCS11 +int wc_ecc_init_id(ecc_key* key, unsigned char* id, int len, void* heap, + int devId) +{ + int ret = 0; + + if (key == NULL) + ret = BAD_FUNC_ARG; + if (ret == 0 && (len < 0 || len > ECC_MAX_ID_LEN)) + ret = BUFFER_E; + + if (ret == 0) + ret = wc_ecc_init_ex(key, heap, devId); + + if (ret == 0 && id != NULL && len != 0) { + XMEMCPY(key->id, id, len); + key->idLen = len; + } + + return ret; +} #endif +int wc_ecc_set_flags(ecc_key* key, word32 flags) +{ + if (key == NULL) { + return BAD_FUNC_ARG; + } + key->flags |= flags; return 0; } +static int wc_ecc_get_curve_order_bit_count(const ecc_set_type* dp) +{ + int err; + word32 orderBits; + DECLARE_CURVE_SPECS(curve, 1); + + ALLOC_CURVE_SPECS(1); + err = wc_ecc_curve_load(dp, &curve, ECC_CURVE_FIELD_ORDER); + if (err != 0) { + FREE_CURVE_SPECS(); + return err; + } + orderBits = mp_count_bits(curve->order); + + wc_ecc_curve_free(curve); + FREE_CURVE_SPECS(); + return (int)orderBits; +} + +#ifdef HAVE_ECC_SIGN + +#ifndef NO_ASN + +#if defined(WOLFSSL_ATECC508A) || defined(PLUTON_CRYPTO_ECC) || \ + defined(WOLFSSL_CRYPTOCELL) +static int wc_ecc_sign_hash_hw(const byte* in, word32 inlen, + mp_int* r, mp_int* s, byte* out, word32 *outlen, WC_RNG* rng, + ecc_key* key) +{ + int err; +#ifdef PLUTON_CRYPTO_ECC + if (key->devId != INVALID_DEVID) /* use hardware */ +#endif + { + #if defined(WOLFSSL_CRYPTOCELL) && !defined(WOLFSSL_ATECC508A) + CRYS_ECDSA_SignUserContext_t sigCtxTemp; + word32 raw_sig_size = *outlen; + word32 msgLenInBytes = inlen; + CRYS_ECPKI_HASH_OpMode_t hash_mode; + #endif + word32 keysize = (word32)key->dp->size; + word32 orderBits = wc_ecc_get_curve_order_bit_count(key->dp); + + /* Check args */ + if (keysize > ECC_MAX_CRYPTO_HW_SIZE || *outlen < keysize*2) { + return ECC_BAD_ARG_E; + } + + #if defined(WOLFSSL_ATECC508A) + key->slot = atmel_ecc_alloc(ATMEL_SLOT_DEVICE); + if (key->slot == ATECC_INVALID_SLOT) { + return ECC_BAD_ARG_E; + } + + /* Sign: Result is 32-bytes of R then 32-bytes of S */ + err = atmel_ecc_sign(key->slot, in, out); + if (err != 0) { + return err; + } + #elif defined(PLUTON_CRYPTO_ECC) + { + /* if the input is larger than curve order, we must truncate */ + if ((inlen * WOLFSSL_BIT_SIZE) > orderBits) { + inlen = (orderBits + WOLFSSL_BIT_SIZE - 1) / WOLFSSL_BIT_SIZE; + } + + /* perform ECC sign */ + word32 raw_sig_size = *outlen; + err = Crypto_EccSign(in, inlen, out, &raw_sig_size); + if (err != CRYPTO_RES_SUCCESS || raw_sig_size != keysize*2){ + return BAD_COND_E; + } + } + #elif defined(WOLFSSL_CRYPTOCELL) + + hash_mode = cc310_hashModeECC(msgLenInBytes); + if (hash_mode == CRYS_ECPKI_HASH_OpModeLast) { + hash_mode = cc310_hashModeECC(keysize); + hash_mode = CRYS_ECPKI_HASH_SHA256_mode; + } + + /* truncate if hash is longer than key size */ + if (msgLenInBytes > keysize) { + msgLenInBytes = keysize; + } + + /* create signature from an input buffer using a private key*/ + err = CRYS_ECDSA_Sign(&wc_rndState, + wc_rndGenVectFunc, + &sigCtxTemp, + &key->ctx.privKey, + hash_mode, + (byte*)in, + msgLenInBytes, + out, + &raw_sig_size); + + if (err != SA_SILIB_RET_OK){ + WOLFSSL_MSG("CRYS_ECDSA_Sign failed"); + return err; + } + #endif + + /* Load R and S */ + err = mp_read_unsigned_bin(r, &out[0], keysize); + if (err != MP_OKAY) { + return err; + } + err = mp_read_unsigned_bin(s, &out[keysize], keysize); + if (err != MP_OKAY) { + return err; + } + + /* Check for zeros */ + if (mp_iszero(r) || mp_iszero(s)) { + return MP_ZERO_E; + } + } +#ifdef PLUTON_CRYPTO_ECC + else { + err = wc_ecc_sign_hash_ex(in, inlen, rng, key, r, s); + } +#endif + (void)rng; + + return err; +} +#endif /* WOLFSSL_ATECC508A || PLUTON_CRYPTO_ECC || WOLFSSL_CRYPTOCELL */ + +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) +static int wc_ecc_sign_hash_async(const byte* in, word32 inlen, byte* out, + word32 *outlen, WC_RNG* rng, ecc_key* key) +{ + int err; + mp_int *r = NULL, *s = NULL; + + if (in == NULL || out == NULL || outlen == NULL || key == NULL || + rng == NULL) { + return ECC_BAD_ARG_E; + } + + err = wc_ecc_alloc_async(key); + if (err != 0) { + return err; + } + r = key->r; + s = key->s; + + switch(key->state) { + case ECC_STATE_NONE: + case ECC_STATE_SIGN_DO: + key->state = ECC_STATE_SIGN_DO; + + if ((err = mp_init_multi(r, s, NULL, NULL, NULL, NULL)) != MP_OKAY){ + break; + } + + err = wc_ecc_sign_hash_ex(in, inlen, rng, key, r, s); + if (err < 0) { + break; + } + + FALL_THROUGH; + + case ECC_STATE_SIGN_ENCODE: + key->state = ECC_STATE_SIGN_ENCODE; + + if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_ECC) { + #ifdef HAVE_CAVIUM_V + /* Nitrox requires r and s in sep buffer, so split it */ + NitroxEccRsSplit(key, &r->raw, &s->raw); + #endif + #ifndef WOLFSSL_ASYNC_CRYPT_TEST + /* only do this if not simulator, since it overwrites result */ + wc_bigint_to_mp(&r->raw, r); + wc_bigint_to_mp(&s->raw, s); + #endif + } + + /* encoded with DSA header */ + err = StoreECC_DSA_Sig(out, outlen, r, s); + + /* done with R/S */ + mp_clear(r); + mp_clear(s); + break; + + default: + err = BAD_STATE_E; + break; + } + + /* if async pending then return and skip done cleanup below */ + if (err == WC_PENDING_E) { + key->state++; + return err; + } + + /* cleanup */ + wc_ecc_free_async(key); + key->state = ECC_STATE_NONE; + + return err; +} +#endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_ECC */ + +/** + Sign a message digest + in The message digest to sign + inlen The length of the digest + out [out] The destination for the signature + outlen [in/out] The max size and resulting size of the signature + key A private ECC key + return MP_OKAY if successful + */ +WOLFSSL_ABI +int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, + WC_RNG* rng, ecc_key* key) +{ + int err; +#if !defined(WOLFSSL_ASYNC_CRYPT) || !defined(WC_ASYNC_ENABLE_ECC) +#ifdef WOLFSSL_SMALL_STACK + mp_int *r = NULL, *s = NULL; +#else + mp_int r[1], s[1]; +#endif +#endif + + if (in == NULL || out == NULL || outlen == NULL || key == NULL || + rng == NULL) { + return ECC_BAD_ARG_E; + } + +#ifdef WOLF_CRYPTO_CB + if (key->devId != INVALID_DEVID) { + err = wc_CryptoCb_EccSign(in, inlen, out, outlen, rng, key); + if (err != CRYPTOCB_UNAVAILABLE) + return err; + /* fall-through when unavailable */ + } +#endif + +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + /* handle async cases */ + err = wc_ecc_sign_hash_async(in, inlen, out, outlen, rng, key); +#else + +#ifdef WOLFSSL_SMALL_STACK + r = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC); + if (r == NULL) + return MEMORY_E; + s = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC); + if (s == NULL) { + XFREE(r, key->heap, DYNAMIC_TYPE_ECC); + return MEMORY_E; + } +#endif + XMEMSET(r, 0, sizeof(mp_int)); + XMEMSET(s, 0, sizeof(mp_int)); + + if ((err = mp_init_multi(r, s, NULL, NULL, NULL, NULL)) != MP_OKAY){ + #ifdef WOLFSSL_SMALL_STACK + XFREE(s, key->heap, DYNAMIC_TYPE_ECC); + XFREE(r, key->heap, DYNAMIC_TYPE_ECC); + #endif + return err; + } + +/* hardware crypto */ +#if defined(WOLFSSL_ATECC508A) || defined(PLUTON_CRYPTO_ECC) || defined(WOLFSSL_CRYPTOCELL) + err = wc_ecc_sign_hash_hw(in, inlen, r, s, out, outlen, rng, key); +#else + err = wc_ecc_sign_hash_ex(in, inlen, rng, key, r, s); +#endif + if (err < 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(s, key->heap, DYNAMIC_TYPE_ECC); + XFREE(r, key->heap, DYNAMIC_TYPE_ECC); + #endif + return err; + } + + /* encoded with DSA header */ + err = StoreECC_DSA_Sig(out, outlen, r, s); + + /* cleanup */ + mp_clear(r); + mp_clear(s); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(s, key->heap, DYNAMIC_TYPE_ECC); + XFREE(r, key->heap, DYNAMIC_TYPE_ECC); +#endif +#endif /* WOLFSSL_ASYNC_CRYPT */ + + return err; +} +#endif /* !NO_ASN */ + +#if defined(WOLFSSL_STM32_PKA) +int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, + ecc_key* key, mp_int *r, mp_int *s) +{ + return stm32_ecc_sign_hash_ex(in, inlen, rng, key, r, s); +} +#elif !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_CRYPTOCELL) /** Sign a message digest in The message digest to sign inlen The length of the digest - out [out] The destination for the signature - outlen [in/out] The max size and resulting size of the signature key A private ECC key + r [out] The destination for r component of the signature + s [out] The destination for s component of the signature return MP_OKAY if successful */ -int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, - RNG* rng, ecc_key* key) +int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, + ecc_key* key, mp_int *r, mp_int *s) { - mp_int r; - mp_int s; - mp_int e; - mp_int p; - int err; + int err = 0; +#ifndef WOLFSSL_SP_MATH + mp_int* e; +#if (!defined(WOLFSSL_ASYNC_CRYPT) || !defined(HAVE_CAVIUM_V)) && \ + !defined(WOLFSSL_SMALL_STACK) + mp_int e_lcl; +#endif - if (in == NULL || out == NULL || outlen == NULL || key == NULL || rng ==NULL) +#if defined(WOLFSSL_ECDSA_SET_K) || \ + (defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) && \ + (defined(HAVE_CAVIUM_V) || defined(HAVE_INTEL_QA))) + DECLARE_CURVE_SPECS(curve, ECC_CURVE_FIELD_COUNT); +#else + DECLARE_CURVE_SPECS(curve, 1); +#endif +#endif /* !WOLFSSL_SP_MATH */ + + if (in == NULL || r == NULL || s == NULL || key == NULL || rng == NULL) { return ECC_BAD_ARG_E; + } /* is this a private key? */ - if (key->type != ECC_PRIVATEKEY) { + if (key->type != ECC_PRIVATEKEY && key->type != ECC_PRIVATEKEY_ONLY) { return ECC_BAD_ARG_E; } - + /* is the IDX valid ? */ - if (ecc_is_valid_idx(key->idx) != 1) { + if (wc_ecc_is_valid_idx(key->idx) != 1) { return ECC_BAD_ARG_E; } +#ifdef WOLFSSL_SP_MATH +#ifndef WOLFSSL_SP_NO_256 + if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP256R1) { + #ifndef WOLFSSL_ECDSA_SET_K + return sp_ecc_sign_256(in, inlen, rng, &key->k, r, s, NULL, key->heap); + #else + return sp_ecc_sign_256(in, inlen, rng, &key->k, r, s, key->sign_k, + key->heap); + #endif + } +#endif +#ifdef WOLFSSL_SP_384 + if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP384R1) { + #ifndef WOLFSSL_ECDSA_SET_K + return sp_ecc_sign_384(in, inlen, rng, &key->k, r, s, NULL, key->heap); + #else + return sp_ecc_sign_384(in, inlen, rng, &key->k, r, s, key->sign_k, + key->heap); + #endif + } +#endif + return WC_KEY_SIZE_E; +#else +#ifdef WOLFSSL_HAVE_SP_ECC + #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + if (key->asyncDev.marker != WOLFSSL_ASYNC_MARKER_ECC) + #endif + { +#ifndef WOLFSSL_SP_NO_256 + if (key->idx != ECC_CUSTOM_IDX && + ecc_sets[key->idx].id == ECC_SECP256R1) { + #ifndef WOLFSSL_ECDSA_SET_K + return sp_ecc_sign_256(in, inlen, rng, &key->k, r, s, NULL, + key->heap); + #else + return sp_ecc_sign_256(in, inlen, rng, &key->k, r, s, key->sign_k, + key->heap); + #endif + } +#endif +#ifdef WOLFSSL_SP_384 + if (key->idx != ECC_CUSTOM_IDX && + ecc_sets[key->idx].id == ECC_SECP384R1) { + #ifndef WOLFSSL_ECDSA_SET_K + return sp_ecc_sign_384(in, inlen, rng, &key->k, r, s, NULL, + key->heap); + #else + return sp_ecc_sign_384(in, inlen, rng, &key->k, r, s, key->sign_k, + key->heap); + #endif + } +#endif + } +#endif /* WOLFSSL_HAVE_SP_ECC */ + + +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) && \ + defined(WOLFSSL_ASYNC_CRYPT_TEST) + if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_ECC) { + if (wc_AsyncTestInit(&key->asyncDev, ASYNC_TEST_ECC_SIGN)) { + WC_ASYNC_TEST* testDev = &key->asyncDev.test; + testDev->eccSign.in = in; + testDev->eccSign.inSz = inlen; + testDev->eccSign.rng = rng; + testDev->eccSign.key = key; + testDev->eccSign.r = r; + testDev->eccSign.s = s; + return WC_PENDING_E; + } + } +#endif + +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_CAVIUM_V) + err = wc_ecc_alloc_mpint(key, &key->e); + if (err != 0) { + return err; + } + e = key->e; +#elif !defined(WOLFSSL_SMALL_STACK) + e = &e_lcl; +#else + e = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC); + if (e == NULL) { + return MEMORY_E; + } +#endif + /* get the hash and load it as a bignum into 'e' */ /* init the bignums */ - if ((err = mp_init_multi(&r, &s, &p, &e, NULL, NULL)) != MP_OKAY) { + if ((err = mp_init(e)) != MP_OKAY) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(e, key->heap, DYNAMIC_TYPE_ECC); + #endif return err; } - err = mp_read_radix(&p, (char *)key->dp->order, 16); + /* load curve info */ +#if defined(WOLFSSL_ECDSA_SET_K) + ALLOC_CURVE_SPECS(ECC_CURVE_FIELD_COUNT); + err = wc_ecc_curve_load(key->dp, &curve, ECC_CURVE_FIELD_ALL); +#else + #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) && \ + (defined(HAVE_CAVIUM_V) || defined(HAVE_INTEL_QA)) + if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_ECC) { + ALLOC_CURVE_SPECS(ECC_CURVE_FIELD_COUNT); + err = wc_ecc_curve_load(key->dp, &curve, ECC_CURVE_FIELD_ALL); + } + else + #endif + { + ALLOC_CURVE_SPECS(1); + err = wc_ecc_curve_load(key->dp, &curve, ECC_CURVE_FIELD_ORDER); + } +#endif + + /* load digest into e */ if (err == MP_OKAY) { /* we may need to truncate if hash is longer than key size */ - word32 orderBits = mp_count_bits(&p); + word32 orderBits = mp_count_bits(curve->order); /* truncate down to byte size, may be all that's needed */ - if ( (WOLFSSL_BIT_SIZE * inlen) > orderBits) - inlen = (orderBits + WOLFSSL_BIT_SIZE - 1)/WOLFSSL_BIT_SIZE; - err = mp_read_unsigned_bin(&e, (byte*)in, inlen); + if ((WOLFSSL_BIT_SIZE * inlen) > orderBits) + inlen = (orderBits + WOLFSSL_BIT_SIZE - 1) / WOLFSSL_BIT_SIZE; + err = mp_read_unsigned_bin(e, (byte*)in, inlen); /* may still need bit truncation too */ if (err == MP_OKAY && (WOLFSSL_BIT_SIZE * inlen) > orderBits) - mp_rshb(&e, WOLFSSL_BIT_SIZE - (orderBits & 0x7)); + mp_rshb(e, WOLFSSL_BIT_SIZE - (orderBits & 0x7)); } /* make up a key and export the public copy */ if (err == MP_OKAY) { - int loop_check = 0; - ecc_key pubkey; - wc_ecc_init(&pubkey); - for (;;) { - if (++loop_check > 64) { - err = RNG_FAILURE_E; - break; + int loop_check = 0; + #ifdef WOLFSSL_SMALL_STACK + ecc_key* pubkey; + #else + ecc_key pubkey[1]; + #endif + + #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_ECC) { + #if defined(HAVE_CAVIUM_V) || defined(HAVE_INTEL_QA) + #ifdef HAVE_CAVIUM_V + if (NitroxEccIsCurveSupported(key)) + #endif + { + word32 keySz = key->dp->size; + mp_int* k; + #ifdef HAVE_CAVIUM_V + err = wc_ecc_alloc_mpint(key, &key->signK); + if (err != 0) + return err; + k = key->signK; + #else + mp_int k_lcl; + k = &k_lcl; + #endif + + err = mp_init(k); + + /* make sure r and s are allocated */ + #ifdef HAVE_CAVIUM_V + /* Nitrox V needs single buffer for R and S */ + if (err == MP_OKAY) + err = wc_bigint_alloc(&key->r->raw, NitroxEccGetSize(key)*2); + /* Nitrox V only needs Prime and Order */ + if (err == MP_OKAY) + err = wc_ecc_curve_load(key->dp, &curve, + (ECC_CURVE_FIELD_PRIME | ECC_CURVE_FIELD_ORDER)); + #else + if (err == MP_OKAY) + err = wc_bigint_alloc(&key->r->raw, key->dp->size); + if (err == MP_OKAY) + err = wc_ecc_curve_load(key->dp, &curve, ECC_CURVE_FIELD_ALL); + #endif + if (err == MP_OKAY) + err = wc_bigint_alloc(&key->s->raw, key->dp->size); + + /* load e and k */ + if (err == MP_OKAY) + err = wc_mp_to_bigint_sz(e, &e->raw, keySz); + if (err == MP_OKAY) + err = wc_mp_to_bigint_sz(&key->k, &key->k.raw, keySz); + if (err == MP_OKAY) + err = wc_ecc_gen_k(rng, key->dp->size, k, curve->order); + if (err == MP_OKAY) + err = wc_mp_to_bigint_sz(k, &k->raw, keySz); + + #ifdef HAVE_CAVIUM_V + if (err == MP_OKAY) + err = NitroxEcdsaSign(key, &e->raw, &key->k.raw, &k->raw, + &r->raw, &s->raw, &curve->prime->raw, &curve->order->raw); + #else + if (err == MP_OKAY) + err = IntelQaEcdsaSign(&key->asyncDev, &e->raw, &key->k.raw, + &k->raw, &r->raw, &s->raw, &curve->Af->raw, &curve->Bf->raw, + &curve->prime->raw, &curve->order->raw, &curve->Gx->raw, + &curve->Gy->raw); + #endif + + #ifndef HAVE_CAVIUM_V + mp_clear(e); + mp_clear(k); + #endif + wc_ecc_curve_free(curve); + FREE_CURVE_SPECS(); + + return err; } - err = wc_ecc_make_key_ex(rng, &pubkey, key->dp); - if (err != MP_OKAY) break; + #endif /* HAVE_CAVIUM_V || HAVE_INTEL_QA */ + } + #endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_ECC */ - /* find r = x1 mod n */ - err = mp_mod(pubkey.pubkey.x, &p, &r); - if (err != MP_OKAY) break; + #ifdef WOLFSSL_SMALL_STACK + pubkey = (ecc_key*)XMALLOC(sizeof(ecc_key), key->heap, DYNAMIC_TYPE_ECC); + if (pubkey == NULL) + err = MEMORY_E; + #endif + + /* don't use async for key, since we don't support async return here */ + if (err == MP_OKAY && (err = wc_ecc_init_ex(pubkey, key->heap, + INVALID_DEVID)) == MP_OKAY) { + #ifdef WOLFSSL_SMALL_STACK + mp_int* b = NULL; + #else + mp_int b[1]; + #endif + + #ifdef WOLFSSL_SMALL_STACK + if (err == MP_OKAY) { + b = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, + DYNAMIC_TYPE_ECC); + if (b == NULL) + err = MEMORY_E; + } + #endif - if (mp_iszero(&r) == MP_YES) { - mp_clear(pubkey.pubkey.x); - mp_clear(pubkey.pubkey.y); - mp_clear(pubkey.pubkey.z); - mp_clear(&pubkey.k); + if (err == MP_OKAY) { + err = mp_init(b); } - else { - /* find s = (e + xr)/k */ - err = mp_invmod(&pubkey.k, &p, &pubkey.k); - if (err != MP_OKAY) break; - err = mp_mulmod(&key->k, &r, &p, &s); /* s = xr */ - if (err != MP_OKAY) break; - - err = mp_add(&e, &s, &s); /* s = e + xr */ - if (err != MP_OKAY) break; + #ifdef WOLFSSL_CUSTOM_CURVES + /* if custom curve, apply params to pubkey */ + if (err == MP_OKAY && key->idx == ECC_CUSTOM_IDX) { + err = wc_ecc_set_custom_curve(pubkey, key->dp); + } + #endif + + if (err == MP_OKAY) { + /* Generate blinding value - non-zero value. */ + do { + if (++loop_check > 64) { + err = RNG_FAILURE_E; + break; + } + + err = wc_ecc_gen_k(rng, key->dp->size, b, curve->order); + } + while (err == MP_ZERO_E); + loop_check = 0; + } + + for (; err == MP_OKAY;) { + if (++loop_check > 64) { + err = RNG_FAILURE_E; + break; + } + #ifdef WOLFSSL_ECDSA_SET_K + if (key->sign_k != NULL) { + if (loop_check > 1) { + err = RNG_FAILURE_E; + break; + } + + err = mp_copy(key->sign_k, &pubkey->k); + if (err != MP_OKAY) break; - err = mp_mod(&s, &p, &s); /* s = e + xr */ + mp_forcezero(key->sign_k); + mp_free(key->sign_k); + XFREE(key->sign_k, key->heap, DYNAMIC_TYPE_ECC); + key->sign_k = NULL; + err = wc_ecc_make_pub_ex(pubkey, curve, NULL); + } + else + #endif + { + err = wc_ecc_make_key_ex(rng, key->dp->size, pubkey, + key->dp->id); + } if (err != MP_OKAY) break; - err = mp_mulmod(&s, &pubkey.k, &p, &s); /* s = (e + xr)/k */ + /* find r = x1 mod n */ + err = mp_mod(pubkey->pubkey.x, curve->order, r); if (err != MP_OKAY) break; - if (mp_iszero(&s) == MP_NO) - break; - } + if (mp_iszero(r) == MP_YES) { + #ifndef ALT_ECC_SIZE + mp_clear(pubkey->pubkey.x); + mp_clear(pubkey->pubkey.y); + mp_clear(pubkey->pubkey.z); + #endif + mp_forcezero(&pubkey->k); + } + else { + /* find s = (e + xr)/k + = b.(e/k.b + x.r/k.b) */ + + /* k = k.b */ + err = mp_mulmod(&pubkey->k, b, curve->order, &pubkey->k); + if (err != MP_OKAY) break; + + /* k = 1/k.b */ + err = mp_invmod(&pubkey->k, curve->order, &pubkey->k); + if (err != MP_OKAY) break; + + /* s = x.r */ + err = mp_mulmod(&key->k, r, curve->order, s); + if (err != MP_OKAY) break; + + /* s = x.r/k.b */ + err = mp_mulmod(&pubkey->k, s, curve->order, s); + if (err != MP_OKAY) break; + + /* e = e/k.b */ + err = mp_mulmod(&pubkey->k, e, curve->order, e); + if (err != MP_OKAY) break; + + /* s = e/k.b + x.r/k.b + = (e + x.r)/k.b */ + err = mp_add(e, s, s); + if (err != MP_OKAY) break; + + /* s = b.(e + x.r)/k.b + = (e + x.r)/k */ + err = mp_mulmod(s, b, curve->order, s); + if (err != MP_OKAY) break; + + /* s = (e + xr)/k */ + err = mp_mod(s, curve->order, s); + if (err != MP_OKAY) break; + + if (mp_iszero(s) == MP_NO) + break; + } + } + mp_clear(b); + mp_free(b); + #ifdef WOLFSSL_SMALL_STACK + XFREE(b, key->heap, DYNAMIC_TYPE_ECC); + #endif + wc_ecc_free(pubkey); + #ifdef WOLFSSL_SMALL_STACK + XFREE(pubkey, key->heap, DYNAMIC_TYPE_ECC); + #endif } - wc_ecc_free(&pubkey); } - /* store as SEQUENCE { r, s -- integer } */ - if (err == MP_OKAY) - err = StoreECC_DSA_Sig(out, outlen, &r, &s); - - mp_clear(&r); - mp_clear(&s); - mp_clear(&p); - mp_clear(&e); + mp_clear(e); + wc_ecc_curve_free(curve); +#ifdef WOLFSSL_SMALL_STACK + XFREE(e, key->heap, DYNAMIC_TYPE_ECC); +#endif + FREE_CURVE_SPECS(); +#endif /* WOLFSSL_SP_MATH */ return err; } +#ifdef WOLFSSL_ECDSA_SET_K +int wc_ecc_sign_set_k(const byte* k, word32 klen, ecc_key* key) +{ + int ret = 0; + + if (k == NULL || klen == 0 || key == NULL) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + if (key->sign_k == NULL) { + key->sign_k = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, + DYNAMIC_TYPE_ECC); + if (key->sign_k == NULL) { + ret = MEMORY_E; + } + } + } + + if (ret == 0) { + ret = mp_init(key->sign_k); + } + if (ret == 0) { + ret = mp_read_unsigned_bin(key->sign_k, k, klen); + } + + return ret; +} +#endif /* WOLFSSL_ECDSA_SET_K */ +#endif /* WOLFSSL_ATECC508A && WOLFSSL_CRYPTOCELL*/ + +#endif /* HAVE_ECC_SIGN */ + +#ifdef WOLFSSL_CUSTOM_CURVES +void wc_ecc_free_curve(const ecc_set_type* curve, void* heap) +{ +#ifndef WOLFSSL_ECC_CURVE_STATIC + if (curve->prime != NULL) + XFREE((void*)curve->prime, heap, DYNAMIC_TYPE_ECC_BUFFER); + if (curve->Af != NULL) + XFREE((void*)curve->Af, heap, DYNAMIC_TYPE_ECC_BUFFER); + if (curve->Bf != NULL) + XFREE((void*)curve->Bf, heap, DYNAMIC_TYPE_ECC_BUFFER); + if (curve->order != NULL) + XFREE((void*)curve->order, heap, DYNAMIC_TYPE_ECC_BUFFER); + if (curve->Gx != NULL) + XFREE((void*)curve->Gx, heap, DYNAMIC_TYPE_ECC_BUFFER); + if (curve->Gy != NULL) + XFREE((void*)curve->Gy, heap, DYNAMIC_TYPE_ECC_BUFFER); +#endif + + XFREE((void*)curve, heap, DYNAMIC_TYPE_ECC_BUFFER); + + (void)heap; +} +#endif /* WOLFSSL_CUSTOM_CURVES */ /** Free an ECC key from memory key The key you wish to free */ -void wc_ecc_free(ecc_key* key) +WOLFSSL_ABI +int wc_ecc_free(ecc_key* key) { - if (key == NULL) - return; + if (key == NULL) { + return 0; + } - mp_clear(key->pubkey.x); - mp_clear(key->pubkey.y); - mp_clear(key->pubkey.z); - mp_clear(&key->k); -} +#ifdef WOLFSSL_ECDSA_SET_K + if (key->sign_k != NULL) { + mp_forcezero(key->sign_k); + mp_free(key->sign_k); + XFREE(key->sign_k, key->heap, DYNAMIC_TYPE_ECC); + } +#endif +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + #ifdef WC_ASYNC_ENABLE_ECC + wolfAsync_DevCtxFree(&key->asyncDev, WOLFSSL_ASYNC_MARKER_ECC); + #endif + wc_ecc_free_async(key); +#endif -#ifdef USE_FAST_MATH - #define GEN_MEM_ERR FP_MEM -#else - #define GEN_MEM_ERR MP_MEM +#ifdef WOLFSSL_ATECC508A + atmel_ecc_free(key->slot); + key->slot = ATECC_INVALID_SLOT; +#endif /* WOLFSSL_ATECC508A */ + + mp_clear(key->pubkey.x); + mp_clear(key->pubkey.y); + mp_clear(key->pubkey.z); + + mp_forcezero(&key->k); + +#ifdef WOLFSSL_CUSTOM_CURVES + if (key->deallocSet && key->dp != NULL) + wc_ecc_free_curve(key->dp, key->heap); #endif + return 0; +} + +#if !defined(WOLFSSL_SP_MATH) && !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_CRYPTOCELL) #ifdef ECC_SHAMIR /** Computes kA*A + kB*B = C using Shamir's Trick @@ -1851,47 +5358,97 @@ void wc_ecc_free(ecc_key* key) B Second point to multiply kB What to multiple B by C [out] Destination point (can overlap with A or B) - modulus Modulus for curve + a ECC curve parameter a + modulus Modulus for curve return MP_OKAY on success */ #ifdef FP_ECC static int normal_ecc_mul2add(ecc_point* A, mp_int* kA, ecc_point* B, mp_int* kB, - ecc_point* C, mp_int* modulus) + ecc_point* C, mp_int* a, mp_int* modulus, + void* heap) #else -static int ecc_mul2add(ecc_point* A, mp_int* kA, +int ecc_mul2add(ecc_point* A, mp_int* kA, ecc_point* B, mp_int* kB, - ecc_point* C, mp_int* modulus) + ecc_point* C, mp_int* a, mp_int* modulus, + void* heap) #endif { - ecc_point* precomp[16]; - unsigned bitbufA, bitbufB, lenA, lenB, len, x, y, nA, nB, nibble; +#ifdef WOLFSSL_SMALL_STACK_CACHE + ecc_key key; +#endif +#ifdef WOLFSSL_SMALL_STACK + ecc_point** precomp = NULL; +#else + ecc_point* precomp[SHAMIR_PRECOMP_SZ]; +#endif + unsigned bitbufA, bitbufB, lenA, lenB, len, nA, nB, nibble; unsigned char* tA; unsigned char* tB; - int err = MP_OKAY, first; - int muInit = 0; - int tableInit = 0; - mp_digit mp; - mp_int mu; - - /* argchks */ - if (A == NULL || kA == NULL || B == NULL || kB == NULL || C == NULL || - modulus == NULL) - return ECC_BAD_ARG_E; + int err = MP_OKAY, first, x, y; + mp_digit mp = 0; + /* argchks */ + if (A == NULL || kA == NULL || B == NULL || kB == NULL || C == NULL || + modulus == NULL) { + return ECC_BAD_ARG_E; + } /* allocate memory */ - tA = (unsigned char*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + tA = (unsigned char*)XMALLOC(ECC_BUFSIZE, heap, DYNAMIC_TYPE_ECC_BUFFER); if (tA == NULL) { return GEN_MEM_ERR; } - tB = (unsigned char*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + tB = (unsigned char*)XMALLOC(ECC_BUFSIZE, heap, DYNAMIC_TYPE_ECC_BUFFER); if (tB == NULL) { - XFREE(tA, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(tA, heap, DYNAMIC_TYPE_ECC_BUFFER); + return GEN_MEM_ERR; + } +#ifdef WOLFSSL_SMALL_STACK + precomp = (ecc_point**)XMALLOC(sizeof(ecc_point*) * SHAMIR_PRECOMP_SZ, heap, + DYNAMIC_TYPE_ECC_BUFFER); + if (precomp == NULL) { + XFREE(tB, heap, DYNAMIC_TYPE_ECC_BUFFER); + XFREE(tA, heap, DYNAMIC_TYPE_ECC_BUFFER); return GEN_MEM_ERR; } +#endif +#ifdef WOLFSSL_SMALL_STACK_CACHE + key.t1 = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); + key.t2 = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); +#ifdef ALT_ECC_SIZE + key.x = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); + key.y = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); + key.z = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); +#endif + if (key.t1 == NULL || key.t2 == NULL +#ifdef ALT_ECC_SIZE + || key.x == NULL || key.y == NULL || key.z == NULL +#endif + ) { +#ifdef ALT_ECC_SIZE + XFREE(key.z, heap, DYNAMIC_TYPE_ECC); + XFREE(key.y, heap, DYNAMIC_TYPE_ECC); + XFREE(key.x, heap, DYNAMIC_TYPE_ECC); +#endif + XFREE(key.t2, heap, DYNAMIC_TYPE_ECC); + XFREE(key.t1, heap, DYNAMIC_TYPE_ECC); + XFREE(precomp, heap, DYNAMIC_TYPE_ECC_BUFFER); + XFREE(tB, heap, DYNAMIC_TYPE_ECC_BUFFER); + XFREE(tA, heap, DYNAMIC_TYPE_ECC_BUFFER); + return MEMORY_E; + } + C->key = &key; +#endif /* WOLFSSL_SMALL_STACK_CACHE */ + + /* init variables */ XMEMSET(tA, 0, ECC_BUFSIZE); XMEMSET(tB, 0, ECC_BUFSIZE); +#ifndef WOLFSSL_SMALL_STACK + XMEMSET(precomp, 0, sizeof(precomp)); +#else + XMEMSET(precomp, 0, sizeof(ecc_point*) * SHAMIR_PRECOMP_SZ); +#endif /* get sizes */ lenA = mp_unsigned_bin_size(kA); @@ -1900,7 +5457,7 @@ static int ecc_mul2add(ecc_point* A, mp_int* kA, /* sanity check */ if ((lenA > ECC_BUFSIZE) || (lenB > ECC_BUFSIZE)) { - err = BAD_FUNC_ARG; + err = BAD_FUNC_ARG; } if (err == MP_OKAY) { @@ -1913,75 +5470,92 @@ static int ecc_mul2add(ecc_point* A, mp_int* kA, /* allocate the table */ if (err == MP_OKAY) { - for (x = 0; x < 16; x++) { - precomp[x] = ecc_new_point(); + for (x = 0; x < SHAMIR_PRECOMP_SZ; x++) { + precomp[x] = wc_ecc_new_point_h(heap); if (precomp[x] == NULL) { - for (y = 0; y < x; ++y) { - ecc_del_point(precomp[y]); - } err = GEN_MEM_ERR; break; } + #ifdef WOLFSSL_SMALL_STACK_CACHE + precomp[x]->key = &key; + #endif } } } if (err == MP_OKAY) - tableInit = 1; + /* init montgomery reduction */ + err = mp_montgomery_setup(modulus, &mp); - if (err == MP_OKAY) - /* init montgomery reduction */ - err = mp_montgomery_setup(modulus, &mp); - - if (err == MP_OKAY) - err = mp_init(&mu); - if (err == MP_OKAY) - muInit = 1; + if (err == MP_OKAY) { + #ifdef WOLFSSL_SMALL_STACK + mp_int* mu; + #else + mp_int mu[1]; + #endif + #ifdef WOLFSSL_SMALL_STACK + mu = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); + if (mu == NULL) + err = MEMORY_E; + #endif + if (err == MP_OKAY) { + err = mp_init(mu); + } + if (err == MP_OKAY) { + err = mp_montgomery_calc_normalization(mu, modulus); - if (err == MP_OKAY) - err = mp_montgomery_calc_normalization(&mu, modulus); + if (err == MP_OKAY) + /* copy ones ... */ + err = mp_mulmod(A->x, mu, modulus, precomp[1]->x); - if (err == MP_OKAY) - /* copy ones ... */ - err = mp_mulmod(A->x, &mu, modulus, precomp[1]->x); + if (err == MP_OKAY) + err = mp_mulmod(A->y, mu, modulus, precomp[1]->y); + if (err == MP_OKAY) + err = mp_mulmod(A->z, mu, modulus, precomp[1]->z); - if (err == MP_OKAY) - err = mp_mulmod(A->y, &mu, modulus, precomp[1]->y); - if (err == MP_OKAY) - err = mp_mulmod(A->z, &mu, modulus, precomp[1]->z); + if (err == MP_OKAY) + err = mp_mulmod(B->x, mu, modulus, precomp[1<<2]->x); + if (err == MP_OKAY) + err = mp_mulmod(B->y, mu, modulus, precomp[1<<2]->y); + if (err == MP_OKAY) + err = mp_mulmod(B->z, mu, modulus, precomp[1<<2]->z); - if (err == MP_OKAY) - err = mp_mulmod(B->x, &mu, modulus, precomp[1<<2]->x); - if (err == MP_OKAY) - err = mp_mulmod(B->y, &mu, modulus, precomp[1<<2]->y); - if (err == MP_OKAY) - err = mp_mulmod(B->z, &mu, modulus, precomp[1<<2]->z); + /* done with mu */ + mp_clear(mu); + } + #ifdef WOLFSSL_SMALL_STACK + if (mu != NULL) { + XFREE(mu, heap, DYNAMIC_TYPE_ECC); + } + #endif + } if (err == MP_OKAY) /* precomp [i,0](A + B) table */ - err = ecc_projective_dbl_point(precomp[1], precomp[2], modulus, &mp); + err = ecc_projective_dbl_point(precomp[1], precomp[2], a, modulus, mp); if (err == MP_OKAY) err = ecc_projective_add_point(precomp[1], precomp[2], precomp[3], - modulus, &mp); + a, modulus, mp); if (err == MP_OKAY) /* precomp [0,i](A + B) table */ - err = ecc_projective_dbl_point(precomp[1<<2], precomp[2<<2], modulus, &mp); + err = ecc_projective_dbl_point(precomp[1<<2], precomp[2<<2], a, modulus, mp); if (err == MP_OKAY) err = ecc_projective_add_point(precomp[1<<2], precomp[2<<2], precomp[3<<2], - modulus, &mp); + a, modulus, mp); if (err == MP_OKAY) { /* precomp [i,j](A + B) table (i != 0, j != 0) */ for (x = 1; x < 4; x++) { - for (y = 1; y < 4; y++) { - if (err == MP_OKAY) - err = ecc_projective_add_point(precomp[x], precomp[(y<<2)], - precomp[x+(y<<2)], modulus, &mp); + for (y = 1; y < 4; y++) { + if (err == MP_OKAY) { + err = ecc_projective_add_point(precomp[x], precomp[(y<<2)], + precomp[x+(y<<2)], a, modulus, mp); } - } - } + } + } + } if (err == MP_OKAY) { nibble = 3; @@ -1990,20 +5564,21 @@ static int ecc_mul2add(ecc_point* A, mp_int* kA, bitbufB = tB[0]; /* for every byte of the multiplicands */ - for (x = -1;; ) { + for (x = 0;; ) { /* grab a nibble */ if (++nibble == 4) { - ++x; if (x == len) break; + if (x == (int)len) break; bitbufA = tA[x]; bitbufB = tB[x]; nibble = 0; + x++; } /* extract two bits from both, shift/update */ nA = (bitbufA >> 6) & 0x03; nB = (bitbufB >> 6) & 0x03; - bitbufA = (bitbufA << 2) & 0xFF; - bitbufB = (bitbufB << 2) & 0xFF; + bitbufA = (bitbufA << 2) & 0xFF; + bitbufB = (bitbufB << 2) & 0xFF; /* if both zero, if first, continue */ if ((nA == 0) && (nB == 0) && (first == 1)) { @@ -2014,9 +5589,9 @@ static int ecc_mul2add(ecc_point* A, mp_int* kA, if (first == 0) { /* double twice */ if (err == MP_OKAY) - err = ecc_projective_dbl_point(C, C, modulus, &mp); + err = ecc_projective_dbl_point(C, C, a, modulus, mp); if (err == MP_OKAY) - err = ecc_projective_dbl_point(C, C, modulus, &mp); + err = ecc_projective_dbl_point(C, C, a, modulus, mp); else break; } @@ -2040,44 +5615,76 @@ static int ecc_mul2add(ecc_point* A, mp_int* kA, /* if not first, add from table */ if (err == MP_OKAY) err = ecc_projective_add_point(C, precomp[nA + (nB<<2)], C, - modulus, &mp); - else + a, modulus, mp); + if (err != MP_OKAY) break; + if (mp_iszero(C->z)) { + /* When all zero then should have done an add */ + if (mp_iszero(C->x) && mp_iszero(C->y)) { + err = ecc_projective_dbl_point(precomp[nA + (nB<<2)], C, + a, modulus, mp); + if (err != MP_OKAY) + break; + } + /* When only Z zero then result is infinity */ + else { + err = mp_set(C->x, 0); + if (err != MP_OKAY) + break; + err = mp_set(C->y, 0); + if (err != MP_OKAY) + break; + err = mp_set(C->z, 1); + if (err != MP_OKAY) + break; + first = 1; + } + } } } } } + /* reduce to affine */ if (err == MP_OKAY) - /* reduce to affine */ - err = ecc_map(C, modulus, &mp); + err = ecc_map(C, modulus, mp); /* clean up */ - if (muInit) - mp_clear(&mu); - - if (tableInit) { - for (x = 0; x < 16; x++) { - ecc_del_point(precomp[x]); - } + for (x = 0; x < SHAMIR_PRECOMP_SZ; x++) { + wc_ecc_del_point_h(precomp[x], heap); } - ForceZero(tA, ECC_BUFSIZE); - ForceZero(tB, ECC_BUFSIZE); - XFREE(tA, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(tB, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return err; -} + ForceZero(tA, ECC_BUFSIZE); + ForceZero(tB, ECC_BUFSIZE); +#ifdef WOLFSSL_SMALL_STACK_CACHE +#ifdef ALT_ECC_SIZE + XFREE(key.z, heap, DYNAMIC_TYPE_ECC); + XFREE(key.y, heap, DYNAMIC_TYPE_ECC); + XFREE(key.x, heap, DYNAMIC_TYPE_ECC); +#endif + XFREE(key.t2, heap, DYNAMIC_TYPE_ECC); + XFREE(key.t1, heap, DYNAMIC_TYPE_ECC); + C->key = NULL; +#endif +#ifdef WOLFSSL_SMALL_STACK + XFREE(precomp, heap, DYNAMIC_TYPE_ECC_BUFFER); +#endif + XFREE(tB, heap, DYNAMIC_TYPE_ECC_BUFFER); + XFREE(tA, heap, DYNAMIC_TYPE_ECC_BUFFER); + return err; +} #endif /* ECC_SHAMIR */ +#endif /* !WOLFSSL_SP_MATH && !WOLFSSL_ATECC508A && !WOLFSSL_CRYPTOCEL*/ - -/* verify +#ifdef HAVE_ECC_VERIFY +#ifndef NO_ASN +/* verify * * w = s^-1 mod n - * u1 = xw + * u1 = xw * u2 = rw * X = u1*G + u2*Q * v = X_x1 mod n @@ -2085,120 +5692,476 @@ static int ecc_mul2add(ecc_point* A, mp_int* kA, */ /** + Verify an ECC signature + sig The signature to verify + siglen The length of the signature (octets) + hash The hash (message digest) that was signed + hashlen The length of the hash (octets) + res Result of signature, 1==valid, 0==invalid + key The corresponding public ECC key + return MP_OKAY if successful (even if the signature is not valid) + */ +int wc_ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash, + word32 hashlen, int* res, ecc_key* key) +{ + int err; + mp_int *r = NULL, *s = NULL; +#if (!defined(WOLFSSL_ASYNC_CRYPT) || !defined(WC_ASYNC_ENABLE_ECC)) && \ + !defined(WOLFSSL_SMALL_STACK) + mp_int r_lcl, s_lcl; +#endif + + if (sig == NULL || hash == NULL || res == NULL || key == NULL) { + return ECC_BAD_ARG_E; + } + +#ifdef WOLF_CRYPTO_CB + if (key->devId != INVALID_DEVID) { + err = wc_CryptoCb_EccVerify(sig, siglen, hash, hashlen, res, key); + if (err != CRYPTOCB_UNAVAILABLE) + return err; + /* fall-through when unavailable */ + } +#endif + +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + err = wc_ecc_alloc_async(key); + if (err != 0) + return err; + r = key->r; + s = key->s; +#else + #ifndef WOLFSSL_SMALL_STACK + r = &r_lcl; + s = &s_lcl; + #else + r = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC); + if (r == NULL) + return MEMORY_E; + s = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC); + if (s == NULL) { + XFREE(r, key->heap, DYNAMIC_TYPE_ECC); + return MEMORY_E; + } + #endif + XMEMSET(r, 0, sizeof(mp_int)); + XMEMSET(s, 0, sizeof(mp_int)); +#endif /* WOLFSSL_ASYNC_CRYPT */ + + switch (key->state) { + case ECC_STATE_NONE: + case ECC_STATE_VERIFY_DECODE: + key->state = ECC_STATE_VERIFY_DECODE; + + /* default to invalid signature */ + *res = 0; + + /* Note, DecodeECC_DSA_Sig() calls mp_init() on r and s. + * If either of those don't allocate correctly, none of + * the rest of this function will execute, and everything + * gets cleaned up at the end. */ + /* decode DSA header */ + err = DecodeECC_DSA_Sig(sig, siglen, r, s); + if (err < 0) { + break; + } + FALL_THROUGH; + + case ECC_STATE_VERIFY_DO: + key->state = ECC_STATE_VERIFY_DO; + + err = wc_ecc_verify_hash_ex(r, s, hash, hashlen, res, key); + + #ifndef WOLFSSL_ASYNC_CRYPT + /* done with R/S */ + mp_clear(r); + mp_clear(s); + #ifdef WOLFSSL_SMALL_STACK + XFREE(s, key->heap, DYNAMIC_TYPE_ECC); + XFREE(r, key->heap, DYNAMIC_TYPE_ECC); + r = NULL; + s = NULL; + #endif + #endif + + if (err < 0) { + break; + } + FALL_THROUGH; + + case ECC_STATE_VERIFY_RES: + key->state = ECC_STATE_VERIFY_RES; + err = 0; + break; + + default: + err = BAD_STATE_E; + } + + /* if async pending then return and skip done cleanup below */ + if (err == WC_PENDING_E) { + key->state++; + return err; + } + + /* cleanup */ +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + wc_ecc_free_async(key); +#elif defined(WOLFSSL_SMALL_STACK) + XFREE(s, key->heap, DYNAMIC_TYPE_ECC); + XFREE(r, key->heap, DYNAMIC_TYPE_ECC); + r = NULL; + s = NULL; +#endif + + key->state = ECC_STATE_NONE; + + return err; +} +#endif /* !NO_ASN */ + + +/** Verify an ECC signature - sig The signature to verify - siglen The length of the signature (octets) + r The signature R component to verify + s The signature S component to verify hash The hash (message digest) that was signed hashlen The length of the hash (octets) - stat Result of signature, 1==valid, 0==invalid + res Result of signature, 1==valid, 0==invalid key The corresponding public ECC key return MP_OKAY if successful (even if the signature is not valid) */ -int wc_ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash, - word32 hashlen, int* stat, ecc_key* key) -{ - ecc_point *mG, *mQ; - mp_int r; - mp_int s; - mp_int v; - mp_int w; - mp_int u1; - mp_int u2; - mp_int e; - mp_int p; - mp_int m; + +int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, + word32 hashlen, int* res, ecc_key* key) +#if defined(WOLFSSL_STM32_PKA) +{ + return stm32_ecc_verify_hash_ex(r, s, hash, hashlen, res, key); +} +#else +{ int err; + word32 keySz; +#ifdef WOLFSSL_ATECC508A + byte sigRS[ATECC_KEY_SIZE*2]; +#elif defined(WOLFSSL_CRYPTOCELL) + byte sigRS[ECC_MAX_CRYPTO_HW_SIZE*2]; + CRYS_ECDSA_VerifyUserContext_t sigCtxTemp; + word32 msgLenInBytes = hashlen; + CRYS_ECPKI_HASH_OpMode_t hash_mode; +#elif !defined(WOLFSSL_SP_MATH) || defined(FREESCALE_LTC_ECC) + int did_init = 0; + ecc_point *mG = NULL, *mQ = NULL; + #ifdef WOLFSSL_SMALL_STACK + mp_int* v = NULL; + mp_int* w = NULL; + mp_int* u1 = NULL; + mp_int* u2 = NULL; + #if !defined(WOLFSSL_ASYNC_CRYPT) || !defined(HAVE_CAVIUM_V) + mp_int* e_lcl = NULL; + #endif + #else /* WOLFSSL_SMALL_STACK */ + mp_int v[1]; + mp_int w[1]; + mp_int u1[1]; + mp_int u2[1]; + #if !defined(WOLFSSL_ASYNC_CRYPT) || !defined(HAVE_CAVIUM_V) + mp_int e_lcl[1]; + #endif + #endif /* WOLFSSL_SMALL_STACK */ + mp_int* e; + DECLARE_CURVE_SPECS(curve, ECC_CURVE_FIELD_COUNT); +#endif - if (sig == NULL || hash == NULL || stat == NULL || key == NULL) - return ECC_BAD_ARG_E; + if (r == NULL || s == NULL || hash == NULL || res == NULL || key == NULL) + return ECC_BAD_ARG_E; /* default to invalid signature */ - *stat = 0; + *res = 0; /* is the IDX valid ? */ - if (ecc_is_valid_idx(key->idx) != 1) { + if (wc_ecc_is_valid_idx(key->idx) != 1) { return ECC_BAD_ARG_E; } - /* allocate ints */ - if ((err = mp_init_multi(&v, &w, &u1, &u2, &p, &e)) != MP_OKAY) { - return MEMORY_E; + keySz = key->dp->size; + +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) && \ + defined(WOLFSSL_ASYNC_CRYPT_TEST) + if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_ECC) { + if (wc_AsyncTestInit(&key->asyncDev, ASYNC_TEST_ECC_VERIFY)) { + WC_ASYNC_TEST* testDev = &key->asyncDev.test; + testDev->eccVerify.r = r; + testDev->eccVerify.s = s; + testDev->eccVerify.hash = hash; + testDev->eccVerify.hashlen = hashlen; + testDev->eccVerify.stat = res; + testDev->eccVerify.key = key; + return WC_PENDING_E; + } + } +#endif + +#ifdef WOLFSSL_ATECC508A + /* Extract R and S */ + err = mp_to_unsigned_bin(r, &sigRS[0]); + if (err != MP_OKAY) { + return err; + } + err = mp_to_unsigned_bin(s, &sigRS[keySz]); + if (err != MP_OKAY) { + return err; + } + + err = atmel_ecc_verify(hash, sigRS, key->pubkey_raw, res); + if (err != 0) { + return err; + } + (void)hashlen; +#elif defined(WOLFSSL_CRYPTOCELL) + + /* Extract R and S */ + + err = mp_to_unsigned_bin(r, &sigRS[0]); + if (err != MP_OKAY) { + return err; + } + err = mp_to_unsigned_bin(s, &sigRS[keySz]); + if (err != MP_OKAY) { + return err; } - if ((err = mp_init(&m)) != MP_OKAY) { - mp_clear(&v); - mp_clear(&w); - mp_clear(&u1); - mp_clear(&u2); - mp_clear(&p); - mp_clear(&e); - return MEMORY_E; + hash_mode = cc310_hashModeECC(msgLenInBytes); + if (hash_mode == CRYS_ECPKI_HASH_OpModeLast) { + /* hash_mode = */ cc310_hashModeECC(keySz); + hash_mode = CRYS_ECPKI_HASH_SHA256_mode; + } + /* truncate if hash is longer than key size */ + if (msgLenInBytes > keySz) { + msgLenInBytes = keySz; } - /* allocate points */ - mG = ecc_new_point(); - mQ = ecc_new_point(); - if (mQ == NULL || mG == NULL) - err = MEMORY_E; - - /* Note, DecodeECC_DSA_Sig() calls mp_init() on r and s. - * If either of those don't allocate correctly, none of - * the rest of this function will execute, and everything - * gets cleaned up at the end. */ - XMEMSET(&r, 0, sizeof(r)); - XMEMSET(&s, 0, sizeof(s)); - if (err == MP_OKAY) - err = DecodeECC_DSA_Sig(sig, siglen, &r, &s); + /* verify the signature using the public key */ + err = CRYS_ECDSA_Verify(&sigCtxTemp, + &key->ctx.pubKey, + hash_mode, + &sigRS[0], + keySz*2, + (byte*)hash, + msgLenInBytes); - /* get the order */ - if (err == MP_OKAY) - err = mp_read_radix(&p, (char *)key->dp->order, 16); + if (err != SA_SILIB_RET_OK) { + WOLFSSL_MSG("CRYS_ECDSA_Verify failed"); + return err; + } + /* valid signature if we get to this point */ + *res = 1; +#else + /* checking if private key with no public part */ + if (key->type == ECC_PRIVATEKEY_ONLY) { + WOLFSSL_MSG("Verify called with private key, generating public part"); + err = wc_ecc_make_pub_ex(key, NULL, NULL); + if (err != MP_OKAY) { + WOLFSSL_MSG("Unable to extract public key"); + return err; + } + } - /* get the modulus */ - if (err == MP_OKAY) - err = mp_read_radix(&m, (char *)key->dp->prime, 16); +#if defined(WOLFSSL_DSP) && !defined(FREESCALE_LTC_ECC) + if (key->handle != -1) { + return sp_dsp_ecc_verify_256(key->handle, hash, hashlen, key->pubkey.x, key->pubkey.y, + key->pubkey.z, r, s, res, key->heap); + } + if (wolfSSL_GetHandleCbSet() == 1) { + return sp_dsp_ecc_verify_256(0, hash, hashlen, key->pubkey.x, key->pubkey.y, + key->pubkey.z, r, s, res, key->heap); + } +#endif +#if defined(WOLFSSL_SP_MATH) && !defined(FREESCALE_LTC_ECC) +#ifndef WOLFSSL_SP_NO_256 + if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP256R1) { + return sp_ecc_verify_256(hash, hashlen, key->pubkey.x, key->pubkey.y, + key->pubkey.z, r, s, res, key->heap); + } +#endif +#ifdef WOLFSSL_SP_384 + if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP384R1) { + return sp_ecc_verify_384(hash, hashlen, key->pubkey.x, key->pubkey.y, + key->pubkey.z, r, s, res, key->heap); + } +#endif + return WC_KEY_SIZE_E; +#else +#if defined WOLFSSL_HAVE_SP_ECC && !defined(FREESCALE_LTC_ECC) + #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + if (key->asyncDev.marker != WOLFSSL_ASYNC_MARKER_ECC) + #endif + { +#ifndef WOLFSSL_SP_NO_256 + if (key->idx != ECC_CUSTOM_IDX && + ecc_sets[key->idx].id == ECC_SECP256R1) { + return sp_ecc_verify_256(hash, hashlen, key->pubkey.x, + key->pubkey.y, key->pubkey.z,r, s, res, + key->heap); + } +#endif /* WOLFSSL_SP_NO_256 */ +#ifdef WOLFSSL_SP_384 + if (key->idx != ECC_CUSTOM_IDX && + ecc_sets[key->idx].id == ECC_SECP384R1) { + return sp_ecc_verify_384(hash, hashlen, key->pubkey.x, + key->pubkey.y, key->pubkey.z,r, s, res, + key->heap); + } +#endif /* WOLFSSL_SP_384 */ + } +#endif /* WOLFSSL_HAVE_SP_ECC */ + + ALLOC_CURVE_SPECS(ECC_CURVE_FIELD_COUNT); + +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(HAVE_CAVIUM_V) + err = wc_ecc_alloc_mpint(key, &key->e); + if (err != 0) { + FREE_CURVE_SPECS(); + return err; + } + e = key->e; +#else +#ifdef WOLFSSL_SMALL_STACK + e_lcl = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC); + if (e_lcl == NULL) { + FREE_CURVE_SPECS(); + return MEMORY_E; + } +#endif + e = e_lcl; +#endif /* WOLFSSL_ASYNC_CRYPT && HAVE_CAVIUM_V */ + + err = mp_init(e); + if (err != MP_OKAY) + return MEMORY_E; + + /* read in the specs for this curve */ + err = wc_ecc_curve_load(key->dp, &curve, ECC_CURVE_FIELD_ALL); /* check for zero */ if (err == MP_OKAY) { - if (mp_iszero(&r) || mp_iszero(&s) || mp_cmp(&r, &p) != MP_LT || - mp_cmp(&s, &p) != MP_LT) - err = MP_ZERO_E; + if (mp_iszero(r) == MP_YES || mp_iszero(s) == MP_YES || + mp_cmp(r, curve->order) != MP_LT || + mp_cmp(s, curve->order) != MP_LT) { + err = MP_ZERO_E; + } } + /* read hash */ if (err == MP_OKAY) { /* we may need to truncate if hash is longer than key size */ - unsigned int orderBits = mp_count_bits(&p); + unsigned int orderBits = mp_count_bits(curve->order); /* truncate down to byte size, may be all that's needed */ if ( (WOLFSSL_BIT_SIZE * hashlen) > orderBits) - hashlen = (orderBits + WOLFSSL_BIT_SIZE - 1)/WOLFSSL_BIT_SIZE; - err = mp_read_unsigned_bin(&e, hash, hashlen); + hashlen = (orderBits + WOLFSSL_BIT_SIZE - 1) / WOLFSSL_BIT_SIZE; + err = mp_read_unsigned_bin(e, hash, hashlen); /* may still need bit truncation too */ if (err == MP_OKAY && (WOLFSSL_BIT_SIZE * hashlen) > orderBits) - mp_rshb(&e, WOLFSSL_BIT_SIZE - (orderBits & 0x7)); + mp_rshb(e, WOLFSSL_BIT_SIZE - (orderBits & 0x7)); + } + + /* check for async hardware acceleration */ +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_ECC) { + #if defined(HAVE_CAVIUM_V) || defined(HAVE_INTEL_QA) + #ifdef HAVE_CAVIUM_V + if (NitroxEccIsCurveSupported(key)) + #endif + { + err = wc_mp_to_bigint_sz(e, &e->raw, keySz); + if (err == MP_OKAY) + err = wc_mp_to_bigint_sz(key->pubkey.x, &key->pubkey.x->raw, keySz); + if (err == MP_OKAY) + err = wc_mp_to_bigint_sz(key->pubkey.y, &key->pubkey.y->raw, keySz); + if (err == MP_OKAY) + #ifdef HAVE_CAVIUM_V + err = NitroxEcdsaVerify(key, &e->raw, &key->pubkey.x->raw, + &key->pubkey.y->raw, &r->raw, &s->raw, + &curve->prime->raw, &curve->order->raw, res); + #else + err = IntelQaEcdsaVerify(&key->asyncDev, &e->raw, &key->pubkey.x->raw, + &key->pubkey.y->raw, &r->raw, &s->raw, &curve->Af->raw, + &curve->Bf->raw, &curve->prime->raw, &curve->order->raw, + &curve->Gx->raw, &curve->Gy->raw, res); + #endif + + #ifndef HAVE_CAVIUM_V + mp_clear(e); + #endif + wc_ecc_curve_free(curve); + FREE_CURVE_SPECS(); + + return err; + } + #endif /* HAVE_CAVIUM_V || HAVE_INTEL_QA */ + } +#endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_ECC */ + +#ifdef WOLFSSL_SMALL_STACK + if (err == MP_OKAY) { + v = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC); + if (v == NULL) + err = MEMORY_E; + } + if (err == MP_OKAY) { + w = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC); + if (w == NULL) + err = MEMORY_E; + } + if (err == MP_OKAY) { + u1 = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC); + if (u1 == NULL) + err = MEMORY_E; + } + if (err == MP_OKAY) { + u2 = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC); + if (u2 == NULL) + err = MEMORY_E; + } +#endif + + /* allocate ints */ + if (err == MP_OKAY) { + if ((err = mp_init_multi(v, w, u1, u2, NULL, NULL)) != MP_OKAY) { + err = MEMORY_E; + } + did_init = 1; + } + + /* allocate points */ + if (err == MP_OKAY) { + mG = wc_ecc_new_point_h(key->heap); + mQ = wc_ecc_new_point_h(key->heap); + if (mQ == NULL || mG == NULL) + err = MEMORY_E; } /* w = s^-1 mod n */ if (err == MP_OKAY) - err = mp_invmod(&s, &p, &w); + err = mp_invmod(s, curve->order, w); /* u1 = ew */ if (err == MP_OKAY) - err = mp_mulmod(&e, &w, &p, &u1); + err = mp_mulmod(e, w, curve->order, u1); /* u2 = rw */ if (err == MP_OKAY) - err = mp_mulmod(&r, &w, &p, &u2); + err = mp_mulmod(r, w, curve->order, u2); /* find mG and mQ */ if (err == MP_OKAY) - err = mp_read_radix(mG->x, (char *)key->dp->Gx, 16); - + err = mp_copy(curve->Gx, mG->x); if (err == MP_OKAY) - err = mp_read_radix(mG->y, (char *)key->dp->Gy, 16); + err = mp_copy(curve->Gy, mG->y); if (err == MP_OKAY) - mp_set(mG->z, 1); + err = mp_set(mG->z, 1); if (err == MP_OKAY) err = mp_copy(key->pubkey.x, mQ->x); @@ -2207,75 +6170,458 @@ int wc_ecc_verify_hash(const byte* sig, word32 siglen, const byte* hash, if (err == MP_OKAY) err = mp_copy(key->pubkey.z, mQ->z); +#if defined(FREESCALE_LTC_ECC) + /* use PKHA to compute u1*mG + u2*mQ */ + if (err == MP_OKAY) + err = wc_ecc_mulmod_ex(u1, mG, mG, curve->Af, curve->prime, 0, key->heap); + if (err == MP_OKAY) + err = wc_ecc_mulmod_ex(u2, mQ, mQ, curve->Af, curve->prime, 0, key->heap); + if (err == MP_OKAY) + err = wc_ecc_point_add(mG, mQ, mG, curve->prime); +#else #ifndef ECC_SHAMIR + if (err == MP_OKAY) { - mp_digit mp; + mp_digit mp = 0; - /* compute u1*mG + u2*mQ = mG */ - if (err == MP_OKAY) - err = ecc_mulmod(&u1, mG, mG, &m, 0); - if (err == MP_OKAY) - err = ecc_mulmod(&u2, mQ, mQ, &m, 0); - - /* find the montgomery mp */ - if (err == MP_OKAY) - err = mp_montgomery_setup(&m, &mp); + if (!mp_iszero(u1)) { + /* compute u1*mG + u2*mQ = mG */ + err = wc_ecc_mulmod_ex(u1, mG, mG, curve->Af, curve->prime, 0, + key->heap); + if (err == MP_OKAY) { + err = wc_ecc_mulmod_ex(u2, mQ, mQ, curve->Af, curve->prime, 0, + key->heap); + } - /* add them */ - if (err == MP_OKAY) - err = ecc_projective_add_point(mQ, mG, mG, &m, &mp); - - /* reduce */ - if (err == MP_OKAY) - err = ecc_map(mG, &m, &mp); + /* find the montgomery mp */ + if (err == MP_OKAY) + err = mp_montgomery_setup(curve->prime, &mp); + + /* add them */ + if (err == MP_OKAY) + err = ecc_projective_add_point(mQ, mG, mG, curve->Af, + curve->prime, mp); + if (err == MP_OKAY && mp_iszero(mG->z)) { + /* When all zero then should have done an add */ + if (mp_iszero(mG->x) && mp_iszero(mG->y)) { + err = ecc_projective_dbl_point(mQ, mG, curve->Af, + curve->prime, mp); + } + /* When only Z zero then result is infinity */ + else { + err = mp_set(mG->x, 0); + if (err == MP_OKAY) + err = mp_set(mG->y, 0); + if (err == MP_OKAY) + err = mp_set(mG->z, 1); + } + } + } + else { + /* compute 0*mG + u2*mQ = mG */ + err = wc_ecc_mulmod_ex(u2, mQ, mG, curve->Af, curve->prime, 0, + key->heap); + /* find the montgomery mp */ + if (err == MP_OKAY) + err = mp_montgomery_setup(curve->prime, &mp); + } + + /* reduce */ + if (err == MP_OKAY) + err = ecc_map(mG, curve->prime, mp); } #else - /* use Shamir's trick to compute u1*mG + u2*mQ using half the doubles */ - if (err == MP_OKAY) - err = ecc_mul2add(mG, &u1, mQ, &u2, mG, &m); -#endif /* ECC_SHAMIR */ - + /* use Shamir's trick to compute u1*mG + u2*mQ using half the doubles */ + if (err == MP_OKAY) { + err = ecc_mul2add(mG, u1, mQ, u2, mG, curve->Af, curve->prime, + key->heap); + } +#endif /* ECC_SHAMIR */ +#endif /* FREESCALE_LTC_ECC */ /* v = X_x1 mod n */ if (err == MP_OKAY) - err = mp_mod(mG->x, &p, &v); + err = mp_mod(mG->x, curve->order, v); /* does v == r */ if (err == MP_OKAY) { - if (mp_cmp(&v, &r) == MP_EQ) - *stat = 1; + if (mp_cmp(v, r) == MP_EQ) + *res = 1; } - ecc_del_point(mG); - ecc_del_point(mQ); + /* cleanup */ + wc_ecc_del_point_h(mG, key->heap); + wc_ecc_del_point_h(mQ, key->heap); + + mp_clear(e); + if (did_init) { + mp_clear(v); + mp_clear(w); + mp_clear(u1); + mp_clear(u2); + } +#ifdef WOLFSSL_SMALL_STACK + XFREE(u2, key->heap, DYNAMIC_TYPE_ECC); + XFREE(u1, key->heap, DYNAMIC_TYPE_ECC); + XFREE(w, key->heap, DYNAMIC_TYPE_ECC); + XFREE(v, key->heap, DYNAMIC_TYPE_ECC); +#if !defined(WOLFSSL_ASYNC_CRYPT) || !defined(HAVE_CAVIUM_V) + XFREE(e_lcl, key->heap, DYNAMIC_TYPE_ECC); +#endif +#endif + + wc_ecc_curve_free(curve); + FREE_CURVE_SPECS(); - mp_clear(&r); - mp_clear(&s); - mp_clear(&v); - mp_clear(&w); - mp_clear(&u1); - mp_clear(&u2); - mp_clear(&p); - mp_clear(&e); - mp_clear(&m); +#endif /* WOLFSSL_SP_MATH */ +#endif /* WOLFSSL_ATECC508A */ + + (void)keySz; + (void)hashlen; return err; } +#endif /* WOLFSSL_STM32_PKA */ +#endif /* HAVE_ECC_VERIFY */ + +#ifdef HAVE_ECC_KEY_IMPORT +/* import point from der + * if shortKeySize != 0 then keysize is always (inLen-1)>>1 */ +int wc_ecc_import_point_der_ex(byte* in, word32 inLen, const int curve_idx, + ecc_point* point, int shortKeySize) +{ + int err = 0; +#ifdef HAVE_COMP_KEY + int compressed = 0; +#endif + int keysize; + byte pointType; + +#ifndef HAVE_COMP_KEY + (void)shortKeySize; +#endif + + if (in == NULL || point == NULL || (curve_idx < 0) || + (wc_ecc_is_valid_idx(curve_idx) == 0)) + return ECC_BAD_ARG_E; + + /* must be odd */ + if ((inLen & 1) == 0) { + return ECC_BAD_ARG_E; + } + + /* init point */ +#ifdef ALT_ECC_SIZE + point->x = (mp_int*)&point->xyz[0]; + point->y = (mp_int*)&point->xyz[1]; + point->z = (mp_int*)&point->xyz[2]; + alt_fp_init(point->x); + alt_fp_init(point->y); + alt_fp_init(point->z); +#else + err = mp_init_multi(point->x, point->y, point->z, NULL, NULL, NULL); +#endif + if (err != MP_OKAY) + return MEMORY_E; + + /* check for point type (4, 2, or 3) */ + pointType = in[0]; + if (pointType != ECC_POINT_UNCOMP && pointType != ECC_POINT_COMP_EVEN && + pointType != ECC_POINT_COMP_ODD) { + err = ASN_PARSE_E; + } + + if (pointType == ECC_POINT_COMP_EVEN || pointType == ECC_POINT_COMP_ODD) { +#ifdef HAVE_COMP_KEY + compressed = 1; +#else + err = NOT_COMPILED_IN; +#endif + } + + /* adjust to skip first byte */ + inLen -= 1; + in += 1; + + /* calculate key size based on inLen / 2 if uncompressed or shortKeySize + * is true */ +#ifdef HAVE_COMP_KEY + keysize = compressed && !shortKeySize ? inLen : inLen>>1; +#else + keysize = inLen>>1; +#endif + + /* read data */ + if (err == MP_OKAY) + err = mp_read_unsigned_bin(point->x, (byte*)in, keysize); + +#ifdef HAVE_COMP_KEY + if (err == MP_OKAY && compressed == 1) { /* build y */ +#ifndef WOLFSSL_SP_MATH + int did_init = 0; + mp_int t1, t2; + DECLARE_CURVE_SPECS(curve, 3); + + ALLOC_CURVE_SPECS(3); + + if (mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL) != MP_OKAY) + err = MEMORY_E; + else + did_init = 1; + + /* load curve info */ + if (err == MP_OKAY) + err = wc_ecc_curve_load(&ecc_sets[curve_idx], &curve, + (ECC_CURVE_FIELD_PRIME | ECC_CURVE_FIELD_AF | + ECC_CURVE_FIELD_BF)); + + /* compute x^3 */ + if (err == MP_OKAY) + err = mp_sqr(point->x, &t1); + if (err == MP_OKAY) + err = mp_mulmod(&t1, point->x, curve->prime, &t1); + + /* compute x^3 + a*x */ + if (err == MP_OKAY) + err = mp_mulmod(curve->Af, point->x, curve->prime, &t2); + if (err == MP_OKAY) + err = mp_add(&t1, &t2, &t1); + + /* compute x^3 + a*x + b */ + if (err == MP_OKAY) + err = mp_add(&t1, curve->Bf, &t1); + + /* compute sqrt(x^3 + a*x + b) */ + if (err == MP_OKAY) + err = mp_sqrtmod_prime(&t1, curve->prime, &t2); + + /* adjust y */ + if (err == MP_OKAY) { + if ((mp_isodd(&t2) == MP_YES && pointType == ECC_POINT_COMP_ODD) || + (mp_isodd(&t2) == MP_NO && pointType == ECC_POINT_COMP_EVEN)) { + err = mp_mod(&t2, curve->prime, point->y); + } + else { + err = mp_submod(curve->prime, &t2, curve->prime, point->y); + } + } + + if (did_init) { + mp_clear(&t2); + mp_clear(&t1); + } + + wc_ecc_curve_free(curve); + FREE_CURVE_SPECS(); +#else + #ifndef WOLFSSL_SP_NO_256 + if (curve_idx != ECC_CUSTOM_IDX && + ecc_sets[curve_idx].id == ECC_SECP256R1) { + sp_ecc_uncompress_256(point->x, pointType, point->y); + } + else + #endif + #ifdef WOLFSSL_SP_384 + if (curve_idx != ECC_CUSTOM_IDX && + ecc_sets[curve_idx].id == ECC_SECP384R1) { + sp_ecc_uncompress_384(point->x, pointType, point->y); + } + else + #endif + { + err = WC_KEY_SIZE_E; + } +#endif + } +#endif + + if (err == MP_OKAY) { +#ifdef HAVE_COMP_KEY + if (compressed == 0) +#endif + err = mp_read_unsigned_bin(point->y, (byte*)in + keysize, keysize); + } + if (err == MP_OKAY) + err = mp_set(point->z, 1); + + if (err != MP_OKAY) { + mp_clear(point->x); + mp_clear(point->y); + mp_clear(point->z); + } + + return err; +} + +/* function for backwards compatiblity with previous implementations */ +int wc_ecc_import_point_der(byte* in, word32 inLen, const int curve_idx, + ecc_point* point) +{ + return wc_ecc_import_point_der_ex(in, inLen, curve_idx, point, 1); +} +#endif /* HAVE_ECC_KEY_IMPORT */ + +#ifdef HAVE_ECC_KEY_EXPORT +/* export point to der */ + +int wc_ecc_export_point_der_ex(const int curve_idx, ecc_point* point, byte* out, + word32* outLen, int compressed) +{ + if (compressed == 0) + return wc_ecc_export_point_der(curve_idx, point, out, outLen); +#ifdef HAVE_COMP_KEY + else + return wc_ecc_export_point_der_compressed(curve_idx, point, out, outLen); +#else + return NOT_COMPILED_IN; +#endif +} + +int wc_ecc_export_point_der(const int curve_idx, ecc_point* point, byte* out, + word32* outLen) +{ + int ret = MP_OKAY; + word32 numlen; +#ifdef WOLFSSL_SMALL_STACK + byte* buf; +#else + byte buf[ECC_BUFSIZE]; +#endif + + if ((curve_idx < 0) || (wc_ecc_is_valid_idx(curve_idx) == 0)) + return ECC_BAD_ARG_E; + + numlen = ecc_sets[curve_idx].size; + + /* return length needed only */ + if (point != NULL && out == NULL && outLen != NULL) { + *outLen = 1 + 2*numlen; + return LENGTH_ONLY_E; + } + + if (point == NULL || out == NULL || outLen == NULL) + return ECC_BAD_ARG_E; + + if (*outLen < (1 + 2*numlen)) { + *outLen = 1 + 2*numlen; + return BUFFER_E; + } + + /* store byte point type */ + out[0] = ECC_POINT_UNCOMP; + +#ifdef WOLFSSL_SMALL_STACK + buf = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_ECC_BUFFER); + if (buf == NULL) + return MEMORY_E; +#endif + + /* pad and store x */ + XMEMSET(buf, 0, ECC_BUFSIZE); + ret = mp_to_unsigned_bin(point->x, buf + + (numlen - mp_unsigned_bin_size(point->x))); + if (ret != MP_OKAY) + goto done; + XMEMCPY(out+1, buf, numlen); + + /* pad and store y */ + XMEMSET(buf, 0, ECC_BUFSIZE); + ret = mp_to_unsigned_bin(point->y, buf + + (numlen - mp_unsigned_bin_size(point->y))); + if (ret != MP_OKAY) + goto done; + XMEMCPY(out+1+numlen, buf, numlen); + + *outLen = 1 + 2*numlen; + +done: +#ifdef WOLFSSL_SMALL_STACK + XFREE(buf, NULL, DYNAMIC_TYPE_ECC_BUFFER); +#endif + + return ret; +} + + +/* export point to der */ +#ifdef HAVE_COMP_KEY +int wc_ecc_export_point_der_compressed(const int curve_idx, ecc_point* point, + byte* out, word32* outLen) +{ + int ret = MP_OKAY; + word32 numlen; + word32 output_len; +#ifdef WOLFSSL_SMALL_STACK + byte* buf; +#else + byte buf[ECC_BUFSIZE]; +#endif + + if ((curve_idx < 0) || (wc_ecc_is_valid_idx(curve_idx) == 0)) + return ECC_BAD_ARG_E; + + numlen = ecc_sets[curve_idx].size; + output_len = 1 + numlen; /* y point type + x */ + + /* return length needed only */ + if (point != NULL && out == NULL && outLen != NULL) { + *outLen = output_len; + return LENGTH_ONLY_E; + } + + if (point == NULL || out == NULL || outLen == NULL) + return ECC_BAD_ARG_E; + + + if (*outLen < output_len) { + *outLen = output_len; + return BUFFER_E; + } + + /* store byte point type */ + out[0] = mp_isodd(point->y) == MP_YES ? ECC_POINT_COMP_ODD : + ECC_POINT_COMP_EVEN; + +#ifdef WOLFSSL_SMALL_STACK + buf = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_ECC_BUFFER); + if (buf == NULL) + return MEMORY_E; +#endif + /* pad and store x */ + XMEMSET(buf, 0, ECC_BUFSIZE); + ret = mp_to_unsigned_bin(point->x, buf + + (numlen - mp_unsigned_bin_size(point->x))); + if (ret != MP_OKAY) + goto done; + XMEMCPY(out+1, buf, numlen); + + *outLen = output_len; + +done: +#ifdef WOLFSSL_SMALL_STACK + XFREE(buf, NULL, DYNAMIC_TYPE_ECC_BUFFER); +#endif + + return ret; +} +#endif /* HAVE_COMP_KEY */ /* export public ECC key in ANSI X9.63 format */ int wc_ecc_export_x963(ecc_key* key, byte* out, word32* outLen) { + int ret = MP_OKAY; + word32 numlen; #ifdef WOLFSSL_SMALL_STACK byte* buf; #else byte buf[ECC_BUFSIZE]; #endif - word32 numlen; - int ret = MP_OKAY; + word32 pubxlen, pubylen; /* return length needed only */ if (key != NULL && out == NULL && outLen != NULL) { - numlen = key->dp->size; + /* if key hasn't been setup assume max bytes for size estimation */ + numlen = key->dp ? key->dp->size : MAX_ECC_BYTES; *outLen = 1 + 2*numlen; return LENGTH_ONLY_E; } @@ -2283,47 +6629,56 @@ int wc_ecc_export_x963(ecc_key* key, byte* out, word32* outLen) if (key == NULL || out == NULL || outLen == NULL) return ECC_BAD_ARG_E; - if (ecc_is_valid_idx(key->idx) == 0) { + if (key->type == ECC_PRIVATEKEY_ONLY) + return ECC_PRIVATEONLY_E; + + if (wc_ecc_is_valid_idx(key->idx) == 0 || key->dp == NULL) { return ECC_BAD_ARG_E; } numlen = key->dp->size; + /* verify room in out buffer */ if (*outLen < (1 + 2*numlen)) { *outLen = 1 + 2*numlen; return BUFFER_E; } - /* store byte 0x04 */ - out[0] = 0x04; + /* verify public key length is less than key size */ + pubxlen = mp_unsigned_bin_size(key->pubkey.x); + pubylen = mp_unsigned_bin_size(key->pubkey.y); + if ((pubxlen > numlen) || (pubylen > numlen)) { + WOLFSSL_MSG("Public key x/y invalid!"); + return BUFFER_E; + } + + /* store byte point type */ + out[0] = ECC_POINT_UNCOMP; #ifdef WOLFSSL_SMALL_STACK - buf = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + buf = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_ECC_BUFFER); if (buf == NULL) return MEMORY_E; #endif - do { - /* pad and store x */ - XMEMSET(buf, 0, ECC_BUFSIZE); - ret = mp_to_unsigned_bin(key->pubkey.x, - buf + (numlen - mp_unsigned_bin_size(key->pubkey.x))); - if (ret != MP_OKAY) - break; - XMEMCPY(out+1, buf, numlen); - - /* pad and store y */ - XMEMSET(buf, 0, ECC_BUFSIZE); - ret = mp_to_unsigned_bin(key->pubkey.y, - buf + (numlen - mp_unsigned_bin_size(key->pubkey.y))); - if (ret != MP_OKAY) - break; - XMEMCPY(out+1+numlen, buf, numlen); - - *outLen = 1 + 2*numlen; - } while (0); - + /* pad and store x */ + XMEMSET(buf, 0, ECC_BUFSIZE); + ret = mp_to_unsigned_bin(key->pubkey.x, buf + (numlen - pubxlen)); + if (ret != MP_OKAY) + goto done; + XMEMCPY(out+1, buf, numlen); + + /* pad and store y */ + XMEMSET(buf, 0, ECC_BUFSIZE); + ret = mp_to_unsigned_bin(key->pubkey.y, buf + (numlen - pubylen)); + if (ret != MP_OKAY) + goto done; + XMEMCPY(out+1+numlen, buf, numlen); + + *outLen = 1 + 2*numlen; + +done: #ifdef WOLFSSL_SMALL_STACK - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(buf, NULL, DYNAMIC_TYPE_ECC_BUFFER); #endif return ret; @@ -2332,158 +6687,264 @@ int wc_ecc_export_x963(ecc_key* key, byte* out, word32* outLen) /* export public ECC key in ANSI X9.63 format, extended with * compression option */ -int wc_ecc_export_x963_ex(ecc_key* key, byte* out, word32* outLen, int compressed) +int wc_ecc_export_x963_ex(ecc_key* key, byte* out, word32* outLen, + int compressed) { if (compressed == 0) return wc_ecc_export_x963(key, out, outLen); #ifdef HAVE_COMP_KEY else return wc_ecc_export_x963_compressed(key, out, outLen); -#endif - +#else return NOT_COMPILED_IN; +#endif } +#endif /* HAVE_ECC_KEY_EXPORT */ + +#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_CRYPTOCELL) -/* is ec point on curve descriped by dp ? */ -static int ecc_is_point(const ecc_set_type* dp, ecc_point* ecp, mp_int* prime) +/* is ecc point on curve described by dp ? */ +int wc_ecc_is_point(ecc_point* ecp, mp_int* a, mp_int* b, mp_int* prime) { - mp_int b, t1, t2; +#ifndef WOLFSSL_SP_MATH int err; +#ifdef WOLFSSL_SMALL_STACK + mp_int* t1; + mp_int* t2; +#else + mp_int t1[1], t2[1]; +#endif - if ((err = mp_init_multi(&b, &t1, &t2, NULL, NULL, NULL)) != MP_OKAY) { - return err; +#ifdef WOLFSSL_SMALL_STACK + t1 = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + if (t1 == NULL) + return MEMORY_E; + t2 = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + if (t2 == NULL) { + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); + return MEMORY_E; } +#endif - /* load b */ - err = mp_read_radix(&b, dp->Bf, 16); + if ((err = mp_init_multi(t1, t2, NULL, NULL, NULL, NULL)) != MP_OKAY) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(t2, NULL, DYNAMIC_TYPE_ECC); + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); + #endif + return err; + } /* compute y^2 */ if (err == MP_OKAY) - err = mp_sqr(ecp->y, &t1); + err = mp_sqr(ecp->y, t1); /* compute x^3 */ if (err == MP_OKAY) - err = mp_sqr(ecp->x, &t2); + err = mp_sqr(ecp->x, t2); if (err == MP_OKAY) - err = mp_mod(&t2, prime, &t2); + err = mp_mod(t2, prime, t2); if (err == MP_OKAY) - err = mp_mul(ecp->x, &t2, &t2); + err = mp_mul(ecp->x, t2, t2); /* compute y^2 - x^3 */ if (err == MP_OKAY) - err = mp_sub(&t1, &t2, &t1); + err = mp_sub(t1, t2, t1); - /* compute y^2 - x^3 + 3x */ - if (err == MP_OKAY) - err = mp_add(&t1, ecp->x, &t1); - if (err == MP_OKAY) - err = mp_add(&t1, ecp->x, &t1); - if (err == MP_OKAY) - err = mp_add(&t1, ecp->x, &t1); - if (err == MP_OKAY) - err = mp_mod(&t1, prime, &t1); + /* Determine if curve "a" should be used in calc */ +#ifdef WOLFSSL_CUSTOM_CURVES + if (err == MP_OKAY) { + /* Use a and prime to determine if a == 3 */ + err = mp_set(t2, 0); + if (err == MP_OKAY) + err = mp_submod(prime, a, prime, t2); + } + if (err == MP_OKAY && mp_cmp_d(t2, 3) != MP_EQ) { + /* compute y^2 - x^3 + a*x */ + if (err == MP_OKAY) + err = mp_mulmod(t2, ecp->x, prime, t2); + if (err == MP_OKAY) + err = mp_addmod(t1, t2, prime, t1); + } + else +#endif /* WOLFSSL_CUSTOM_CURVES */ + { + /* assumes "a" == 3 */ + (void)a; + + /* compute y^2 - x^3 + 3x */ + if (err == MP_OKAY) + err = mp_add(t1, ecp->x, t1); + if (err == MP_OKAY) + err = mp_add(t1, ecp->x, t1); + if (err == MP_OKAY) + err = mp_add(t1, ecp->x, t1); + if (err == MP_OKAY) + err = mp_mod(t1, prime, t1); + } - while (err == MP_OKAY && mp_cmp_d(&t1, 0) == MP_LT) { - err = mp_add(&t1, prime, &t1); + /* adjust range (0, prime) */ + while (err == MP_OKAY && mp_isneg(t1)) { + err = mp_add(t1, prime, t1); } - while (err == MP_OKAY && mp_cmp(&t1, prime) != MP_LT) { - err = mp_sub(&t1, prime, &t1); + while (err == MP_OKAY && mp_cmp(t1, prime) != MP_LT) { + err = mp_sub(t1, prime, t1); } /* compare to b */ if (err == MP_OKAY) { - if (mp_cmp(&t1, &b) != MP_EQ) { + if (mp_cmp(t1, b) != MP_EQ) { err = MP_VAL; } else { err = MP_OKAY; } } - mp_clear(&b); - mp_clear(&t1); - mp_clear(&t2); + mp_clear(t1); + mp_clear(t2); +#ifdef WOLFSSL_SMALL_STACK + XFREE(t2, NULL, DYNAMIC_TYPE_ECC); + XFREE(t1, NULL, DYNAMIC_TYPE_ECC); +#endif return err; -} +#else + (void)a; + (void)b; +#ifndef WOLFSSL_SP_NO_256 + if (mp_count_bits(prime) == 256) { + return sp_ecc_is_point_256(ecp->x, ecp->y); + } +#endif +#ifdef WOLFSSL_SP_384 + if (mp_count_bits(prime) == 384) { + return sp_ecc_is_point_384(ecp->x, ecp->y); + } +#endif + return WC_KEY_SIZE_E; +#endif +} +#ifndef WOLFSSL_SP_MATH /* validate privkey * generator == pubkey, 0 on success */ -static int ecc_check_privkey_gen(ecc_key* key, mp_int* prime) +static int ecc_check_privkey_gen(ecc_key* key, mp_int* a, mp_int* prime) { + int err = MP_OKAY; ecc_point* base = NULL; ecc_point* res = NULL; - int err; + DECLARE_CURVE_SPECS(curve, 2); if (key == NULL) return BAD_FUNC_ARG; - base = ecc_new_point(); - if (base == NULL) - return MEMORY_E; + ALLOC_CURVE_SPECS(2); - /* set up base generator */ - err = mp_read_radix(base->x, (char*)key->dp->Gx, 16); - if (err == MP_OKAY) - err = mp_read_radix(base->y, (char*)key->dp->Gy, 16); - if (err == MP_OKAY) - mp_set(base->z, 1); + res = wc_ecc_new_point_h(key->heap); + if (res == NULL) + err = MEMORY_E; - if (err == MP_OKAY) { - res = ecc_new_point(); - if (res == NULL) +#ifdef WOLFSSL_HAVE_SP_ECC +#ifndef WOLFSSL_SP_NO_256 + if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP256R1) { + if (err == MP_OKAY) { + err = sp_ecc_mulmod_base_256(&key->k, res, 1, key->heap); + } + } + else +#endif +#ifdef WOLFSSL_SP_384 + if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP384R1) { + if (err == MP_OKAY) { + err = sp_ecc_mulmod_base_384(&key->k, res, 1, key->heap); + } + } + else +#endif +#endif + { + base = wc_ecc_new_point_h(key->heap); + if (base == NULL) err = MEMORY_E; - else { - err = ecc_mulmod(&key->k, base, res, prime, 1); - if (err == MP_OKAY) { - /* compare result to public key */ - if (mp_cmp(res->x, key->pubkey.x) != MP_EQ || - mp_cmp(res->y, key->pubkey.y) != MP_EQ || - mp_cmp(res->z, key->pubkey.z) != MP_EQ) { - /* didn't match */ - err = ECC_PRIV_KEY_E; - } - } + + if (err == MP_OKAY) { + /* load curve info */ + err = wc_ecc_curve_load(key->dp, &curve, + (ECC_CURVE_FIELD_GX | ECC_CURVE_FIELD_GY)); + } + + /* set up base generator */ + if (err == MP_OKAY) + err = mp_copy(curve->Gx, base->x); + if (err == MP_OKAY) + err = mp_copy(curve->Gy, base->y); + if (err == MP_OKAY) + err = mp_set(base->z, 1); + + if (err == MP_OKAY) + err = wc_ecc_mulmod_ex(&key->k, base, res, a, prime, 1, key->heap); + } + + if (err == MP_OKAY) { + /* compare result to public key */ + if (mp_cmp(res->x, key->pubkey.x) != MP_EQ || + mp_cmp(res->y, key->pubkey.y) != MP_EQ || + mp_cmp(res->z, key->pubkey.z) != MP_EQ) { + /* didn't match */ + err = ECC_PRIV_KEY_E; } } - ecc_del_point(res); - ecc_del_point(base); + wc_ecc_curve_free(curve); + wc_ecc_del_point_h(res, key->heap); + wc_ecc_del_point_h(base, key->heap); + FREE_CURVE_SPECS(); return err; } - +#endif #ifdef WOLFSSL_VALIDATE_ECC_IMPORT /* check privkey generator helper, creates prime needed */ static int ecc_check_privkey_gen_helper(ecc_key* key) { - mp_int prime; int err; +#ifndef WOLFSSL_ATECC508A + DECLARE_CURVE_SPECS(curve, 2); +#endif if (key == NULL) return BAD_FUNC_ARG; - err = mp_init(&prime); - if (err != MP_OKAY) - return err; +#ifdef WOLFSSL_ATECC508A + /* Hardware based private key, so this operation is not supported */ + err = MP_OKAY; /* just report success */ + +#else + ALLOC_CURVE_SPECS(2); - err = mp_read_radix(&prime, (char*)key->dp->prime, 16); + /* load curve info */ + err = wc_ecc_curve_load(key->dp, &curve, + (ECC_CURVE_FIELD_PRIME | ECC_CURVE_FIELD_AF)); + + if (err == MP_OKAY) + err = ecc_check_privkey_gen(key, curve->Af, curve->prime); - if (err == MP_OKAY); - err = ecc_check_privkey_gen(key, &prime); + wc_ecc_curve_free(curve); + FREE_CURVE_SPECS(); - mp_clear(&prime); +#endif /* WOLFSSL_ATECC508A */ return err; } #endif /* WOLFSSL_VALIDATE_ECC_IMPORT */ - +#if defined(WOLFSSL_VALIDATE_ECC_KEYGEN) || !defined(WOLFSSL_SP_MATH) /* validate order * pubkey = point at infinity, 0 on success */ -static int ecc_check_pubkey_order(ecc_key* key, mp_int* prime, mp_int* order) +static int ecc_check_pubkey_order(ecc_key* key, ecc_point* pubkey, mp_int* a, + mp_int* prime, mp_int* order) { ecc_point* inf = NULL; int err; @@ -2491,258 +6952,613 @@ static int ecc_check_pubkey_order(ecc_key* key, mp_int* prime, mp_int* order) if (key == NULL) return BAD_FUNC_ARG; - inf = ecc_new_point(); + inf = wc_ecc_new_point_h(key->heap); if (inf == NULL) err = MEMORY_E; else { - err = ecc_mulmod(order, &key->pubkey, inf, prime, 1); - if (err == MP_OKAY && !ecc_point_is_at_infinity(inf)) +#ifdef WOLFSSL_HAVE_SP_ECC +#ifndef WOLFSSL_SP_NO_256 + if (key->idx != ECC_CUSTOM_IDX && + ecc_sets[key->idx].id == ECC_SECP256R1) { + err = sp_ecc_mulmod_256(order, pubkey, inf, 1, key->heap); + } + else +#endif +#ifdef WOLFSSL_SP_384 + if (key->idx != ECC_CUSTOM_IDX && + ecc_sets[key->idx].id == ECC_SECP384R1) { + err = sp_ecc_mulmod_384(order, pubkey, inf, 1, key->heap); + } + else +#endif +#endif +#ifndef WOLFSSL_SP_MATH + err = wc_ecc_mulmod_ex(order, pubkey, inf, a, prime, 1, key->heap); + if (err == MP_OKAY && !wc_ecc_point_is_at_infinity(inf)) err = ECC_INF_E; +#else + (void)a; + (void)prime; + + err = WC_KEY_SIZE_E; +#endif } - ecc_del_point(inf); + wc_ecc_del_point_h(inf, key->heap); return err; } +#endif +#endif /* !WOLFSSL_ATECC508A && !WOLFSSL_CRYPTOCELL*/ + +#ifdef OPENSSL_EXTRA +int wc_ecc_get_generator(ecc_point* ecp, int curve_idx) +{ + int err = MP_OKAY; + DECLARE_CURVE_SPECS(curve, 2); + + if (!ecp || curve_idx < 0 || curve_idx > (int)(ECC_SET_COUNT-1)) + return BAD_FUNC_ARG; + ALLOC_CURVE_SPECS(2); + + err = wc_ecc_curve_load(&ecc_sets[curve_idx], &curve, + (ECC_CURVE_FIELD_GX | ECC_CURVE_FIELD_GY)); + if (err == MP_OKAY) + err = mp_copy(curve->Gx, ecp->x); + if (err == MP_OKAY) + err = mp_copy(curve->Gy, ecp->y); + if (err == MP_OKAY) + err = mp_set(ecp->z, 1); + + wc_ecc_curve_free(curve); + FREE_CURVE_SPECS(); + + return err; +} +#endif /* OPENSSLALL */ -/* perform sanity checks on ec key validity, 0 on success */ +/* perform sanity checks on ecc key validity, 0 on success */ int wc_ecc_check_key(ecc_key* key) { - mp_int prime; /* used by multiple calls so let's cache */ - mp_int order; /* other callers have, so let's gen here */ int err; +#ifndef WOLFSSL_SP_MATH +#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_CRYPTOCELL) + mp_int* b = NULL; +#ifdef USE_ECC_B_PARAM + DECLARE_CURVE_SPECS(curve, 4); +#else +#ifndef WOLFSSL_SMALL_STACK + mp_int b_lcl; +#endif + DECLARE_CURVE_SPECS(curve, 3); +#endif /* USE_ECC_B_PARAM */ +#endif /* WOLFSSL_ATECC508A */ if (key == NULL) return BAD_FUNC_ARG; - /* pubkey point cannot be at inifinity */ - if (ecc_point_is_at_infinity(&key->pubkey)) - return ECC_INF_E; +#if defined(WOLFSSL_ATECC508A) || defined(WOLFSSL_CRYPTOCELL) - err = mp_init_multi(&prime, &order, NULL, NULL, NULL, NULL); - if (err != MP_OKAY) - return err; + err = 0; /* consider key check success on ATECC508A */ - err = mp_read_radix(&prime, (char*)key->dp->prime, 16); +#else + #ifdef USE_ECC_B_PARAM + ALLOC_CURVE_SPECS(4); + #else + ALLOC_CURVE_SPECS(3); + #ifndef WOLFSSL_SMALL_STACK + b = &b_lcl; + #else + b = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC); + if (b == NULL) { + FREE_CURVE_SPECS(); + return MEMORY_E; + } + #endif + XMEMSET(b, 0, sizeof(mp_int)); + #endif - /* make sure point is actually on curve */ + /* SP 800-56Ar3, section 5.6.2.3.3, process step 1 */ + /* pubkey point cannot be at infinity */ + if (wc_ecc_point_is_at_infinity(&key->pubkey)) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(b, key->heap, DYNAMIC_TYPE_ECC); + #endif + FREE_CURVE_SPECS(); + return ECC_INF_E; + } + + /* load curve info */ + err = wc_ecc_curve_load(key->dp, &curve, (ECC_CURVE_FIELD_PRIME | + ECC_CURVE_FIELD_AF | ECC_CURVE_FIELD_ORDER +#ifdef USE_ECC_B_PARAM + | ECC_CURVE_FIELD_BF +#endif + )); + +#ifndef USE_ECC_B_PARAM + /* load curve b parameter */ + if (err == MP_OKAY) + err = mp_init(b); if (err == MP_OKAY) - err = ecc_is_point(key->dp, &key->pubkey, &prime); + err = mp_read_radix(b, key->dp->Bf, MP_RADIX_HEX); +#else + if (err == MP_OKAY) + b = curve->Bf; +#endif + + /* SP 800-56Ar3, section 5.6.2.3.3, process step 2 */ + /* Qx must be in the range [0, p-1] */ + if (err == MP_OKAY) { + if (mp_cmp(key->pubkey.x, curve->prime) != MP_LT) + err = ECC_OUT_OF_RANGE_E; + } + /* Qy must be in the range [0, p-1] */ + if (err == MP_OKAY) { + if (mp_cmp(key->pubkey.y, curve->prime) != MP_LT) + err = ECC_OUT_OF_RANGE_E; + } + + /* SP 800-56Ar3, section 5.6.2.3.3, process steps 3 */ + /* make sure point is actually on curve */ if (err == MP_OKAY) - err = mp_read_radix(&order, (char*)key->dp->order, 16); + err = wc_ecc_is_point(&key->pubkey, curve->Af, b, curve->prime); + /* SP 800-56Ar3, section 5.6.2.3.3, process steps 4 */ /* pubkey * order must be at infinity */ if (err == MP_OKAY) - err = ecc_check_pubkey_order(key, &prime, &order); + err = ecc_check_pubkey_order(key, &key->pubkey, curve->Af, curve->prime, + curve->order); + /* SP 800-56Ar3, section 5.6.2.1.4, method (b) for ECC */ /* private * base generator must equal pubkey */ if (err == MP_OKAY && key->type == ECC_PRIVATEKEY) - err = ecc_check_privkey_gen(key, &prime); + err = ecc_check_privkey_gen(key, curve->Af, curve->prime); + + wc_ecc_curve_free(curve); + +#ifndef USE_ECC_B_PARAM + mp_clear(b); + #ifdef WOLFSSL_SMALL_STACK + XFREE(b, key->heap, DYNAMIC_TYPE_ECC); + #endif +#endif + + FREE_CURVE_SPECS(); + +#endif /* WOLFSSL_ATECC508A */ +#else + if (key == NULL) + return BAD_FUNC_ARG; - mp_clear(&order); - mp_clear(&prime); + /* pubkey point cannot be at infinity */ +#ifndef WOLFSSL_SP_NO_256 + if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP256R1) { + err = sp_ecc_check_key_256(key->pubkey.x, key->pubkey.y, &key->k, + key->heap); + } + else +#endif +#ifdef WOLFSSL_SP_384 + if (key->idx != ECC_CUSTOM_IDX && ecc_sets[key->idx].id == ECC_SECP384R1) { + err = sp_ecc_check_key_384(key->pubkey.x, key->pubkey.y, &key->k, + key->heap); + } + else +#endif + { + err = WC_KEY_SIZE_E; + } +#endif return err; } - +#ifdef HAVE_ECC_KEY_IMPORT /* import public ECC key in ANSI X9.63 format */ -int wc_ecc_import_x963(const byte* in, word32 inLen, ecc_key* key) +int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key, + int curve_id) { - int x, err; - int compressed = 0; - - if (in == NULL || key == NULL) - return ECC_BAD_ARG_E; + int err = MP_OKAY; +#ifdef HAVE_COMP_KEY + int compressed = 0; +#endif + int keysize = 0; + byte pointType; - /* must be odd */ - if ((inLen & 1) == 0) { - return ECC_BAD_ARG_E; - } + if (in == NULL || key == NULL) + return BAD_FUNC_ARG; - /* init key */ -#ifdef ALT_ECC_SIZE - key->pubkey.x = (mp_int*)&key->pubkey.xyz[0]; - key->pubkey.y = (mp_int*)&key->pubkey.xyz[1]; - key->pubkey.z = (mp_int*)&key->pubkey.xyz[2]; - alt_fp_init(key->pubkey.x); - alt_fp_init(key->pubkey.y); - alt_fp_init(key->pubkey.z); - err = mp_init(&key->k); -#else - err = mp_init_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, &key->k, - NULL, NULL); -#endif - if (err != MP_OKAY) - return MEMORY_E; + /* must be odd */ + if ((inLen & 1) == 0) { + return ECC_BAD_ARG_E; + } - /* check for 4, 2, or 3 */ - if (in[0] != 0x04 && in[0] != 0x02 && in[0] != 0x03) { - err = ASN_PARSE_E; - } + /* make sure required variables are reset */ + wc_ecc_reset(key); - if (in[0] == 0x02 || in[0] == 0x03) { -#ifdef HAVE_COMP_KEY - compressed = 1; -#else - err = NOT_COMPILED_IN; -#endif - } + /* init key */ + #ifdef ALT_ECC_SIZE + key->pubkey.x = (mp_int*)&key->pubkey.xyz[0]; + key->pubkey.y = (mp_int*)&key->pubkey.xyz[1]; + key->pubkey.z = (mp_int*)&key->pubkey.xyz[2]; + alt_fp_init(key->pubkey.x); + alt_fp_init(key->pubkey.y); + alt_fp_init(key->pubkey.z); + err = mp_init(&key->k); + #else + err = mp_init_multi(&key->k, + key->pubkey.x, key->pubkey.y, key->pubkey.z, NULL, NULL); + #endif + if (err != MP_OKAY) + return MEMORY_E; - if (err == MP_OKAY) { - /* determine the idx */ + /* check for point type (4, 2, or 3) */ + pointType = in[0]; + if (pointType != ECC_POINT_UNCOMP && pointType != ECC_POINT_COMP_EVEN && + pointType != ECC_POINT_COMP_ODD) { + err = ASN_PARSE_E; + } - if (compressed) - inLen = (inLen-1)*2 + 1; /* used uncompressed len */ + if (pointType == ECC_POINT_COMP_EVEN || pointType == ECC_POINT_COMP_ODD) { + #ifdef HAVE_COMP_KEY + compressed = 1; + #else + err = NOT_COMPILED_IN; + #endif + } - for (x = 0; ecc_sets[x].size != 0; x++) { - if ((unsigned)ecc_sets[x].size >= ((inLen-1)>>1)) { - break; - } - } - if (ecc_sets[x].size == 0) { - err = ASN_PARSE_E; - } else { - /* set the idx */ - key->idx = x; - key->dp = &ecc_sets[x]; - key->type = ECC_PUBLICKEY; - } - } + /* adjust to skip first byte */ + inLen -= 1; + in += 1; - /* read data */ - if (err == MP_OKAY) - err = mp_read_unsigned_bin(key->pubkey.x, (byte*)in+1, (inLen-1)>>1); +#ifdef WOLFSSL_ATECC508A + /* For SECP256R1 only save raw public key for hardware */ + if (curve_id == ECC_SECP256R1 && inLen <= sizeof(key->pubkey_raw)) { + #ifdef HAVE_COMP_KEY + if (!compressed) + #endif + XMEMCPY(key->pubkey_raw, (byte*)in, inLen); + } +#endif -#ifdef HAVE_COMP_KEY - if (err == MP_OKAY && compressed == 1) { /* build y */ - mp_int t1, t2, prime, a, b; + if (err == MP_OKAY) { + #ifdef HAVE_COMP_KEY + /* adjust inLen if compressed */ + if (compressed) + inLen = inLen*2 + 1; /* used uncompressed len */ + #endif - if (mp_init_multi(&t1, &t2, &prime, &a, &b, NULL) != MP_OKAY) - err = MEMORY_E; + /* determine key size */ + keysize = (inLen>>1); + err = wc_ecc_set_curve(key, keysize, curve_id); + key->type = ECC_PUBLICKEY; + } - /* load prime */ - if (err == MP_OKAY) - err = mp_read_radix(&prime, (char *)key->dp->prime, 16); + /* read data */ + if (err == MP_OKAY) + err = mp_read_unsigned_bin(key->pubkey.x, (byte*)in, keysize); - /* load a */ - if (err == MP_OKAY) - err = mp_read_radix(&a, (char *)key->dp->Af, 16); +#ifdef HAVE_COMP_KEY + if (err == MP_OKAY && compressed == 1) { /* build y */ +#ifndef WOLFSSL_SP_MATH + mp_int t1, t2; + int did_init = 0; + + DECLARE_CURVE_SPECS(curve, 3); + ALLOC_CURVE_SPECS(3); + + if (mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL) != MP_OKAY) + err = MEMORY_E; + else + did_init = 1; - /* load b */ + /* load curve info */ if (err == MP_OKAY) - err = mp_read_radix(&b, (char *)key->dp->Bf, 16); + err = wc_ecc_curve_load(key->dp, &curve, + (ECC_CURVE_FIELD_PRIME | ECC_CURVE_FIELD_AF | + ECC_CURVE_FIELD_BF)); /* compute x^3 */ if (err == MP_OKAY) err = mp_sqr(key->pubkey.x, &t1); - if (err == MP_OKAY) - err = mp_mulmod(&t1, key->pubkey.x, &prime, &t1); + err = mp_mulmod(&t1, key->pubkey.x, curve->prime, &t1); /* compute x^3 + a*x */ if (err == MP_OKAY) - err = mp_mulmod(&a, key->pubkey.x, &prime, &t2); - + err = mp_mulmod(curve->Af, key->pubkey.x, curve->prime, &t2); if (err == MP_OKAY) err = mp_add(&t1, &t2, &t1); /* compute x^3 + a*x + b */ if (err == MP_OKAY) - err = mp_add(&t1, &b, &t1); + err = mp_add(&t1, curve->Bf, &t1); /* compute sqrt(x^3 + a*x + b) */ if (err == MP_OKAY) - err = mp_sqrtmod_prime(&t1, &prime, &t2); + err = mp_sqrtmod_prime(&t1, curve->prime, &t2); /* adjust y */ if (err == MP_OKAY) { - if ((mp_isodd(&t2) && in[0] == 0x03) || - (!mp_isodd(&t2) && in[0] == 0x02)) { - err = mp_mod(&t2, &prime, key->pubkey.y); + if ((mp_isodd(&t2) == MP_YES && pointType == ECC_POINT_COMP_ODD) || + (mp_isodd(&t2) == MP_NO && pointType == ECC_POINT_COMP_EVEN)) { + err = mp_mod(&t2, curve->prime, &t2); } else { - err = mp_submod(&prime, &t2, &prime, key->pubkey.y); + err = mp_submod(curve->prime, &t2, curve->prime, &t2); } + if (err == MP_OKAY) + err = mp_copy(&t2, key->pubkey.y); } - mp_clear(&a); - mp_clear(&b); - mp_clear(&prime); - mp_clear(&t2); - mp_clear(&t1); - } + if (did_init) { + mp_clear(&t2); + mp_clear(&t1); + } + + wc_ecc_curve_free(curve); + FREE_CURVE_SPECS(); +#else + #ifndef WOLFSSL_SP_NO_256 + if (key->dp->id == ECC_SECP256R1) { + sp_ecc_uncompress_256(key->pubkey.x, pointType, key->pubkey.y); + } + else + #endif + #ifdef WOLFSSL_SP_384 + if (key->dp->id == ECC_SECP384R1) { + sp_ecc_uncompress_384(key->pubkey.x, pointType, key->pubkey.y); + } + else + #endif + { + err = WC_KEY_SIZE_E; + } #endif + } +#endif /* HAVE_COMP_KEY */ - if (err == MP_OKAY && compressed == 0) - err = mp_read_unsigned_bin(key->pubkey.y, (byte*)in+1+((inLen-1)>>1), - (inLen-1)>>1); - if (err == MP_OKAY) - mp_set(key->pubkey.z, 1); + if (err == MP_OKAY) { + #ifdef HAVE_COMP_KEY + if (compressed == 0) + #endif + { + err = mp_read_unsigned_bin(key->pubkey.y, (byte*)in + keysize, + keysize); + } + } + if (err == MP_OKAY) + err = mp_set(key->pubkey.z, 1); #ifdef WOLFSSL_VALIDATE_ECC_IMPORT - if (err == MP_OKAY) - err = wc_ecc_check_key(key); + if (err == MP_OKAY) + err = wc_ecc_check_key(key); #endif - if (err != MP_OKAY) { - mp_clear(key->pubkey.x); - mp_clear(key->pubkey.y); - mp_clear(key->pubkey.z); - mp_clear(&key->k); - } + if (err != MP_OKAY) { + mp_clear(key->pubkey.x); + mp_clear(key->pubkey.y); + mp_clear(key->pubkey.z); + mp_clear(&key->k); + } - return err; + return err; +} + +WOLFSSL_ABI +int wc_ecc_import_x963(const byte* in, word32 inLen, ecc_key* key) +{ + return wc_ecc_import_x963_ex(in, inLen, key, ECC_CURVE_DEF); +} +#endif /* HAVE_ECC_KEY_IMPORT */ + +#ifdef HAVE_ECC_KEY_EXPORT + +/* export ecc key to component form, d is optional if only exporting public + * encType is WC_TYPE_UNSIGNED_BIN or WC_TYPE_HEX_STR + * return MP_OKAY on success */ +int wc_ecc_export_ex(ecc_key* key, byte* qx, word32* qxLen, + byte* qy, word32* qyLen, byte* d, word32* dLen, int encType) +{ + int err = 0; + word32 keySz; + + if (key == NULL) { + return BAD_FUNC_ARG; + } + + if (wc_ecc_is_valid_idx(key->idx) == 0) { + return ECC_BAD_ARG_E; + } + keySz = key->dp->size; + + /* private key, d */ + if (d != NULL) { + if (dLen == NULL || + (key->type != ECC_PRIVATEKEY && key->type != ECC_PRIVATEKEY_ONLY)) + return BAD_FUNC_ARG; + + #ifdef WOLFSSL_ATECC508A + /* Hardware cannot export private portion */ + return NOT_COMPILED_IN; + #else + err = wc_export_int(&key->k, d, dLen, keySz, encType); + if (err != MP_OKAY) + return err; + #endif + } + + /* public x component */ + if (qx != NULL) { + if (qxLen == NULL || key->type == ECC_PRIVATEKEY_ONLY) + return BAD_FUNC_ARG; + + err = wc_export_int(key->pubkey.x, qx, qxLen, keySz, encType); + if (err != MP_OKAY) + return err; + } + + /* public y component */ + if (qy != NULL) { + if (qyLen == NULL || key->type == ECC_PRIVATEKEY_ONLY) + return BAD_FUNC_ARG; + + err = wc_export_int(key->pubkey.y, qy, qyLen, keySz, encType); + if (err != MP_OKAY) + return err; + } + + return err; } -/* export ecc private key only raw, outLen is in/out size +/* export ecc private key only raw, outLen is in/out size as unsigned bin return MP_OKAY on success */ int wc_ecc_export_private_only(ecc_key* key, byte* out, word32* outLen) { - word32 numlen; + if (out == NULL || outLen == NULL) { + return BAD_FUNC_ARG; + } - if (key == NULL || out == NULL || outLen == NULL) - return ECC_BAD_ARG_E; + return wc_ecc_export_ex(key, NULL, NULL, NULL, NULL, out, outLen, + WC_TYPE_UNSIGNED_BIN); +} - if (ecc_is_valid_idx(key->idx) == 0) { - return ECC_BAD_ARG_E; - } - numlen = key->dp->size; +/* export public key to raw elements including public (Qx,Qy) as unsigned bin + * return MP_OKAY on success, negative on error */ +int wc_ecc_export_public_raw(ecc_key* key, byte* qx, word32* qxLen, + byte* qy, word32* qyLen) +{ + if (qx == NULL || qxLen == NULL || qy == NULL || qyLen == NULL) { + return BAD_FUNC_ARG; + } - if (*outLen < numlen) { - *outLen = numlen; - return BUFFER_E; - } - *outLen = numlen; - XMEMSET(out, 0, *outLen); - return mp_to_unsigned_bin(&key->k, out + (numlen - - mp_unsigned_bin_size(&key->k))); + return wc_ecc_export_ex(key, qx, qxLen, qy, qyLen, NULL, NULL, + WC_TYPE_UNSIGNED_BIN); } +/* export ecc key to raw elements including public (Qx,Qy) and + * private (d) as unsigned bin + * return MP_OKAY on success, negative on error */ +int wc_ecc_export_private_raw(ecc_key* key, byte* qx, word32* qxLen, + byte* qy, word32* qyLen, byte* d, word32* dLen) +{ + return wc_ecc_export_ex(key, qx, qxLen, qy, qyLen, d, dLen, + WC_TYPE_UNSIGNED_BIN); +} -/* ecc private key import, public key in ANSI X9.63 format, private raw */ -int wc_ecc_import_private_key(const byte* priv, word32 privSz, const byte* pub, - word32 pubSz, ecc_key* key) +#endif /* HAVE_ECC_KEY_EXPORT */ + +#ifdef HAVE_ECC_KEY_IMPORT +/* import private key, public part optional if (pub) passed as NULL */ +int wc_ecc_import_private_key_ex(const byte* priv, word32 privSz, + const byte* pub, word32 pubSz, ecc_key* key, + int curve_id) { - int ret = wc_ecc_import_x963(pub, pubSz, key); + int ret; +#if defined(WOLFSSL_CRYPTOCELL) && !defined(WOLFSSL_ATECC508A) + const CRYS_ECPKI_Domain_t* pDomain; + CRYS_ECPKI_BUILD_TempData_t tempBuff; +#endif + if (key == NULL || priv == NULL) + return BAD_FUNC_ARG; + + /* public optional, NULL if only importing private */ + if (pub != NULL) { + #ifndef NO_ASN + word32 idx = 0; + ret = wc_ecc_import_x963_ex(pub, pubSz, key, curve_id); + if (ret < 0) + ret = wc_EccPublicKeyDecode(pub, &idx, key, pubSz); + key->type = ECC_PRIVATEKEY; + #else + ret = NOT_COMPILED_IN; + #endif + } + else { + /* make sure required variables are reset */ + wc_ecc_reset(key); + + /* set key size */ + ret = wc_ecc_set_curve(key, privSz, curve_id); + key->type = ECC_PRIVATEKEY_ONLY; + } + if (ret != 0) return ret; - key->type = ECC_PRIVATEKEY; +#ifdef WOLFSSL_ATECC508A + /* Hardware does not support loading private keys */ + return NOT_COMPILED_IN; +#elif defined(WOLFSSL_CRYPTOCELL) + pDomain = CRYS_ECPKI_GetEcDomain(cc310_mapCurve(curve_id)); + + if (pub != NULL && pub[0] != '\0') { + /* create public key from external key buffer */ + ret = CRYS_ECPKI_BuildPublKeyFullCheck(pDomain, + (byte*)pub, + pubSz, + &key->ctx.pubKey, + &tempBuff); + + if (ret != SA_SILIB_RET_OK){ + WOLFSSL_MSG("CRYS_ECPKI_BuildPublKeyFullCheck failed"); + return ret; + } + } + /* import private key */ + if (priv != NULL && priv[0] != '\0') { + + /* Create private key from external key buffer*/ + ret = CRYS_ECPKI_BuildPrivKey(pDomain, + priv, + privSz, + &key->ctx.privKey); + + if (ret != SA_SILIB_RET_OK) { + WOLFSSL_MSG("CRYS_ECPKI_BuildPrivKey failed"); + return ret; + } + + ret = mp_read_unsigned_bin(&key->k, priv, privSz); + } + +#else ret = mp_read_unsigned_bin(&key->k, priv, privSz); +#ifdef HAVE_WOLF_BIGINT + if (ret == 0 && + wc_bigint_from_unsigned_bin(&key->k.raw, priv, privSz) != 0) { + mp_clear(&key->k); + ret = ASN_GETINT_E; + } +#endif /* HAVE_WOLF_BIGINT */ + + +#endif /* WOLFSSL_ATECC508A */ #ifdef WOLFSSL_VALIDATE_ECC_IMPORT - if (ret == MP_OKAY) + if ((pub != NULL) && (ret == MP_OKAY)) + /* public key needed to perform key validation */ ret = ecc_check_privkey_gen_helper(key); #endif return ret; } +/* ecc private key import, public key in ANSI X9.63 format, private raw */ +int wc_ecc_import_private_key(const byte* priv, word32 privSz, const byte* pub, + word32 pubSz, ecc_key* key) +{ + return wc_ecc_import_private_key_ex(priv, privSz, pub, pubSz, key, + ECC_CURVE_DEF); +} +#endif /* HAVE_ECC_KEY_IMPORT */ + +#ifndef NO_ASN /** Convert ECC R,S to signature r R component of signature @@ -2754,53 +7570,232 @@ int wc_ecc_import_private_key(const byte* priv, word32 privSz, const byte* pub, int wc_ecc_rs_to_sig(const char* r, const char* s, byte* out, word32* outlen) { int err; - mp_int rtmp; - mp_int stmp; +#ifdef WOLFSSL_SMALL_STACK + mp_int* rtmp = NULL; + mp_int* stmp = NULL; +#else + mp_int rtmp[1]; + mp_int stmp[1]; +#endif if (r == NULL || s == NULL || out == NULL || outlen == NULL) return ECC_BAD_ARG_E; - err = mp_init_multi(&rtmp, &stmp, NULL, NULL, NULL, NULL); - if (err != MP_OKAY) +#ifdef WOLFSSL_SMALL_STACK + rtmp = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + if (rtmp == NULL) + return MEMORY_E; + stmp = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + if (stmp == NULL) { + XFREE(rtmp, NULL, DYNAMIC_TYPE_ECC); + return MEMORY_E; + } +#endif + + err = mp_init_multi(rtmp, stmp, NULL, NULL, NULL, NULL); + if (err != MP_OKAY) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(stmp, NULL, DYNAMIC_TYPE_ECC); + XFREE(rtmp, NULL, DYNAMIC_TYPE_ECC); + #endif + return err; + } + + err = mp_read_radix(rtmp, r, MP_RADIX_HEX); + if (err == MP_OKAY) + err = mp_read_radix(stmp, s, MP_RADIX_HEX); + + /* convert mp_ints to ECDSA sig, initializes rtmp and stmp internally */ + if (err == MP_OKAY) + err = StoreECC_DSA_Sig(out, outlen, rtmp, stmp); + + if (err == MP_OKAY) { + if (mp_iszero(rtmp) == MP_YES || mp_iszero(stmp) == MP_YES) + err = MP_ZERO_E; + } + + mp_clear(rtmp); + mp_clear(stmp); +#ifdef WOLFSSL_SMALL_STACK + XFREE(stmp, NULL, DYNAMIC_TYPE_ECC); + XFREE(rtmp, NULL, DYNAMIC_TYPE_ECC); +#endif + + return err; +} + +/** + Convert ECC R,S raw unsigned bin to signature + r R component of signature + rSz R size + s S component of signature + sSz S size + out DER-encoded ECDSA signature + outlen [in/out] output buffer size, output signature size + return MP_OKAY on success +*/ +int wc_ecc_rs_raw_to_sig(const byte* r, word32 rSz, const byte* s, word32 sSz, + byte* out, word32* outlen) +{ + int err; +#ifdef WOLFSSL_SMALL_STACK + mp_int* rtmp = NULL; + mp_int* stmp = NULL; +#else + mp_int rtmp[1]; + mp_int stmp[1]; +#endif + + if (r == NULL || s == NULL || out == NULL || outlen == NULL) + return ECC_BAD_ARG_E; + +#ifdef WOLFSSL_SMALL_STACK + rtmp = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + if (rtmp == NULL) + return MEMORY_E; + stmp = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + if (stmp == NULL) { + XFREE(rtmp, NULL, DYNAMIC_TYPE_ECC); + return MEMORY_E; + } +#endif + + err = mp_init_multi(rtmp, stmp, NULL, NULL, NULL, NULL); + if (err != MP_OKAY) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(stmp, NULL, DYNAMIC_TYPE_ECC); + XFREE(rtmp, NULL, DYNAMIC_TYPE_ECC); + #endif return err; + } - err = mp_read_radix(&rtmp, r, 16); + err = mp_read_unsigned_bin(rtmp, r, rSz); if (err == MP_OKAY) - err = mp_read_radix(&stmp, s, 16); + err = mp_read_unsigned_bin(stmp, s, sSz); /* convert mp_ints to ECDSA sig, initializes rtmp and stmp internally */ if (err == MP_OKAY) - err = StoreECC_DSA_Sig(out, outlen, &rtmp, &stmp); + err = StoreECC_DSA_Sig(out, outlen, rtmp, stmp); if (err == MP_OKAY) { - if (mp_iszero(&rtmp) || mp_iszero(&stmp)) + if (mp_iszero(rtmp) == MP_YES || mp_iszero(stmp) == MP_YES) err = MP_ZERO_E; } - mp_clear(&rtmp); - mp_clear(&stmp); + mp_clear(rtmp); + mp_clear(stmp); +#ifdef WOLFSSL_SMALL_STACK + XFREE(stmp, NULL, DYNAMIC_TYPE_ECC); + XFREE(rtmp, NULL, DYNAMIC_TYPE_ECC); +#endif return err; } /** - Import raw ECC key - key The destination ecc_key structure - qx x component of base point, as ASCII hex string - qy y component of base point, as ASCII hex string - d private key, as ASCII hex string - curveName ECC curve name, from ecc_sets[] - return MP_OKAY on success + Convert ECC signature to R,S + sig DER-encoded ECDSA signature + sigLen length of signature in octets + r R component of signature + rLen [in/out] output "r" buffer size, output "r" size + s S component of signature + sLen [in/out] output "s" buffer size, output "s" size + return MP_OKAY on success, negative on error */ -int wc_ecc_import_raw(ecc_key* key, const char* qx, const char* qy, - const char* d, const char* curveName) +int wc_ecc_sig_to_rs(const byte* sig, word32 sigLen, byte* r, word32* rLen, + byte* s, word32* sLen) { - int err, x; + int err; + int tmp_valid = 0; + word32 x = 0; +#ifdef WOLFSSL_SMALL_STACK + mp_int* rtmp = NULL; + mp_int* stmp = NULL; +#else + mp_int rtmp[1]; + mp_int stmp[1]; +#endif - if (key == NULL || qx == NULL || qy == NULL || d == NULL || - curveName == NULL) + if (sig == NULL || r == NULL || rLen == NULL || s == NULL || sLen == NULL) return ECC_BAD_ARG_E; +#ifdef WOLFSSL_SMALL_STACK + rtmp = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + if (rtmp == NULL) + return MEMORY_E; + stmp = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_ECC); + if (stmp == NULL) { + XFREE(rtmp, NULL, DYNAMIC_TYPE_ECC); + return MEMORY_E; + } +#endif + + err = DecodeECC_DSA_Sig(sig, sigLen, rtmp, stmp); + + /* rtmp and stmp are initialized */ + if (err == MP_OKAY) { + tmp_valid = 1; + + /* extract r */ + x = mp_unsigned_bin_size(rtmp); + if (*rLen < x) + err = BUFFER_E; + } + if (err == MP_OKAY) { + *rLen = x; + err = mp_to_unsigned_bin(rtmp, r); + } + + /* extract s */ + if (err == MP_OKAY) { + x = mp_unsigned_bin_size(stmp); + if (*sLen < x) + err = BUFFER_E; + + if (err == MP_OKAY) { + *sLen = x; + err = mp_to_unsigned_bin(stmp, s); + } + } + + if (tmp_valid) { + mp_clear(rtmp); + mp_clear(stmp); + } +#ifdef WOLFSSL_SMALL_STACK + XFREE(stmp, NULL, DYNAMIC_TYPE_ECC); + XFREE(rtmp, NULL, DYNAMIC_TYPE_ECC); +#endif + + return err; +} +#endif /* !NO_ASN */ + +#ifdef HAVE_ECC_KEY_IMPORT +static int wc_ecc_import_raw_private(ecc_key* key, const char* qx, + const char* qy, const char* d, int curve_id, int encType) +{ + int err = MP_OKAY; +#if defined(WOLFSSL_CRYPTOCELL) && !defined(WOLFSSL_ATECC508A) + const CRYS_ECPKI_Domain_t* pDomain; + CRYS_ECPKI_BUILD_TempData_t tempBuff; + byte key_raw[ECC_MAX_CRYPTO_HW_SIZE*2 + 1]; + word32 keySz = 0; +#endif + /* if d is NULL, only import as public key using Qx,Qy */ + if (key == NULL || qx == NULL || qy == NULL) { + return BAD_FUNC_ARG; + } + + /* make sure required variables are reset */ + wc_ecc_reset(key); + + /* set curve type and index */ + err = wc_ecc_set_curve(key, 0, curve_id); + if (err != 0) { + return err; + } + /* init key */ #ifdef ALT_ECC_SIZE key->pubkey.x = (mp_int*)&key->pubkey.xyz[0]; @@ -2811,45 +7806,120 @@ int wc_ecc_import_raw(ecc_key* key, const char* qx, const char* qy, alt_fp_init(key->pubkey.z); err = mp_init(&key->k); #else - err = mp_init_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, &key->k, - NULL, NULL); + err = mp_init_multi(&key->k, key->pubkey.x, key->pubkey.y, key->pubkey.z, + NULL, NULL); #endif if (err != MP_OKAY) return MEMORY_E; /* read Qx */ - if (err == MP_OKAY) - err = mp_read_radix(key->pubkey.x, qx, 16); + if (err == MP_OKAY) { + if (encType == WC_TYPE_HEX_STR) + err = mp_read_radix(key->pubkey.x, qx, MP_RADIX_HEX); + else + err = mp_read_unsigned_bin(key->pubkey.x, (const byte*)qx, + key->dp->size); + } /* read Qy */ - if (err == MP_OKAY) - err = mp_read_radix(key->pubkey.y, qy, 16); + if (err == MP_OKAY) { + if (encType == WC_TYPE_HEX_STR) + err = mp_read_radix(key->pubkey.y, qy, MP_RADIX_HEX); + else + err = mp_read_unsigned_bin(key->pubkey.y, (const byte*)qy, + key->dp->size); - if (err == MP_OKAY) - mp_set(key->pubkey.z, 1); + } - /* read and set the curve */ + if (err == MP_OKAY) + err = mp_set(key->pubkey.z, 1); + +#ifdef WOLFSSL_ATECC508A + /* For SECP256R1 only save raw public key for hardware */ + if (err == MP_OKAY && curve_id == ECC_SECP256R1) { + word32 keySz = key->dp->size; + err = wc_export_int(key->pubkey.x, key->pubkey_raw, + &keySz, keySz, WC_TYPE_UNSIGNED_BIN); + if (err == MP_OKAY) + err = wc_export_int(key->pubkey.y, &key->pubkey_raw[keySz], + &keySz, keySz, WC_TYPE_UNSIGNED_BIN); + } +#elif defined(WOLFSSL_CRYPTOCELL) if (err == MP_OKAY) { - for (x = 0; ecc_sets[x].size != 0; x++) { - if (XSTRNCMP(ecc_sets[x].name, curveName, - XSTRLEN(curveName)) == 0) { - break; - } + key_raw[0] = ECC_POINT_UNCOMP; + keySz = (word32)key->dp->size; + err = wc_export_int(key->pubkey.x, &key_raw[1], &keySz, keySz, + WC_TYPE_UNSIGNED_BIN); + if (err == MP_OKAY) { + err = wc_export_int(key->pubkey.y, &key_raw[1+keySz], + &keySz, keySz, WC_TYPE_UNSIGNED_BIN); } - if (ecc_sets[x].size == 0) { - err = ASN_PARSE_E; - } else { - /* set the curve */ - key->idx = x; - key->dp = &ecc_sets[x]; - key->type = ECC_PUBLICKEY; + + if (err == MP_OKAY) { + pDomain = CRYS_ECPKI_GetEcDomain(cc310_mapCurve(curve_id)); + + /* create public key from external key buffer */ + err = CRYS_ECPKI_BuildPublKeyFullCheck(pDomain, + key_raw, + keySz*2 + 1, + &key->ctx.pubKey, + &tempBuff); + } + + if (err != SA_SILIB_RET_OK){ + WOLFSSL_MSG("CRYS_ECPKI_BuildPublKeyFullCheck failed"); + return err; } } +#endif + /* import private key */ if (err == MP_OKAY) { - key->type = ECC_PRIVATEKEY; - err = mp_read_radix(&key->k, d, 16); + if (d != NULL && d[0] != '\0') { + #ifdef WOLFSSL_ATECC508A + /* Hardware doesn't support loading private key */ + err = NOT_COMPILED_IN; + + #elif defined(WOLFSSL_CRYPTOCELL) + + key->type = ECC_PRIVATEKEY; + + if (encType == WC_TYPE_HEX_STR) + err = mp_read_radix(&key->k, d, MP_RADIX_HEX); + else + err = mp_read_unsigned_bin(&key->k, (const byte*)d, + key->dp->size); + if (err == MP_OKAY) { + err = wc_export_int(&key->k, &key_raw[0], &keySz, keySz, + WC_TYPE_UNSIGNED_BIN); + } + + if (err == MP_OKAY) { + /* Create private key from external key buffer*/ + err = CRYS_ECPKI_BuildPrivKey(pDomain, + key_raw, + keySz, + &key->ctx.privKey); + + if (err != SA_SILIB_RET_OK){ + WOLFSSL_MSG("CRYS_ECPKI_BuildPrivKey failed"); + return err; + } + } + + #else + key->type = ECC_PRIVATEKEY; + + if (encType == WC_TYPE_HEX_STR) + err = mp_read_radix(&key->k, d, MP_RADIX_HEX); + else + err = mp_read_unsigned_bin(&key->k, (const byte*)d, + key->dp->size); + #endif /* WOLFSSL_ATECC508A */ + } else { + key->type = ECC_PUBLICKEY; + } } #ifdef WOLFSSL_VALIDATE_ECC_IMPORT @@ -2867,25 +7937,127 @@ int wc_ecc_import_raw(ecc_key* key, const char* qx, const char* qy, return err; } +/** + Import raw ECC key + key The destination ecc_key structure + qx x component of the public key, as ASCII hex string + qy y component of the public key, as ASCII hex string + d private key, as ASCII hex string, optional if importing public + key only + dp Custom ecc_set_type + return MP_OKAY on success +*/ +int wc_ecc_import_raw_ex(ecc_key* key, const char* qx, const char* qy, + const char* d, int curve_id) +{ + return wc_ecc_import_raw_private(key, qx, qy, d, curve_id, + WC_TYPE_HEX_STR); + +} + +/* Import x, y and optional private (d) as unsigned binary */ +int wc_ecc_import_unsigned(ecc_key* key, byte* qx, byte* qy, + byte* d, int curve_id) +{ + return wc_ecc_import_raw_private(key, (const char*)qx, (const char*)qy, + (const char*)d, curve_id, WC_TYPE_UNSIGNED_BIN); +} + +/** + Import raw ECC key + key The destination ecc_key structure + qx x component of the public key, as ASCII hex string + qy y component of the public key, as ASCII hex string + d private key, as ASCII hex string, optional if importing public + key only + curveName ECC curve name, from ecc_sets[] + return MP_OKAY on success +*/ +int wc_ecc_import_raw(ecc_key* key, const char* qx, const char* qy, + const char* d, const char* curveName) +{ + int err, x; + + /* if d is NULL, only import as public key using Qx,Qy */ + if (key == NULL || qx == NULL || qy == NULL || curveName == NULL) { + return BAD_FUNC_ARG; + } + + /* set curve type and index */ + for (x = 0; ecc_sets[x].size != 0; x++) { + if (XSTRNCMP(ecc_sets[x].name, curveName, + XSTRLEN(curveName)) == 0) { + break; + } + } + + if (ecc_sets[x].size == 0) { + WOLFSSL_MSG("ecc_set curve name not found"); + err = ASN_PARSE_E; + } else { + return wc_ecc_import_raw_private(key, qx, qy, d, ecc_sets[x].id, + WC_TYPE_HEX_STR); + } + + return err; +} +#endif /* HAVE_ECC_KEY_IMPORT */ /* key size in octets */ int wc_ecc_size(ecc_key* key) { - if (key == NULL) return 0; + if (key == NULL) + return 0; return key->dp->size; } +/* maximum signature size based on key size */ +int wc_ecc_sig_size_calc(int sz) +{ + int maxSigSz = 0; + + /* calculate based on key bits */ + /* maximum possible signature header size is 7 bytes plus 2 bytes padding */ + maxSigSz = (sz * 2) + SIG_HEADER_SZ + ECC_MAX_PAD_SZ; -/* worst case estimate, check actual return from wc_ecc_sign_hash for actual value - of signature size in octets */ + /* if total length is less than 128 + SEQ(1)+LEN(1) then subtract 1 */ + if (maxSigSz < (128 + 2)) { + maxSigSz -= 1; + } + + return maxSigSz; +} + +/* maximum signature size based on actual key curve */ int wc_ecc_sig_size(ecc_key* key) { - int sz = wc_ecc_size(key); - if (sz <= 0) - return sz; + int maxSigSz; + int orderBits, keySz; + + if (key == NULL || key->dp == NULL) + return 0; + + /* the signature r and s will always be less than order */ + /* if the order MSB (top bit of byte) is set then ASN encoding needs + extra byte for r and s, so add 2 */ + keySz = key->dp->size; + orderBits = wc_ecc_get_curve_order_bit_count(key->dp); + if (orderBits > keySz * 8) { + keySz = (orderBits + 7) / 8; + } + /* maximum possible signature header size is 7 bytes */ + maxSigSz = (keySz * 2) + SIG_HEADER_SZ; + if ((orderBits % 8) == 0) { + /* MSB can be set, so add 2 */ + maxSigSz += ECC_MAX_PAD_SZ; + } + /* if total length is less than 128 + SEQ(1)+LEN(1) then subtract 1 */ + if (maxSigSz < (128 + 2)) { + maxSigSz -= 1; + } - return sz * 2 + SIG_HEADER_SZ + 4; /* (4) worst case estimate */ + return maxSigSz; } @@ -2894,7 +8066,7 @@ int wc_ecc_sig_size(ecc_key* key) /* fixed point ECC cache */ /* number of entries in the cache */ #ifndef FP_ENTRIES - #define FP_ENTRIES 16 + #define FP_ENTRIES 15 #endif /* number of bits in LUT */ @@ -2914,10 +8086,12 @@ int wc_ecc_sig_size(ecc_key* key) #endif +#ifndef WOLFSSL_SP_MATH + /** Our FP cache */ typedef struct { ecc_point* g; /* cached COPY of base point */ - ecc_point* LUT[1U<<FP_LUT]; /* fixed point lookup */ + ecc_point* LUT[1U<<FP_LUT]; /* fixed point lookup */ mp_int mu; /* copy of the montgomery constant */ int lru_count; /* amount of times this entry has been used */ int lock; /* flag to indicate cache eviction */ @@ -2936,524 +8110,524 @@ static THREAD_LS_T fp_cache_t fp_cache[FP_ENTRIES]; static const struct { int ham, terma, termb; } lut_orders[] = { - { 0, 0, 0 }, { 1, 0, 0 }, { 1, 0, 0 }, { 2, 1, 2 }, { 1, 0, 0 }, { 2, 1, 4 }, { 2, 2, 4 }, { 3, 3, 4 }, - { 1, 0, 0 }, { 2, 1, 8 }, { 2, 2, 8 }, { 3, 3, 8 }, { 2, 4, 8 }, { 3, 5, 8 }, { 3, 6, 8 }, { 4, 7, 8 }, - { 1, 0, 0 }, { 2, 1, 16 }, { 2, 2, 16 }, { 3, 3, 16 }, { 2, 4, 16 }, { 3, 5, 16 }, { 3, 6, 16 }, { 4, 7, 16 }, - { 2, 8, 16 }, { 3, 9, 16 }, { 3, 10, 16 }, { 4, 11, 16 }, { 3, 12, 16 }, { 4, 13, 16 }, { 4, 14, 16 }, { 5, 15, 16 }, - { 1, 0, 0 }, { 2, 1, 32 }, { 2, 2, 32 }, { 3, 3, 32 }, { 2, 4, 32 }, { 3, 5, 32 }, { 3, 6, 32 }, { 4, 7, 32 }, - { 2, 8, 32 }, { 3, 9, 32 }, { 3, 10, 32 }, { 4, 11, 32 }, { 3, 12, 32 }, { 4, 13, 32 }, { 4, 14, 32 }, { 5, 15, 32 }, - { 2, 16, 32 }, { 3, 17, 32 }, { 3, 18, 32 }, { 4, 19, 32 }, { 3, 20, 32 }, { 4, 21, 32 }, { 4, 22, 32 }, { 5, 23, 32 }, - { 3, 24, 32 }, { 4, 25, 32 }, { 4, 26, 32 }, { 5, 27, 32 }, { 4, 28, 32 }, { 5, 29, 32 }, { 5, 30, 32 }, { 6, 31, 32 }, + { 0, 0, 0 }, { 1, 0, 0 }, { 1, 0, 0 }, { 2, 1, 2 }, { 1, 0, 0 }, { 2, 1, 4 }, { 2, 2, 4 }, { 3, 3, 4 }, + { 1, 0, 0 }, { 2, 1, 8 }, { 2, 2, 8 }, { 3, 3, 8 }, { 2, 4, 8 }, { 3, 5, 8 }, { 3, 6, 8 }, { 4, 7, 8 }, + { 1, 0, 0 }, { 2, 1, 16 }, { 2, 2, 16 }, { 3, 3, 16 }, { 2, 4, 16 }, { 3, 5, 16 }, { 3, 6, 16 }, { 4, 7, 16 }, + { 2, 8, 16 }, { 3, 9, 16 }, { 3, 10, 16 }, { 4, 11, 16 }, { 3, 12, 16 }, { 4, 13, 16 }, { 4, 14, 16 }, { 5, 15, 16 }, + { 1, 0, 0 }, { 2, 1, 32 }, { 2, 2, 32 }, { 3, 3, 32 }, { 2, 4, 32 }, { 3, 5, 32 }, { 3, 6, 32 }, { 4, 7, 32 }, + { 2, 8, 32 }, { 3, 9, 32 }, { 3, 10, 32 }, { 4, 11, 32 }, { 3, 12, 32 }, { 4, 13, 32 }, { 4, 14, 32 }, { 5, 15, 32 }, + { 2, 16, 32 }, { 3, 17, 32 }, { 3, 18, 32 }, { 4, 19, 32 }, { 3, 20, 32 }, { 4, 21, 32 }, { 4, 22, 32 }, { 5, 23, 32 }, + { 3, 24, 32 }, { 4, 25, 32 }, { 4, 26, 32 }, { 5, 27, 32 }, { 4, 28, 32 }, { 5, 29, 32 }, { 5, 30, 32 }, { 6, 31, 32 }, #if FP_LUT > 6 - { 1, 0, 0 }, { 2, 1, 64 }, { 2, 2, 64 }, { 3, 3, 64 }, { 2, 4, 64 }, { 3, 5, 64 }, { 3, 6, 64 }, { 4, 7, 64 }, - { 2, 8, 64 }, { 3, 9, 64 }, { 3, 10, 64 }, { 4, 11, 64 }, { 3, 12, 64 }, { 4, 13, 64 }, { 4, 14, 64 }, { 5, 15, 64 }, - { 2, 16, 64 }, { 3, 17, 64 }, { 3, 18, 64 }, { 4, 19, 64 }, { 3, 20, 64 }, { 4, 21, 64 }, { 4, 22, 64 }, { 5, 23, 64 }, - { 3, 24, 64 }, { 4, 25, 64 }, { 4, 26, 64 }, { 5, 27, 64 }, { 4, 28, 64 }, { 5, 29, 64 }, { 5, 30, 64 }, { 6, 31, 64 }, - { 2, 32, 64 }, { 3, 33, 64 }, { 3, 34, 64 }, { 4, 35, 64 }, { 3, 36, 64 }, { 4, 37, 64 }, { 4, 38, 64 }, { 5, 39, 64 }, - { 3, 40, 64 }, { 4, 41, 64 }, { 4, 42, 64 }, { 5, 43, 64 }, { 4, 44, 64 }, { 5, 45, 64 }, { 5, 46, 64 }, { 6, 47, 64 }, - { 3, 48, 64 }, { 4, 49, 64 }, { 4, 50, 64 }, { 5, 51, 64 }, { 4, 52, 64 }, { 5, 53, 64 }, { 5, 54, 64 }, { 6, 55, 64 }, - { 4, 56, 64 }, { 5, 57, 64 }, { 5, 58, 64 }, { 6, 59, 64 }, { 5, 60, 64 }, { 6, 61, 64 }, { 6, 62, 64 }, { 7, 63, 64 }, + { 1, 0, 0 }, { 2, 1, 64 }, { 2, 2, 64 }, { 3, 3, 64 }, { 2, 4, 64 }, { 3, 5, 64 }, { 3, 6, 64 }, { 4, 7, 64 }, + { 2, 8, 64 }, { 3, 9, 64 }, { 3, 10, 64 }, { 4, 11, 64 }, { 3, 12, 64 }, { 4, 13, 64 }, { 4, 14, 64 }, { 5, 15, 64 }, + { 2, 16, 64 }, { 3, 17, 64 }, { 3, 18, 64 }, { 4, 19, 64 }, { 3, 20, 64 }, { 4, 21, 64 }, { 4, 22, 64 }, { 5, 23, 64 }, + { 3, 24, 64 }, { 4, 25, 64 }, { 4, 26, 64 }, { 5, 27, 64 }, { 4, 28, 64 }, { 5, 29, 64 }, { 5, 30, 64 }, { 6, 31, 64 }, + { 2, 32, 64 }, { 3, 33, 64 }, { 3, 34, 64 }, { 4, 35, 64 }, { 3, 36, 64 }, { 4, 37, 64 }, { 4, 38, 64 }, { 5, 39, 64 }, + { 3, 40, 64 }, { 4, 41, 64 }, { 4, 42, 64 }, { 5, 43, 64 }, { 4, 44, 64 }, { 5, 45, 64 }, { 5, 46, 64 }, { 6, 47, 64 }, + { 3, 48, 64 }, { 4, 49, 64 }, { 4, 50, 64 }, { 5, 51, 64 }, { 4, 52, 64 }, { 5, 53, 64 }, { 5, 54, 64 }, { 6, 55, 64 }, + { 4, 56, 64 }, { 5, 57, 64 }, { 5, 58, 64 }, { 6, 59, 64 }, { 5, 60, 64 }, { 6, 61, 64 }, { 6, 62, 64 }, { 7, 63, 64 }, #if FP_LUT > 7 - { 1, 0, 0 }, { 2, 1, 128 }, { 2, 2, 128 }, { 3, 3, 128 }, { 2, 4, 128 }, { 3, 5, 128 }, { 3, 6, 128 }, { 4, 7, 128 }, - { 2, 8, 128 }, { 3, 9, 128 }, { 3, 10, 128 }, { 4, 11, 128 }, { 3, 12, 128 }, { 4, 13, 128 }, { 4, 14, 128 }, { 5, 15, 128 }, - { 2, 16, 128 }, { 3, 17, 128 }, { 3, 18, 128 }, { 4, 19, 128 }, { 3, 20, 128 }, { 4, 21, 128 }, { 4, 22, 128 }, { 5, 23, 128 }, - { 3, 24, 128 }, { 4, 25, 128 }, { 4, 26, 128 }, { 5, 27, 128 }, { 4, 28, 128 }, { 5, 29, 128 }, { 5, 30, 128 }, { 6, 31, 128 }, - { 2, 32, 128 }, { 3, 33, 128 }, { 3, 34, 128 }, { 4, 35, 128 }, { 3, 36, 128 }, { 4, 37, 128 }, { 4, 38, 128 }, { 5, 39, 128 }, - { 3, 40, 128 }, { 4, 41, 128 }, { 4, 42, 128 }, { 5, 43, 128 }, { 4, 44, 128 }, { 5, 45, 128 }, { 5, 46, 128 }, { 6, 47, 128 }, - { 3, 48, 128 }, { 4, 49, 128 }, { 4, 50, 128 }, { 5, 51, 128 }, { 4, 52, 128 }, { 5, 53, 128 }, { 5, 54, 128 }, { 6, 55, 128 }, - { 4, 56, 128 }, { 5, 57, 128 }, { 5, 58, 128 }, { 6, 59, 128 }, { 5, 60, 128 }, { 6, 61, 128 }, { 6, 62, 128 }, { 7, 63, 128 }, - { 2, 64, 128 }, { 3, 65, 128 }, { 3, 66, 128 }, { 4, 67, 128 }, { 3, 68, 128 }, { 4, 69, 128 }, { 4, 70, 128 }, { 5, 71, 128 }, - { 3, 72, 128 }, { 4, 73, 128 }, { 4, 74, 128 }, { 5, 75, 128 }, { 4, 76, 128 }, { 5, 77, 128 }, { 5, 78, 128 }, { 6, 79, 128 }, - { 3, 80, 128 }, { 4, 81, 128 }, { 4, 82, 128 }, { 5, 83, 128 }, { 4, 84, 128 }, { 5, 85, 128 }, { 5, 86, 128 }, { 6, 87, 128 }, - { 4, 88, 128 }, { 5, 89, 128 }, { 5, 90, 128 }, { 6, 91, 128 }, { 5, 92, 128 }, { 6, 93, 128 }, { 6, 94, 128 }, { 7, 95, 128 }, - { 3, 96, 128 }, { 4, 97, 128 }, { 4, 98, 128 }, { 5, 99, 128 }, { 4, 100, 128 }, { 5, 101, 128 }, { 5, 102, 128 }, { 6, 103, 128 }, - { 4, 104, 128 }, { 5, 105, 128 }, { 5, 106, 128 }, { 6, 107, 128 }, { 5, 108, 128 }, { 6, 109, 128 }, { 6, 110, 128 }, { 7, 111, 128 }, - { 4, 112, 128 }, { 5, 113, 128 }, { 5, 114, 128 }, { 6, 115, 128 }, { 5, 116, 128 }, { 6, 117, 128 }, { 6, 118, 128 }, { 7, 119, 128 }, - { 5, 120, 128 }, { 6, 121, 128 }, { 6, 122, 128 }, { 7, 123, 128 }, { 6, 124, 128 }, { 7, 125, 128 }, { 7, 126, 128 }, { 8, 127, 128 }, + { 1, 0, 0 }, { 2, 1, 128 }, { 2, 2, 128 }, { 3, 3, 128 }, { 2, 4, 128 }, { 3, 5, 128 }, { 3, 6, 128 }, { 4, 7, 128 }, + { 2, 8, 128 }, { 3, 9, 128 }, { 3, 10, 128 }, { 4, 11, 128 }, { 3, 12, 128 }, { 4, 13, 128 }, { 4, 14, 128 }, { 5, 15, 128 }, + { 2, 16, 128 }, { 3, 17, 128 }, { 3, 18, 128 }, { 4, 19, 128 }, { 3, 20, 128 }, { 4, 21, 128 }, { 4, 22, 128 }, { 5, 23, 128 }, + { 3, 24, 128 }, { 4, 25, 128 }, { 4, 26, 128 }, { 5, 27, 128 }, { 4, 28, 128 }, { 5, 29, 128 }, { 5, 30, 128 }, { 6, 31, 128 }, + { 2, 32, 128 }, { 3, 33, 128 }, { 3, 34, 128 }, { 4, 35, 128 }, { 3, 36, 128 }, { 4, 37, 128 }, { 4, 38, 128 }, { 5, 39, 128 }, + { 3, 40, 128 }, { 4, 41, 128 }, { 4, 42, 128 }, { 5, 43, 128 }, { 4, 44, 128 }, { 5, 45, 128 }, { 5, 46, 128 }, { 6, 47, 128 }, + { 3, 48, 128 }, { 4, 49, 128 }, { 4, 50, 128 }, { 5, 51, 128 }, { 4, 52, 128 }, { 5, 53, 128 }, { 5, 54, 128 }, { 6, 55, 128 }, + { 4, 56, 128 }, { 5, 57, 128 }, { 5, 58, 128 }, { 6, 59, 128 }, { 5, 60, 128 }, { 6, 61, 128 }, { 6, 62, 128 }, { 7, 63, 128 }, + { 2, 64, 128 }, { 3, 65, 128 }, { 3, 66, 128 }, { 4, 67, 128 }, { 3, 68, 128 }, { 4, 69, 128 }, { 4, 70, 128 }, { 5, 71, 128 }, + { 3, 72, 128 }, { 4, 73, 128 }, { 4, 74, 128 }, { 5, 75, 128 }, { 4, 76, 128 }, { 5, 77, 128 }, { 5, 78, 128 }, { 6, 79, 128 }, + { 3, 80, 128 }, { 4, 81, 128 }, { 4, 82, 128 }, { 5, 83, 128 }, { 4, 84, 128 }, { 5, 85, 128 }, { 5, 86, 128 }, { 6, 87, 128 }, + { 4, 88, 128 }, { 5, 89, 128 }, { 5, 90, 128 }, { 6, 91, 128 }, { 5, 92, 128 }, { 6, 93, 128 }, { 6, 94, 128 }, { 7, 95, 128 }, + { 3, 96, 128 }, { 4, 97, 128 }, { 4, 98, 128 }, { 5, 99, 128 }, { 4, 100, 128 }, { 5, 101, 128 }, { 5, 102, 128 }, { 6, 103, 128 }, + { 4, 104, 128 }, { 5, 105, 128 }, { 5, 106, 128 }, { 6, 107, 128 }, { 5, 108, 128 }, { 6, 109, 128 }, { 6, 110, 128 }, { 7, 111, 128 }, + { 4, 112, 128 }, { 5, 113, 128 }, { 5, 114, 128 }, { 6, 115, 128 }, { 5, 116, 128 }, { 6, 117, 128 }, { 6, 118, 128 }, { 7, 119, 128 }, + { 5, 120, 128 }, { 6, 121, 128 }, { 6, 122, 128 }, { 7, 123, 128 }, { 6, 124, 128 }, { 7, 125, 128 }, { 7, 126, 128 }, { 8, 127, 128 }, #if FP_LUT > 8 - { 1, 0, 0 }, { 2, 1, 256 }, { 2, 2, 256 }, { 3, 3, 256 }, { 2, 4, 256 }, { 3, 5, 256 }, { 3, 6, 256 }, { 4, 7, 256 }, - { 2, 8, 256 }, { 3, 9, 256 }, { 3, 10, 256 }, { 4, 11, 256 }, { 3, 12, 256 }, { 4, 13, 256 }, { 4, 14, 256 }, { 5, 15, 256 }, - { 2, 16, 256 }, { 3, 17, 256 }, { 3, 18, 256 }, { 4, 19, 256 }, { 3, 20, 256 }, { 4, 21, 256 }, { 4, 22, 256 }, { 5, 23, 256 }, - { 3, 24, 256 }, { 4, 25, 256 }, { 4, 26, 256 }, { 5, 27, 256 }, { 4, 28, 256 }, { 5, 29, 256 }, { 5, 30, 256 }, { 6, 31, 256 }, - { 2, 32, 256 }, { 3, 33, 256 }, { 3, 34, 256 }, { 4, 35, 256 }, { 3, 36, 256 }, { 4, 37, 256 }, { 4, 38, 256 }, { 5, 39, 256 }, - { 3, 40, 256 }, { 4, 41, 256 }, { 4, 42, 256 }, { 5, 43, 256 }, { 4, 44, 256 }, { 5, 45, 256 }, { 5, 46, 256 }, { 6, 47, 256 }, - { 3, 48, 256 }, { 4, 49, 256 }, { 4, 50, 256 }, { 5, 51, 256 }, { 4, 52, 256 }, { 5, 53, 256 }, { 5, 54, 256 }, { 6, 55, 256 }, - { 4, 56, 256 }, { 5, 57, 256 }, { 5, 58, 256 }, { 6, 59, 256 }, { 5, 60, 256 }, { 6, 61, 256 }, { 6, 62, 256 }, { 7, 63, 256 }, - { 2, 64, 256 }, { 3, 65, 256 }, { 3, 66, 256 }, { 4, 67, 256 }, { 3, 68, 256 }, { 4, 69, 256 }, { 4, 70, 256 }, { 5, 71, 256 }, - { 3, 72, 256 }, { 4, 73, 256 }, { 4, 74, 256 }, { 5, 75, 256 }, { 4, 76, 256 }, { 5, 77, 256 }, { 5, 78, 256 }, { 6, 79, 256 }, - { 3, 80, 256 }, { 4, 81, 256 }, { 4, 82, 256 }, { 5, 83, 256 }, { 4, 84, 256 }, { 5, 85, 256 }, { 5, 86, 256 }, { 6, 87, 256 }, - { 4, 88, 256 }, { 5, 89, 256 }, { 5, 90, 256 }, { 6, 91, 256 }, { 5, 92, 256 }, { 6, 93, 256 }, { 6, 94, 256 }, { 7, 95, 256 }, - { 3, 96, 256 }, { 4, 97, 256 }, { 4, 98, 256 }, { 5, 99, 256 }, { 4, 100, 256 }, { 5, 101, 256 }, { 5, 102, 256 }, { 6, 103, 256 }, - { 4, 104, 256 }, { 5, 105, 256 }, { 5, 106, 256 }, { 6, 107, 256 }, { 5, 108, 256 }, { 6, 109, 256 }, { 6, 110, 256 }, { 7, 111, 256 }, - { 4, 112, 256 }, { 5, 113, 256 }, { 5, 114, 256 }, { 6, 115, 256 }, { 5, 116, 256 }, { 6, 117, 256 }, { 6, 118, 256 }, { 7, 119, 256 }, - { 5, 120, 256 }, { 6, 121, 256 }, { 6, 122, 256 }, { 7, 123, 256 }, { 6, 124, 256 }, { 7, 125, 256 }, { 7, 126, 256 }, { 8, 127, 256 }, - { 2, 128, 256 }, { 3, 129, 256 }, { 3, 130, 256 }, { 4, 131, 256 }, { 3, 132, 256 }, { 4, 133, 256 }, { 4, 134, 256 }, { 5, 135, 256 }, - { 3, 136, 256 }, { 4, 137, 256 }, { 4, 138, 256 }, { 5, 139, 256 }, { 4, 140, 256 }, { 5, 141, 256 }, { 5, 142, 256 }, { 6, 143, 256 }, - { 3, 144, 256 }, { 4, 145, 256 }, { 4, 146, 256 }, { 5, 147, 256 }, { 4, 148, 256 }, { 5, 149, 256 }, { 5, 150, 256 }, { 6, 151, 256 }, - { 4, 152, 256 }, { 5, 153, 256 }, { 5, 154, 256 }, { 6, 155, 256 }, { 5, 156, 256 }, { 6, 157, 256 }, { 6, 158, 256 }, { 7, 159, 256 }, - { 3, 160, 256 }, { 4, 161, 256 }, { 4, 162, 256 }, { 5, 163, 256 }, { 4, 164, 256 }, { 5, 165, 256 }, { 5, 166, 256 }, { 6, 167, 256 }, - { 4, 168, 256 }, { 5, 169, 256 }, { 5, 170, 256 }, { 6, 171, 256 }, { 5, 172, 256 }, { 6, 173, 256 }, { 6, 174, 256 }, { 7, 175, 256 }, - { 4, 176, 256 }, { 5, 177, 256 }, { 5, 178, 256 }, { 6, 179, 256 }, { 5, 180, 256 }, { 6, 181, 256 }, { 6, 182, 256 }, { 7, 183, 256 }, - { 5, 184, 256 }, { 6, 185, 256 }, { 6, 186, 256 }, { 7, 187, 256 }, { 6, 188, 256 }, { 7, 189, 256 }, { 7, 190, 256 }, { 8, 191, 256 }, - { 3, 192, 256 }, { 4, 193, 256 }, { 4, 194, 256 }, { 5, 195, 256 }, { 4, 196, 256 }, { 5, 197, 256 }, { 5, 198, 256 }, { 6, 199, 256 }, - { 4, 200, 256 }, { 5, 201, 256 }, { 5, 202, 256 }, { 6, 203, 256 }, { 5, 204, 256 }, { 6, 205, 256 }, { 6, 206, 256 }, { 7, 207, 256 }, - { 4, 208, 256 }, { 5, 209, 256 }, { 5, 210, 256 }, { 6, 211, 256 }, { 5, 212, 256 }, { 6, 213, 256 }, { 6, 214, 256 }, { 7, 215, 256 }, - { 5, 216, 256 }, { 6, 217, 256 }, { 6, 218, 256 }, { 7, 219, 256 }, { 6, 220, 256 }, { 7, 221, 256 }, { 7, 222, 256 }, { 8, 223, 256 }, - { 4, 224, 256 }, { 5, 225, 256 }, { 5, 226, 256 }, { 6, 227, 256 }, { 5, 228, 256 }, { 6, 229, 256 }, { 6, 230, 256 }, { 7, 231, 256 }, - { 5, 232, 256 }, { 6, 233, 256 }, { 6, 234, 256 }, { 7, 235, 256 }, { 6, 236, 256 }, { 7, 237, 256 }, { 7, 238, 256 }, { 8, 239, 256 }, - { 5, 240, 256 }, { 6, 241, 256 }, { 6, 242, 256 }, { 7, 243, 256 }, { 6, 244, 256 }, { 7, 245, 256 }, { 7, 246, 256 }, { 8, 247, 256 }, - { 6, 248, 256 }, { 7, 249, 256 }, { 7, 250, 256 }, { 8, 251, 256 }, { 7, 252, 256 }, { 8, 253, 256 }, { 8, 254, 256 }, { 9, 255, 256 }, + { 1, 0, 0 }, { 2, 1, 256 }, { 2, 2, 256 }, { 3, 3, 256 }, { 2, 4, 256 }, { 3, 5, 256 }, { 3, 6, 256 }, { 4, 7, 256 }, + { 2, 8, 256 }, { 3, 9, 256 }, { 3, 10, 256 }, { 4, 11, 256 }, { 3, 12, 256 }, { 4, 13, 256 }, { 4, 14, 256 }, { 5, 15, 256 }, + { 2, 16, 256 }, { 3, 17, 256 }, { 3, 18, 256 }, { 4, 19, 256 }, { 3, 20, 256 }, { 4, 21, 256 }, { 4, 22, 256 }, { 5, 23, 256 }, + { 3, 24, 256 }, { 4, 25, 256 }, { 4, 26, 256 }, { 5, 27, 256 }, { 4, 28, 256 }, { 5, 29, 256 }, { 5, 30, 256 }, { 6, 31, 256 }, + { 2, 32, 256 }, { 3, 33, 256 }, { 3, 34, 256 }, { 4, 35, 256 }, { 3, 36, 256 }, { 4, 37, 256 }, { 4, 38, 256 }, { 5, 39, 256 }, + { 3, 40, 256 }, { 4, 41, 256 }, { 4, 42, 256 }, { 5, 43, 256 }, { 4, 44, 256 }, { 5, 45, 256 }, { 5, 46, 256 }, { 6, 47, 256 }, + { 3, 48, 256 }, { 4, 49, 256 }, { 4, 50, 256 }, { 5, 51, 256 }, { 4, 52, 256 }, { 5, 53, 256 }, { 5, 54, 256 }, { 6, 55, 256 }, + { 4, 56, 256 }, { 5, 57, 256 }, { 5, 58, 256 }, { 6, 59, 256 }, { 5, 60, 256 }, { 6, 61, 256 }, { 6, 62, 256 }, { 7, 63, 256 }, + { 2, 64, 256 }, { 3, 65, 256 }, { 3, 66, 256 }, { 4, 67, 256 }, { 3, 68, 256 }, { 4, 69, 256 }, { 4, 70, 256 }, { 5, 71, 256 }, + { 3, 72, 256 }, { 4, 73, 256 }, { 4, 74, 256 }, { 5, 75, 256 }, { 4, 76, 256 }, { 5, 77, 256 }, { 5, 78, 256 }, { 6, 79, 256 }, + { 3, 80, 256 }, { 4, 81, 256 }, { 4, 82, 256 }, { 5, 83, 256 }, { 4, 84, 256 }, { 5, 85, 256 }, { 5, 86, 256 }, { 6, 87, 256 }, + { 4, 88, 256 }, { 5, 89, 256 }, { 5, 90, 256 }, { 6, 91, 256 }, { 5, 92, 256 }, { 6, 93, 256 }, { 6, 94, 256 }, { 7, 95, 256 }, + { 3, 96, 256 }, { 4, 97, 256 }, { 4, 98, 256 }, { 5, 99, 256 }, { 4, 100, 256 }, { 5, 101, 256 }, { 5, 102, 256 }, { 6, 103, 256 }, + { 4, 104, 256 }, { 5, 105, 256 }, { 5, 106, 256 }, { 6, 107, 256 }, { 5, 108, 256 }, { 6, 109, 256 }, { 6, 110, 256 }, { 7, 111, 256 }, + { 4, 112, 256 }, { 5, 113, 256 }, { 5, 114, 256 }, { 6, 115, 256 }, { 5, 116, 256 }, { 6, 117, 256 }, { 6, 118, 256 }, { 7, 119, 256 }, + { 5, 120, 256 }, { 6, 121, 256 }, { 6, 122, 256 }, { 7, 123, 256 }, { 6, 124, 256 }, { 7, 125, 256 }, { 7, 126, 256 }, { 8, 127, 256 }, + { 2, 128, 256 }, { 3, 129, 256 }, { 3, 130, 256 }, { 4, 131, 256 }, { 3, 132, 256 }, { 4, 133, 256 }, { 4, 134, 256 }, { 5, 135, 256 }, + { 3, 136, 256 }, { 4, 137, 256 }, { 4, 138, 256 }, { 5, 139, 256 }, { 4, 140, 256 }, { 5, 141, 256 }, { 5, 142, 256 }, { 6, 143, 256 }, + { 3, 144, 256 }, { 4, 145, 256 }, { 4, 146, 256 }, { 5, 147, 256 }, { 4, 148, 256 }, { 5, 149, 256 }, { 5, 150, 256 }, { 6, 151, 256 }, + { 4, 152, 256 }, { 5, 153, 256 }, { 5, 154, 256 }, { 6, 155, 256 }, { 5, 156, 256 }, { 6, 157, 256 }, { 6, 158, 256 }, { 7, 159, 256 }, + { 3, 160, 256 }, { 4, 161, 256 }, { 4, 162, 256 }, { 5, 163, 256 }, { 4, 164, 256 }, { 5, 165, 256 }, { 5, 166, 256 }, { 6, 167, 256 }, + { 4, 168, 256 }, { 5, 169, 256 }, { 5, 170, 256 }, { 6, 171, 256 }, { 5, 172, 256 }, { 6, 173, 256 }, { 6, 174, 256 }, { 7, 175, 256 }, + { 4, 176, 256 }, { 5, 177, 256 }, { 5, 178, 256 }, { 6, 179, 256 }, { 5, 180, 256 }, { 6, 181, 256 }, { 6, 182, 256 }, { 7, 183, 256 }, + { 5, 184, 256 }, { 6, 185, 256 }, { 6, 186, 256 }, { 7, 187, 256 }, { 6, 188, 256 }, { 7, 189, 256 }, { 7, 190, 256 }, { 8, 191, 256 }, + { 3, 192, 256 }, { 4, 193, 256 }, { 4, 194, 256 }, { 5, 195, 256 }, { 4, 196, 256 }, { 5, 197, 256 }, { 5, 198, 256 }, { 6, 199, 256 }, + { 4, 200, 256 }, { 5, 201, 256 }, { 5, 202, 256 }, { 6, 203, 256 }, { 5, 204, 256 }, { 6, 205, 256 }, { 6, 206, 256 }, { 7, 207, 256 }, + { 4, 208, 256 }, { 5, 209, 256 }, { 5, 210, 256 }, { 6, 211, 256 }, { 5, 212, 256 }, { 6, 213, 256 }, { 6, 214, 256 }, { 7, 215, 256 }, + { 5, 216, 256 }, { 6, 217, 256 }, { 6, 218, 256 }, { 7, 219, 256 }, { 6, 220, 256 }, { 7, 221, 256 }, { 7, 222, 256 }, { 8, 223, 256 }, + { 4, 224, 256 }, { 5, 225, 256 }, { 5, 226, 256 }, { 6, 227, 256 }, { 5, 228, 256 }, { 6, 229, 256 }, { 6, 230, 256 }, { 7, 231, 256 }, + { 5, 232, 256 }, { 6, 233, 256 }, { 6, 234, 256 }, { 7, 235, 256 }, { 6, 236, 256 }, { 7, 237, 256 }, { 7, 238, 256 }, { 8, 239, 256 }, + { 5, 240, 256 }, { 6, 241, 256 }, { 6, 242, 256 }, { 7, 243, 256 }, { 6, 244, 256 }, { 7, 245, 256 }, { 7, 246, 256 }, { 8, 247, 256 }, + { 6, 248, 256 }, { 7, 249, 256 }, { 7, 250, 256 }, { 8, 251, 256 }, { 7, 252, 256 }, { 8, 253, 256 }, { 8, 254, 256 }, { 9, 255, 256 }, #if FP_LUT > 9 - { 1, 0, 0 }, { 2, 1, 512 }, { 2, 2, 512 }, { 3, 3, 512 }, { 2, 4, 512 }, { 3, 5, 512 }, { 3, 6, 512 }, { 4, 7, 512 }, - { 2, 8, 512 }, { 3, 9, 512 }, { 3, 10, 512 }, { 4, 11, 512 }, { 3, 12, 512 }, { 4, 13, 512 }, { 4, 14, 512 }, { 5, 15, 512 }, - { 2, 16, 512 }, { 3, 17, 512 }, { 3, 18, 512 }, { 4, 19, 512 }, { 3, 20, 512 }, { 4, 21, 512 }, { 4, 22, 512 }, { 5, 23, 512 }, - { 3, 24, 512 }, { 4, 25, 512 }, { 4, 26, 512 }, { 5, 27, 512 }, { 4, 28, 512 }, { 5, 29, 512 }, { 5, 30, 512 }, { 6, 31, 512 }, - { 2, 32, 512 }, { 3, 33, 512 }, { 3, 34, 512 }, { 4, 35, 512 }, { 3, 36, 512 }, { 4, 37, 512 }, { 4, 38, 512 }, { 5, 39, 512 }, - { 3, 40, 512 }, { 4, 41, 512 }, { 4, 42, 512 }, { 5, 43, 512 }, { 4, 44, 512 }, { 5, 45, 512 }, { 5, 46, 512 }, { 6, 47, 512 }, - { 3, 48, 512 }, { 4, 49, 512 }, { 4, 50, 512 }, { 5, 51, 512 }, { 4, 52, 512 }, { 5, 53, 512 }, { 5, 54, 512 }, { 6, 55, 512 }, - { 4, 56, 512 }, { 5, 57, 512 }, { 5, 58, 512 }, { 6, 59, 512 }, { 5, 60, 512 }, { 6, 61, 512 }, { 6, 62, 512 }, { 7, 63, 512 }, - { 2, 64, 512 }, { 3, 65, 512 }, { 3, 66, 512 }, { 4, 67, 512 }, { 3, 68, 512 }, { 4, 69, 512 }, { 4, 70, 512 }, { 5, 71, 512 }, - { 3, 72, 512 }, { 4, 73, 512 }, { 4, 74, 512 }, { 5, 75, 512 }, { 4, 76, 512 }, { 5, 77, 512 }, { 5, 78, 512 }, { 6, 79, 512 }, - { 3, 80, 512 }, { 4, 81, 512 }, { 4, 82, 512 }, { 5, 83, 512 }, { 4, 84, 512 }, { 5, 85, 512 }, { 5, 86, 512 }, { 6, 87, 512 }, - { 4, 88, 512 }, { 5, 89, 512 }, { 5, 90, 512 }, { 6, 91, 512 }, { 5, 92, 512 }, { 6, 93, 512 }, { 6, 94, 512 }, { 7, 95, 512 }, - { 3, 96, 512 }, { 4, 97, 512 }, { 4, 98, 512 }, { 5, 99, 512 }, { 4, 100, 512 }, { 5, 101, 512 }, { 5, 102, 512 }, { 6, 103, 512 }, - { 4, 104, 512 }, { 5, 105, 512 }, { 5, 106, 512 }, { 6, 107, 512 }, { 5, 108, 512 }, { 6, 109, 512 }, { 6, 110, 512 }, { 7, 111, 512 }, - { 4, 112, 512 }, { 5, 113, 512 }, { 5, 114, 512 }, { 6, 115, 512 }, { 5, 116, 512 }, { 6, 117, 512 }, { 6, 118, 512 }, { 7, 119, 512 }, - { 5, 120, 512 }, { 6, 121, 512 }, { 6, 122, 512 }, { 7, 123, 512 }, { 6, 124, 512 }, { 7, 125, 512 }, { 7, 126, 512 }, { 8, 127, 512 }, - { 2, 128, 512 }, { 3, 129, 512 }, { 3, 130, 512 }, { 4, 131, 512 }, { 3, 132, 512 }, { 4, 133, 512 }, { 4, 134, 512 }, { 5, 135, 512 }, - { 3, 136, 512 }, { 4, 137, 512 }, { 4, 138, 512 }, { 5, 139, 512 }, { 4, 140, 512 }, { 5, 141, 512 }, { 5, 142, 512 }, { 6, 143, 512 }, - { 3, 144, 512 }, { 4, 145, 512 }, { 4, 146, 512 }, { 5, 147, 512 }, { 4, 148, 512 }, { 5, 149, 512 }, { 5, 150, 512 }, { 6, 151, 512 }, - { 4, 152, 512 }, { 5, 153, 512 }, { 5, 154, 512 }, { 6, 155, 512 }, { 5, 156, 512 }, { 6, 157, 512 }, { 6, 158, 512 }, { 7, 159, 512 }, - { 3, 160, 512 }, { 4, 161, 512 }, { 4, 162, 512 }, { 5, 163, 512 }, { 4, 164, 512 }, { 5, 165, 512 }, { 5, 166, 512 }, { 6, 167, 512 }, - { 4, 168, 512 }, { 5, 169, 512 }, { 5, 170, 512 }, { 6, 171, 512 }, { 5, 172, 512 }, { 6, 173, 512 }, { 6, 174, 512 }, { 7, 175, 512 }, - { 4, 176, 512 }, { 5, 177, 512 }, { 5, 178, 512 }, { 6, 179, 512 }, { 5, 180, 512 }, { 6, 181, 512 }, { 6, 182, 512 }, { 7, 183, 512 }, - { 5, 184, 512 }, { 6, 185, 512 }, { 6, 186, 512 }, { 7, 187, 512 }, { 6, 188, 512 }, { 7, 189, 512 }, { 7, 190, 512 }, { 8, 191, 512 }, - { 3, 192, 512 }, { 4, 193, 512 }, { 4, 194, 512 }, { 5, 195, 512 }, { 4, 196, 512 }, { 5, 197, 512 }, { 5, 198, 512 }, { 6, 199, 512 }, - { 4, 200, 512 }, { 5, 201, 512 }, { 5, 202, 512 }, { 6, 203, 512 }, { 5, 204, 512 }, { 6, 205, 512 }, { 6, 206, 512 }, { 7, 207, 512 }, - { 4, 208, 512 }, { 5, 209, 512 }, { 5, 210, 512 }, { 6, 211, 512 }, { 5, 212, 512 }, { 6, 213, 512 }, { 6, 214, 512 }, { 7, 215, 512 }, - { 5, 216, 512 }, { 6, 217, 512 }, { 6, 218, 512 }, { 7, 219, 512 }, { 6, 220, 512 }, { 7, 221, 512 }, { 7, 222, 512 }, { 8, 223, 512 }, - { 4, 224, 512 }, { 5, 225, 512 }, { 5, 226, 512 }, { 6, 227, 512 }, { 5, 228, 512 }, { 6, 229, 512 }, { 6, 230, 512 }, { 7, 231, 512 }, - { 5, 232, 512 }, { 6, 233, 512 }, { 6, 234, 512 }, { 7, 235, 512 }, { 6, 236, 512 }, { 7, 237, 512 }, { 7, 238, 512 }, { 8, 239, 512 }, - { 5, 240, 512 }, { 6, 241, 512 }, { 6, 242, 512 }, { 7, 243, 512 }, { 6, 244, 512 }, { 7, 245, 512 }, { 7, 246, 512 }, { 8, 247, 512 }, - { 6, 248, 512 }, { 7, 249, 512 }, { 7, 250, 512 }, { 8, 251, 512 }, { 7, 252, 512 }, { 8, 253, 512 }, { 8, 254, 512 }, { 9, 255, 512 }, - { 2, 256, 512 }, { 3, 257, 512 }, { 3, 258, 512 }, { 4, 259, 512 }, { 3, 260, 512 }, { 4, 261, 512 }, { 4, 262, 512 }, { 5, 263, 512 }, - { 3, 264, 512 }, { 4, 265, 512 }, { 4, 266, 512 }, { 5, 267, 512 }, { 4, 268, 512 }, { 5, 269, 512 }, { 5, 270, 512 }, { 6, 271, 512 }, - { 3, 272, 512 }, { 4, 273, 512 }, { 4, 274, 512 }, { 5, 275, 512 }, { 4, 276, 512 }, { 5, 277, 512 }, { 5, 278, 512 }, { 6, 279, 512 }, - { 4, 280, 512 }, { 5, 281, 512 }, { 5, 282, 512 }, { 6, 283, 512 }, { 5, 284, 512 }, { 6, 285, 512 }, { 6, 286, 512 }, { 7, 287, 512 }, - { 3, 288, 512 }, { 4, 289, 512 }, { 4, 290, 512 }, { 5, 291, 512 }, { 4, 292, 512 }, { 5, 293, 512 }, { 5, 294, 512 }, { 6, 295, 512 }, - { 4, 296, 512 }, { 5, 297, 512 }, { 5, 298, 512 }, { 6, 299, 512 }, { 5, 300, 512 }, { 6, 301, 512 }, { 6, 302, 512 }, { 7, 303, 512 }, - { 4, 304, 512 }, { 5, 305, 512 }, { 5, 306, 512 }, { 6, 307, 512 }, { 5, 308, 512 }, { 6, 309, 512 }, { 6, 310, 512 }, { 7, 311, 512 }, - { 5, 312, 512 }, { 6, 313, 512 }, { 6, 314, 512 }, { 7, 315, 512 }, { 6, 316, 512 }, { 7, 317, 512 }, { 7, 318, 512 }, { 8, 319, 512 }, - { 3, 320, 512 }, { 4, 321, 512 }, { 4, 322, 512 }, { 5, 323, 512 }, { 4, 324, 512 }, { 5, 325, 512 }, { 5, 326, 512 }, { 6, 327, 512 }, - { 4, 328, 512 }, { 5, 329, 512 }, { 5, 330, 512 }, { 6, 331, 512 }, { 5, 332, 512 }, { 6, 333, 512 }, { 6, 334, 512 }, { 7, 335, 512 }, - { 4, 336, 512 }, { 5, 337, 512 }, { 5, 338, 512 }, { 6, 339, 512 }, { 5, 340, 512 }, { 6, 341, 512 }, { 6, 342, 512 }, { 7, 343, 512 }, - { 5, 344, 512 }, { 6, 345, 512 }, { 6, 346, 512 }, { 7, 347, 512 }, { 6, 348, 512 }, { 7, 349, 512 }, { 7, 350, 512 }, { 8, 351, 512 }, - { 4, 352, 512 }, { 5, 353, 512 }, { 5, 354, 512 }, { 6, 355, 512 }, { 5, 356, 512 }, { 6, 357, 512 }, { 6, 358, 512 }, { 7, 359, 512 }, - { 5, 360, 512 }, { 6, 361, 512 }, { 6, 362, 512 }, { 7, 363, 512 }, { 6, 364, 512 }, { 7, 365, 512 }, { 7, 366, 512 }, { 8, 367, 512 }, - { 5, 368, 512 }, { 6, 369, 512 }, { 6, 370, 512 }, { 7, 371, 512 }, { 6, 372, 512 }, { 7, 373, 512 }, { 7, 374, 512 }, { 8, 375, 512 }, - { 6, 376, 512 }, { 7, 377, 512 }, { 7, 378, 512 }, { 8, 379, 512 }, { 7, 380, 512 }, { 8, 381, 512 }, { 8, 382, 512 }, { 9, 383, 512 }, - { 3, 384, 512 }, { 4, 385, 512 }, { 4, 386, 512 }, { 5, 387, 512 }, { 4, 388, 512 }, { 5, 389, 512 }, { 5, 390, 512 }, { 6, 391, 512 }, - { 4, 392, 512 }, { 5, 393, 512 }, { 5, 394, 512 }, { 6, 395, 512 }, { 5, 396, 512 }, { 6, 397, 512 }, { 6, 398, 512 }, { 7, 399, 512 }, - { 4, 400, 512 }, { 5, 401, 512 }, { 5, 402, 512 }, { 6, 403, 512 }, { 5, 404, 512 }, { 6, 405, 512 }, { 6, 406, 512 }, { 7, 407, 512 }, - { 5, 408, 512 }, { 6, 409, 512 }, { 6, 410, 512 }, { 7, 411, 512 }, { 6, 412, 512 }, { 7, 413, 512 }, { 7, 414, 512 }, { 8, 415, 512 }, - { 4, 416, 512 }, { 5, 417, 512 }, { 5, 418, 512 }, { 6, 419, 512 }, { 5, 420, 512 }, { 6, 421, 512 }, { 6, 422, 512 }, { 7, 423, 512 }, - { 5, 424, 512 }, { 6, 425, 512 }, { 6, 426, 512 }, { 7, 427, 512 }, { 6, 428, 512 }, { 7, 429, 512 }, { 7, 430, 512 }, { 8, 431, 512 }, - { 5, 432, 512 }, { 6, 433, 512 }, { 6, 434, 512 }, { 7, 435, 512 }, { 6, 436, 512 }, { 7, 437, 512 }, { 7, 438, 512 }, { 8, 439, 512 }, - { 6, 440, 512 }, { 7, 441, 512 }, { 7, 442, 512 }, { 8, 443, 512 }, { 7, 444, 512 }, { 8, 445, 512 }, { 8, 446, 512 }, { 9, 447, 512 }, - { 4, 448, 512 }, { 5, 449, 512 }, { 5, 450, 512 }, { 6, 451, 512 }, { 5, 452, 512 }, { 6, 453, 512 }, { 6, 454, 512 }, { 7, 455, 512 }, - { 5, 456, 512 }, { 6, 457, 512 }, { 6, 458, 512 }, { 7, 459, 512 }, { 6, 460, 512 }, { 7, 461, 512 }, { 7, 462, 512 }, { 8, 463, 512 }, - { 5, 464, 512 }, { 6, 465, 512 }, { 6, 466, 512 }, { 7, 467, 512 }, { 6, 468, 512 }, { 7, 469, 512 }, { 7, 470, 512 }, { 8, 471, 512 }, - { 6, 472, 512 }, { 7, 473, 512 }, { 7, 474, 512 }, { 8, 475, 512 }, { 7, 476, 512 }, { 8, 477, 512 }, { 8, 478, 512 }, { 9, 479, 512 }, - { 5, 480, 512 }, { 6, 481, 512 }, { 6, 482, 512 }, { 7, 483, 512 }, { 6, 484, 512 }, { 7, 485, 512 }, { 7, 486, 512 }, { 8, 487, 512 }, - { 6, 488, 512 }, { 7, 489, 512 }, { 7, 490, 512 }, { 8, 491, 512 }, { 7, 492, 512 }, { 8, 493, 512 }, { 8, 494, 512 }, { 9, 495, 512 }, - { 6, 496, 512 }, { 7, 497, 512 }, { 7, 498, 512 }, { 8, 499, 512 }, { 7, 500, 512 }, { 8, 501, 512 }, { 8, 502, 512 }, { 9, 503, 512 }, - { 7, 504, 512 }, { 8, 505, 512 }, { 8, 506, 512 }, { 9, 507, 512 }, { 8, 508, 512 }, { 9, 509, 512 }, { 9, 510, 512 }, { 10, 511, 512 }, + { 1, 0, 0 }, { 2, 1, 512 }, { 2, 2, 512 }, { 3, 3, 512 }, { 2, 4, 512 }, { 3, 5, 512 }, { 3, 6, 512 }, { 4, 7, 512 }, + { 2, 8, 512 }, { 3, 9, 512 }, { 3, 10, 512 }, { 4, 11, 512 }, { 3, 12, 512 }, { 4, 13, 512 }, { 4, 14, 512 }, { 5, 15, 512 }, + { 2, 16, 512 }, { 3, 17, 512 }, { 3, 18, 512 }, { 4, 19, 512 }, { 3, 20, 512 }, { 4, 21, 512 }, { 4, 22, 512 }, { 5, 23, 512 }, + { 3, 24, 512 }, { 4, 25, 512 }, { 4, 26, 512 }, { 5, 27, 512 }, { 4, 28, 512 }, { 5, 29, 512 }, { 5, 30, 512 }, { 6, 31, 512 }, + { 2, 32, 512 }, { 3, 33, 512 }, { 3, 34, 512 }, { 4, 35, 512 }, { 3, 36, 512 }, { 4, 37, 512 }, { 4, 38, 512 }, { 5, 39, 512 }, + { 3, 40, 512 }, { 4, 41, 512 }, { 4, 42, 512 }, { 5, 43, 512 }, { 4, 44, 512 }, { 5, 45, 512 }, { 5, 46, 512 }, { 6, 47, 512 }, + { 3, 48, 512 }, { 4, 49, 512 }, { 4, 50, 512 }, { 5, 51, 512 }, { 4, 52, 512 }, { 5, 53, 512 }, { 5, 54, 512 }, { 6, 55, 512 }, + { 4, 56, 512 }, { 5, 57, 512 }, { 5, 58, 512 }, { 6, 59, 512 }, { 5, 60, 512 }, { 6, 61, 512 }, { 6, 62, 512 }, { 7, 63, 512 }, + { 2, 64, 512 }, { 3, 65, 512 }, { 3, 66, 512 }, { 4, 67, 512 }, { 3, 68, 512 }, { 4, 69, 512 }, { 4, 70, 512 }, { 5, 71, 512 }, + { 3, 72, 512 }, { 4, 73, 512 }, { 4, 74, 512 }, { 5, 75, 512 }, { 4, 76, 512 }, { 5, 77, 512 }, { 5, 78, 512 }, { 6, 79, 512 }, + { 3, 80, 512 }, { 4, 81, 512 }, { 4, 82, 512 }, { 5, 83, 512 }, { 4, 84, 512 }, { 5, 85, 512 }, { 5, 86, 512 }, { 6, 87, 512 }, + { 4, 88, 512 }, { 5, 89, 512 }, { 5, 90, 512 }, { 6, 91, 512 }, { 5, 92, 512 }, { 6, 93, 512 }, { 6, 94, 512 }, { 7, 95, 512 }, + { 3, 96, 512 }, { 4, 97, 512 }, { 4, 98, 512 }, { 5, 99, 512 }, { 4, 100, 512 }, { 5, 101, 512 }, { 5, 102, 512 }, { 6, 103, 512 }, + { 4, 104, 512 }, { 5, 105, 512 }, { 5, 106, 512 }, { 6, 107, 512 }, { 5, 108, 512 }, { 6, 109, 512 }, { 6, 110, 512 }, { 7, 111, 512 }, + { 4, 112, 512 }, { 5, 113, 512 }, { 5, 114, 512 }, { 6, 115, 512 }, { 5, 116, 512 }, { 6, 117, 512 }, { 6, 118, 512 }, { 7, 119, 512 }, + { 5, 120, 512 }, { 6, 121, 512 }, { 6, 122, 512 }, { 7, 123, 512 }, { 6, 124, 512 }, { 7, 125, 512 }, { 7, 126, 512 }, { 8, 127, 512 }, + { 2, 128, 512 }, { 3, 129, 512 }, { 3, 130, 512 }, { 4, 131, 512 }, { 3, 132, 512 }, { 4, 133, 512 }, { 4, 134, 512 }, { 5, 135, 512 }, + { 3, 136, 512 }, { 4, 137, 512 }, { 4, 138, 512 }, { 5, 139, 512 }, { 4, 140, 512 }, { 5, 141, 512 }, { 5, 142, 512 }, { 6, 143, 512 }, + { 3, 144, 512 }, { 4, 145, 512 }, { 4, 146, 512 }, { 5, 147, 512 }, { 4, 148, 512 }, { 5, 149, 512 }, { 5, 150, 512 }, { 6, 151, 512 }, + { 4, 152, 512 }, { 5, 153, 512 }, { 5, 154, 512 }, { 6, 155, 512 }, { 5, 156, 512 }, { 6, 157, 512 }, { 6, 158, 512 }, { 7, 159, 512 }, + { 3, 160, 512 }, { 4, 161, 512 }, { 4, 162, 512 }, { 5, 163, 512 }, { 4, 164, 512 }, { 5, 165, 512 }, { 5, 166, 512 }, { 6, 167, 512 }, + { 4, 168, 512 }, { 5, 169, 512 }, { 5, 170, 512 }, { 6, 171, 512 }, { 5, 172, 512 }, { 6, 173, 512 }, { 6, 174, 512 }, { 7, 175, 512 }, + { 4, 176, 512 }, { 5, 177, 512 }, { 5, 178, 512 }, { 6, 179, 512 }, { 5, 180, 512 }, { 6, 181, 512 }, { 6, 182, 512 }, { 7, 183, 512 }, + { 5, 184, 512 }, { 6, 185, 512 }, { 6, 186, 512 }, { 7, 187, 512 }, { 6, 188, 512 }, { 7, 189, 512 }, { 7, 190, 512 }, { 8, 191, 512 }, + { 3, 192, 512 }, { 4, 193, 512 }, { 4, 194, 512 }, { 5, 195, 512 }, { 4, 196, 512 }, { 5, 197, 512 }, { 5, 198, 512 }, { 6, 199, 512 }, + { 4, 200, 512 }, { 5, 201, 512 }, { 5, 202, 512 }, { 6, 203, 512 }, { 5, 204, 512 }, { 6, 205, 512 }, { 6, 206, 512 }, { 7, 207, 512 }, + { 4, 208, 512 }, { 5, 209, 512 }, { 5, 210, 512 }, { 6, 211, 512 }, { 5, 212, 512 }, { 6, 213, 512 }, { 6, 214, 512 }, { 7, 215, 512 }, + { 5, 216, 512 }, { 6, 217, 512 }, { 6, 218, 512 }, { 7, 219, 512 }, { 6, 220, 512 }, { 7, 221, 512 }, { 7, 222, 512 }, { 8, 223, 512 }, + { 4, 224, 512 }, { 5, 225, 512 }, { 5, 226, 512 }, { 6, 227, 512 }, { 5, 228, 512 }, { 6, 229, 512 }, { 6, 230, 512 }, { 7, 231, 512 }, + { 5, 232, 512 }, { 6, 233, 512 }, { 6, 234, 512 }, { 7, 235, 512 }, { 6, 236, 512 }, { 7, 237, 512 }, { 7, 238, 512 }, { 8, 239, 512 }, + { 5, 240, 512 }, { 6, 241, 512 }, { 6, 242, 512 }, { 7, 243, 512 }, { 6, 244, 512 }, { 7, 245, 512 }, { 7, 246, 512 }, { 8, 247, 512 }, + { 6, 248, 512 }, { 7, 249, 512 }, { 7, 250, 512 }, { 8, 251, 512 }, { 7, 252, 512 }, { 8, 253, 512 }, { 8, 254, 512 }, { 9, 255, 512 }, + { 2, 256, 512 }, { 3, 257, 512 }, { 3, 258, 512 }, { 4, 259, 512 }, { 3, 260, 512 }, { 4, 261, 512 }, { 4, 262, 512 }, { 5, 263, 512 }, + { 3, 264, 512 }, { 4, 265, 512 }, { 4, 266, 512 }, { 5, 267, 512 }, { 4, 268, 512 }, { 5, 269, 512 }, { 5, 270, 512 }, { 6, 271, 512 }, + { 3, 272, 512 }, { 4, 273, 512 }, { 4, 274, 512 }, { 5, 275, 512 }, { 4, 276, 512 }, { 5, 277, 512 }, { 5, 278, 512 }, { 6, 279, 512 }, + { 4, 280, 512 }, { 5, 281, 512 }, { 5, 282, 512 }, { 6, 283, 512 }, { 5, 284, 512 }, { 6, 285, 512 }, { 6, 286, 512 }, { 7, 287, 512 }, + { 3, 288, 512 }, { 4, 289, 512 }, { 4, 290, 512 }, { 5, 291, 512 }, { 4, 292, 512 }, { 5, 293, 512 }, { 5, 294, 512 }, { 6, 295, 512 }, + { 4, 296, 512 }, { 5, 297, 512 }, { 5, 298, 512 }, { 6, 299, 512 }, { 5, 300, 512 }, { 6, 301, 512 }, { 6, 302, 512 }, { 7, 303, 512 }, + { 4, 304, 512 }, { 5, 305, 512 }, { 5, 306, 512 }, { 6, 307, 512 }, { 5, 308, 512 }, { 6, 309, 512 }, { 6, 310, 512 }, { 7, 311, 512 }, + { 5, 312, 512 }, { 6, 313, 512 }, { 6, 314, 512 }, { 7, 315, 512 }, { 6, 316, 512 }, { 7, 317, 512 }, { 7, 318, 512 }, { 8, 319, 512 }, + { 3, 320, 512 }, { 4, 321, 512 }, { 4, 322, 512 }, { 5, 323, 512 }, { 4, 324, 512 }, { 5, 325, 512 }, { 5, 326, 512 }, { 6, 327, 512 }, + { 4, 328, 512 }, { 5, 329, 512 }, { 5, 330, 512 }, { 6, 331, 512 }, { 5, 332, 512 }, { 6, 333, 512 }, { 6, 334, 512 }, { 7, 335, 512 }, + { 4, 336, 512 }, { 5, 337, 512 }, { 5, 338, 512 }, { 6, 339, 512 }, { 5, 340, 512 }, { 6, 341, 512 }, { 6, 342, 512 }, { 7, 343, 512 }, + { 5, 344, 512 }, { 6, 345, 512 }, { 6, 346, 512 }, { 7, 347, 512 }, { 6, 348, 512 }, { 7, 349, 512 }, { 7, 350, 512 }, { 8, 351, 512 }, + { 4, 352, 512 }, { 5, 353, 512 }, { 5, 354, 512 }, { 6, 355, 512 }, { 5, 356, 512 }, { 6, 357, 512 }, { 6, 358, 512 }, { 7, 359, 512 }, + { 5, 360, 512 }, { 6, 361, 512 }, { 6, 362, 512 }, { 7, 363, 512 }, { 6, 364, 512 }, { 7, 365, 512 }, { 7, 366, 512 }, { 8, 367, 512 }, + { 5, 368, 512 }, { 6, 369, 512 }, { 6, 370, 512 }, { 7, 371, 512 }, { 6, 372, 512 }, { 7, 373, 512 }, { 7, 374, 512 }, { 8, 375, 512 }, + { 6, 376, 512 }, { 7, 377, 512 }, { 7, 378, 512 }, { 8, 379, 512 }, { 7, 380, 512 }, { 8, 381, 512 }, { 8, 382, 512 }, { 9, 383, 512 }, + { 3, 384, 512 }, { 4, 385, 512 }, { 4, 386, 512 }, { 5, 387, 512 }, { 4, 388, 512 }, { 5, 389, 512 }, { 5, 390, 512 }, { 6, 391, 512 }, + { 4, 392, 512 }, { 5, 393, 512 }, { 5, 394, 512 }, { 6, 395, 512 }, { 5, 396, 512 }, { 6, 397, 512 }, { 6, 398, 512 }, { 7, 399, 512 }, + { 4, 400, 512 }, { 5, 401, 512 }, { 5, 402, 512 }, { 6, 403, 512 }, { 5, 404, 512 }, { 6, 405, 512 }, { 6, 406, 512 }, { 7, 407, 512 }, + { 5, 408, 512 }, { 6, 409, 512 }, { 6, 410, 512 }, { 7, 411, 512 }, { 6, 412, 512 }, { 7, 413, 512 }, { 7, 414, 512 }, { 8, 415, 512 }, + { 4, 416, 512 }, { 5, 417, 512 }, { 5, 418, 512 }, { 6, 419, 512 }, { 5, 420, 512 }, { 6, 421, 512 }, { 6, 422, 512 }, { 7, 423, 512 }, + { 5, 424, 512 }, { 6, 425, 512 }, { 6, 426, 512 }, { 7, 427, 512 }, { 6, 428, 512 }, { 7, 429, 512 }, { 7, 430, 512 }, { 8, 431, 512 }, + { 5, 432, 512 }, { 6, 433, 512 }, { 6, 434, 512 }, { 7, 435, 512 }, { 6, 436, 512 }, { 7, 437, 512 }, { 7, 438, 512 }, { 8, 439, 512 }, + { 6, 440, 512 }, { 7, 441, 512 }, { 7, 442, 512 }, { 8, 443, 512 }, { 7, 444, 512 }, { 8, 445, 512 }, { 8, 446, 512 }, { 9, 447, 512 }, + { 4, 448, 512 }, { 5, 449, 512 }, { 5, 450, 512 }, { 6, 451, 512 }, { 5, 452, 512 }, { 6, 453, 512 }, { 6, 454, 512 }, { 7, 455, 512 }, + { 5, 456, 512 }, { 6, 457, 512 }, { 6, 458, 512 }, { 7, 459, 512 }, { 6, 460, 512 }, { 7, 461, 512 }, { 7, 462, 512 }, { 8, 463, 512 }, + { 5, 464, 512 }, { 6, 465, 512 }, { 6, 466, 512 }, { 7, 467, 512 }, { 6, 468, 512 }, { 7, 469, 512 }, { 7, 470, 512 }, { 8, 471, 512 }, + { 6, 472, 512 }, { 7, 473, 512 }, { 7, 474, 512 }, { 8, 475, 512 }, { 7, 476, 512 }, { 8, 477, 512 }, { 8, 478, 512 }, { 9, 479, 512 }, + { 5, 480, 512 }, { 6, 481, 512 }, { 6, 482, 512 }, { 7, 483, 512 }, { 6, 484, 512 }, { 7, 485, 512 }, { 7, 486, 512 }, { 8, 487, 512 }, + { 6, 488, 512 }, { 7, 489, 512 }, { 7, 490, 512 }, { 8, 491, 512 }, { 7, 492, 512 }, { 8, 493, 512 }, { 8, 494, 512 }, { 9, 495, 512 }, + { 6, 496, 512 }, { 7, 497, 512 }, { 7, 498, 512 }, { 8, 499, 512 }, { 7, 500, 512 }, { 8, 501, 512 }, { 8, 502, 512 }, { 9, 503, 512 }, + { 7, 504, 512 }, { 8, 505, 512 }, { 8, 506, 512 }, { 9, 507, 512 }, { 8, 508, 512 }, { 9, 509, 512 }, { 9, 510, 512 }, { 10, 511, 512 }, #if FP_LUT > 10 - { 1, 0, 0 }, { 2, 1, 1024 }, { 2, 2, 1024 }, { 3, 3, 1024 }, { 2, 4, 1024 }, { 3, 5, 1024 }, { 3, 6, 1024 }, { 4, 7, 1024 }, - { 2, 8, 1024 }, { 3, 9, 1024 }, { 3, 10, 1024 }, { 4, 11, 1024 }, { 3, 12, 1024 }, { 4, 13, 1024 }, { 4, 14, 1024 }, { 5, 15, 1024 }, - { 2, 16, 1024 }, { 3, 17, 1024 }, { 3, 18, 1024 }, { 4, 19, 1024 }, { 3, 20, 1024 }, { 4, 21, 1024 }, { 4, 22, 1024 }, { 5, 23, 1024 }, - { 3, 24, 1024 }, { 4, 25, 1024 }, { 4, 26, 1024 }, { 5, 27, 1024 }, { 4, 28, 1024 }, { 5, 29, 1024 }, { 5, 30, 1024 }, { 6, 31, 1024 }, - { 2, 32, 1024 }, { 3, 33, 1024 }, { 3, 34, 1024 }, { 4, 35, 1024 }, { 3, 36, 1024 }, { 4, 37, 1024 }, { 4, 38, 1024 }, { 5, 39, 1024 }, - { 3, 40, 1024 }, { 4, 41, 1024 }, { 4, 42, 1024 }, { 5, 43, 1024 }, { 4, 44, 1024 }, { 5, 45, 1024 }, { 5, 46, 1024 }, { 6, 47, 1024 }, - { 3, 48, 1024 }, { 4, 49, 1024 }, { 4, 50, 1024 }, { 5, 51, 1024 }, { 4, 52, 1024 }, { 5, 53, 1024 }, { 5, 54, 1024 }, { 6, 55, 1024 }, - { 4, 56, 1024 }, { 5, 57, 1024 }, { 5, 58, 1024 }, { 6, 59, 1024 }, { 5, 60, 1024 }, { 6, 61, 1024 }, { 6, 62, 1024 }, { 7, 63, 1024 }, - { 2, 64, 1024 }, { 3, 65, 1024 }, { 3, 66, 1024 }, { 4, 67, 1024 }, { 3, 68, 1024 }, { 4, 69, 1024 }, { 4, 70, 1024 }, { 5, 71, 1024 }, - { 3, 72, 1024 }, { 4, 73, 1024 }, { 4, 74, 1024 }, { 5, 75, 1024 }, { 4, 76, 1024 }, { 5, 77, 1024 }, { 5, 78, 1024 }, { 6, 79, 1024 }, - { 3, 80, 1024 }, { 4, 81, 1024 }, { 4, 82, 1024 }, { 5, 83, 1024 }, { 4, 84, 1024 }, { 5, 85, 1024 }, { 5, 86, 1024 }, { 6, 87, 1024 }, - { 4, 88, 1024 }, { 5, 89, 1024 }, { 5, 90, 1024 }, { 6, 91, 1024 }, { 5, 92, 1024 }, { 6, 93, 1024 }, { 6, 94, 1024 }, { 7, 95, 1024 }, - { 3, 96, 1024 }, { 4, 97, 1024 }, { 4, 98, 1024 }, { 5, 99, 1024 }, { 4, 100, 1024 }, { 5, 101, 1024 }, { 5, 102, 1024 }, { 6, 103, 1024 }, - { 4, 104, 1024 }, { 5, 105, 1024 }, { 5, 106, 1024 }, { 6, 107, 1024 }, { 5, 108, 1024 }, { 6, 109, 1024 }, { 6, 110, 1024 }, { 7, 111, 1024 }, - { 4, 112, 1024 }, { 5, 113, 1024 }, { 5, 114, 1024 }, { 6, 115, 1024 }, { 5, 116, 1024 }, { 6, 117, 1024 }, { 6, 118, 1024 }, { 7, 119, 1024 }, - { 5, 120, 1024 }, { 6, 121, 1024 }, { 6, 122, 1024 }, { 7, 123, 1024 }, { 6, 124, 1024 }, { 7, 125, 1024 }, { 7, 126, 1024 }, { 8, 127, 1024 }, - { 2, 128, 1024 }, { 3, 129, 1024 }, { 3, 130, 1024 }, { 4, 131, 1024 }, { 3, 132, 1024 }, { 4, 133, 1024 }, { 4, 134, 1024 }, { 5, 135, 1024 }, - { 3, 136, 1024 }, { 4, 137, 1024 }, { 4, 138, 1024 }, { 5, 139, 1024 }, { 4, 140, 1024 }, { 5, 141, 1024 }, { 5, 142, 1024 }, { 6, 143, 1024 }, - { 3, 144, 1024 }, { 4, 145, 1024 }, { 4, 146, 1024 }, { 5, 147, 1024 }, { 4, 148, 1024 }, { 5, 149, 1024 }, { 5, 150, 1024 }, { 6, 151, 1024 }, - { 4, 152, 1024 }, { 5, 153, 1024 }, { 5, 154, 1024 }, { 6, 155, 1024 }, { 5, 156, 1024 }, { 6, 157, 1024 }, { 6, 158, 1024 }, { 7, 159, 1024 }, - { 3, 160, 1024 }, { 4, 161, 1024 }, { 4, 162, 1024 }, { 5, 163, 1024 }, { 4, 164, 1024 }, { 5, 165, 1024 }, { 5, 166, 1024 }, { 6, 167, 1024 }, - { 4, 168, 1024 }, { 5, 169, 1024 }, { 5, 170, 1024 }, { 6, 171, 1024 }, { 5, 172, 1024 }, { 6, 173, 1024 }, { 6, 174, 1024 }, { 7, 175, 1024 }, - { 4, 176, 1024 }, { 5, 177, 1024 }, { 5, 178, 1024 }, { 6, 179, 1024 }, { 5, 180, 1024 }, { 6, 181, 1024 }, { 6, 182, 1024 }, { 7, 183, 1024 }, - { 5, 184, 1024 }, { 6, 185, 1024 }, { 6, 186, 1024 }, { 7, 187, 1024 }, { 6, 188, 1024 }, { 7, 189, 1024 }, { 7, 190, 1024 }, { 8, 191, 1024 }, - { 3, 192, 1024 }, { 4, 193, 1024 }, { 4, 194, 1024 }, { 5, 195, 1024 }, { 4, 196, 1024 }, { 5, 197, 1024 }, { 5, 198, 1024 }, { 6, 199, 1024 }, - { 4, 200, 1024 }, { 5, 201, 1024 }, { 5, 202, 1024 }, { 6, 203, 1024 }, { 5, 204, 1024 }, { 6, 205, 1024 }, { 6, 206, 1024 }, { 7, 207, 1024 }, - { 4, 208, 1024 }, { 5, 209, 1024 }, { 5, 210, 1024 }, { 6, 211, 1024 }, { 5, 212, 1024 }, { 6, 213, 1024 }, { 6, 214, 1024 }, { 7, 215, 1024 }, - { 5, 216, 1024 }, { 6, 217, 1024 }, { 6, 218, 1024 }, { 7, 219, 1024 }, { 6, 220, 1024 }, { 7, 221, 1024 }, { 7, 222, 1024 }, { 8, 223, 1024 }, - { 4, 224, 1024 }, { 5, 225, 1024 }, { 5, 226, 1024 }, { 6, 227, 1024 }, { 5, 228, 1024 }, { 6, 229, 1024 }, { 6, 230, 1024 }, { 7, 231, 1024 }, - { 5, 232, 1024 }, { 6, 233, 1024 }, { 6, 234, 1024 }, { 7, 235, 1024 }, { 6, 236, 1024 }, { 7, 237, 1024 }, { 7, 238, 1024 }, { 8, 239, 1024 }, - { 5, 240, 1024 }, { 6, 241, 1024 }, { 6, 242, 1024 }, { 7, 243, 1024 }, { 6, 244, 1024 }, { 7, 245, 1024 }, { 7, 246, 1024 }, { 8, 247, 1024 }, - { 6, 248, 1024 }, { 7, 249, 1024 }, { 7, 250, 1024 }, { 8, 251, 1024 }, { 7, 252, 1024 }, { 8, 253, 1024 }, { 8, 254, 1024 }, { 9, 255, 1024 }, - { 2, 256, 1024 }, { 3, 257, 1024 }, { 3, 258, 1024 }, { 4, 259, 1024 }, { 3, 260, 1024 }, { 4, 261, 1024 }, { 4, 262, 1024 }, { 5, 263, 1024 }, - { 3, 264, 1024 }, { 4, 265, 1024 }, { 4, 266, 1024 }, { 5, 267, 1024 }, { 4, 268, 1024 }, { 5, 269, 1024 }, { 5, 270, 1024 }, { 6, 271, 1024 }, - { 3, 272, 1024 }, { 4, 273, 1024 }, { 4, 274, 1024 }, { 5, 275, 1024 }, { 4, 276, 1024 }, { 5, 277, 1024 }, { 5, 278, 1024 }, { 6, 279, 1024 }, - { 4, 280, 1024 }, { 5, 281, 1024 }, { 5, 282, 1024 }, { 6, 283, 1024 }, { 5, 284, 1024 }, { 6, 285, 1024 }, { 6, 286, 1024 }, { 7, 287, 1024 }, - { 3, 288, 1024 }, { 4, 289, 1024 }, { 4, 290, 1024 }, { 5, 291, 1024 }, { 4, 292, 1024 }, { 5, 293, 1024 }, { 5, 294, 1024 }, { 6, 295, 1024 }, - { 4, 296, 1024 }, { 5, 297, 1024 }, { 5, 298, 1024 }, { 6, 299, 1024 }, { 5, 300, 1024 }, { 6, 301, 1024 }, { 6, 302, 1024 }, { 7, 303, 1024 }, - { 4, 304, 1024 }, { 5, 305, 1024 }, { 5, 306, 1024 }, { 6, 307, 1024 }, { 5, 308, 1024 }, { 6, 309, 1024 }, { 6, 310, 1024 }, { 7, 311, 1024 }, - { 5, 312, 1024 }, { 6, 313, 1024 }, { 6, 314, 1024 }, { 7, 315, 1024 }, { 6, 316, 1024 }, { 7, 317, 1024 }, { 7, 318, 1024 }, { 8, 319, 1024 }, - { 3, 320, 1024 }, { 4, 321, 1024 }, { 4, 322, 1024 }, { 5, 323, 1024 }, { 4, 324, 1024 }, { 5, 325, 1024 }, { 5, 326, 1024 }, { 6, 327, 1024 }, - { 4, 328, 1024 }, { 5, 329, 1024 }, { 5, 330, 1024 }, { 6, 331, 1024 }, { 5, 332, 1024 }, { 6, 333, 1024 }, { 6, 334, 1024 }, { 7, 335, 1024 }, - { 4, 336, 1024 }, { 5, 337, 1024 }, { 5, 338, 1024 }, { 6, 339, 1024 }, { 5, 340, 1024 }, { 6, 341, 1024 }, { 6, 342, 1024 }, { 7, 343, 1024 }, - { 5, 344, 1024 }, { 6, 345, 1024 }, { 6, 346, 1024 }, { 7, 347, 1024 }, { 6, 348, 1024 }, { 7, 349, 1024 }, { 7, 350, 1024 }, { 8, 351, 1024 }, - { 4, 352, 1024 }, { 5, 353, 1024 }, { 5, 354, 1024 }, { 6, 355, 1024 }, { 5, 356, 1024 }, { 6, 357, 1024 }, { 6, 358, 1024 }, { 7, 359, 1024 }, - { 5, 360, 1024 }, { 6, 361, 1024 }, { 6, 362, 1024 }, { 7, 363, 1024 }, { 6, 364, 1024 }, { 7, 365, 1024 }, { 7, 366, 1024 }, { 8, 367, 1024 }, - { 5, 368, 1024 }, { 6, 369, 1024 }, { 6, 370, 1024 }, { 7, 371, 1024 }, { 6, 372, 1024 }, { 7, 373, 1024 }, { 7, 374, 1024 }, { 8, 375, 1024 }, - { 6, 376, 1024 }, { 7, 377, 1024 }, { 7, 378, 1024 }, { 8, 379, 1024 }, { 7, 380, 1024 }, { 8, 381, 1024 }, { 8, 382, 1024 }, { 9, 383, 1024 }, - { 3, 384, 1024 }, { 4, 385, 1024 }, { 4, 386, 1024 }, { 5, 387, 1024 }, { 4, 388, 1024 }, { 5, 389, 1024 }, { 5, 390, 1024 }, { 6, 391, 1024 }, - { 4, 392, 1024 }, { 5, 393, 1024 }, { 5, 394, 1024 }, { 6, 395, 1024 }, { 5, 396, 1024 }, { 6, 397, 1024 }, { 6, 398, 1024 }, { 7, 399, 1024 }, - { 4, 400, 1024 }, { 5, 401, 1024 }, { 5, 402, 1024 }, { 6, 403, 1024 }, { 5, 404, 1024 }, { 6, 405, 1024 }, { 6, 406, 1024 }, { 7, 407, 1024 }, - { 5, 408, 1024 }, { 6, 409, 1024 }, { 6, 410, 1024 }, { 7, 411, 1024 }, { 6, 412, 1024 }, { 7, 413, 1024 }, { 7, 414, 1024 }, { 8, 415, 1024 }, - { 4, 416, 1024 }, { 5, 417, 1024 }, { 5, 418, 1024 }, { 6, 419, 1024 }, { 5, 420, 1024 }, { 6, 421, 1024 }, { 6, 422, 1024 }, { 7, 423, 1024 }, - { 5, 424, 1024 }, { 6, 425, 1024 }, { 6, 426, 1024 }, { 7, 427, 1024 }, { 6, 428, 1024 }, { 7, 429, 1024 }, { 7, 430, 1024 }, { 8, 431, 1024 }, - { 5, 432, 1024 }, { 6, 433, 1024 }, { 6, 434, 1024 }, { 7, 435, 1024 }, { 6, 436, 1024 }, { 7, 437, 1024 }, { 7, 438, 1024 }, { 8, 439, 1024 }, - { 6, 440, 1024 }, { 7, 441, 1024 }, { 7, 442, 1024 }, { 8, 443, 1024 }, { 7, 444, 1024 }, { 8, 445, 1024 }, { 8, 446, 1024 }, { 9, 447, 1024 }, - { 4, 448, 1024 }, { 5, 449, 1024 }, { 5, 450, 1024 }, { 6, 451, 1024 }, { 5, 452, 1024 }, { 6, 453, 1024 }, { 6, 454, 1024 }, { 7, 455, 1024 }, - { 5, 456, 1024 }, { 6, 457, 1024 }, { 6, 458, 1024 }, { 7, 459, 1024 }, { 6, 460, 1024 }, { 7, 461, 1024 }, { 7, 462, 1024 }, { 8, 463, 1024 }, - { 5, 464, 1024 }, { 6, 465, 1024 }, { 6, 466, 1024 }, { 7, 467, 1024 }, { 6, 468, 1024 }, { 7, 469, 1024 }, { 7, 470, 1024 }, { 8, 471, 1024 }, - { 6, 472, 1024 }, { 7, 473, 1024 }, { 7, 474, 1024 }, { 8, 475, 1024 }, { 7, 476, 1024 }, { 8, 477, 1024 }, { 8, 478, 1024 }, { 9, 479, 1024 }, - { 5, 480, 1024 }, { 6, 481, 1024 }, { 6, 482, 1024 }, { 7, 483, 1024 }, { 6, 484, 1024 }, { 7, 485, 1024 }, { 7, 486, 1024 }, { 8, 487, 1024 }, - { 6, 488, 1024 }, { 7, 489, 1024 }, { 7, 490, 1024 }, { 8, 491, 1024 }, { 7, 492, 1024 }, { 8, 493, 1024 }, { 8, 494, 1024 }, { 9, 495, 1024 }, - { 6, 496, 1024 }, { 7, 497, 1024 }, { 7, 498, 1024 }, { 8, 499, 1024 }, { 7, 500, 1024 }, { 8, 501, 1024 }, { 8, 502, 1024 }, { 9, 503, 1024 }, - { 7, 504, 1024 }, { 8, 505, 1024 }, { 8, 506, 1024 }, { 9, 507, 1024 }, { 8, 508, 1024 }, { 9, 509, 1024 }, { 9, 510, 1024 }, { 10, 511, 1024 }, - { 2, 512, 1024 }, { 3, 513, 1024 }, { 3, 514, 1024 }, { 4, 515, 1024 }, { 3, 516, 1024 }, { 4, 517, 1024 }, { 4, 518, 1024 }, { 5, 519, 1024 }, - { 3, 520, 1024 }, { 4, 521, 1024 }, { 4, 522, 1024 }, { 5, 523, 1024 }, { 4, 524, 1024 }, { 5, 525, 1024 }, { 5, 526, 1024 }, { 6, 527, 1024 }, - { 3, 528, 1024 }, { 4, 529, 1024 }, { 4, 530, 1024 }, { 5, 531, 1024 }, { 4, 532, 1024 }, { 5, 533, 1024 }, { 5, 534, 1024 }, { 6, 535, 1024 }, - { 4, 536, 1024 }, { 5, 537, 1024 }, { 5, 538, 1024 }, { 6, 539, 1024 }, { 5, 540, 1024 }, { 6, 541, 1024 }, { 6, 542, 1024 }, { 7, 543, 1024 }, - { 3, 544, 1024 }, { 4, 545, 1024 }, { 4, 546, 1024 }, { 5, 547, 1024 }, { 4, 548, 1024 }, { 5, 549, 1024 }, { 5, 550, 1024 }, { 6, 551, 1024 }, - { 4, 552, 1024 }, { 5, 553, 1024 }, { 5, 554, 1024 }, { 6, 555, 1024 }, { 5, 556, 1024 }, { 6, 557, 1024 }, { 6, 558, 1024 }, { 7, 559, 1024 }, - { 4, 560, 1024 }, { 5, 561, 1024 }, { 5, 562, 1024 }, { 6, 563, 1024 }, { 5, 564, 1024 }, { 6, 565, 1024 }, { 6, 566, 1024 }, { 7, 567, 1024 }, - { 5, 568, 1024 }, { 6, 569, 1024 }, { 6, 570, 1024 }, { 7, 571, 1024 }, { 6, 572, 1024 }, { 7, 573, 1024 }, { 7, 574, 1024 }, { 8, 575, 1024 }, - { 3, 576, 1024 }, { 4, 577, 1024 }, { 4, 578, 1024 }, { 5, 579, 1024 }, { 4, 580, 1024 }, { 5, 581, 1024 }, { 5, 582, 1024 }, { 6, 583, 1024 }, - { 4, 584, 1024 }, { 5, 585, 1024 }, { 5, 586, 1024 }, { 6, 587, 1024 }, { 5, 588, 1024 }, { 6, 589, 1024 }, { 6, 590, 1024 }, { 7, 591, 1024 }, - { 4, 592, 1024 }, { 5, 593, 1024 }, { 5, 594, 1024 }, { 6, 595, 1024 }, { 5, 596, 1024 }, { 6, 597, 1024 }, { 6, 598, 1024 }, { 7, 599, 1024 }, - { 5, 600, 1024 }, { 6, 601, 1024 }, { 6, 602, 1024 }, { 7, 603, 1024 }, { 6, 604, 1024 }, { 7, 605, 1024 }, { 7, 606, 1024 }, { 8, 607, 1024 }, - { 4, 608, 1024 }, { 5, 609, 1024 }, { 5, 610, 1024 }, { 6, 611, 1024 }, { 5, 612, 1024 }, { 6, 613, 1024 }, { 6, 614, 1024 }, { 7, 615, 1024 }, - { 5, 616, 1024 }, { 6, 617, 1024 }, { 6, 618, 1024 }, { 7, 619, 1024 }, { 6, 620, 1024 }, { 7, 621, 1024 }, { 7, 622, 1024 }, { 8, 623, 1024 }, - { 5, 624, 1024 }, { 6, 625, 1024 }, { 6, 626, 1024 }, { 7, 627, 1024 }, { 6, 628, 1024 }, { 7, 629, 1024 }, { 7, 630, 1024 }, { 8, 631, 1024 }, - { 6, 632, 1024 }, { 7, 633, 1024 }, { 7, 634, 1024 }, { 8, 635, 1024 }, { 7, 636, 1024 }, { 8, 637, 1024 }, { 8, 638, 1024 }, { 9, 639, 1024 }, - { 3, 640, 1024 }, { 4, 641, 1024 }, { 4, 642, 1024 }, { 5, 643, 1024 }, { 4, 644, 1024 }, { 5, 645, 1024 }, { 5, 646, 1024 }, { 6, 647, 1024 }, - { 4, 648, 1024 }, { 5, 649, 1024 }, { 5, 650, 1024 }, { 6, 651, 1024 }, { 5, 652, 1024 }, { 6, 653, 1024 }, { 6, 654, 1024 }, { 7, 655, 1024 }, - { 4, 656, 1024 }, { 5, 657, 1024 }, { 5, 658, 1024 }, { 6, 659, 1024 }, { 5, 660, 1024 }, { 6, 661, 1024 }, { 6, 662, 1024 }, { 7, 663, 1024 }, - { 5, 664, 1024 }, { 6, 665, 1024 }, { 6, 666, 1024 }, { 7, 667, 1024 }, { 6, 668, 1024 }, { 7, 669, 1024 }, { 7, 670, 1024 }, { 8, 671, 1024 }, - { 4, 672, 1024 }, { 5, 673, 1024 }, { 5, 674, 1024 }, { 6, 675, 1024 }, { 5, 676, 1024 }, { 6, 677, 1024 }, { 6, 678, 1024 }, { 7, 679, 1024 }, - { 5, 680, 1024 }, { 6, 681, 1024 }, { 6, 682, 1024 }, { 7, 683, 1024 }, { 6, 684, 1024 }, { 7, 685, 1024 }, { 7, 686, 1024 }, { 8, 687, 1024 }, - { 5, 688, 1024 }, { 6, 689, 1024 }, { 6, 690, 1024 }, { 7, 691, 1024 }, { 6, 692, 1024 }, { 7, 693, 1024 }, { 7, 694, 1024 }, { 8, 695, 1024 }, - { 6, 696, 1024 }, { 7, 697, 1024 }, { 7, 698, 1024 }, { 8, 699, 1024 }, { 7, 700, 1024 }, { 8, 701, 1024 }, { 8, 702, 1024 }, { 9, 703, 1024 }, - { 4, 704, 1024 }, { 5, 705, 1024 }, { 5, 706, 1024 }, { 6, 707, 1024 }, { 5, 708, 1024 }, { 6, 709, 1024 }, { 6, 710, 1024 }, { 7, 711, 1024 }, - { 5, 712, 1024 }, { 6, 713, 1024 }, { 6, 714, 1024 }, { 7, 715, 1024 }, { 6, 716, 1024 }, { 7, 717, 1024 }, { 7, 718, 1024 }, { 8, 719, 1024 }, - { 5, 720, 1024 }, { 6, 721, 1024 }, { 6, 722, 1024 }, { 7, 723, 1024 }, { 6, 724, 1024 }, { 7, 725, 1024 }, { 7, 726, 1024 }, { 8, 727, 1024 }, - { 6, 728, 1024 }, { 7, 729, 1024 }, { 7, 730, 1024 }, { 8, 731, 1024 }, { 7, 732, 1024 }, { 8, 733, 1024 }, { 8, 734, 1024 }, { 9, 735, 1024 }, - { 5, 736, 1024 }, { 6, 737, 1024 }, { 6, 738, 1024 }, { 7, 739, 1024 }, { 6, 740, 1024 }, { 7, 741, 1024 }, { 7, 742, 1024 }, { 8, 743, 1024 }, - { 6, 744, 1024 }, { 7, 745, 1024 }, { 7, 746, 1024 }, { 8, 747, 1024 }, { 7, 748, 1024 }, { 8, 749, 1024 }, { 8, 750, 1024 }, { 9, 751, 1024 }, - { 6, 752, 1024 }, { 7, 753, 1024 }, { 7, 754, 1024 }, { 8, 755, 1024 }, { 7, 756, 1024 }, { 8, 757, 1024 }, { 8, 758, 1024 }, { 9, 759, 1024 }, - { 7, 760, 1024 }, { 8, 761, 1024 }, { 8, 762, 1024 }, { 9, 763, 1024 }, { 8, 764, 1024 }, { 9, 765, 1024 }, { 9, 766, 1024 }, { 10, 767, 1024 }, - { 3, 768, 1024 }, { 4, 769, 1024 }, { 4, 770, 1024 }, { 5, 771, 1024 }, { 4, 772, 1024 }, { 5, 773, 1024 }, { 5, 774, 1024 }, { 6, 775, 1024 }, - { 4, 776, 1024 }, { 5, 777, 1024 }, { 5, 778, 1024 }, { 6, 779, 1024 }, { 5, 780, 1024 }, { 6, 781, 1024 }, { 6, 782, 1024 }, { 7, 783, 1024 }, - { 4, 784, 1024 }, { 5, 785, 1024 }, { 5, 786, 1024 }, { 6, 787, 1024 }, { 5, 788, 1024 }, { 6, 789, 1024 }, { 6, 790, 1024 }, { 7, 791, 1024 }, - { 5, 792, 1024 }, { 6, 793, 1024 }, { 6, 794, 1024 }, { 7, 795, 1024 }, { 6, 796, 1024 }, { 7, 797, 1024 }, { 7, 798, 1024 }, { 8, 799, 1024 }, - { 4, 800, 1024 }, { 5, 801, 1024 }, { 5, 802, 1024 }, { 6, 803, 1024 }, { 5, 804, 1024 }, { 6, 805, 1024 }, { 6, 806, 1024 }, { 7, 807, 1024 }, - { 5, 808, 1024 }, { 6, 809, 1024 }, { 6, 810, 1024 }, { 7, 811, 1024 }, { 6, 812, 1024 }, { 7, 813, 1024 }, { 7, 814, 1024 }, { 8, 815, 1024 }, - { 5, 816, 1024 }, { 6, 817, 1024 }, { 6, 818, 1024 }, { 7, 819, 1024 }, { 6, 820, 1024 }, { 7, 821, 1024 }, { 7, 822, 1024 }, { 8, 823, 1024 }, - { 6, 824, 1024 }, { 7, 825, 1024 }, { 7, 826, 1024 }, { 8, 827, 1024 }, { 7, 828, 1024 }, { 8, 829, 1024 }, { 8, 830, 1024 }, { 9, 831, 1024 }, - { 4, 832, 1024 }, { 5, 833, 1024 }, { 5, 834, 1024 }, { 6, 835, 1024 }, { 5, 836, 1024 }, { 6, 837, 1024 }, { 6, 838, 1024 }, { 7, 839, 1024 }, - { 5, 840, 1024 }, { 6, 841, 1024 }, { 6, 842, 1024 }, { 7, 843, 1024 }, { 6, 844, 1024 }, { 7, 845, 1024 }, { 7, 846, 1024 }, { 8, 847, 1024 }, - { 5, 848, 1024 }, { 6, 849, 1024 }, { 6, 850, 1024 }, { 7, 851, 1024 }, { 6, 852, 1024 }, { 7, 853, 1024 }, { 7, 854, 1024 }, { 8, 855, 1024 }, - { 6, 856, 1024 }, { 7, 857, 1024 }, { 7, 858, 1024 }, { 8, 859, 1024 }, { 7, 860, 1024 }, { 8, 861, 1024 }, { 8, 862, 1024 }, { 9, 863, 1024 }, - { 5, 864, 1024 }, { 6, 865, 1024 }, { 6, 866, 1024 }, { 7, 867, 1024 }, { 6, 868, 1024 }, { 7, 869, 1024 }, { 7, 870, 1024 }, { 8, 871, 1024 }, - { 6, 872, 1024 }, { 7, 873, 1024 }, { 7, 874, 1024 }, { 8, 875, 1024 }, { 7, 876, 1024 }, { 8, 877, 1024 }, { 8, 878, 1024 }, { 9, 879, 1024 }, - { 6, 880, 1024 }, { 7, 881, 1024 }, { 7, 882, 1024 }, { 8, 883, 1024 }, { 7, 884, 1024 }, { 8, 885, 1024 }, { 8, 886, 1024 }, { 9, 887, 1024 }, - { 7, 888, 1024 }, { 8, 889, 1024 }, { 8, 890, 1024 }, { 9, 891, 1024 }, { 8, 892, 1024 }, { 9, 893, 1024 }, { 9, 894, 1024 }, { 10, 895, 1024 }, - { 4, 896, 1024 }, { 5, 897, 1024 }, { 5, 898, 1024 }, { 6, 899, 1024 }, { 5, 900, 1024 }, { 6, 901, 1024 }, { 6, 902, 1024 }, { 7, 903, 1024 }, - { 5, 904, 1024 }, { 6, 905, 1024 }, { 6, 906, 1024 }, { 7, 907, 1024 }, { 6, 908, 1024 }, { 7, 909, 1024 }, { 7, 910, 1024 }, { 8, 911, 1024 }, - { 5, 912, 1024 }, { 6, 913, 1024 }, { 6, 914, 1024 }, { 7, 915, 1024 }, { 6, 916, 1024 }, { 7, 917, 1024 }, { 7, 918, 1024 }, { 8, 919, 1024 }, - { 6, 920, 1024 }, { 7, 921, 1024 }, { 7, 922, 1024 }, { 8, 923, 1024 }, { 7, 924, 1024 }, { 8, 925, 1024 }, { 8, 926, 1024 }, { 9, 927, 1024 }, - { 5, 928, 1024 }, { 6, 929, 1024 }, { 6, 930, 1024 }, { 7, 931, 1024 }, { 6, 932, 1024 }, { 7, 933, 1024 }, { 7, 934, 1024 }, { 8, 935, 1024 }, - { 6, 936, 1024 }, { 7, 937, 1024 }, { 7, 938, 1024 }, { 8, 939, 1024 }, { 7, 940, 1024 }, { 8, 941, 1024 }, { 8, 942, 1024 }, { 9, 943, 1024 }, - { 6, 944, 1024 }, { 7, 945, 1024 }, { 7, 946, 1024 }, { 8, 947, 1024 }, { 7, 948, 1024 }, { 8, 949, 1024 }, { 8, 950, 1024 }, { 9, 951, 1024 }, - { 7, 952, 1024 }, { 8, 953, 1024 }, { 8, 954, 1024 }, { 9, 955, 1024 }, { 8, 956, 1024 }, { 9, 957, 1024 }, { 9, 958, 1024 }, { 10, 959, 1024 }, - { 5, 960, 1024 }, { 6, 961, 1024 }, { 6, 962, 1024 }, { 7, 963, 1024 }, { 6, 964, 1024 }, { 7, 965, 1024 }, { 7, 966, 1024 }, { 8, 967, 1024 }, - { 6, 968, 1024 }, { 7, 969, 1024 }, { 7, 970, 1024 }, { 8, 971, 1024 }, { 7, 972, 1024 }, { 8, 973, 1024 }, { 8, 974, 1024 }, { 9, 975, 1024 }, - { 6, 976, 1024 }, { 7, 977, 1024 }, { 7, 978, 1024 }, { 8, 979, 1024 }, { 7, 980, 1024 }, { 8, 981, 1024 }, { 8, 982, 1024 }, { 9, 983, 1024 }, - { 7, 984, 1024 }, { 8, 985, 1024 }, { 8, 986, 1024 }, { 9, 987, 1024 }, { 8, 988, 1024 }, { 9, 989, 1024 }, { 9, 990, 1024 }, { 10, 991, 1024 }, - { 6, 992, 1024 }, { 7, 993, 1024 }, { 7, 994, 1024 }, { 8, 995, 1024 }, { 7, 996, 1024 }, { 8, 997, 1024 }, { 8, 998, 1024 }, { 9, 999, 1024 }, - { 7, 1000, 1024 }, { 8, 1001, 1024 }, { 8, 1002, 1024 }, { 9, 1003, 1024 }, { 8, 1004, 1024 }, { 9, 1005, 1024 }, { 9, 1006, 1024 }, { 10, 1007, 1024 }, - { 7, 1008, 1024 }, { 8, 1009, 1024 }, { 8, 1010, 1024 }, { 9, 1011, 1024 }, { 8, 1012, 1024 }, { 9, 1013, 1024 }, { 9, 1014, 1024 }, { 10, 1015, 1024 }, - { 8, 1016, 1024 }, { 9, 1017, 1024 }, { 9, 1018, 1024 }, { 10, 1019, 1024 }, { 9, 1020, 1024 }, { 10, 1021, 1024 }, { 10, 1022, 1024 }, { 11, 1023, 1024 }, + { 1, 0, 0 }, { 2, 1, 1024 }, { 2, 2, 1024 }, { 3, 3, 1024 }, { 2, 4, 1024 }, { 3, 5, 1024 }, { 3, 6, 1024 }, { 4, 7, 1024 }, + { 2, 8, 1024 }, { 3, 9, 1024 }, { 3, 10, 1024 }, { 4, 11, 1024 }, { 3, 12, 1024 }, { 4, 13, 1024 }, { 4, 14, 1024 }, { 5, 15, 1024 }, + { 2, 16, 1024 }, { 3, 17, 1024 }, { 3, 18, 1024 }, { 4, 19, 1024 }, { 3, 20, 1024 }, { 4, 21, 1024 }, { 4, 22, 1024 }, { 5, 23, 1024 }, + { 3, 24, 1024 }, { 4, 25, 1024 }, { 4, 26, 1024 }, { 5, 27, 1024 }, { 4, 28, 1024 }, { 5, 29, 1024 }, { 5, 30, 1024 }, { 6, 31, 1024 }, + { 2, 32, 1024 }, { 3, 33, 1024 }, { 3, 34, 1024 }, { 4, 35, 1024 }, { 3, 36, 1024 }, { 4, 37, 1024 }, { 4, 38, 1024 }, { 5, 39, 1024 }, + { 3, 40, 1024 }, { 4, 41, 1024 }, { 4, 42, 1024 }, { 5, 43, 1024 }, { 4, 44, 1024 }, { 5, 45, 1024 }, { 5, 46, 1024 }, { 6, 47, 1024 }, + { 3, 48, 1024 }, { 4, 49, 1024 }, { 4, 50, 1024 }, { 5, 51, 1024 }, { 4, 52, 1024 }, { 5, 53, 1024 }, { 5, 54, 1024 }, { 6, 55, 1024 }, + { 4, 56, 1024 }, { 5, 57, 1024 }, { 5, 58, 1024 }, { 6, 59, 1024 }, { 5, 60, 1024 }, { 6, 61, 1024 }, { 6, 62, 1024 }, { 7, 63, 1024 }, + { 2, 64, 1024 }, { 3, 65, 1024 }, { 3, 66, 1024 }, { 4, 67, 1024 }, { 3, 68, 1024 }, { 4, 69, 1024 }, { 4, 70, 1024 }, { 5, 71, 1024 }, + { 3, 72, 1024 }, { 4, 73, 1024 }, { 4, 74, 1024 }, { 5, 75, 1024 }, { 4, 76, 1024 }, { 5, 77, 1024 }, { 5, 78, 1024 }, { 6, 79, 1024 }, + { 3, 80, 1024 }, { 4, 81, 1024 }, { 4, 82, 1024 }, { 5, 83, 1024 }, { 4, 84, 1024 }, { 5, 85, 1024 }, { 5, 86, 1024 }, { 6, 87, 1024 }, + { 4, 88, 1024 }, { 5, 89, 1024 }, { 5, 90, 1024 }, { 6, 91, 1024 }, { 5, 92, 1024 }, { 6, 93, 1024 }, { 6, 94, 1024 }, { 7, 95, 1024 }, + { 3, 96, 1024 }, { 4, 97, 1024 }, { 4, 98, 1024 }, { 5, 99, 1024 }, { 4, 100, 1024 }, { 5, 101, 1024 }, { 5, 102, 1024 }, { 6, 103, 1024 }, + { 4, 104, 1024 }, { 5, 105, 1024 }, { 5, 106, 1024 }, { 6, 107, 1024 }, { 5, 108, 1024 }, { 6, 109, 1024 }, { 6, 110, 1024 }, { 7, 111, 1024 }, + { 4, 112, 1024 }, { 5, 113, 1024 }, { 5, 114, 1024 }, { 6, 115, 1024 }, { 5, 116, 1024 }, { 6, 117, 1024 }, { 6, 118, 1024 }, { 7, 119, 1024 }, + { 5, 120, 1024 }, { 6, 121, 1024 }, { 6, 122, 1024 }, { 7, 123, 1024 }, { 6, 124, 1024 }, { 7, 125, 1024 }, { 7, 126, 1024 }, { 8, 127, 1024 }, + { 2, 128, 1024 }, { 3, 129, 1024 }, { 3, 130, 1024 }, { 4, 131, 1024 }, { 3, 132, 1024 }, { 4, 133, 1024 }, { 4, 134, 1024 }, { 5, 135, 1024 }, + { 3, 136, 1024 }, { 4, 137, 1024 }, { 4, 138, 1024 }, { 5, 139, 1024 }, { 4, 140, 1024 }, { 5, 141, 1024 }, { 5, 142, 1024 }, { 6, 143, 1024 }, + { 3, 144, 1024 }, { 4, 145, 1024 }, { 4, 146, 1024 }, { 5, 147, 1024 }, { 4, 148, 1024 }, { 5, 149, 1024 }, { 5, 150, 1024 }, { 6, 151, 1024 }, + { 4, 152, 1024 }, { 5, 153, 1024 }, { 5, 154, 1024 }, { 6, 155, 1024 }, { 5, 156, 1024 }, { 6, 157, 1024 }, { 6, 158, 1024 }, { 7, 159, 1024 }, + { 3, 160, 1024 }, { 4, 161, 1024 }, { 4, 162, 1024 }, { 5, 163, 1024 }, { 4, 164, 1024 }, { 5, 165, 1024 }, { 5, 166, 1024 }, { 6, 167, 1024 }, + { 4, 168, 1024 }, { 5, 169, 1024 }, { 5, 170, 1024 }, { 6, 171, 1024 }, { 5, 172, 1024 }, { 6, 173, 1024 }, { 6, 174, 1024 }, { 7, 175, 1024 }, + { 4, 176, 1024 }, { 5, 177, 1024 }, { 5, 178, 1024 }, { 6, 179, 1024 }, { 5, 180, 1024 }, { 6, 181, 1024 }, { 6, 182, 1024 }, { 7, 183, 1024 }, + { 5, 184, 1024 }, { 6, 185, 1024 }, { 6, 186, 1024 }, { 7, 187, 1024 }, { 6, 188, 1024 }, { 7, 189, 1024 }, { 7, 190, 1024 }, { 8, 191, 1024 }, + { 3, 192, 1024 }, { 4, 193, 1024 }, { 4, 194, 1024 }, { 5, 195, 1024 }, { 4, 196, 1024 }, { 5, 197, 1024 }, { 5, 198, 1024 }, { 6, 199, 1024 }, + { 4, 200, 1024 }, { 5, 201, 1024 }, { 5, 202, 1024 }, { 6, 203, 1024 }, { 5, 204, 1024 }, { 6, 205, 1024 }, { 6, 206, 1024 }, { 7, 207, 1024 }, + { 4, 208, 1024 }, { 5, 209, 1024 }, { 5, 210, 1024 }, { 6, 211, 1024 }, { 5, 212, 1024 }, { 6, 213, 1024 }, { 6, 214, 1024 }, { 7, 215, 1024 }, + { 5, 216, 1024 }, { 6, 217, 1024 }, { 6, 218, 1024 }, { 7, 219, 1024 }, { 6, 220, 1024 }, { 7, 221, 1024 }, { 7, 222, 1024 }, { 8, 223, 1024 }, + { 4, 224, 1024 }, { 5, 225, 1024 }, { 5, 226, 1024 }, { 6, 227, 1024 }, { 5, 228, 1024 }, { 6, 229, 1024 }, { 6, 230, 1024 }, { 7, 231, 1024 }, + { 5, 232, 1024 }, { 6, 233, 1024 }, { 6, 234, 1024 }, { 7, 235, 1024 }, { 6, 236, 1024 }, { 7, 237, 1024 }, { 7, 238, 1024 }, { 8, 239, 1024 }, + { 5, 240, 1024 }, { 6, 241, 1024 }, { 6, 242, 1024 }, { 7, 243, 1024 }, { 6, 244, 1024 }, { 7, 245, 1024 }, { 7, 246, 1024 }, { 8, 247, 1024 }, + { 6, 248, 1024 }, { 7, 249, 1024 }, { 7, 250, 1024 }, { 8, 251, 1024 }, { 7, 252, 1024 }, { 8, 253, 1024 }, { 8, 254, 1024 }, { 9, 255, 1024 }, + { 2, 256, 1024 }, { 3, 257, 1024 }, { 3, 258, 1024 }, { 4, 259, 1024 }, { 3, 260, 1024 }, { 4, 261, 1024 }, { 4, 262, 1024 }, { 5, 263, 1024 }, + { 3, 264, 1024 }, { 4, 265, 1024 }, { 4, 266, 1024 }, { 5, 267, 1024 }, { 4, 268, 1024 }, { 5, 269, 1024 }, { 5, 270, 1024 }, { 6, 271, 1024 }, + { 3, 272, 1024 }, { 4, 273, 1024 }, { 4, 274, 1024 }, { 5, 275, 1024 }, { 4, 276, 1024 }, { 5, 277, 1024 }, { 5, 278, 1024 }, { 6, 279, 1024 }, + { 4, 280, 1024 }, { 5, 281, 1024 }, { 5, 282, 1024 }, { 6, 283, 1024 }, { 5, 284, 1024 }, { 6, 285, 1024 }, { 6, 286, 1024 }, { 7, 287, 1024 }, + { 3, 288, 1024 }, { 4, 289, 1024 }, { 4, 290, 1024 }, { 5, 291, 1024 }, { 4, 292, 1024 }, { 5, 293, 1024 }, { 5, 294, 1024 }, { 6, 295, 1024 }, + { 4, 296, 1024 }, { 5, 297, 1024 }, { 5, 298, 1024 }, { 6, 299, 1024 }, { 5, 300, 1024 }, { 6, 301, 1024 }, { 6, 302, 1024 }, { 7, 303, 1024 }, + { 4, 304, 1024 }, { 5, 305, 1024 }, { 5, 306, 1024 }, { 6, 307, 1024 }, { 5, 308, 1024 }, { 6, 309, 1024 }, { 6, 310, 1024 }, { 7, 311, 1024 }, + { 5, 312, 1024 }, { 6, 313, 1024 }, { 6, 314, 1024 }, { 7, 315, 1024 }, { 6, 316, 1024 }, { 7, 317, 1024 }, { 7, 318, 1024 }, { 8, 319, 1024 }, + { 3, 320, 1024 }, { 4, 321, 1024 }, { 4, 322, 1024 }, { 5, 323, 1024 }, { 4, 324, 1024 }, { 5, 325, 1024 }, { 5, 326, 1024 }, { 6, 327, 1024 }, + { 4, 328, 1024 }, { 5, 329, 1024 }, { 5, 330, 1024 }, { 6, 331, 1024 }, { 5, 332, 1024 }, { 6, 333, 1024 }, { 6, 334, 1024 }, { 7, 335, 1024 }, + { 4, 336, 1024 }, { 5, 337, 1024 }, { 5, 338, 1024 }, { 6, 339, 1024 }, { 5, 340, 1024 }, { 6, 341, 1024 }, { 6, 342, 1024 }, { 7, 343, 1024 }, + { 5, 344, 1024 }, { 6, 345, 1024 }, { 6, 346, 1024 }, { 7, 347, 1024 }, { 6, 348, 1024 }, { 7, 349, 1024 }, { 7, 350, 1024 }, { 8, 351, 1024 }, + { 4, 352, 1024 }, { 5, 353, 1024 }, { 5, 354, 1024 }, { 6, 355, 1024 }, { 5, 356, 1024 }, { 6, 357, 1024 }, { 6, 358, 1024 }, { 7, 359, 1024 }, + { 5, 360, 1024 }, { 6, 361, 1024 }, { 6, 362, 1024 }, { 7, 363, 1024 }, { 6, 364, 1024 }, { 7, 365, 1024 }, { 7, 366, 1024 }, { 8, 367, 1024 }, + { 5, 368, 1024 }, { 6, 369, 1024 }, { 6, 370, 1024 }, { 7, 371, 1024 }, { 6, 372, 1024 }, { 7, 373, 1024 }, { 7, 374, 1024 }, { 8, 375, 1024 }, + { 6, 376, 1024 }, { 7, 377, 1024 }, { 7, 378, 1024 }, { 8, 379, 1024 }, { 7, 380, 1024 }, { 8, 381, 1024 }, { 8, 382, 1024 }, { 9, 383, 1024 }, + { 3, 384, 1024 }, { 4, 385, 1024 }, { 4, 386, 1024 }, { 5, 387, 1024 }, { 4, 388, 1024 }, { 5, 389, 1024 }, { 5, 390, 1024 }, { 6, 391, 1024 }, + { 4, 392, 1024 }, { 5, 393, 1024 }, { 5, 394, 1024 }, { 6, 395, 1024 }, { 5, 396, 1024 }, { 6, 397, 1024 }, { 6, 398, 1024 }, { 7, 399, 1024 }, + { 4, 400, 1024 }, { 5, 401, 1024 }, { 5, 402, 1024 }, { 6, 403, 1024 }, { 5, 404, 1024 }, { 6, 405, 1024 }, { 6, 406, 1024 }, { 7, 407, 1024 }, + { 5, 408, 1024 }, { 6, 409, 1024 }, { 6, 410, 1024 }, { 7, 411, 1024 }, { 6, 412, 1024 }, { 7, 413, 1024 }, { 7, 414, 1024 }, { 8, 415, 1024 }, + { 4, 416, 1024 }, { 5, 417, 1024 }, { 5, 418, 1024 }, { 6, 419, 1024 }, { 5, 420, 1024 }, { 6, 421, 1024 }, { 6, 422, 1024 }, { 7, 423, 1024 }, + { 5, 424, 1024 }, { 6, 425, 1024 }, { 6, 426, 1024 }, { 7, 427, 1024 }, { 6, 428, 1024 }, { 7, 429, 1024 }, { 7, 430, 1024 }, { 8, 431, 1024 }, + { 5, 432, 1024 }, { 6, 433, 1024 }, { 6, 434, 1024 }, { 7, 435, 1024 }, { 6, 436, 1024 }, { 7, 437, 1024 }, { 7, 438, 1024 }, { 8, 439, 1024 }, + { 6, 440, 1024 }, { 7, 441, 1024 }, { 7, 442, 1024 }, { 8, 443, 1024 }, { 7, 444, 1024 }, { 8, 445, 1024 }, { 8, 446, 1024 }, { 9, 447, 1024 }, + { 4, 448, 1024 }, { 5, 449, 1024 }, { 5, 450, 1024 }, { 6, 451, 1024 }, { 5, 452, 1024 }, { 6, 453, 1024 }, { 6, 454, 1024 }, { 7, 455, 1024 }, + { 5, 456, 1024 }, { 6, 457, 1024 }, { 6, 458, 1024 }, { 7, 459, 1024 }, { 6, 460, 1024 }, { 7, 461, 1024 }, { 7, 462, 1024 }, { 8, 463, 1024 }, + { 5, 464, 1024 }, { 6, 465, 1024 }, { 6, 466, 1024 }, { 7, 467, 1024 }, { 6, 468, 1024 }, { 7, 469, 1024 }, { 7, 470, 1024 }, { 8, 471, 1024 }, + { 6, 472, 1024 }, { 7, 473, 1024 }, { 7, 474, 1024 }, { 8, 475, 1024 }, { 7, 476, 1024 }, { 8, 477, 1024 }, { 8, 478, 1024 }, { 9, 479, 1024 }, + { 5, 480, 1024 }, { 6, 481, 1024 }, { 6, 482, 1024 }, { 7, 483, 1024 }, { 6, 484, 1024 }, { 7, 485, 1024 }, { 7, 486, 1024 }, { 8, 487, 1024 }, + { 6, 488, 1024 }, { 7, 489, 1024 }, { 7, 490, 1024 }, { 8, 491, 1024 }, { 7, 492, 1024 }, { 8, 493, 1024 }, { 8, 494, 1024 }, { 9, 495, 1024 }, + { 6, 496, 1024 }, { 7, 497, 1024 }, { 7, 498, 1024 }, { 8, 499, 1024 }, { 7, 500, 1024 }, { 8, 501, 1024 }, { 8, 502, 1024 }, { 9, 503, 1024 }, + { 7, 504, 1024 }, { 8, 505, 1024 }, { 8, 506, 1024 }, { 9, 507, 1024 }, { 8, 508, 1024 }, { 9, 509, 1024 }, { 9, 510, 1024 }, { 10, 511, 1024 }, + { 2, 512, 1024 }, { 3, 513, 1024 }, { 3, 514, 1024 }, { 4, 515, 1024 }, { 3, 516, 1024 }, { 4, 517, 1024 }, { 4, 518, 1024 }, { 5, 519, 1024 }, + { 3, 520, 1024 }, { 4, 521, 1024 }, { 4, 522, 1024 }, { 5, 523, 1024 }, { 4, 524, 1024 }, { 5, 525, 1024 }, { 5, 526, 1024 }, { 6, 527, 1024 }, + { 3, 528, 1024 }, { 4, 529, 1024 }, { 4, 530, 1024 }, { 5, 531, 1024 }, { 4, 532, 1024 }, { 5, 533, 1024 }, { 5, 534, 1024 }, { 6, 535, 1024 }, + { 4, 536, 1024 }, { 5, 537, 1024 }, { 5, 538, 1024 }, { 6, 539, 1024 }, { 5, 540, 1024 }, { 6, 541, 1024 }, { 6, 542, 1024 }, { 7, 543, 1024 }, + { 3, 544, 1024 }, { 4, 545, 1024 }, { 4, 546, 1024 }, { 5, 547, 1024 }, { 4, 548, 1024 }, { 5, 549, 1024 }, { 5, 550, 1024 }, { 6, 551, 1024 }, + { 4, 552, 1024 }, { 5, 553, 1024 }, { 5, 554, 1024 }, { 6, 555, 1024 }, { 5, 556, 1024 }, { 6, 557, 1024 }, { 6, 558, 1024 }, { 7, 559, 1024 }, + { 4, 560, 1024 }, { 5, 561, 1024 }, { 5, 562, 1024 }, { 6, 563, 1024 }, { 5, 564, 1024 }, { 6, 565, 1024 }, { 6, 566, 1024 }, { 7, 567, 1024 }, + { 5, 568, 1024 }, { 6, 569, 1024 }, { 6, 570, 1024 }, { 7, 571, 1024 }, { 6, 572, 1024 }, { 7, 573, 1024 }, { 7, 574, 1024 }, { 8, 575, 1024 }, + { 3, 576, 1024 }, { 4, 577, 1024 }, { 4, 578, 1024 }, { 5, 579, 1024 }, { 4, 580, 1024 }, { 5, 581, 1024 }, { 5, 582, 1024 }, { 6, 583, 1024 }, + { 4, 584, 1024 }, { 5, 585, 1024 }, { 5, 586, 1024 }, { 6, 587, 1024 }, { 5, 588, 1024 }, { 6, 589, 1024 }, { 6, 590, 1024 }, { 7, 591, 1024 }, + { 4, 592, 1024 }, { 5, 593, 1024 }, { 5, 594, 1024 }, { 6, 595, 1024 }, { 5, 596, 1024 }, { 6, 597, 1024 }, { 6, 598, 1024 }, { 7, 599, 1024 }, + { 5, 600, 1024 }, { 6, 601, 1024 }, { 6, 602, 1024 }, { 7, 603, 1024 }, { 6, 604, 1024 }, { 7, 605, 1024 }, { 7, 606, 1024 }, { 8, 607, 1024 }, + { 4, 608, 1024 }, { 5, 609, 1024 }, { 5, 610, 1024 }, { 6, 611, 1024 }, { 5, 612, 1024 }, { 6, 613, 1024 }, { 6, 614, 1024 }, { 7, 615, 1024 }, + { 5, 616, 1024 }, { 6, 617, 1024 }, { 6, 618, 1024 }, { 7, 619, 1024 }, { 6, 620, 1024 }, { 7, 621, 1024 }, { 7, 622, 1024 }, { 8, 623, 1024 }, + { 5, 624, 1024 }, { 6, 625, 1024 }, { 6, 626, 1024 }, { 7, 627, 1024 }, { 6, 628, 1024 }, { 7, 629, 1024 }, { 7, 630, 1024 }, { 8, 631, 1024 }, + { 6, 632, 1024 }, { 7, 633, 1024 }, { 7, 634, 1024 }, { 8, 635, 1024 }, { 7, 636, 1024 }, { 8, 637, 1024 }, { 8, 638, 1024 }, { 9, 639, 1024 }, + { 3, 640, 1024 }, { 4, 641, 1024 }, { 4, 642, 1024 }, { 5, 643, 1024 }, { 4, 644, 1024 }, { 5, 645, 1024 }, { 5, 646, 1024 }, { 6, 647, 1024 }, + { 4, 648, 1024 }, { 5, 649, 1024 }, { 5, 650, 1024 }, { 6, 651, 1024 }, { 5, 652, 1024 }, { 6, 653, 1024 }, { 6, 654, 1024 }, { 7, 655, 1024 }, + { 4, 656, 1024 }, { 5, 657, 1024 }, { 5, 658, 1024 }, { 6, 659, 1024 }, { 5, 660, 1024 }, { 6, 661, 1024 }, { 6, 662, 1024 }, { 7, 663, 1024 }, + { 5, 664, 1024 }, { 6, 665, 1024 }, { 6, 666, 1024 }, { 7, 667, 1024 }, { 6, 668, 1024 }, { 7, 669, 1024 }, { 7, 670, 1024 }, { 8, 671, 1024 }, + { 4, 672, 1024 }, { 5, 673, 1024 }, { 5, 674, 1024 }, { 6, 675, 1024 }, { 5, 676, 1024 }, { 6, 677, 1024 }, { 6, 678, 1024 }, { 7, 679, 1024 }, + { 5, 680, 1024 }, { 6, 681, 1024 }, { 6, 682, 1024 }, { 7, 683, 1024 }, { 6, 684, 1024 }, { 7, 685, 1024 }, { 7, 686, 1024 }, { 8, 687, 1024 }, + { 5, 688, 1024 }, { 6, 689, 1024 }, { 6, 690, 1024 }, { 7, 691, 1024 }, { 6, 692, 1024 }, { 7, 693, 1024 }, { 7, 694, 1024 }, { 8, 695, 1024 }, + { 6, 696, 1024 }, { 7, 697, 1024 }, { 7, 698, 1024 }, { 8, 699, 1024 }, { 7, 700, 1024 }, { 8, 701, 1024 }, { 8, 702, 1024 }, { 9, 703, 1024 }, + { 4, 704, 1024 }, { 5, 705, 1024 }, { 5, 706, 1024 }, { 6, 707, 1024 }, { 5, 708, 1024 }, { 6, 709, 1024 }, { 6, 710, 1024 }, { 7, 711, 1024 }, + { 5, 712, 1024 }, { 6, 713, 1024 }, { 6, 714, 1024 }, { 7, 715, 1024 }, { 6, 716, 1024 }, { 7, 717, 1024 }, { 7, 718, 1024 }, { 8, 719, 1024 }, + { 5, 720, 1024 }, { 6, 721, 1024 }, { 6, 722, 1024 }, { 7, 723, 1024 }, { 6, 724, 1024 }, { 7, 725, 1024 }, { 7, 726, 1024 }, { 8, 727, 1024 }, + { 6, 728, 1024 }, { 7, 729, 1024 }, { 7, 730, 1024 }, { 8, 731, 1024 }, { 7, 732, 1024 }, { 8, 733, 1024 }, { 8, 734, 1024 }, { 9, 735, 1024 }, + { 5, 736, 1024 }, { 6, 737, 1024 }, { 6, 738, 1024 }, { 7, 739, 1024 }, { 6, 740, 1024 }, { 7, 741, 1024 }, { 7, 742, 1024 }, { 8, 743, 1024 }, + { 6, 744, 1024 }, { 7, 745, 1024 }, { 7, 746, 1024 }, { 8, 747, 1024 }, { 7, 748, 1024 }, { 8, 749, 1024 }, { 8, 750, 1024 }, { 9, 751, 1024 }, + { 6, 752, 1024 }, { 7, 753, 1024 }, { 7, 754, 1024 }, { 8, 755, 1024 }, { 7, 756, 1024 }, { 8, 757, 1024 }, { 8, 758, 1024 }, { 9, 759, 1024 }, + { 7, 760, 1024 }, { 8, 761, 1024 }, { 8, 762, 1024 }, { 9, 763, 1024 }, { 8, 764, 1024 }, { 9, 765, 1024 }, { 9, 766, 1024 }, { 10, 767, 1024 }, + { 3, 768, 1024 }, { 4, 769, 1024 }, { 4, 770, 1024 }, { 5, 771, 1024 }, { 4, 772, 1024 }, { 5, 773, 1024 }, { 5, 774, 1024 }, { 6, 775, 1024 }, + { 4, 776, 1024 }, { 5, 777, 1024 }, { 5, 778, 1024 }, { 6, 779, 1024 }, { 5, 780, 1024 }, { 6, 781, 1024 }, { 6, 782, 1024 }, { 7, 783, 1024 }, + { 4, 784, 1024 }, { 5, 785, 1024 }, { 5, 786, 1024 }, { 6, 787, 1024 }, { 5, 788, 1024 }, { 6, 789, 1024 }, { 6, 790, 1024 }, { 7, 791, 1024 }, + { 5, 792, 1024 }, { 6, 793, 1024 }, { 6, 794, 1024 }, { 7, 795, 1024 }, { 6, 796, 1024 }, { 7, 797, 1024 }, { 7, 798, 1024 }, { 8, 799, 1024 }, + { 4, 800, 1024 }, { 5, 801, 1024 }, { 5, 802, 1024 }, { 6, 803, 1024 }, { 5, 804, 1024 }, { 6, 805, 1024 }, { 6, 806, 1024 }, { 7, 807, 1024 }, + { 5, 808, 1024 }, { 6, 809, 1024 }, { 6, 810, 1024 }, { 7, 811, 1024 }, { 6, 812, 1024 }, { 7, 813, 1024 }, { 7, 814, 1024 }, { 8, 815, 1024 }, + { 5, 816, 1024 }, { 6, 817, 1024 }, { 6, 818, 1024 }, { 7, 819, 1024 }, { 6, 820, 1024 }, { 7, 821, 1024 }, { 7, 822, 1024 }, { 8, 823, 1024 }, + { 6, 824, 1024 }, { 7, 825, 1024 }, { 7, 826, 1024 }, { 8, 827, 1024 }, { 7, 828, 1024 }, { 8, 829, 1024 }, { 8, 830, 1024 }, { 9, 831, 1024 }, + { 4, 832, 1024 }, { 5, 833, 1024 }, { 5, 834, 1024 }, { 6, 835, 1024 }, { 5, 836, 1024 }, { 6, 837, 1024 }, { 6, 838, 1024 }, { 7, 839, 1024 }, + { 5, 840, 1024 }, { 6, 841, 1024 }, { 6, 842, 1024 }, { 7, 843, 1024 }, { 6, 844, 1024 }, { 7, 845, 1024 }, { 7, 846, 1024 }, { 8, 847, 1024 }, + { 5, 848, 1024 }, { 6, 849, 1024 }, { 6, 850, 1024 }, { 7, 851, 1024 }, { 6, 852, 1024 }, { 7, 853, 1024 }, { 7, 854, 1024 }, { 8, 855, 1024 }, + { 6, 856, 1024 }, { 7, 857, 1024 }, { 7, 858, 1024 }, { 8, 859, 1024 }, { 7, 860, 1024 }, { 8, 861, 1024 }, { 8, 862, 1024 }, { 9, 863, 1024 }, + { 5, 864, 1024 }, { 6, 865, 1024 }, { 6, 866, 1024 }, { 7, 867, 1024 }, { 6, 868, 1024 }, { 7, 869, 1024 }, { 7, 870, 1024 }, { 8, 871, 1024 }, + { 6, 872, 1024 }, { 7, 873, 1024 }, { 7, 874, 1024 }, { 8, 875, 1024 }, { 7, 876, 1024 }, { 8, 877, 1024 }, { 8, 878, 1024 }, { 9, 879, 1024 }, + { 6, 880, 1024 }, { 7, 881, 1024 }, { 7, 882, 1024 }, { 8, 883, 1024 }, { 7, 884, 1024 }, { 8, 885, 1024 }, { 8, 886, 1024 }, { 9, 887, 1024 }, + { 7, 888, 1024 }, { 8, 889, 1024 }, { 8, 890, 1024 }, { 9, 891, 1024 }, { 8, 892, 1024 }, { 9, 893, 1024 }, { 9, 894, 1024 }, { 10, 895, 1024 }, + { 4, 896, 1024 }, { 5, 897, 1024 }, { 5, 898, 1024 }, { 6, 899, 1024 }, { 5, 900, 1024 }, { 6, 901, 1024 }, { 6, 902, 1024 }, { 7, 903, 1024 }, + { 5, 904, 1024 }, { 6, 905, 1024 }, { 6, 906, 1024 }, { 7, 907, 1024 }, { 6, 908, 1024 }, { 7, 909, 1024 }, { 7, 910, 1024 }, { 8, 911, 1024 }, + { 5, 912, 1024 }, { 6, 913, 1024 }, { 6, 914, 1024 }, { 7, 915, 1024 }, { 6, 916, 1024 }, { 7, 917, 1024 }, { 7, 918, 1024 }, { 8, 919, 1024 }, + { 6, 920, 1024 }, { 7, 921, 1024 }, { 7, 922, 1024 }, { 8, 923, 1024 }, { 7, 924, 1024 }, { 8, 925, 1024 }, { 8, 926, 1024 }, { 9, 927, 1024 }, + { 5, 928, 1024 }, { 6, 929, 1024 }, { 6, 930, 1024 }, { 7, 931, 1024 }, { 6, 932, 1024 }, { 7, 933, 1024 }, { 7, 934, 1024 }, { 8, 935, 1024 }, + { 6, 936, 1024 }, { 7, 937, 1024 }, { 7, 938, 1024 }, { 8, 939, 1024 }, { 7, 940, 1024 }, { 8, 941, 1024 }, { 8, 942, 1024 }, { 9, 943, 1024 }, + { 6, 944, 1024 }, { 7, 945, 1024 }, { 7, 946, 1024 }, { 8, 947, 1024 }, { 7, 948, 1024 }, { 8, 949, 1024 }, { 8, 950, 1024 }, { 9, 951, 1024 }, + { 7, 952, 1024 }, { 8, 953, 1024 }, { 8, 954, 1024 }, { 9, 955, 1024 }, { 8, 956, 1024 }, { 9, 957, 1024 }, { 9, 958, 1024 }, { 10, 959, 1024 }, + { 5, 960, 1024 }, { 6, 961, 1024 }, { 6, 962, 1024 }, { 7, 963, 1024 }, { 6, 964, 1024 }, { 7, 965, 1024 }, { 7, 966, 1024 }, { 8, 967, 1024 }, + { 6, 968, 1024 }, { 7, 969, 1024 }, { 7, 970, 1024 }, { 8, 971, 1024 }, { 7, 972, 1024 }, { 8, 973, 1024 }, { 8, 974, 1024 }, { 9, 975, 1024 }, + { 6, 976, 1024 }, { 7, 977, 1024 }, { 7, 978, 1024 }, { 8, 979, 1024 }, { 7, 980, 1024 }, { 8, 981, 1024 }, { 8, 982, 1024 }, { 9, 983, 1024 }, + { 7, 984, 1024 }, { 8, 985, 1024 }, { 8, 986, 1024 }, { 9, 987, 1024 }, { 8, 988, 1024 }, { 9, 989, 1024 }, { 9, 990, 1024 }, { 10, 991, 1024 }, + { 6, 992, 1024 }, { 7, 993, 1024 }, { 7, 994, 1024 }, { 8, 995, 1024 }, { 7, 996, 1024 }, { 8, 997, 1024 }, { 8, 998, 1024 }, { 9, 999, 1024 }, + { 7, 1000, 1024 }, { 8, 1001, 1024 }, { 8, 1002, 1024 }, { 9, 1003, 1024 }, { 8, 1004, 1024 }, { 9, 1005, 1024 }, { 9, 1006, 1024 }, { 10, 1007, 1024 }, + { 7, 1008, 1024 }, { 8, 1009, 1024 }, { 8, 1010, 1024 }, { 9, 1011, 1024 }, { 8, 1012, 1024 }, { 9, 1013, 1024 }, { 9, 1014, 1024 }, { 10, 1015, 1024 }, + { 8, 1016, 1024 }, { 9, 1017, 1024 }, { 9, 1018, 1024 }, { 10, 1019, 1024 }, { 9, 1020, 1024 }, { 10, 1021, 1024 }, { 10, 1022, 1024 }, { 11, 1023, 1024 }, #if FP_LUT > 11 - { 1, 0, 0 }, { 2, 1, 2048 }, { 2, 2, 2048 }, { 3, 3, 2048 }, { 2, 4, 2048 }, { 3, 5, 2048 }, { 3, 6, 2048 }, { 4, 7, 2048 }, - { 2, 8, 2048 }, { 3, 9, 2048 }, { 3, 10, 2048 }, { 4, 11, 2048 }, { 3, 12, 2048 }, { 4, 13, 2048 }, { 4, 14, 2048 }, { 5, 15, 2048 }, - { 2, 16, 2048 }, { 3, 17, 2048 }, { 3, 18, 2048 }, { 4, 19, 2048 }, { 3, 20, 2048 }, { 4, 21, 2048 }, { 4, 22, 2048 }, { 5, 23, 2048 }, - { 3, 24, 2048 }, { 4, 25, 2048 }, { 4, 26, 2048 }, { 5, 27, 2048 }, { 4, 28, 2048 }, { 5, 29, 2048 }, { 5, 30, 2048 }, { 6, 31, 2048 }, - { 2, 32, 2048 }, { 3, 33, 2048 }, { 3, 34, 2048 }, { 4, 35, 2048 }, { 3, 36, 2048 }, { 4, 37, 2048 }, { 4, 38, 2048 }, { 5, 39, 2048 }, - { 3, 40, 2048 }, { 4, 41, 2048 }, { 4, 42, 2048 }, { 5, 43, 2048 }, { 4, 44, 2048 }, { 5, 45, 2048 }, { 5, 46, 2048 }, { 6, 47, 2048 }, - { 3, 48, 2048 }, { 4, 49, 2048 }, { 4, 50, 2048 }, { 5, 51, 2048 }, { 4, 52, 2048 }, { 5, 53, 2048 }, { 5, 54, 2048 }, { 6, 55, 2048 }, - { 4, 56, 2048 }, { 5, 57, 2048 }, { 5, 58, 2048 }, { 6, 59, 2048 }, { 5, 60, 2048 }, { 6, 61, 2048 }, { 6, 62, 2048 }, { 7, 63, 2048 }, - { 2, 64, 2048 }, { 3, 65, 2048 }, { 3, 66, 2048 }, { 4, 67, 2048 }, { 3, 68, 2048 }, { 4, 69, 2048 }, { 4, 70, 2048 }, { 5, 71, 2048 }, - { 3, 72, 2048 }, { 4, 73, 2048 }, { 4, 74, 2048 }, { 5, 75, 2048 }, { 4, 76, 2048 }, { 5, 77, 2048 }, { 5, 78, 2048 }, { 6, 79, 2048 }, - { 3, 80, 2048 }, { 4, 81, 2048 }, { 4, 82, 2048 }, { 5, 83, 2048 }, { 4, 84, 2048 }, { 5, 85, 2048 }, { 5, 86, 2048 }, { 6, 87, 2048 }, - { 4, 88, 2048 }, { 5, 89, 2048 }, { 5, 90, 2048 }, { 6, 91, 2048 }, { 5, 92, 2048 }, { 6, 93, 2048 }, { 6, 94, 2048 }, { 7, 95, 2048 }, - { 3, 96, 2048 }, { 4, 97, 2048 }, { 4, 98, 2048 }, { 5, 99, 2048 }, { 4, 100, 2048 }, { 5, 101, 2048 }, { 5, 102, 2048 }, { 6, 103, 2048 }, - { 4, 104, 2048 }, { 5, 105, 2048 }, { 5, 106, 2048 }, { 6, 107, 2048 }, { 5, 108, 2048 }, { 6, 109, 2048 }, { 6, 110, 2048 }, { 7, 111, 2048 }, - { 4, 112, 2048 }, { 5, 113, 2048 }, { 5, 114, 2048 }, { 6, 115, 2048 }, { 5, 116, 2048 }, { 6, 117, 2048 }, { 6, 118, 2048 }, { 7, 119, 2048 }, - { 5, 120, 2048 }, { 6, 121, 2048 }, { 6, 122, 2048 }, { 7, 123, 2048 }, { 6, 124, 2048 }, { 7, 125, 2048 }, { 7, 126, 2048 }, { 8, 127, 2048 }, - { 2, 128, 2048 }, { 3, 129, 2048 }, { 3, 130, 2048 }, { 4, 131, 2048 }, { 3, 132, 2048 }, { 4, 133, 2048 }, { 4, 134, 2048 }, { 5, 135, 2048 }, - { 3, 136, 2048 }, { 4, 137, 2048 }, { 4, 138, 2048 }, { 5, 139, 2048 }, { 4, 140, 2048 }, { 5, 141, 2048 }, { 5, 142, 2048 }, { 6, 143, 2048 }, - { 3, 144, 2048 }, { 4, 145, 2048 }, { 4, 146, 2048 }, { 5, 147, 2048 }, { 4, 148, 2048 }, { 5, 149, 2048 }, { 5, 150, 2048 }, { 6, 151, 2048 }, - { 4, 152, 2048 }, { 5, 153, 2048 }, { 5, 154, 2048 }, { 6, 155, 2048 }, { 5, 156, 2048 }, { 6, 157, 2048 }, { 6, 158, 2048 }, { 7, 159, 2048 }, - { 3, 160, 2048 }, { 4, 161, 2048 }, { 4, 162, 2048 }, { 5, 163, 2048 }, { 4, 164, 2048 }, { 5, 165, 2048 }, { 5, 166, 2048 }, { 6, 167, 2048 }, - { 4, 168, 2048 }, { 5, 169, 2048 }, { 5, 170, 2048 }, { 6, 171, 2048 }, { 5, 172, 2048 }, { 6, 173, 2048 }, { 6, 174, 2048 }, { 7, 175, 2048 }, - { 4, 176, 2048 }, { 5, 177, 2048 }, { 5, 178, 2048 }, { 6, 179, 2048 }, { 5, 180, 2048 }, { 6, 181, 2048 }, { 6, 182, 2048 }, { 7, 183, 2048 }, - { 5, 184, 2048 }, { 6, 185, 2048 }, { 6, 186, 2048 }, { 7, 187, 2048 }, { 6, 188, 2048 }, { 7, 189, 2048 }, { 7, 190, 2048 }, { 8, 191, 2048 }, - { 3, 192, 2048 }, { 4, 193, 2048 }, { 4, 194, 2048 }, { 5, 195, 2048 }, { 4, 196, 2048 }, { 5, 197, 2048 }, { 5, 198, 2048 }, { 6, 199, 2048 }, - { 4, 200, 2048 }, { 5, 201, 2048 }, { 5, 202, 2048 }, { 6, 203, 2048 }, { 5, 204, 2048 }, { 6, 205, 2048 }, { 6, 206, 2048 }, { 7, 207, 2048 }, - { 4, 208, 2048 }, { 5, 209, 2048 }, { 5, 210, 2048 }, { 6, 211, 2048 }, { 5, 212, 2048 }, { 6, 213, 2048 }, { 6, 214, 2048 }, { 7, 215, 2048 }, - { 5, 216, 2048 }, { 6, 217, 2048 }, { 6, 218, 2048 }, { 7, 219, 2048 }, { 6, 220, 2048 }, { 7, 221, 2048 }, { 7, 222, 2048 }, { 8, 223, 2048 }, - { 4, 224, 2048 }, { 5, 225, 2048 }, { 5, 226, 2048 }, { 6, 227, 2048 }, { 5, 228, 2048 }, { 6, 229, 2048 }, { 6, 230, 2048 }, { 7, 231, 2048 }, - { 5, 232, 2048 }, { 6, 233, 2048 }, { 6, 234, 2048 }, { 7, 235, 2048 }, { 6, 236, 2048 }, { 7, 237, 2048 }, { 7, 238, 2048 }, { 8, 239, 2048 }, - { 5, 240, 2048 }, { 6, 241, 2048 }, { 6, 242, 2048 }, { 7, 243, 2048 }, { 6, 244, 2048 }, { 7, 245, 2048 }, { 7, 246, 2048 }, { 8, 247, 2048 }, - { 6, 248, 2048 }, { 7, 249, 2048 }, { 7, 250, 2048 }, { 8, 251, 2048 }, { 7, 252, 2048 }, { 8, 253, 2048 }, { 8, 254, 2048 }, { 9, 255, 2048 }, - { 2, 256, 2048 }, { 3, 257, 2048 }, { 3, 258, 2048 }, { 4, 259, 2048 }, { 3, 260, 2048 }, { 4, 261, 2048 }, { 4, 262, 2048 }, { 5, 263, 2048 }, - { 3, 264, 2048 }, { 4, 265, 2048 }, { 4, 266, 2048 }, { 5, 267, 2048 }, { 4, 268, 2048 }, { 5, 269, 2048 }, { 5, 270, 2048 }, { 6, 271, 2048 }, - { 3, 272, 2048 }, { 4, 273, 2048 }, { 4, 274, 2048 }, { 5, 275, 2048 }, { 4, 276, 2048 }, { 5, 277, 2048 }, { 5, 278, 2048 }, { 6, 279, 2048 }, - { 4, 280, 2048 }, { 5, 281, 2048 }, { 5, 282, 2048 }, { 6, 283, 2048 }, { 5, 284, 2048 }, { 6, 285, 2048 }, { 6, 286, 2048 }, { 7, 287, 2048 }, - { 3, 288, 2048 }, { 4, 289, 2048 }, { 4, 290, 2048 }, { 5, 291, 2048 }, { 4, 292, 2048 }, { 5, 293, 2048 }, { 5, 294, 2048 }, { 6, 295, 2048 }, - { 4, 296, 2048 }, { 5, 297, 2048 }, { 5, 298, 2048 }, { 6, 299, 2048 }, { 5, 300, 2048 }, { 6, 301, 2048 }, { 6, 302, 2048 }, { 7, 303, 2048 }, - { 4, 304, 2048 }, { 5, 305, 2048 }, { 5, 306, 2048 }, { 6, 307, 2048 }, { 5, 308, 2048 }, { 6, 309, 2048 }, { 6, 310, 2048 }, { 7, 311, 2048 }, - { 5, 312, 2048 }, { 6, 313, 2048 }, { 6, 314, 2048 }, { 7, 315, 2048 }, { 6, 316, 2048 }, { 7, 317, 2048 }, { 7, 318, 2048 }, { 8, 319, 2048 }, - { 3, 320, 2048 }, { 4, 321, 2048 }, { 4, 322, 2048 }, { 5, 323, 2048 }, { 4, 324, 2048 }, { 5, 325, 2048 }, { 5, 326, 2048 }, { 6, 327, 2048 }, - { 4, 328, 2048 }, { 5, 329, 2048 }, { 5, 330, 2048 }, { 6, 331, 2048 }, { 5, 332, 2048 }, { 6, 333, 2048 }, { 6, 334, 2048 }, { 7, 335, 2048 }, - { 4, 336, 2048 }, { 5, 337, 2048 }, { 5, 338, 2048 }, { 6, 339, 2048 }, { 5, 340, 2048 }, { 6, 341, 2048 }, { 6, 342, 2048 }, { 7, 343, 2048 }, - { 5, 344, 2048 }, { 6, 345, 2048 }, { 6, 346, 2048 }, { 7, 347, 2048 }, { 6, 348, 2048 }, { 7, 349, 2048 }, { 7, 350, 2048 }, { 8, 351, 2048 }, - { 4, 352, 2048 }, { 5, 353, 2048 }, { 5, 354, 2048 }, { 6, 355, 2048 }, { 5, 356, 2048 }, { 6, 357, 2048 }, { 6, 358, 2048 }, { 7, 359, 2048 }, - { 5, 360, 2048 }, { 6, 361, 2048 }, { 6, 362, 2048 }, { 7, 363, 2048 }, { 6, 364, 2048 }, { 7, 365, 2048 }, { 7, 366, 2048 }, { 8, 367, 2048 }, - { 5, 368, 2048 }, { 6, 369, 2048 }, { 6, 370, 2048 }, { 7, 371, 2048 }, { 6, 372, 2048 }, { 7, 373, 2048 }, { 7, 374, 2048 }, { 8, 375, 2048 }, - { 6, 376, 2048 }, { 7, 377, 2048 }, { 7, 378, 2048 }, { 8, 379, 2048 }, { 7, 380, 2048 }, { 8, 381, 2048 }, { 8, 382, 2048 }, { 9, 383, 2048 }, - { 3, 384, 2048 }, { 4, 385, 2048 }, { 4, 386, 2048 }, { 5, 387, 2048 }, { 4, 388, 2048 }, { 5, 389, 2048 }, { 5, 390, 2048 }, { 6, 391, 2048 }, - { 4, 392, 2048 }, { 5, 393, 2048 }, { 5, 394, 2048 }, { 6, 395, 2048 }, { 5, 396, 2048 }, { 6, 397, 2048 }, { 6, 398, 2048 }, { 7, 399, 2048 }, - { 4, 400, 2048 }, { 5, 401, 2048 }, { 5, 402, 2048 }, { 6, 403, 2048 }, { 5, 404, 2048 }, { 6, 405, 2048 }, { 6, 406, 2048 }, { 7, 407, 2048 }, - { 5, 408, 2048 }, { 6, 409, 2048 }, { 6, 410, 2048 }, { 7, 411, 2048 }, { 6, 412, 2048 }, { 7, 413, 2048 }, { 7, 414, 2048 }, { 8, 415, 2048 }, - { 4, 416, 2048 }, { 5, 417, 2048 }, { 5, 418, 2048 }, { 6, 419, 2048 }, { 5, 420, 2048 }, { 6, 421, 2048 }, { 6, 422, 2048 }, { 7, 423, 2048 }, - { 5, 424, 2048 }, { 6, 425, 2048 }, { 6, 426, 2048 }, { 7, 427, 2048 }, { 6, 428, 2048 }, { 7, 429, 2048 }, { 7, 430, 2048 }, { 8, 431, 2048 }, - { 5, 432, 2048 }, { 6, 433, 2048 }, { 6, 434, 2048 }, { 7, 435, 2048 }, { 6, 436, 2048 }, { 7, 437, 2048 }, { 7, 438, 2048 }, { 8, 439, 2048 }, - { 6, 440, 2048 }, { 7, 441, 2048 }, { 7, 442, 2048 }, { 8, 443, 2048 }, { 7, 444, 2048 }, { 8, 445, 2048 }, { 8, 446, 2048 }, { 9, 447, 2048 }, - { 4, 448, 2048 }, { 5, 449, 2048 }, { 5, 450, 2048 }, { 6, 451, 2048 }, { 5, 452, 2048 }, { 6, 453, 2048 }, { 6, 454, 2048 }, { 7, 455, 2048 }, - { 5, 456, 2048 }, { 6, 457, 2048 }, { 6, 458, 2048 }, { 7, 459, 2048 }, { 6, 460, 2048 }, { 7, 461, 2048 }, { 7, 462, 2048 }, { 8, 463, 2048 }, - { 5, 464, 2048 }, { 6, 465, 2048 }, { 6, 466, 2048 }, { 7, 467, 2048 }, { 6, 468, 2048 }, { 7, 469, 2048 }, { 7, 470, 2048 }, { 8, 471, 2048 }, - { 6, 472, 2048 }, { 7, 473, 2048 }, { 7, 474, 2048 }, { 8, 475, 2048 }, { 7, 476, 2048 }, { 8, 477, 2048 }, { 8, 478, 2048 }, { 9, 479, 2048 }, - { 5, 480, 2048 }, { 6, 481, 2048 }, { 6, 482, 2048 }, { 7, 483, 2048 }, { 6, 484, 2048 }, { 7, 485, 2048 }, { 7, 486, 2048 }, { 8, 487, 2048 }, - { 6, 488, 2048 }, { 7, 489, 2048 }, { 7, 490, 2048 }, { 8, 491, 2048 }, { 7, 492, 2048 }, { 8, 493, 2048 }, { 8, 494, 2048 }, { 9, 495, 2048 }, - { 6, 496, 2048 }, { 7, 497, 2048 }, { 7, 498, 2048 }, { 8, 499, 2048 }, { 7, 500, 2048 }, { 8, 501, 2048 }, { 8, 502, 2048 }, { 9, 503, 2048 }, - { 7, 504, 2048 }, { 8, 505, 2048 }, { 8, 506, 2048 }, { 9, 507, 2048 }, { 8, 508, 2048 }, { 9, 509, 2048 }, { 9, 510, 2048 }, { 10, 511, 2048 }, - { 2, 512, 2048 }, { 3, 513, 2048 }, { 3, 514, 2048 }, { 4, 515, 2048 }, { 3, 516, 2048 }, { 4, 517, 2048 }, { 4, 518, 2048 }, { 5, 519, 2048 }, - { 3, 520, 2048 }, { 4, 521, 2048 }, { 4, 522, 2048 }, { 5, 523, 2048 }, { 4, 524, 2048 }, { 5, 525, 2048 }, { 5, 526, 2048 }, { 6, 527, 2048 }, - { 3, 528, 2048 }, { 4, 529, 2048 }, { 4, 530, 2048 }, { 5, 531, 2048 }, { 4, 532, 2048 }, { 5, 533, 2048 }, { 5, 534, 2048 }, { 6, 535, 2048 }, - { 4, 536, 2048 }, { 5, 537, 2048 }, { 5, 538, 2048 }, { 6, 539, 2048 }, { 5, 540, 2048 }, { 6, 541, 2048 }, { 6, 542, 2048 }, { 7, 543, 2048 }, - { 3, 544, 2048 }, { 4, 545, 2048 }, { 4, 546, 2048 }, { 5, 547, 2048 }, { 4, 548, 2048 }, { 5, 549, 2048 }, { 5, 550, 2048 }, { 6, 551, 2048 }, - { 4, 552, 2048 }, { 5, 553, 2048 }, { 5, 554, 2048 }, { 6, 555, 2048 }, { 5, 556, 2048 }, { 6, 557, 2048 }, { 6, 558, 2048 }, { 7, 559, 2048 }, - { 4, 560, 2048 }, { 5, 561, 2048 }, { 5, 562, 2048 }, { 6, 563, 2048 }, { 5, 564, 2048 }, { 6, 565, 2048 }, { 6, 566, 2048 }, { 7, 567, 2048 }, - { 5, 568, 2048 }, { 6, 569, 2048 }, { 6, 570, 2048 }, { 7, 571, 2048 }, { 6, 572, 2048 }, { 7, 573, 2048 }, { 7, 574, 2048 }, { 8, 575, 2048 }, - { 3, 576, 2048 }, { 4, 577, 2048 }, { 4, 578, 2048 }, { 5, 579, 2048 }, { 4, 580, 2048 }, { 5, 581, 2048 }, { 5, 582, 2048 }, { 6, 583, 2048 }, - { 4, 584, 2048 }, { 5, 585, 2048 }, { 5, 586, 2048 }, { 6, 587, 2048 }, { 5, 588, 2048 }, { 6, 589, 2048 }, { 6, 590, 2048 }, { 7, 591, 2048 }, - { 4, 592, 2048 }, { 5, 593, 2048 }, { 5, 594, 2048 }, { 6, 595, 2048 }, { 5, 596, 2048 }, { 6, 597, 2048 }, { 6, 598, 2048 }, { 7, 599, 2048 }, - { 5, 600, 2048 }, { 6, 601, 2048 }, { 6, 602, 2048 }, { 7, 603, 2048 }, { 6, 604, 2048 }, { 7, 605, 2048 }, { 7, 606, 2048 }, { 8, 607, 2048 }, - { 4, 608, 2048 }, { 5, 609, 2048 }, { 5, 610, 2048 }, { 6, 611, 2048 }, { 5, 612, 2048 }, { 6, 613, 2048 }, { 6, 614, 2048 }, { 7, 615, 2048 }, - { 5, 616, 2048 }, { 6, 617, 2048 }, { 6, 618, 2048 }, { 7, 619, 2048 }, { 6, 620, 2048 }, { 7, 621, 2048 }, { 7, 622, 2048 }, { 8, 623, 2048 }, - { 5, 624, 2048 }, { 6, 625, 2048 }, { 6, 626, 2048 }, { 7, 627, 2048 }, { 6, 628, 2048 }, { 7, 629, 2048 }, { 7, 630, 2048 }, { 8, 631, 2048 }, - { 6, 632, 2048 }, { 7, 633, 2048 }, { 7, 634, 2048 }, { 8, 635, 2048 }, { 7, 636, 2048 }, { 8, 637, 2048 }, { 8, 638, 2048 }, { 9, 639, 2048 }, - { 3, 640, 2048 }, { 4, 641, 2048 }, { 4, 642, 2048 }, { 5, 643, 2048 }, { 4, 644, 2048 }, { 5, 645, 2048 }, { 5, 646, 2048 }, { 6, 647, 2048 }, - { 4, 648, 2048 }, { 5, 649, 2048 }, { 5, 650, 2048 }, { 6, 651, 2048 }, { 5, 652, 2048 }, { 6, 653, 2048 }, { 6, 654, 2048 }, { 7, 655, 2048 }, - { 4, 656, 2048 }, { 5, 657, 2048 }, { 5, 658, 2048 }, { 6, 659, 2048 }, { 5, 660, 2048 }, { 6, 661, 2048 }, { 6, 662, 2048 }, { 7, 663, 2048 }, - { 5, 664, 2048 }, { 6, 665, 2048 }, { 6, 666, 2048 }, { 7, 667, 2048 }, { 6, 668, 2048 }, { 7, 669, 2048 }, { 7, 670, 2048 }, { 8, 671, 2048 }, - { 4, 672, 2048 }, { 5, 673, 2048 }, { 5, 674, 2048 }, { 6, 675, 2048 }, { 5, 676, 2048 }, { 6, 677, 2048 }, { 6, 678, 2048 }, { 7, 679, 2048 }, - { 5, 680, 2048 }, { 6, 681, 2048 }, { 6, 682, 2048 }, { 7, 683, 2048 }, { 6, 684, 2048 }, { 7, 685, 2048 }, { 7, 686, 2048 }, { 8, 687, 2048 }, - { 5, 688, 2048 }, { 6, 689, 2048 }, { 6, 690, 2048 }, { 7, 691, 2048 }, { 6, 692, 2048 }, { 7, 693, 2048 }, { 7, 694, 2048 }, { 8, 695, 2048 }, - { 6, 696, 2048 }, { 7, 697, 2048 }, { 7, 698, 2048 }, { 8, 699, 2048 }, { 7, 700, 2048 }, { 8, 701, 2048 }, { 8, 702, 2048 }, { 9, 703, 2048 }, - { 4, 704, 2048 }, { 5, 705, 2048 }, { 5, 706, 2048 }, { 6, 707, 2048 }, { 5, 708, 2048 }, { 6, 709, 2048 }, { 6, 710, 2048 }, { 7, 711, 2048 }, - { 5, 712, 2048 }, { 6, 713, 2048 }, { 6, 714, 2048 }, { 7, 715, 2048 }, { 6, 716, 2048 }, { 7, 717, 2048 }, { 7, 718, 2048 }, { 8, 719, 2048 }, - { 5, 720, 2048 }, { 6, 721, 2048 }, { 6, 722, 2048 }, { 7, 723, 2048 }, { 6, 724, 2048 }, { 7, 725, 2048 }, { 7, 726, 2048 }, { 8, 727, 2048 }, - { 6, 728, 2048 }, { 7, 729, 2048 }, { 7, 730, 2048 }, { 8, 731, 2048 }, { 7, 732, 2048 }, { 8, 733, 2048 }, { 8, 734, 2048 }, { 9, 735, 2048 }, - { 5, 736, 2048 }, { 6, 737, 2048 }, { 6, 738, 2048 }, { 7, 739, 2048 }, { 6, 740, 2048 }, { 7, 741, 2048 }, { 7, 742, 2048 }, { 8, 743, 2048 }, - { 6, 744, 2048 }, { 7, 745, 2048 }, { 7, 746, 2048 }, { 8, 747, 2048 }, { 7, 748, 2048 }, { 8, 749, 2048 }, { 8, 750, 2048 }, { 9, 751, 2048 }, - { 6, 752, 2048 }, { 7, 753, 2048 }, { 7, 754, 2048 }, { 8, 755, 2048 }, { 7, 756, 2048 }, { 8, 757, 2048 }, { 8, 758, 2048 }, { 9, 759, 2048 }, - { 7, 760, 2048 }, { 8, 761, 2048 }, { 8, 762, 2048 }, { 9, 763, 2048 }, { 8, 764, 2048 }, { 9, 765, 2048 }, { 9, 766, 2048 }, { 10, 767, 2048 }, - { 3, 768, 2048 }, { 4, 769, 2048 }, { 4, 770, 2048 }, { 5, 771, 2048 }, { 4, 772, 2048 }, { 5, 773, 2048 }, { 5, 774, 2048 }, { 6, 775, 2048 }, - { 4, 776, 2048 }, { 5, 777, 2048 }, { 5, 778, 2048 }, { 6, 779, 2048 }, { 5, 780, 2048 }, { 6, 781, 2048 }, { 6, 782, 2048 }, { 7, 783, 2048 }, - { 4, 784, 2048 }, { 5, 785, 2048 }, { 5, 786, 2048 }, { 6, 787, 2048 }, { 5, 788, 2048 }, { 6, 789, 2048 }, { 6, 790, 2048 }, { 7, 791, 2048 }, - { 5, 792, 2048 }, { 6, 793, 2048 }, { 6, 794, 2048 }, { 7, 795, 2048 }, { 6, 796, 2048 }, { 7, 797, 2048 }, { 7, 798, 2048 }, { 8, 799, 2048 }, - { 4, 800, 2048 }, { 5, 801, 2048 }, { 5, 802, 2048 }, { 6, 803, 2048 }, { 5, 804, 2048 }, { 6, 805, 2048 }, { 6, 806, 2048 }, { 7, 807, 2048 }, - { 5, 808, 2048 }, { 6, 809, 2048 }, { 6, 810, 2048 }, { 7, 811, 2048 }, { 6, 812, 2048 }, { 7, 813, 2048 }, { 7, 814, 2048 }, { 8, 815, 2048 }, - { 5, 816, 2048 }, { 6, 817, 2048 }, { 6, 818, 2048 }, { 7, 819, 2048 }, { 6, 820, 2048 }, { 7, 821, 2048 }, { 7, 822, 2048 }, { 8, 823, 2048 }, - { 6, 824, 2048 }, { 7, 825, 2048 }, { 7, 826, 2048 }, { 8, 827, 2048 }, { 7, 828, 2048 }, { 8, 829, 2048 }, { 8, 830, 2048 }, { 9, 831, 2048 }, - { 4, 832, 2048 }, { 5, 833, 2048 }, { 5, 834, 2048 }, { 6, 835, 2048 }, { 5, 836, 2048 }, { 6, 837, 2048 }, { 6, 838, 2048 }, { 7, 839, 2048 }, - { 5, 840, 2048 }, { 6, 841, 2048 }, { 6, 842, 2048 }, { 7, 843, 2048 }, { 6, 844, 2048 }, { 7, 845, 2048 }, { 7, 846, 2048 }, { 8, 847, 2048 }, - { 5, 848, 2048 }, { 6, 849, 2048 }, { 6, 850, 2048 }, { 7, 851, 2048 }, { 6, 852, 2048 }, { 7, 853, 2048 }, { 7, 854, 2048 }, { 8, 855, 2048 }, - { 6, 856, 2048 }, { 7, 857, 2048 }, { 7, 858, 2048 }, { 8, 859, 2048 }, { 7, 860, 2048 }, { 8, 861, 2048 }, { 8, 862, 2048 }, { 9, 863, 2048 }, - { 5, 864, 2048 }, { 6, 865, 2048 }, { 6, 866, 2048 }, { 7, 867, 2048 }, { 6, 868, 2048 }, { 7, 869, 2048 }, { 7, 870, 2048 }, { 8, 871, 2048 }, - { 6, 872, 2048 }, { 7, 873, 2048 }, { 7, 874, 2048 }, { 8, 875, 2048 }, { 7, 876, 2048 }, { 8, 877, 2048 }, { 8, 878, 2048 }, { 9, 879, 2048 }, - { 6, 880, 2048 }, { 7, 881, 2048 }, { 7, 882, 2048 }, { 8, 883, 2048 }, { 7, 884, 2048 }, { 8, 885, 2048 }, { 8, 886, 2048 }, { 9, 887, 2048 }, - { 7, 888, 2048 }, { 8, 889, 2048 }, { 8, 890, 2048 }, { 9, 891, 2048 }, { 8, 892, 2048 }, { 9, 893, 2048 }, { 9, 894, 2048 }, { 10, 895, 2048 }, - { 4, 896, 2048 }, { 5, 897, 2048 }, { 5, 898, 2048 }, { 6, 899, 2048 }, { 5, 900, 2048 }, { 6, 901, 2048 }, { 6, 902, 2048 }, { 7, 903, 2048 }, - { 5, 904, 2048 }, { 6, 905, 2048 }, { 6, 906, 2048 }, { 7, 907, 2048 }, { 6, 908, 2048 }, { 7, 909, 2048 }, { 7, 910, 2048 }, { 8, 911, 2048 }, - { 5, 912, 2048 }, { 6, 913, 2048 }, { 6, 914, 2048 }, { 7, 915, 2048 }, { 6, 916, 2048 }, { 7, 917, 2048 }, { 7, 918, 2048 }, { 8, 919, 2048 }, - { 6, 920, 2048 }, { 7, 921, 2048 }, { 7, 922, 2048 }, { 8, 923, 2048 }, { 7, 924, 2048 }, { 8, 925, 2048 }, { 8, 926, 2048 }, { 9, 927, 2048 }, - { 5, 928, 2048 }, { 6, 929, 2048 }, { 6, 930, 2048 }, { 7, 931, 2048 }, { 6, 932, 2048 }, { 7, 933, 2048 }, { 7, 934, 2048 }, { 8, 935, 2048 }, - { 6, 936, 2048 }, { 7, 937, 2048 }, { 7, 938, 2048 }, { 8, 939, 2048 }, { 7, 940, 2048 }, { 8, 941, 2048 }, { 8, 942, 2048 }, { 9, 943, 2048 }, - { 6, 944, 2048 }, { 7, 945, 2048 }, { 7, 946, 2048 }, { 8, 947, 2048 }, { 7, 948, 2048 }, { 8, 949, 2048 }, { 8, 950, 2048 }, { 9, 951, 2048 }, - { 7, 952, 2048 }, { 8, 953, 2048 }, { 8, 954, 2048 }, { 9, 955, 2048 }, { 8, 956, 2048 }, { 9, 957, 2048 }, { 9, 958, 2048 }, { 10, 959, 2048 }, - { 5, 960, 2048 }, { 6, 961, 2048 }, { 6, 962, 2048 }, { 7, 963, 2048 }, { 6, 964, 2048 }, { 7, 965, 2048 }, { 7, 966, 2048 }, { 8, 967, 2048 }, - { 6, 968, 2048 }, { 7, 969, 2048 }, { 7, 970, 2048 }, { 8, 971, 2048 }, { 7, 972, 2048 }, { 8, 973, 2048 }, { 8, 974, 2048 }, { 9, 975, 2048 }, - { 6, 976, 2048 }, { 7, 977, 2048 }, { 7, 978, 2048 }, { 8, 979, 2048 }, { 7, 980, 2048 }, { 8, 981, 2048 }, { 8, 982, 2048 }, { 9, 983, 2048 }, - { 7, 984, 2048 }, { 8, 985, 2048 }, { 8, 986, 2048 }, { 9, 987, 2048 }, { 8, 988, 2048 }, { 9, 989, 2048 }, { 9, 990, 2048 }, { 10, 991, 2048 }, - { 6, 992, 2048 }, { 7, 993, 2048 }, { 7, 994, 2048 }, { 8, 995, 2048 }, { 7, 996, 2048 }, { 8, 997, 2048 }, { 8, 998, 2048 }, { 9, 999, 2048 }, - { 7, 1000, 2048 }, { 8, 1001, 2048 }, { 8, 1002, 2048 }, { 9, 1003, 2048 }, { 8, 1004, 2048 }, { 9, 1005, 2048 }, { 9, 1006, 2048 }, { 10, 1007, 2048 }, - { 7, 1008, 2048 }, { 8, 1009, 2048 }, { 8, 1010, 2048 }, { 9, 1011, 2048 }, { 8, 1012, 2048 }, { 9, 1013, 2048 }, { 9, 1014, 2048 }, { 10, 1015, 2048 }, - { 8, 1016, 2048 }, { 9, 1017, 2048 }, { 9, 1018, 2048 }, { 10, 1019, 2048 }, { 9, 1020, 2048 }, { 10, 1021, 2048 }, { 10, 1022, 2048 }, { 11, 1023, 2048 }, - { 2, 1024, 2048 }, { 3, 1025, 2048 }, { 3, 1026, 2048 }, { 4, 1027, 2048 }, { 3, 1028, 2048 }, { 4, 1029, 2048 }, { 4, 1030, 2048 }, { 5, 1031, 2048 }, - { 3, 1032, 2048 }, { 4, 1033, 2048 }, { 4, 1034, 2048 }, { 5, 1035, 2048 }, { 4, 1036, 2048 }, { 5, 1037, 2048 }, { 5, 1038, 2048 }, { 6, 1039, 2048 }, - { 3, 1040, 2048 }, { 4, 1041, 2048 }, { 4, 1042, 2048 }, { 5, 1043, 2048 }, { 4, 1044, 2048 }, { 5, 1045, 2048 }, { 5, 1046, 2048 }, { 6, 1047, 2048 }, - { 4, 1048, 2048 }, { 5, 1049, 2048 }, { 5, 1050, 2048 }, { 6, 1051, 2048 }, { 5, 1052, 2048 }, { 6, 1053, 2048 }, { 6, 1054, 2048 }, { 7, 1055, 2048 }, - { 3, 1056, 2048 }, { 4, 1057, 2048 }, { 4, 1058, 2048 }, { 5, 1059, 2048 }, { 4, 1060, 2048 }, { 5, 1061, 2048 }, { 5, 1062, 2048 }, { 6, 1063, 2048 }, - { 4, 1064, 2048 }, { 5, 1065, 2048 }, { 5, 1066, 2048 }, { 6, 1067, 2048 }, { 5, 1068, 2048 }, { 6, 1069, 2048 }, { 6, 1070, 2048 }, { 7, 1071, 2048 }, - { 4, 1072, 2048 }, { 5, 1073, 2048 }, { 5, 1074, 2048 }, { 6, 1075, 2048 }, { 5, 1076, 2048 }, { 6, 1077, 2048 }, { 6, 1078, 2048 }, { 7, 1079, 2048 }, - { 5, 1080, 2048 }, { 6, 1081, 2048 }, { 6, 1082, 2048 }, { 7, 1083, 2048 }, { 6, 1084, 2048 }, { 7, 1085, 2048 }, { 7, 1086, 2048 }, { 8, 1087, 2048 }, - { 3, 1088, 2048 }, { 4, 1089, 2048 }, { 4, 1090, 2048 }, { 5, 1091, 2048 }, { 4, 1092, 2048 }, { 5, 1093, 2048 }, { 5, 1094, 2048 }, { 6, 1095, 2048 }, - { 4, 1096, 2048 }, { 5, 1097, 2048 }, { 5, 1098, 2048 }, { 6, 1099, 2048 }, { 5, 1100, 2048 }, { 6, 1101, 2048 }, { 6, 1102, 2048 }, { 7, 1103, 2048 }, - { 4, 1104, 2048 }, { 5, 1105, 2048 }, { 5, 1106, 2048 }, { 6, 1107, 2048 }, { 5, 1108, 2048 }, { 6, 1109, 2048 }, { 6, 1110, 2048 }, { 7, 1111, 2048 }, - { 5, 1112, 2048 }, { 6, 1113, 2048 }, { 6, 1114, 2048 }, { 7, 1115, 2048 }, { 6, 1116, 2048 }, { 7, 1117, 2048 }, { 7, 1118, 2048 }, { 8, 1119, 2048 }, - { 4, 1120, 2048 }, { 5, 1121, 2048 }, { 5, 1122, 2048 }, { 6, 1123, 2048 }, { 5, 1124, 2048 }, { 6, 1125, 2048 }, { 6, 1126, 2048 }, { 7, 1127, 2048 }, - { 5, 1128, 2048 }, { 6, 1129, 2048 }, { 6, 1130, 2048 }, { 7, 1131, 2048 }, { 6, 1132, 2048 }, { 7, 1133, 2048 }, { 7, 1134, 2048 }, { 8, 1135, 2048 }, - { 5, 1136, 2048 }, { 6, 1137, 2048 }, { 6, 1138, 2048 }, { 7, 1139, 2048 }, { 6, 1140, 2048 }, { 7, 1141, 2048 }, { 7, 1142, 2048 }, { 8, 1143, 2048 }, - { 6, 1144, 2048 }, { 7, 1145, 2048 }, { 7, 1146, 2048 }, { 8, 1147, 2048 }, { 7, 1148, 2048 }, { 8, 1149, 2048 }, { 8, 1150, 2048 }, { 9, 1151, 2048 }, - { 3, 1152, 2048 }, { 4, 1153, 2048 }, { 4, 1154, 2048 }, { 5, 1155, 2048 }, { 4, 1156, 2048 }, { 5, 1157, 2048 }, { 5, 1158, 2048 }, { 6, 1159, 2048 }, - { 4, 1160, 2048 }, { 5, 1161, 2048 }, { 5, 1162, 2048 }, { 6, 1163, 2048 }, { 5, 1164, 2048 }, { 6, 1165, 2048 }, { 6, 1166, 2048 }, { 7, 1167, 2048 }, - { 4, 1168, 2048 }, { 5, 1169, 2048 }, { 5, 1170, 2048 }, { 6, 1171, 2048 }, { 5, 1172, 2048 }, { 6, 1173, 2048 }, { 6, 1174, 2048 }, { 7, 1175, 2048 }, - { 5, 1176, 2048 }, { 6, 1177, 2048 }, { 6, 1178, 2048 }, { 7, 1179, 2048 }, { 6, 1180, 2048 }, { 7, 1181, 2048 }, { 7, 1182, 2048 }, { 8, 1183, 2048 }, - { 4, 1184, 2048 }, { 5, 1185, 2048 }, { 5, 1186, 2048 }, { 6, 1187, 2048 }, { 5, 1188, 2048 }, { 6, 1189, 2048 }, { 6, 1190, 2048 }, { 7, 1191, 2048 }, - { 5, 1192, 2048 }, { 6, 1193, 2048 }, { 6, 1194, 2048 }, { 7, 1195, 2048 }, { 6, 1196, 2048 }, { 7, 1197, 2048 }, { 7, 1198, 2048 }, { 8, 1199, 2048 }, - { 5, 1200, 2048 }, { 6, 1201, 2048 }, { 6, 1202, 2048 }, { 7, 1203, 2048 }, { 6, 1204, 2048 }, { 7, 1205, 2048 }, { 7, 1206, 2048 }, { 8, 1207, 2048 }, - { 6, 1208, 2048 }, { 7, 1209, 2048 }, { 7, 1210, 2048 }, { 8, 1211, 2048 }, { 7, 1212, 2048 }, { 8, 1213, 2048 }, { 8, 1214, 2048 }, { 9, 1215, 2048 }, - { 4, 1216, 2048 }, { 5, 1217, 2048 }, { 5, 1218, 2048 }, { 6, 1219, 2048 }, { 5, 1220, 2048 }, { 6, 1221, 2048 }, { 6, 1222, 2048 }, { 7, 1223, 2048 }, - { 5, 1224, 2048 }, { 6, 1225, 2048 }, { 6, 1226, 2048 }, { 7, 1227, 2048 }, { 6, 1228, 2048 }, { 7, 1229, 2048 }, { 7, 1230, 2048 }, { 8, 1231, 2048 }, - { 5, 1232, 2048 }, { 6, 1233, 2048 }, { 6, 1234, 2048 }, { 7, 1235, 2048 }, { 6, 1236, 2048 }, { 7, 1237, 2048 }, { 7, 1238, 2048 }, { 8, 1239, 2048 }, - { 6, 1240, 2048 }, { 7, 1241, 2048 }, { 7, 1242, 2048 }, { 8, 1243, 2048 }, { 7, 1244, 2048 }, { 8, 1245, 2048 }, { 8, 1246, 2048 }, { 9, 1247, 2048 }, - { 5, 1248, 2048 }, { 6, 1249, 2048 }, { 6, 1250, 2048 }, { 7, 1251, 2048 }, { 6, 1252, 2048 }, { 7, 1253, 2048 }, { 7, 1254, 2048 }, { 8, 1255, 2048 }, - { 6, 1256, 2048 }, { 7, 1257, 2048 }, { 7, 1258, 2048 }, { 8, 1259, 2048 }, { 7, 1260, 2048 }, { 8, 1261, 2048 }, { 8, 1262, 2048 }, { 9, 1263, 2048 }, - { 6, 1264, 2048 }, { 7, 1265, 2048 }, { 7, 1266, 2048 }, { 8, 1267, 2048 }, { 7, 1268, 2048 }, { 8, 1269, 2048 }, { 8, 1270, 2048 }, { 9, 1271, 2048 }, - { 7, 1272, 2048 }, { 8, 1273, 2048 }, { 8, 1274, 2048 }, { 9, 1275, 2048 }, { 8, 1276, 2048 }, { 9, 1277, 2048 }, { 9, 1278, 2048 }, { 10, 1279, 2048 }, - { 3, 1280, 2048 }, { 4, 1281, 2048 }, { 4, 1282, 2048 }, { 5, 1283, 2048 }, { 4, 1284, 2048 }, { 5, 1285, 2048 }, { 5, 1286, 2048 }, { 6, 1287, 2048 }, - { 4, 1288, 2048 }, { 5, 1289, 2048 }, { 5, 1290, 2048 }, { 6, 1291, 2048 }, { 5, 1292, 2048 }, { 6, 1293, 2048 }, { 6, 1294, 2048 }, { 7, 1295, 2048 }, - { 4, 1296, 2048 }, { 5, 1297, 2048 }, { 5, 1298, 2048 }, { 6, 1299, 2048 }, { 5, 1300, 2048 }, { 6, 1301, 2048 }, { 6, 1302, 2048 }, { 7, 1303, 2048 }, - { 5, 1304, 2048 }, { 6, 1305, 2048 }, { 6, 1306, 2048 }, { 7, 1307, 2048 }, { 6, 1308, 2048 }, { 7, 1309, 2048 }, { 7, 1310, 2048 }, { 8, 1311, 2048 }, - { 4, 1312, 2048 }, { 5, 1313, 2048 }, { 5, 1314, 2048 }, { 6, 1315, 2048 }, { 5, 1316, 2048 }, { 6, 1317, 2048 }, { 6, 1318, 2048 }, { 7, 1319, 2048 }, - { 5, 1320, 2048 }, { 6, 1321, 2048 }, { 6, 1322, 2048 }, { 7, 1323, 2048 }, { 6, 1324, 2048 }, { 7, 1325, 2048 }, { 7, 1326, 2048 }, { 8, 1327, 2048 }, - { 5, 1328, 2048 }, { 6, 1329, 2048 }, { 6, 1330, 2048 }, { 7, 1331, 2048 }, { 6, 1332, 2048 }, { 7, 1333, 2048 }, { 7, 1334, 2048 }, { 8, 1335, 2048 }, - { 6, 1336, 2048 }, { 7, 1337, 2048 }, { 7, 1338, 2048 }, { 8, 1339, 2048 }, { 7, 1340, 2048 }, { 8, 1341, 2048 }, { 8, 1342, 2048 }, { 9, 1343, 2048 }, - { 4, 1344, 2048 }, { 5, 1345, 2048 }, { 5, 1346, 2048 }, { 6, 1347, 2048 }, { 5, 1348, 2048 }, { 6, 1349, 2048 }, { 6, 1350, 2048 }, { 7, 1351, 2048 }, - { 5, 1352, 2048 }, { 6, 1353, 2048 }, { 6, 1354, 2048 }, { 7, 1355, 2048 }, { 6, 1356, 2048 }, { 7, 1357, 2048 }, { 7, 1358, 2048 }, { 8, 1359, 2048 }, - { 5, 1360, 2048 }, { 6, 1361, 2048 }, { 6, 1362, 2048 }, { 7, 1363, 2048 }, { 6, 1364, 2048 }, { 7, 1365, 2048 }, { 7, 1366, 2048 }, { 8, 1367, 2048 }, - { 6, 1368, 2048 }, { 7, 1369, 2048 }, { 7, 1370, 2048 }, { 8, 1371, 2048 }, { 7, 1372, 2048 }, { 8, 1373, 2048 }, { 8, 1374, 2048 }, { 9, 1375, 2048 }, - { 5, 1376, 2048 }, { 6, 1377, 2048 }, { 6, 1378, 2048 }, { 7, 1379, 2048 }, { 6, 1380, 2048 }, { 7, 1381, 2048 }, { 7, 1382, 2048 }, { 8, 1383, 2048 }, - { 6, 1384, 2048 }, { 7, 1385, 2048 }, { 7, 1386, 2048 }, { 8, 1387, 2048 }, { 7, 1388, 2048 }, { 8, 1389, 2048 }, { 8, 1390, 2048 }, { 9, 1391, 2048 }, - { 6, 1392, 2048 }, { 7, 1393, 2048 }, { 7, 1394, 2048 }, { 8, 1395, 2048 }, { 7, 1396, 2048 }, { 8, 1397, 2048 }, { 8, 1398, 2048 }, { 9, 1399, 2048 }, - { 7, 1400, 2048 }, { 8, 1401, 2048 }, { 8, 1402, 2048 }, { 9, 1403, 2048 }, { 8, 1404, 2048 }, { 9, 1405, 2048 }, { 9, 1406, 2048 }, { 10, 1407, 2048 }, - { 4, 1408, 2048 }, { 5, 1409, 2048 }, { 5, 1410, 2048 }, { 6, 1411, 2048 }, { 5, 1412, 2048 }, { 6, 1413, 2048 }, { 6, 1414, 2048 }, { 7, 1415, 2048 }, - { 5, 1416, 2048 }, { 6, 1417, 2048 }, { 6, 1418, 2048 }, { 7, 1419, 2048 }, { 6, 1420, 2048 }, { 7, 1421, 2048 }, { 7, 1422, 2048 }, { 8, 1423, 2048 }, - { 5, 1424, 2048 }, { 6, 1425, 2048 }, { 6, 1426, 2048 }, { 7, 1427, 2048 }, { 6, 1428, 2048 }, { 7, 1429, 2048 }, { 7, 1430, 2048 }, { 8, 1431, 2048 }, - { 6, 1432, 2048 }, { 7, 1433, 2048 }, { 7, 1434, 2048 }, { 8, 1435, 2048 }, { 7, 1436, 2048 }, { 8, 1437, 2048 }, { 8, 1438, 2048 }, { 9, 1439, 2048 }, - { 5, 1440, 2048 }, { 6, 1441, 2048 }, { 6, 1442, 2048 }, { 7, 1443, 2048 }, { 6, 1444, 2048 }, { 7, 1445, 2048 }, { 7, 1446, 2048 }, { 8, 1447, 2048 }, - { 6, 1448, 2048 }, { 7, 1449, 2048 }, { 7, 1450, 2048 }, { 8, 1451, 2048 }, { 7, 1452, 2048 }, { 8, 1453, 2048 }, { 8, 1454, 2048 }, { 9, 1455, 2048 }, - { 6, 1456, 2048 }, { 7, 1457, 2048 }, { 7, 1458, 2048 }, { 8, 1459, 2048 }, { 7, 1460, 2048 }, { 8, 1461, 2048 }, { 8, 1462, 2048 }, { 9, 1463, 2048 }, - { 7, 1464, 2048 }, { 8, 1465, 2048 }, { 8, 1466, 2048 }, { 9, 1467, 2048 }, { 8, 1468, 2048 }, { 9, 1469, 2048 }, { 9, 1470, 2048 }, { 10, 1471, 2048 }, - { 5, 1472, 2048 }, { 6, 1473, 2048 }, { 6, 1474, 2048 }, { 7, 1475, 2048 }, { 6, 1476, 2048 }, { 7, 1477, 2048 }, { 7, 1478, 2048 }, { 8, 1479, 2048 }, - { 6, 1480, 2048 }, { 7, 1481, 2048 }, { 7, 1482, 2048 }, { 8, 1483, 2048 }, { 7, 1484, 2048 }, { 8, 1485, 2048 }, { 8, 1486, 2048 }, { 9, 1487, 2048 }, - { 6, 1488, 2048 }, { 7, 1489, 2048 }, { 7, 1490, 2048 }, { 8, 1491, 2048 }, { 7, 1492, 2048 }, { 8, 1493, 2048 }, { 8, 1494, 2048 }, { 9, 1495, 2048 }, - { 7, 1496, 2048 }, { 8, 1497, 2048 }, { 8, 1498, 2048 }, { 9, 1499, 2048 }, { 8, 1500, 2048 }, { 9, 1501, 2048 }, { 9, 1502, 2048 }, { 10, 1503, 2048 }, - { 6, 1504, 2048 }, { 7, 1505, 2048 }, { 7, 1506, 2048 }, { 8, 1507, 2048 }, { 7, 1508, 2048 }, { 8, 1509, 2048 }, { 8, 1510, 2048 }, { 9, 1511, 2048 }, - { 7, 1512, 2048 }, { 8, 1513, 2048 }, { 8, 1514, 2048 }, { 9, 1515, 2048 }, { 8, 1516, 2048 }, { 9, 1517, 2048 }, { 9, 1518, 2048 }, { 10, 1519, 2048 }, - { 7, 1520, 2048 }, { 8, 1521, 2048 }, { 8, 1522, 2048 }, { 9, 1523, 2048 }, { 8, 1524, 2048 }, { 9, 1525, 2048 }, { 9, 1526, 2048 }, { 10, 1527, 2048 }, - { 8, 1528, 2048 }, { 9, 1529, 2048 }, { 9, 1530, 2048 }, { 10, 1531, 2048 }, { 9, 1532, 2048 }, { 10, 1533, 2048 }, { 10, 1534, 2048 }, { 11, 1535, 2048 }, - { 3, 1536, 2048 }, { 4, 1537, 2048 }, { 4, 1538, 2048 }, { 5, 1539, 2048 }, { 4, 1540, 2048 }, { 5, 1541, 2048 }, { 5, 1542, 2048 }, { 6, 1543, 2048 }, - { 4, 1544, 2048 }, { 5, 1545, 2048 }, { 5, 1546, 2048 }, { 6, 1547, 2048 }, { 5, 1548, 2048 }, { 6, 1549, 2048 }, { 6, 1550, 2048 }, { 7, 1551, 2048 }, - { 4, 1552, 2048 }, { 5, 1553, 2048 }, { 5, 1554, 2048 }, { 6, 1555, 2048 }, { 5, 1556, 2048 }, { 6, 1557, 2048 }, { 6, 1558, 2048 }, { 7, 1559, 2048 }, - { 5, 1560, 2048 }, { 6, 1561, 2048 }, { 6, 1562, 2048 }, { 7, 1563, 2048 }, { 6, 1564, 2048 }, { 7, 1565, 2048 }, { 7, 1566, 2048 }, { 8, 1567, 2048 }, - { 4, 1568, 2048 }, { 5, 1569, 2048 }, { 5, 1570, 2048 }, { 6, 1571, 2048 }, { 5, 1572, 2048 }, { 6, 1573, 2048 }, { 6, 1574, 2048 }, { 7, 1575, 2048 }, - { 5, 1576, 2048 }, { 6, 1577, 2048 }, { 6, 1578, 2048 }, { 7, 1579, 2048 }, { 6, 1580, 2048 }, { 7, 1581, 2048 }, { 7, 1582, 2048 }, { 8, 1583, 2048 }, - { 5, 1584, 2048 }, { 6, 1585, 2048 }, { 6, 1586, 2048 }, { 7, 1587, 2048 }, { 6, 1588, 2048 }, { 7, 1589, 2048 }, { 7, 1590, 2048 }, { 8, 1591, 2048 }, - { 6, 1592, 2048 }, { 7, 1593, 2048 }, { 7, 1594, 2048 }, { 8, 1595, 2048 }, { 7, 1596, 2048 }, { 8, 1597, 2048 }, { 8, 1598, 2048 }, { 9, 1599, 2048 }, - { 4, 1600, 2048 }, { 5, 1601, 2048 }, { 5, 1602, 2048 }, { 6, 1603, 2048 }, { 5, 1604, 2048 }, { 6, 1605, 2048 }, { 6, 1606, 2048 }, { 7, 1607, 2048 }, - { 5, 1608, 2048 }, { 6, 1609, 2048 }, { 6, 1610, 2048 }, { 7, 1611, 2048 }, { 6, 1612, 2048 }, { 7, 1613, 2048 }, { 7, 1614, 2048 }, { 8, 1615, 2048 }, - { 5, 1616, 2048 }, { 6, 1617, 2048 }, { 6, 1618, 2048 }, { 7, 1619, 2048 }, { 6, 1620, 2048 }, { 7, 1621, 2048 }, { 7, 1622, 2048 }, { 8, 1623, 2048 }, - { 6, 1624, 2048 }, { 7, 1625, 2048 }, { 7, 1626, 2048 }, { 8, 1627, 2048 }, { 7, 1628, 2048 }, { 8, 1629, 2048 }, { 8, 1630, 2048 }, { 9, 1631, 2048 }, - { 5, 1632, 2048 }, { 6, 1633, 2048 }, { 6, 1634, 2048 }, { 7, 1635, 2048 }, { 6, 1636, 2048 }, { 7, 1637, 2048 }, { 7, 1638, 2048 }, { 8, 1639, 2048 }, - { 6, 1640, 2048 }, { 7, 1641, 2048 }, { 7, 1642, 2048 }, { 8, 1643, 2048 }, { 7, 1644, 2048 }, { 8, 1645, 2048 }, { 8, 1646, 2048 }, { 9, 1647, 2048 }, - { 6, 1648, 2048 }, { 7, 1649, 2048 }, { 7, 1650, 2048 }, { 8, 1651, 2048 }, { 7, 1652, 2048 }, { 8, 1653, 2048 }, { 8, 1654, 2048 }, { 9, 1655, 2048 }, - { 7, 1656, 2048 }, { 8, 1657, 2048 }, { 8, 1658, 2048 }, { 9, 1659, 2048 }, { 8, 1660, 2048 }, { 9, 1661, 2048 }, { 9, 1662, 2048 }, { 10, 1663, 2048 }, - { 4, 1664, 2048 }, { 5, 1665, 2048 }, { 5, 1666, 2048 }, { 6, 1667, 2048 }, { 5, 1668, 2048 }, { 6, 1669, 2048 }, { 6, 1670, 2048 }, { 7, 1671, 2048 }, - { 5, 1672, 2048 }, { 6, 1673, 2048 }, { 6, 1674, 2048 }, { 7, 1675, 2048 }, { 6, 1676, 2048 }, { 7, 1677, 2048 }, { 7, 1678, 2048 }, { 8, 1679, 2048 }, - { 5, 1680, 2048 }, { 6, 1681, 2048 }, { 6, 1682, 2048 }, { 7, 1683, 2048 }, { 6, 1684, 2048 }, { 7, 1685, 2048 }, { 7, 1686, 2048 }, { 8, 1687, 2048 }, - { 6, 1688, 2048 }, { 7, 1689, 2048 }, { 7, 1690, 2048 }, { 8, 1691, 2048 }, { 7, 1692, 2048 }, { 8, 1693, 2048 }, { 8, 1694, 2048 }, { 9, 1695, 2048 }, - { 5, 1696, 2048 }, { 6, 1697, 2048 }, { 6, 1698, 2048 }, { 7, 1699, 2048 }, { 6, 1700, 2048 }, { 7, 1701, 2048 }, { 7, 1702, 2048 }, { 8, 1703, 2048 }, - { 6, 1704, 2048 }, { 7, 1705, 2048 }, { 7, 1706, 2048 }, { 8, 1707, 2048 }, { 7, 1708, 2048 }, { 8, 1709, 2048 }, { 8, 1710, 2048 }, { 9, 1711, 2048 }, - { 6, 1712, 2048 }, { 7, 1713, 2048 }, { 7, 1714, 2048 }, { 8, 1715, 2048 }, { 7, 1716, 2048 }, { 8, 1717, 2048 }, { 8, 1718, 2048 }, { 9, 1719, 2048 }, - { 7, 1720, 2048 }, { 8, 1721, 2048 }, { 8, 1722, 2048 }, { 9, 1723, 2048 }, { 8, 1724, 2048 }, { 9, 1725, 2048 }, { 9, 1726, 2048 }, { 10, 1727, 2048 }, - { 5, 1728, 2048 }, { 6, 1729, 2048 }, { 6, 1730, 2048 }, { 7, 1731, 2048 }, { 6, 1732, 2048 }, { 7, 1733, 2048 }, { 7, 1734, 2048 }, { 8, 1735, 2048 }, - { 6, 1736, 2048 }, { 7, 1737, 2048 }, { 7, 1738, 2048 }, { 8, 1739, 2048 }, { 7, 1740, 2048 }, { 8, 1741, 2048 }, { 8, 1742, 2048 }, { 9, 1743, 2048 }, - { 6, 1744, 2048 }, { 7, 1745, 2048 }, { 7, 1746, 2048 }, { 8, 1747, 2048 }, { 7, 1748, 2048 }, { 8, 1749, 2048 }, { 8, 1750, 2048 }, { 9, 1751, 2048 }, - { 7, 1752, 2048 }, { 8, 1753, 2048 }, { 8, 1754, 2048 }, { 9, 1755, 2048 }, { 8, 1756, 2048 }, { 9, 1757, 2048 }, { 9, 1758, 2048 }, { 10, 1759, 2048 }, - { 6, 1760, 2048 }, { 7, 1761, 2048 }, { 7, 1762, 2048 }, { 8, 1763, 2048 }, { 7, 1764, 2048 }, { 8, 1765, 2048 }, { 8, 1766, 2048 }, { 9, 1767, 2048 }, - { 7, 1768, 2048 }, { 8, 1769, 2048 }, { 8, 1770, 2048 }, { 9, 1771, 2048 }, { 8, 1772, 2048 }, { 9, 1773, 2048 }, { 9, 1774, 2048 }, { 10, 1775, 2048 }, - { 7, 1776, 2048 }, { 8, 1777, 2048 }, { 8, 1778, 2048 }, { 9, 1779, 2048 }, { 8, 1780, 2048 }, { 9, 1781, 2048 }, { 9, 1782, 2048 }, { 10, 1783, 2048 }, - { 8, 1784, 2048 }, { 9, 1785, 2048 }, { 9, 1786, 2048 }, { 10, 1787, 2048 }, { 9, 1788, 2048 }, { 10, 1789, 2048 }, { 10, 1790, 2048 }, { 11, 1791, 2048 }, - { 4, 1792, 2048 }, { 5, 1793, 2048 }, { 5, 1794, 2048 }, { 6, 1795, 2048 }, { 5, 1796, 2048 }, { 6, 1797, 2048 }, { 6, 1798, 2048 }, { 7, 1799, 2048 }, - { 5, 1800, 2048 }, { 6, 1801, 2048 }, { 6, 1802, 2048 }, { 7, 1803, 2048 }, { 6, 1804, 2048 }, { 7, 1805, 2048 }, { 7, 1806, 2048 }, { 8, 1807, 2048 }, - { 5, 1808, 2048 }, { 6, 1809, 2048 }, { 6, 1810, 2048 }, { 7, 1811, 2048 }, { 6, 1812, 2048 }, { 7, 1813, 2048 }, { 7, 1814, 2048 }, { 8, 1815, 2048 }, - { 6, 1816, 2048 }, { 7, 1817, 2048 }, { 7, 1818, 2048 }, { 8, 1819, 2048 }, { 7, 1820, 2048 }, { 8, 1821, 2048 }, { 8, 1822, 2048 }, { 9, 1823, 2048 }, - { 5, 1824, 2048 }, { 6, 1825, 2048 }, { 6, 1826, 2048 }, { 7, 1827, 2048 }, { 6, 1828, 2048 }, { 7, 1829, 2048 }, { 7, 1830, 2048 }, { 8, 1831, 2048 }, - { 6, 1832, 2048 }, { 7, 1833, 2048 }, { 7, 1834, 2048 }, { 8, 1835, 2048 }, { 7, 1836, 2048 }, { 8, 1837, 2048 }, { 8, 1838, 2048 }, { 9, 1839, 2048 }, - { 6, 1840, 2048 }, { 7, 1841, 2048 }, { 7, 1842, 2048 }, { 8, 1843, 2048 }, { 7, 1844, 2048 }, { 8, 1845, 2048 }, { 8, 1846, 2048 }, { 9, 1847, 2048 }, - { 7, 1848, 2048 }, { 8, 1849, 2048 }, { 8, 1850, 2048 }, { 9, 1851, 2048 }, { 8, 1852, 2048 }, { 9, 1853, 2048 }, { 9, 1854, 2048 }, { 10, 1855, 2048 }, - { 5, 1856, 2048 }, { 6, 1857, 2048 }, { 6, 1858, 2048 }, { 7, 1859, 2048 }, { 6, 1860, 2048 }, { 7, 1861, 2048 }, { 7, 1862, 2048 }, { 8, 1863, 2048 }, - { 6, 1864, 2048 }, { 7, 1865, 2048 }, { 7, 1866, 2048 }, { 8, 1867, 2048 }, { 7, 1868, 2048 }, { 8, 1869, 2048 }, { 8, 1870, 2048 }, { 9, 1871, 2048 }, - { 6, 1872, 2048 }, { 7, 1873, 2048 }, { 7, 1874, 2048 }, { 8, 1875, 2048 }, { 7, 1876, 2048 }, { 8, 1877, 2048 }, { 8, 1878, 2048 }, { 9, 1879, 2048 }, - { 7, 1880, 2048 }, { 8, 1881, 2048 }, { 8, 1882, 2048 }, { 9, 1883, 2048 }, { 8, 1884, 2048 }, { 9, 1885, 2048 }, { 9, 1886, 2048 }, { 10, 1887, 2048 }, - { 6, 1888, 2048 }, { 7, 1889, 2048 }, { 7, 1890, 2048 }, { 8, 1891, 2048 }, { 7, 1892, 2048 }, { 8, 1893, 2048 }, { 8, 1894, 2048 }, { 9, 1895, 2048 }, - { 7, 1896, 2048 }, { 8, 1897, 2048 }, { 8, 1898, 2048 }, { 9, 1899, 2048 }, { 8, 1900, 2048 }, { 9, 1901, 2048 }, { 9, 1902, 2048 }, { 10, 1903, 2048 }, - { 7, 1904, 2048 }, { 8, 1905, 2048 }, { 8, 1906, 2048 }, { 9, 1907, 2048 }, { 8, 1908, 2048 }, { 9, 1909, 2048 }, { 9, 1910, 2048 }, { 10, 1911, 2048 }, - { 8, 1912, 2048 }, { 9, 1913, 2048 }, { 9, 1914, 2048 }, { 10, 1915, 2048 }, { 9, 1916, 2048 }, { 10, 1917, 2048 }, { 10, 1918, 2048 }, { 11, 1919, 2048 }, - { 5, 1920, 2048 }, { 6, 1921, 2048 }, { 6, 1922, 2048 }, { 7, 1923, 2048 }, { 6, 1924, 2048 }, { 7, 1925, 2048 }, { 7, 1926, 2048 }, { 8, 1927, 2048 }, - { 6, 1928, 2048 }, { 7, 1929, 2048 }, { 7, 1930, 2048 }, { 8, 1931, 2048 }, { 7, 1932, 2048 }, { 8, 1933, 2048 }, { 8, 1934, 2048 }, { 9, 1935, 2048 }, - { 6, 1936, 2048 }, { 7, 1937, 2048 }, { 7, 1938, 2048 }, { 8, 1939, 2048 }, { 7, 1940, 2048 }, { 8, 1941, 2048 }, { 8, 1942, 2048 }, { 9, 1943, 2048 }, - { 7, 1944, 2048 }, { 8, 1945, 2048 }, { 8, 1946, 2048 }, { 9, 1947, 2048 }, { 8, 1948, 2048 }, { 9, 1949, 2048 }, { 9, 1950, 2048 }, { 10, 1951, 2048 }, - { 6, 1952, 2048 }, { 7, 1953, 2048 }, { 7, 1954, 2048 }, { 8, 1955, 2048 }, { 7, 1956, 2048 }, { 8, 1957, 2048 }, { 8, 1958, 2048 }, { 9, 1959, 2048 }, - { 7, 1960, 2048 }, { 8, 1961, 2048 }, { 8, 1962, 2048 }, { 9, 1963, 2048 }, { 8, 1964, 2048 }, { 9, 1965, 2048 }, { 9, 1966, 2048 }, { 10, 1967, 2048 }, - { 7, 1968, 2048 }, { 8, 1969, 2048 }, { 8, 1970, 2048 }, { 9, 1971, 2048 }, { 8, 1972, 2048 }, { 9, 1973, 2048 }, { 9, 1974, 2048 }, { 10, 1975, 2048 }, - { 8, 1976, 2048 }, { 9, 1977, 2048 }, { 9, 1978, 2048 }, { 10, 1979, 2048 }, { 9, 1980, 2048 }, { 10, 1981, 2048 }, { 10, 1982, 2048 }, { 11, 1983, 2048 }, - { 6, 1984, 2048 }, { 7, 1985, 2048 }, { 7, 1986, 2048 }, { 8, 1987, 2048 }, { 7, 1988, 2048 }, { 8, 1989, 2048 }, { 8, 1990, 2048 }, { 9, 1991, 2048 }, - { 7, 1992, 2048 }, { 8, 1993, 2048 }, { 8, 1994, 2048 }, { 9, 1995, 2048 }, { 8, 1996, 2048 }, { 9, 1997, 2048 }, { 9, 1998, 2048 }, { 10, 1999, 2048 }, - { 7, 2000, 2048 }, { 8, 2001, 2048 }, { 8, 2002, 2048 }, { 9, 2003, 2048 }, { 8, 2004, 2048 }, { 9, 2005, 2048 }, { 9, 2006, 2048 }, { 10, 2007, 2048 }, - { 8, 2008, 2048 }, { 9, 2009, 2048 }, { 9, 2010, 2048 }, { 10, 2011, 2048 }, { 9, 2012, 2048 }, { 10, 2013, 2048 }, { 10, 2014, 2048 }, { 11, 2015, 2048 }, - { 7, 2016, 2048 }, { 8, 2017, 2048 }, { 8, 2018, 2048 }, { 9, 2019, 2048 }, { 8, 2020, 2048 }, { 9, 2021, 2048 }, { 9, 2022, 2048 }, { 10, 2023, 2048 }, - { 8, 2024, 2048 }, { 9, 2025, 2048 }, { 9, 2026, 2048 }, { 10, 2027, 2048 }, { 9, 2028, 2048 }, { 10, 2029, 2048 }, { 10, 2030, 2048 }, { 11, 2031, 2048 }, - { 8, 2032, 2048 }, { 9, 2033, 2048 }, { 9, 2034, 2048 }, { 10, 2035, 2048 }, { 9, 2036, 2048 }, { 10, 2037, 2048 }, { 10, 2038, 2048 }, { 11, 2039, 2048 }, - { 9, 2040, 2048 }, { 10, 2041, 2048 }, { 10, 2042, 2048 }, { 11, 2043, 2048 }, { 10, 2044, 2048 }, { 11, 2045, 2048 }, { 11, 2046, 2048 }, { 12, 2047, 2048 }, + { 1, 0, 0 }, { 2, 1, 2048 }, { 2, 2, 2048 }, { 3, 3, 2048 }, { 2, 4, 2048 }, { 3, 5, 2048 }, { 3, 6, 2048 }, { 4, 7, 2048 }, + { 2, 8, 2048 }, { 3, 9, 2048 }, { 3, 10, 2048 }, { 4, 11, 2048 }, { 3, 12, 2048 }, { 4, 13, 2048 }, { 4, 14, 2048 }, { 5, 15, 2048 }, + { 2, 16, 2048 }, { 3, 17, 2048 }, { 3, 18, 2048 }, { 4, 19, 2048 }, { 3, 20, 2048 }, { 4, 21, 2048 }, { 4, 22, 2048 }, { 5, 23, 2048 }, + { 3, 24, 2048 }, { 4, 25, 2048 }, { 4, 26, 2048 }, { 5, 27, 2048 }, { 4, 28, 2048 }, { 5, 29, 2048 }, { 5, 30, 2048 }, { 6, 31, 2048 }, + { 2, 32, 2048 }, { 3, 33, 2048 }, { 3, 34, 2048 }, { 4, 35, 2048 }, { 3, 36, 2048 }, { 4, 37, 2048 }, { 4, 38, 2048 }, { 5, 39, 2048 }, + { 3, 40, 2048 }, { 4, 41, 2048 }, { 4, 42, 2048 }, { 5, 43, 2048 }, { 4, 44, 2048 }, { 5, 45, 2048 }, { 5, 46, 2048 }, { 6, 47, 2048 }, + { 3, 48, 2048 }, { 4, 49, 2048 }, { 4, 50, 2048 }, { 5, 51, 2048 }, { 4, 52, 2048 }, { 5, 53, 2048 }, { 5, 54, 2048 }, { 6, 55, 2048 }, + { 4, 56, 2048 }, { 5, 57, 2048 }, { 5, 58, 2048 }, { 6, 59, 2048 }, { 5, 60, 2048 }, { 6, 61, 2048 }, { 6, 62, 2048 }, { 7, 63, 2048 }, + { 2, 64, 2048 }, { 3, 65, 2048 }, { 3, 66, 2048 }, { 4, 67, 2048 }, { 3, 68, 2048 }, { 4, 69, 2048 }, { 4, 70, 2048 }, { 5, 71, 2048 }, + { 3, 72, 2048 }, { 4, 73, 2048 }, { 4, 74, 2048 }, { 5, 75, 2048 }, { 4, 76, 2048 }, { 5, 77, 2048 }, { 5, 78, 2048 }, { 6, 79, 2048 }, + { 3, 80, 2048 }, { 4, 81, 2048 }, { 4, 82, 2048 }, { 5, 83, 2048 }, { 4, 84, 2048 }, { 5, 85, 2048 }, { 5, 86, 2048 }, { 6, 87, 2048 }, + { 4, 88, 2048 }, { 5, 89, 2048 }, { 5, 90, 2048 }, { 6, 91, 2048 }, { 5, 92, 2048 }, { 6, 93, 2048 }, { 6, 94, 2048 }, { 7, 95, 2048 }, + { 3, 96, 2048 }, { 4, 97, 2048 }, { 4, 98, 2048 }, { 5, 99, 2048 }, { 4, 100, 2048 }, { 5, 101, 2048 }, { 5, 102, 2048 }, { 6, 103, 2048 }, + { 4, 104, 2048 }, { 5, 105, 2048 }, { 5, 106, 2048 }, { 6, 107, 2048 }, { 5, 108, 2048 }, { 6, 109, 2048 }, { 6, 110, 2048 }, { 7, 111, 2048 }, + { 4, 112, 2048 }, { 5, 113, 2048 }, { 5, 114, 2048 }, { 6, 115, 2048 }, { 5, 116, 2048 }, { 6, 117, 2048 }, { 6, 118, 2048 }, { 7, 119, 2048 }, + { 5, 120, 2048 }, { 6, 121, 2048 }, { 6, 122, 2048 }, { 7, 123, 2048 }, { 6, 124, 2048 }, { 7, 125, 2048 }, { 7, 126, 2048 }, { 8, 127, 2048 }, + { 2, 128, 2048 }, { 3, 129, 2048 }, { 3, 130, 2048 }, { 4, 131, 2048 }, { 3, 132, 2048 }, { 4, 133, 2048 }, { 4, 134, 2048 }, { 5, 135, 2048 }, + { 3, 136, 2048 }, { 4, 137, 2048 }, { 4, 138, 2048 }, { 5, 139, 2048 }, { 4, 140, 2048 }, { 5, 141, 2048 }, { 5, 142, 2048 }, { 6, 143, 2048 }, + { 3, 144, 2048 }, { 4, 145, 2048 }, { 4, 146, 2048 }, { 5, 147, 2048 }, { 4, 148, 2048 }, { 5, 149, 2048 }, { 5, 150, 2048 }, { 6, 151, 2048 }, + { 4, 152, 2048 }, { 5, 153, 2048 }, { 5, 154, 2048 }, { 6, 155, 2048 }, { 5, 156, 2048 }, { 6, 157, 2048 }, { 6, 158, 2048 }, { 7, 159, 2048 }, + { 3, 160, 2048 }, { 4, 161, 2048 }, { 4, 162, 2048 }, { 5, 163, 2048 }, { 4, 164, 2048 }, { 5, 165, 2048 }, { 5, 166, 2048 }, { 6, 167, 2048 }, + { 4, 168, 2048 }, { 5, 169, 2048 }, { 5, 170, 2048 }, { 6, 171, 2048 }, { 5, 172, 2048 }, { 6, 173, 2048 }, { 6, 174, 2048 }, { 7, 175, 2048 }, + { 4, 176, 2048 }, { 5, 177, 2048 }, { 5, 178, 2048 }, { 6, 179, 2048 }, { 5, 180, 2048 }, { 6, 181, 2048 }, { 6, 182, 2048 }, { 7, 183, 2048 }, + { 5, 184, 2048 }, { 6, 185, 2048 }, { 6, 186, 2048 }, { 7, 187, 2048 }, { 6, 188, 2048 }, { 7, 189, 2048 }, { 7, 190, 2048 }, { 8, 191, 2048 }, + { 3, 192, 2048 }, { 4, 193, 2048 }, { 4, 194, 2048 }, { 5, 195, 2048 }, { 4, 196, 2048 }, { 5, 197, 2048 }, { 5, 198, 2048 }, { 6, 199, 2048 }, + { 4, 200, 2048 }, { 5, 201, 2048 }, { 5, 202, 2048 }, { 6, 203, 2048 }, { 5, 204, 2048 }, { 6, 205, 2048 }, { 6, 206, 2048 }, { 7, 207, 2048 }, + { 4, 208, 2048 }, { 5, 209, 2048 }, { 5, 210, 2048 }, { 6, 211, 2048 }, { 5, 212, 2048 }, { 6, 213, 2048 }, { 6, 214, 2048 }, { 7, 215, 2048 }, + { 5, 216, 2048 }, { 6, 217, 2048 }, { 6, 218, 2048 }, { 7, 219, 2048 }, { 6, 220, 2048 }, { 7, 221, 2048 }, { 7, 222, 2048 }, { 8, 223, 2048 }, + { 4, 224, 2048 }, { 5, 225, 2048 }, { 5, 226, 2048 }, { 6, 227, 2048 }, { 5, 228, 2048 }, { 6, 229, 2048 }, { 6, 230, 2048 }, { 7, 231, 2048 }, + { 5, 232, 2048 }, { 6, 233, 2048 }, { 6, 234, 2048 }, { 7, 235, 2048 }, { 6, 236, 2048 }, { 7, 237, 2048 }, { 7, 238, 2048 }, { 8, 239, 2048 }, + { 5, 240, 2048 }, { 6, 241, 2048 }, { 6, 242, 2048 }, { 7, 243, 2048 }, { 6, 244, 2048 }, { 7, 245, 2048 }, { 7, 246, 2048 }, { 8, 247, 2048 }, + { 6, 248, 2048 }, { 7, 249, 2048 }, { 7, 250, 2048 }, { 8, 251, 2048 }, { 7, 252, 2048 }, { 8, 253, 2048 }, { 8, 254, 2048 }, { 9, 255, 2048 }, + { 2, 256, 2048 }, { 3, 257, 2048 }, { 3, 258, 2048 }, { 4, 259, 2048 }, { 3, 260, 2048 }, { 4, 261, 2048 }, { 4, 262, 2048 }, { 5, 263, 2048 }, + { 3, 264, 2048 }, { 4, 265, 2048 }, { 4, 266, 2048 }, { 5, 267, 2048 }, { 4, 268, 2048 }, { 5, 269, 2048 }, { 5, 270, 2048 }, { 6, 271, 2048 }, + { 3, 272, 2048 }, { 4, 273, 2048 }, { 4, 274, 2048 }, { 5, 275, 2048 }, { 4, 276, 2048 }, { 5, 277, 2048 }, { 5, 278, 2048 }, { 6, 279, 2048 }, + { 4, 280, 2048 }, { 5, 281, 2048 }, { 5, 282, 2048 }, { 6, 283, 2048 }, { 5, 284, 2048 }, { 6, 285, 2048 }, { 6, 286, 2048 }, { 7, 287, 2048 }, + { 3, 288, 2048 }, { 4, 289, 2048 }, { 4, 290, 2048 }, { 5, 291, 2048 }, { 4, 292, 2048 }, { 5, 293, 2048 }, { 5, 294, 2048 }, { 6, 295, 2048 }, + { 4, 296, 2048 }, { 5, 297, 2048 }, { 5, 298, 2048 }, { 6, 299, 2048 }, { 5, 300, 2048 }, { 6, 301, 2048 }, { 6, 302, 2048 }, { 7, 303, 2048 }, + { 4, 304, 2048 }, { 5, 305, 2048 }, { 5, 306, 2048 }, { 6, 307, 2048 }, { 5, 308, 2048 }, { 6, 309, 2048 }, { 6, 310, 2048 }, { 7, 311, 2048 }, + { 5, 312, 2048 }, { 6, 313, 2048 }, { 6, 314, 2048 }, { 7, 315, 2048 }, { 6, 316, 2048 }, { 7, 317, 2048 }, { 7, 318, 2048 }, { 8, 319, 2048 }, + { 3, 320, 2048 }, { 4, 321, 2048 }, { 4, 322, 2048 }, { 5, 323, 2048 }, { 4, 324, 2048 }, { 5, 325, 2048 }, { 5, 326, 2048 }, { 6, 327, 2048 }, + { 4, 328, 2048 }, { 5, 329, 2048 }, { 5, 330, 2048 }, { 6, 331, 2048 }, { 5, 332, 2048 }, { 6, 333, 2048 }, { 6, 334, 2048 }, { 7, 335, 2048 }, + { 4, 336, 2048 }, { 5, 337, 2048 }, { 5, 338, 2048 }, { 6, 339, 2048 }, { 5, 340, 2048 }, { 6, 341, 2048 }, { 6, 342, 2048 }, { 7, 343, 2048 }, + { 5, 344, 2048 }, { 6, 345, 2048 }, { 6, 346, 2048 }, { 7, 347, 2048 }, { 6, 348, 2048 }, { 7, 349, 2048 }, { 7, 350, 2048 }, { 8, 351, 2048 }, + { 4, 352, 2048 }, { 5, 353, 2048 }, { 5, 354, 2048 }, { 6, 355, 2048 }, { 5, 356, 2048 }, { 6, 357, 2048 }, { 6, 358, 2048 }, { 7, 359, 2048 }, + { 5, 360, 2048 }, { 6, 361, 2048 }, { 6, 362, 2048 }, { 7, 363, 2048 }, { 6, 364, 2048 }, { 7, 365, 2048 }, { 7, 366, 2048 }, { 8, 367, 2048 }, + { 5, 368, 2048 }, { 6, 369, 2048 }, { 6, 370, 2048 }, { 7, 371, 2048 }, { 6, 372, 2048 }, { 7, 373, 2048 }, { 7, 374, 2048 }, { 8, 375, 2048 }, + { 6, 376, 2048 }, { 7, 377, 2048 }, { 7, 378, 2048 }, { 8, 379, 2048 }, { 7, 380, 2048 }, { 8, 381, 2048 }, { 8, 382, 2048 }, { 9, 383, 2048 }, + { 3, 384, 2048 }, { 4, 385, 2048 }, { 4, 386, 2048 }, { 5, 387, 2048 }, { 4, 388, 2048 }, { 5, 389, 2048 }, { 5, 390, 2048 }, { 6, 391, 2048 }, + { 4, 392, 2048 }, { 5, 393, 2048 }, { 5, 394, 2048 }, { 6, 395, 2048 }, { 5, 396, 2048 }, { 6, 397, 2048 }, { 6, 398, 2048 }, { 7, 399, 2048 }, + { 4, 400, 2048 }, { 5, 401, 2048 }, { 5, 402, 2048 }, { 6, 403, 2048 }, { 5, 404, 2048 }, { 6, 405, 2048 }, { 6, 406, 2048 }, { 7, 407, 2048 }, + { 5, 408, 2048 }, { 6, 409, 2048 }, { 6, 410, 2048 }, { 7, 411, 2048 }, { 6, 412, 2048 }, { 7, 413, 2048 }, { 7, 414, 2048 }, { 8, 415, 2048 }, + { 4, 416, 2048 }, { 5, 417, 2048 }, { 5, 418, 2048 }, { 6, 419, 2048 }, { 5, 420, 2048 }, { 6, 421, 2048 }, { 6, 422, 2048 }, { 7, 423, 2048 }, + { 5, 424, 2048 }, { 6, 425, 2048 }, { 6, 426, 2048 }, { 7, 427, 2048 }, { 6, 428, 2048 }, { 7, 429, 2048 }, { 7, 430, 2048 }, { 8, 431, 2048 }, + { 5, 432, 2048 }, { 6, 433, 2048 }, { 6, 434, 2048 }, { 7, 435, 2048 }, { 6, 436, 2048 }, { 7, 437, 2048 }, { 7, 438, 2048 }, { 8, 439, 2048 }, + { 6, 440, 2048 }, { 7, 441, 2048 }, { 7, 442, 2048 }, { 8, 443, 2048 }, { 7, 444, 2048 }, { 8, 445, 2048 }, { 8, 446, 2048 }, { 9, 447, 2048 }, + { 4, 448, 2048 }, { 5, 449, 2048 }, { 5, 450, 2048 }, { 6, 451, 2048 }, { 5, 452, 2048 }, { 6, 453, 2048 }, { 6, 454, 2048 }, { 7, 455, 2048 }, + { 5, 456, 2048 }, { 6, 457, 2048 }, { 6, 458, 2048 }, { 7, 459, 2048 }, { 6, 460, 2048 }, { 7, 461, 2048 }, { 7, 462, 2048 }, { 8, 463, 2048 }, + { 5, 464, 2048 }, { 6, 465, 2048 }, { 6, 466, 2048 }, { 7, 467, 2048 }, { 6, 468, 2048 }, { 7, 469, 2048 }, { 7, 470, 2048 }, { 8, 471, 2048 }, + { 6, 472, 2048 }, { 7, 473, 2048 }, { 7, 474, 2048 }, { 8, 475, 2048 }, { 7, 476, 2048 }, { 8, 477, 2048 }, { 8, 478, 2048 }, { 9, 479, 2048 }, + { 5, 480, 2048 }, { 6, 481, 2048 }, { 6, 482, 2048 }, { 7, 483, 2048 }, { 6, 484, 2048 }, { 7, 485, 2048 }, { 7, 486, 2048 }, { 8, 487, 2048 }, + { 6, 488, 2048 }, { 7, 489, 2048 }, { 7, 490, 2048 }, { 8, 491, 2048 }, { 7, 492, 2048 }, { 8, 493, 2048 }, { 8, 494, 2048 }, { 9, 495, 2048 }, + { 6, 496, 2048 }, { 7, 497, 2048 }, { 7, 498, 2048 }, { 8, 499, 2048 }, { 7, 500, 2048 }, { 8, 501, 2048 }, { 8, 502, 2048 }, { 9, 503, 2048 }, + { 7, 504, 2048 }, { 8, 505, 2048 }, { 8, 506, 2048 }, { 9, 507, 2048 }, { 8, 508, 2048 }, { 9, 509, 2048 }, { 9, 510, 2048 }, { 10, 511, 2048 }, + { 2, 512, 2048 }, { 3, 513, 2048 }, { 3, 514, 2048 }, { 4, 515, 2048 }, { 3, 516, 2048 }, { 4, 517, 2048 }, { 4, 518, 2048 }, { 5, 519, 2048 }, + { 3, 520, 2048 }, { 4, 521, 2048 }, { 4, 522, 2048 }, { 5, 523, 2048 }, { 4, 524, 2048 }, { 5, 525, 2048 }, { 5, 526, 2048 }, { 6, 527, 2048 }, + { 3, 528, 2048 }, { 4, 529, 2048 }, { 4, 530, 2048 }, { 5, 531, 2048 }, { 4, 532, 2048 }, { 5, 533, 2048 }, { 5, 534, 2048 }, { 6, 535, 2048 }, + { 4, 536, 2048 }, { 5, 537, 2048 }, { 5, 538, 2048 }, { 6, 539, 2048 }, { 5, 540, 2048 }, { 6, 541, 2048 }, { 6, 542, 2048 }, { 7, 543, 2048 }, + { 3, 544, 2048 }, { 4, 545, 2048 }, { 4, 546, 2048 }, { 5, 547, 2048 }, { 4, 548, 2048 }, { 5, 549, 2048 }, { 5, 550, 2048 }, { 6, 551, 2048 }, + { 4, 552, 2048 }, { 5, 553, 2048 }, { 5, 554, 2048 }, { 6, 555, 2048 }, { 5, 556, 2048 }, { 6, 557, 2048 }, { 6, 558, 2048 }, { 7, 559, 2048 }, + { 4, 560, 2048 }, { 5, 561, 2048 }, { 5, 562, 2048 }, { 6, 563, 2048 }, { 5, 564, 2048 }, { 6, 565, 2048 }, { 6, 566, 2048 }, { 7, 567, 2048 }, + { 5, 568, 2048 }, { 6, 569, 2048 }, { 6, 570, 2048 }, { 7, 571, 2048 }, { 6, 572, 2048 }, { 7, 573, 2048 }, { 7, 574, 2048 }, { 8, 575, 2048 }, + { 3, 576, 2048 }, { 4, 577, 2048 }, { 4, 578, 2048 }, { 5, 579, 2048 }, { 4, 580, 2048 }, { 5, 581, 2048 }, { 5, 582, 2048 }, { 6, 583, 2048 }, + { 4, 584, 2048 }, { 5, 585, 2048 }, { 5, 586, 2048 }, { 6, 587, 2048 }, { 5, 588, 2048 }, { 6, 589, 2048 }, { 6, 590, 2048 }, { 7, 591, 2048 }, + { 4, 592, 2048 }, { 5, 593, 2048 }, { 5, 594, 2048 }, { 6, 595, 2048 }, { 5, 596, 2048 }, { 6, 597, 2048 }, { 6, 598, 2048 }, { 7, 599, 2048 }, + { 5, 600, 2048 }, { 6, 601, 2048 }, { 6, 602, 2048 }, { 7, 603, 2048 }, { 6, 604, 2048 }, { 7, 605, 2048 }, { 7, 606, 2048 }, { 8, 607, 2048 }, + { 4, 608, 2048 }, { 5, 609, 2048 }, { 5, 610, 2048 }, { 6, 611, 2048 }, { 5, 612, 2048 }, { 6, 613, 2048 }, { 6, 614, 2048 }, { 7, 615, 2048 }, + { 5, 616, 2048 }, { 6, 617, 2048 }, { 6, 618, 2048 }, { 7, 619, 2048 }, { 6, 620, 2048 }, { 7, 621, 2048 }, { 7, 622, 2048 }, { 8, 623, 2048 }, + { 5, 624, 2048 }, { 6, 625, 2048 }, { 6, 626, 2048 }, { 7, 627, 2048 }, { 6, 628, 2048 }, { 7, 629, 2048 }, { 7, 630, 2048 }, { 8, 631, 2048 }, + { 6, 632, 2048 }, { 7, 633, 2048 }, { 7, 634, 2048 }, { 8, 635, 2048 }, { 7, 636, 2048 }, { 8, 637, 2048 }, { 8, 638, 2048 }, { 9, 639, 2048 }, + { 3, 640, 2048 }, { 4, 641, 2048 }, { 4, 642, 2048 }, { 5, 643, 2048 }, { 4, 644, 2048 }, { 5, 645, 2048 }, { 5, 646, 2048 }, { 6, 647, 2048 }, + { 4, 648, 2048 }, { 5, 649, 2048 }, { 5, 650, 2048 }, { 6, 651, 2048 }, { 5, 652, 2048 }, { 6, 653, 2048 }, { 6, 654, 2048 }, { 7, 655, 2048 }, + { 4, 656, 2048 }, { 5, 657, 2048 }, { 5, 658, 2048 }, { 6, 659, 2048 }, { 5, 660, 2048 }, { 6, 661, 2048 }, { 6, 662, 2048 }, { 7, 663, 2048 }, + { 5, 664, 2048 }, { 6, 665, 2048 }, { 6, 666, 2048 }, { 7, 667, 2048 }, { 6, 668, 2048 }, { 7, 669, 2048 }, { 7, 670, 2048 }, { 8, 671, 2048 }, + { 4, 672, 2048 }, { 5, 673, 2048 }, { 5, 674, 2048 }, { 6, 675, 2048 }, { 5, 676, 2048 }, { 6, 677, 2048 }, { 6, 678, 2048 }, { 7, 679, 2048 }, + { 5, 680, 2048 }, { 6, 681, 2048 }, { 6, 682, 2048 }, { 7, 683, 2048 }, { 6, 684, 2048 }, { 7, 685, 2048 }, { 7, 686, 2048 }, { 8, 687, 2048 }, + { 5, 688, 2048 }, { 6, 689, 2048 }, { 6, 690, 2048 }, { 7, 691, 2048 }, { 6, 692, 2048 }, { 7, 693, 2048 }, { 7, 694, 2048 }, { 8, 695, 2048 }, + { 6, 696, 2048 }, { 7, 697, 2048 }, { 7, 698, 2048 }, { 8, 699, 2048 }, { 7, 700, 2048 }, { 8, 701, 2048 }, { 8, 702, 2048 }, { 9, 703, 2048 }, + { 4, 704, 2048 }, { 5, 705, 2048 }, { 5, 706, 2048 }, { 6, 707, 2048 }, { 5, 708, 2048 }, { 6, 709, 2048 }, { 6, 710, 2048 }, { 7, 711, 2048 }, + { 5, 712, 2048 }, { 6, 713, 2048 }, { 6, 714, 2048 }, { 7, 715, 2048 }, { 6, 716, 2048 }, { 7, 717, 2048 }, { 7, 718, 2048 }, { 8, 719, 2048 }, + { 5, 720, 2048 }, { 6, 721, 2048 }, { 6, 722, 2048 }, { 7, 723, 2048 }, { 6, 724, 2048 }, { 7, 725, 2048 }, { 7, 726, 2048 }, { 8, 727, 2048 }, + { 6, 728, 2048 }, { 7, 729, 2048 }, { 7, 730, 2048 }, { 8, 731, 2048 }, { 7, 732, 2048 }, { 8, 733, 2048 }, { 8, 734, 2048 }, { 9, 735, 2048 }, + { 5, 736, 2048 }, { 6, 737, 2048 }, { 6, 738, 2048 }, { 7, 739, 2048 }, { 6, 740, 2048 }, { 7, 741, 2048 }, { 7, 742, 2048 }, { 8, 743, 2048 }, + { 6, 744, 2048 }, { 7, 745, 2048 }, { 7, 746, 2048 }, { 8, 747, 2048 }, { 7, 748, 2048 }, { 8, 749, 2048 }, { 8, 750, 2048 }, { 9, 751, 2048 }, + { 6, 752, 2048 }, { 7, 753, 2048 }, { 7, 754, 2048 }, { 8, 755, 2048 }, { 7, 756, 2048 }, { 8, 757, 2048 }, { 8, 758, 2048 }, { 9, 759, 2048 }, + { 7, 760, 2048 }, { 8, 761, 2048 }, { 8, 762, 2048 }, { 9, 763, 2048 }, { 8, 764, 2048 }, { 9, 765, 2048 }, { 9, 766, 2048 }, { 10, 767, 2048 }, + { 3, 768, 2048 }, { 4, 769, 2048 }, { 4, 770, 2048 }, { 5, 771, 2048 }, { 4, 772, 2048 }, { 5, 773, 2048 }, { 5, 774, 2048 }, { 6, 775, 2048 }, + { 4, 776, 2048 }, { 5, 777, 2048 }, { 5, 778, 2048 }, { 6, 779, 2048 }, { 5, 780, 2048 }, { 6, 781, 2048 }, { 6, 782, 2048 }, { 7, 783, 2048 }, + { 4, 784, 2048 }, { 5, 785, 2048 }, { 5, 786, 2048 }, { 6, 787, 2048 }, { 5, 788, 2048 }, { 6, 789, 2048 }, { 6, 790, 2048 }, { 7, 791, 2048 }, + { 5, 792, 2048 }, { 6, 793, 2048 }, { 6, 794, 2048 }, { 7, 795, 2048 }, { 6, 796, 2048 }, { 7, 797, 2048 }, { 7, 798, 2048 }, { 8, 799, 2048 }, + { 4, 800, 2048 }, { 5, 801, 2048 }, { 5, 802, 2048 }, { 6, 803, 2048 }, { 5, 804, 2048 }, { 6, 805, 2048 }, { 6, 806, 2048 }, { 7, 807, 2048 }, + { 5, 808, 2048 }, { 6, 809, 2048 }, { 6, 810, 2048 }, { 7, 811, 2048 }, { 6, 812, 2048 }, { 7, 813, 2048 }, { 7, 814, 2048 }, { 8, 815, 2048 }, + { 5, 816, 2048 }, { 6, 817, 2048 }, { 6, 818, 2048 }, { 7, 819, 2048 }, { 6, 820, 2048 }, { 7, 821, 2048 }, { 7, 822, 2048 }, { 8, 823, 2048 }, + { 6, 824, 2048 }, { 7, 825, 2048 }, { 7, 826, 2048 }, { 8, 827, 2048 }, { 7, 828, 2048 }, { 8, 829, 2048 }, { 8, 830, 2048 }, { 9, 831, 2048 }, + { 4, 832, 2048 }, { 5, 833, 2048 }, { 5, 834, 2048 }, { 6, 835, 2048 }, { 5, 836, 2048 }, { 6, 837, 2048 }, { 6, 838, 2048 }, { 7, 839, 2048 }, + { 5, 840, 2048 }, { 6, 841, 2048 }, { 6, 842, 2048 }, { 7, 843, 2048 }, { 6, 844, 2048 }, { 7, 845, 2048 }, { 7, 846, 2048 }, { 8, 847, 2048 }, + { 5, 848, 2048 }, { 6, 849, 2048 }, { 6, 850, 2048 }, { 7, 851, 2048 }, { 6, 852, 2048 }, { 7, 853, 2048 }, { 7, 854, 2048 }, { 8, 855, 2048 }, + { 6, 856, 2048 }, { 7, 857, 2048 }, { 7, 858, 2048 }, { 8, 859, 2048 }, { 7, 860, 2048 }, { 8, 861, 2048 }, { 8, 862, 2048 }, { 9, 863, 2048 }, + { 5, 864, 2048 }, { 6, 865, 2048 }, { 6, 866, 2048 }, { 7, 867, 2048 }, { 6, 868, 2048 }, { 7, 869, 2048 }, { 7, 870, 2048 }, { 8, 871, 2048 }, + { 6, 872, 2048 }, { 7, 873, 2048 }, { 7, 874, 2048 }, { 8, 875, 2048 }, { 7, 876, 2048 }, { 8, 877, 2048 }, { 8, 878, 2048 }, { 9, 879, 2048 }, + { 6, 880, 2048 }, { 7, 881, 2048 }, { 7, 882, 2048 }, { 8, 883, 2048 }, { 7, 884, 2048 }, { 8, 885, 2048 }, { 8, 886, 2048 }, { 9, 887, 2048 }, + { 7, 888, 2048 }, { 8, 889, 2048 }, { 8, 890, 2048 }, { 9, 891, 2048 }, { 8, 892, 2048 }, { 9, 893, 2048 }, { 9, 894, 2048 }, { 10, 895, 2048 }, + { 4, 896, 2048 }, { 5, 897, 2048 }, { 5, 898, 2048 }, { 6, 899, 2048 }, { 5, 900, 2048 }, { 6, 901, 2048 }, { 6, 902, 2048 }, { 7, 903, 2048 }, + { 5, 904, 2048 }, { 6, 905, 2048 }, { 6, 906, 2048 }, { 7, 907, 2048 }, { 6, 908, 2048 }, { 7, 909, 2048 }, { 7, 910, 2048 }, { 8, 911, 2048 }, + { 5, 912, 2048 }, { 6, 913, 2048 }, { 6, 914, 2048 }, { 7, 915, 2048 }, { 6, 916, 2048 }, { 7, 917, 2048 }, { 7, 918, 2048 }, { 8, 919, 2048 }, + { 6, 920, 2048 }, { 7, 921, 2048 }, { 7, 922, 2048 }, { 8, 923, 2048 }, { 7, 924, 2048 }, { 8, 925, 2048 }, { 8, 926, 2048 }, { 9, 927, 2048 }, + { 5, 928, 2048 }, { 6, 929, 2048 }, { 6, 930, 2048 }, { 7, 931, 2048 }, { 6, 932, 2048 }, { 7, 933, 2048 }, { 7, 934, 2048 }, { 8, 935, 2048 }, + { 6, 936, 2048 }, { 7, 937, 2048 }, { 7, 938, 2048 }, { 8, 939, 2048 }, { 7, 940, 2048 }, { 8, 941, 2048 }, { 8, 942, 2048 }, { 9, 943, 2048 }, + { 6, 944, 2048 }, { 7, 945, 2048 }, { 7, 946, 2048 }, { 8, 947, 2048 }, { 7, 948, 2048 }, { 8, 949, 2048 }, { 8, 950, 2048 }, { 9, 951, 2048 }, + { 7, 952, 2048 }, { 8, 953, 2048 }, { 8, 954, 2048 }, { 9, 955, 2048 }, { 8, 956, 2048 }, { 9, 957, 2048 }, { 9, 958, 2048 }, { 10, 959, 2048 }, + { 5, 960, 2048 }, { 6, 961, 2048 }, { 6, 962, 2048 }, { 7, 963, 2048 }, { 6, 964, 2048 }, { 7, 965, 2048 }, { 7, 966, 2048 }, { 8, 967, 2048 }, + { 6, 968, 2048 }, { 7, 969, 2048 }, { 7, 970, 2048 }, { 8, 971, 2048 }, { 7, 972, 2048 }, { 8, 973, 2048 }, { 8, 974, 2048 }, { 9, 975, 2048 }, + { 6, 976, 2048 }, { 7, 977, 2048 }, { 7, 978, 2048 }, { 8, 979, 2048 }, { 7, 980, 2048 }, { 8, 981, 2048 }, { 8, 982, 2048 }, { 9, 983, 2048 }, + { 7, 984, 2048 }, { 8, 985, 2048 }, { 8, 986, 2048 }, { 9, 987, 2048 }, { 8, 988, 2048 }, { 9, 989, 2048 }, { 9, 990, 2048 }, { 10, 991, 2048 }, + { 6, 992, 2048 }, { 7, 993, 2048 }, { 7, 994, 2048 }, { 8, 995, 2048 }, { 7, 996, 2048 }, { 8, 997, 2048 }, { 8, 998, 2048 }, { 9, 999, 2048 }, + { 7, 1000, 2048 }, { 8, 1001, 2048 }, { 8, 1002, 2048 }, { 9, 1003, 2048 }, { 8, 1004, 2048 }, { 9, 1005, 2048 }, { 9, 1006, 2048 }, { 10, 1007, 2048 }, + { 7, 1008, 2048 }, { 8, 1009, 2048 }, { 8, 1010, 2048 }, { 9, 1011, 2048 }, { 8, 1012, 2048 }, { 9, 1013, 2048 }, { 9, 1014, 2048 }, { 10, 1015, 2048 }, + { 8, 1016, 2048 }, { 9, 1017, 2048 }, { 9, 1018, 2048 }, { 10, 1019, 2048 }, { 9, 1020, 2048 }, { 10, 1021, 2048 }, { 10, 1022, 2048 }, { 11, 1023, 2048 }, + { 2, 1024, 2048 }, { 3, 1025, 2048 }, { 3, 1026, 2048 }, { 4, 1027, 2048 }, { 3, 1028, 2048 }, { 4, 1029, 2048 }, { 4, 1030, 2048 }, { 5, 1031, 2048 }, + { 3, 1032, 2048 }, { 4, 1033, 2048 }, { 4, 1034, 2048 }, { 5, 1035, 2048 }, { 4, 1036, 2048 }, { 5, 1037, 2048 }, { 5, 1038, 2048 }, { 6, 1039, 2048 }, + { 3, 1040, 2048 }, { 4, 1041, 2048 }, { 4, 1042, 2048 }, { 5, 1043, 2048 }, { 4, 1044, 2048 }, { 5, 1045, 2048 }, { 5, 1046, 2048 }, { 6, 1047, 2048 }, + { 4, 1048, 2048 }, { 5, 1049, 2048 }, { 5, 1050, 2048 }, { 6, 1051, 2048 }, { 5, 1052, 2048 }, { 6, 1053, 2048 }, { 6, 1054, 2048 }, { 7, 1055, 2048 }, + { 3, 1056, 2048 }, { 4, 1057, 2048 }, { 4, 1058, 2048 }, { 5, 1059, 2048 }, { 4, 1060, 2048 }, { 5, 1061, 2048 }, { 5, 1062, 2048 }, { 6, 1063, 2048 }, + { 4, 1064, 2048 }, { 5, 1065, 2048 }, { 5, 1066, 2048 }, { 6, 1067, 2048 }, { 5, 1068, 2048 }, { 6, 1069, 2048 }, { 6, 1070, 2048 }, { 7, 1071, 2048 }, + { 4, 1072, 2048 }, { 5, 1073, 2048 }, { 5, 1074, 2048 }, { 6, 1075, 2048 }, { 5, 1076, 2048 }, { 6, 1077, 2048 }, { 6, 1078, 2048 }, { 7, 1079, 2048 }, + { 5, 1080, 2048 }, { 6, 1081, 2048 }, { 6, 1082, 2048 }, { 7, 1083, 2048 }, { 6, 1084, 2048 }, { 7, 1085, 2048 }, { 7, 1086, 2048 }, { 8, 1087, 2048 }, + { 3, 1088, 2048 }, { 4, 1089, 2048 }, { 4, 1090, 2048 }, { 5, 1091, 2048 }, { 4, 1092, 2048 }, { 5, 1093, 2048 }, { 5, 1094, 2048 }, { 6, 1095, 2048 }, + { 4, 1096, 2048 }, { 5, 1097, 2048 }, { 5, 1098, 2048 }, { 6, 1099, 2048 }, { 5, 1100, 2048 }, { 6, 1101, 2048 }, { 6, 1102, 2048 }, { 7, 1103, 2048 }, + { 4, 1104, 2048 }, { 5, 1105, 2048 }, { 5, 1106, 2048 }, { 6, 1107, 2048 }, { 5, 1108, 2048 }, { 6, 1109, 2048 }, { 6, 1110, 2048 }, { 7, 1111, 2048 }, + { 5, 1112, 2048 }, { 6, 1113, 2048 }, { 6, 1114, 2048 }, { 7, 1115, 2048 }, { 6, 1116, 2048 }, { 7, 1117, 2048 }, { 7, 1118, 2048 }, { 8, 1119, 2048 }, + { 4, 1120, 2048 }, { 5, 1121, 2048 }, { 5, 1122, 2048 }, { 6, 1123, 2048 }, { 5, 1124, 2048 }, { 6, 1125, 2048 }, { 6, 1126, 2048 }, { 7, 1127, 2048 }, + { 5, 1128, 2048 }, { 6, 1129, 2048 }, { 6, 1130, 2048 }, { 7, 1131, 2048 }, { 6, 1132, 2048 }, { 7, 1133, 2048 }, { 7, 1134, 2048 }, { 8, 1135, 2048 }, + { 5, 1136, 2048 }, { 6, 1137, 2048 }, { 6, 1138, 2048 }, { 7, 1139, 2048 }, { 6, 1140, 2048 }, { 7, 1141, 2048 }, { 7, 1142, 2048 }, { 8, 1143, 2048 }, + { 6, 1144, 2048 }, { 7, 1145, 2048 }, { 7, 1146, 2048 }, { 8, 1147, 2048 }, { 7, 1148, 2048 }, { 8, 1149, 2048 }, { 8, 1150, 2048 }, { 9, 1151, 2048 }, + { 3, 1152, 2048 }, { 4, 1153, 2048 }, { 4, 1154, 2048 }, { 5, 1155, 2048 }, { 4, 1156, 2048 }, { 5, 1157, 2048 }, { 5, 1158, 2048 }, { 6, 1159, 2048 }, + { 4, 1160, 2048 }, { 5, 1161, 2048 }, { 5, 1162, 2048 }, { 6, 1163, 2048 }, { 5, 1164, 2048 }, { 6, 1165, 2048 }, { 6, 1166, 2048 }, { 7, 1167, 2048 }, + { 4, 1168, 2048 }, { 5, 1169, 2048 }, { 5, 1170, 2048 }, { 6, 1171, 2048 }, { 5, 1172, 2048 }, { 6, 1173, 2048 }, { 6, 1174, 2048 }, { 7, 1175, 2048 }, + { 5, 1176, 2048 }, { 6, 1177, 2048 }, { 6, 1178, 2048 }, { 7, 1179, 2048 }, { 6, 1180, 2048 }, { 7, 1181, 2048 }, { 7, 1182, 2048 }, { 8, 1183, 2048 }, + { 4, 1184, 2048 }, { 5, 1185, 2048 }, { 5, 1186, 2048 }, { 6, 1187, 2048 }, { 5, 1188, 2048 }, { 6, 1189, 2048 }, { 6, 1190, 2048 }, { 7, 1191, 2048 }, + { 5, 1192, 2048 }, { 6, 1193, 2048 }, { 6, 1194, 2048 }, { 7, 1195, 2048 }, { 6, 1196, 2048 }, { 7, 1197, 2048 }, { 7, 1198, 2048 }, { 8, 1199, 2048 }, + { 5, 1200, 2048 }, { 6, 1201, 2048 }, { 6, 1202, 2048 }, { 7, 1203, 2048 }, { 6, 1204, 2048 }, { 7, 1205, 2048 }, { 7, 1206, 2048 }, { 8, 1207, 2048 }, + { 6, 1208, 2048 }, { 7, 1209, 2048 }, { 7, 1210, 2048 }, { 8, 1211, 2048 }, { 7, 1212, 2048 }, { 8, 1213, 2048 }, { 8, 1214, 2048 }, { 9, 1215, 2048 }, + { 4, 1216, 2048 }, { 5, 1217, 2048 }, { 5, 1218, 2048 }, { 6, 1219, 2048 }, { 5, 1220, 2048 }, { 6, 1221, 2048 }, { 6, 1222, 2048 }, { 7, 1223, 2048 }, + { 5, 1224, 2048 }, { 6, 1225, 2048 }, { 6, 1226, 2048 }, { 7, 1227, 2048 }, { 6, 1228, 2048 }, { 7, 1229, 2048 }, { 7, 1230, 2048 }, { 8, 1231, 2048 }, + { 5, 1232, 2048 }, { 6, 1233, 2048 }, { 6, 1234, 2048 }, { 7, 1235, 2048 }, { 6, 1236, 2048 }, { 7, 1237, 2048 }, { 7, 1238, 2048 }, { 8, 1239, 2048 }, + { 6, 1240, 2048 }, { 7, 1241, 2048 }, { 7, 1242, 2048 }, { 8, 1243, 2048 }, { 7, 1244, 2048 }, { 8, 1245, 2048 }, { 8, 1246, 2048 }, { 9, 1247, 2048 }, + { 5, 1248, 2048 }, { 6, 1249, 2048 }, { 6, 1250, 2048 }, { 7, 1251, 2048 }, { 6, 1252, 2048 }, { 7, 1253, 2048 }, { 7, 1254, 2048 }, { 8, 1255, 2048 }, + { 6, 1256, 2048 }, { 7, 1257, 2048 }, { 7, 1258, 2048 }, { 8, 1259, 2048 }, { 7, 1260, 2048 }, { 8, 1261, 2048 }, { 8, 1262, 2048 }, { 9, 1263, 2048 }, + { 6, 1264, 2048 }, { 7, 1265, 2048 }, { 7, 1266, 2048 }, { 8, 1267, 2048 }, { 7, 1268, 2048 }, { 8, 1269, 2048 }, { 8, 1270, 2048 }, { 9, 1271, 2048 }, + { 7, 1272, 2048 }, { 8, 1273, 2048 }, { 8, 1274, 2048 }, { 9, 1275, 2048 }, { 8, 1276, 2048 }, { 9, 1277, 2048 }, { 9, 1278, 2048 }, { 10, 1279, 2048 }, + { 3, 1280, 2048 }, { 4, 1281, 2048 }, { 4, 1282, 2048 }, { 5, 1283, 2048 }, { 4, 1284, 2048 }, { 5, 1285, 2048 }, { 5, 1286, 2048 }, { 6, 1287, 2048 }, + { 4, 1288, 2048 }, { 5, 1289, 2048 }, { 5, 1290, 2048 }, { 6, 1291, 2048 }, { 5, 1292, 2048 }, { 6, 1293, 2048 }, { 6, 1294, 2048 }, { 7, 1295, 2048 }, + { 4, 1296, 2048 }, { 5, 1297, 2048 }, { 5, 1298, 2048 }, { 6, 1299, 2048 }, { 5, 1300, 2048 }, { 6, 1301, 2048 }, { 6, 1302, 2048 }, { 7, 1303, 2048 }, + { 5, 1304, 2048 }, { 6, 1305, 2048 }, { 6, 1306, 2048 }, { 7, 1307, 2048 }, { 6, 1308, 2048 }, { 7, 1309, 2048 }, { 7, 1310, 2048 }, { 8, 1311, 2048 }, + { 4, 1312, 2048 }, { 5, 1313, 2048 }, { 5, 1314, 2048 }, { 6, 1315, 2048 }, { 5, 1316, 2048 }, { 6, 1317, 2048 }, { 6, 1318, 2048 }, { 7, 1319, 2048 }, + { 5, 1320, 2048 }, { 6, 1321, 2048 }, { 6, 1322, 2048 }, { 7, 1323, 2048 }, { 6, 1324, 2048 }, { 7, 1325, 2048 }, { 7, 1326, 2048 }, { 8, 1327, 2048 }, + { 5, 1328, 2048 }, { 6, 1329, 2048 }, { 6, 1330, 2048 }, { 7, 1331, 2048 }, { 6, 1332, 2048 }, { 7, 1333, 2048 }, { 7, 1334, 2048 }, { 8, 1335, 2048 }, + { 6, 1336, 2048 }, { 7, 1337, 2048 }, { 7, 1338, 2048 }, { 8, 1339, 2048 }, { 7, 1340, 2048 }, { 8, 1341, 2048 }, { 8, 1342, 2048 }, { 9, 1343, 2048 }, + { 4, 1344, 2048 }, { 5, 1345, 2048 }, { 5, 1346, 2048 }, { 6, 1347, 2048 }, { 5, 1348, 2048 }, { 6, 1349, 2048 }, { 6, 1350, 2048 }, { 7, 1351, 2048 }, + { 5, 1352, 2048 }, { 6, 1353, 2048 }, { 6, 1354, 2048 }, { 7, 1355, 2048 }, { 6, 1356, 2048 }, { 7, 1357, 2048 }, { 7, 1358, 2048 }, { 8, 1359, 2048 }, + { 5, 1360, 2048 }, { 6, 1361, 2048 }, { 6, 1362, 2048 }, { 7, 1363, 2048 }, { 6, 1364, 2048 }, { 7, 1365, 2048 }, { 7, 1366, 2048 }, { 8, 1367, 2048 }, + { 6, 1368, 2048 }, { 7, 1369, 2048 }, { 7, 1370, 2048 }, { 8, 1371, 2048 }, { 7, 1372, 2048 }, { 8, 1373, 2048 }, { 8, 1374, 2048 }, { 9, 1375, 2048 }, + { 5, 1376, 2048 }, { 6, 1377, 2048 }, { 6, 1378, 2048 }, { 7, 1379, 2048 }, { 6, 1380, 2048 }, { 7, 1381, 2048 }, { 7, 1382, 2048 }, { 8, 1383, 2048 }, + { 6, 1384, 2048 }, { 7, 1385, 2048 }, { 7, 1386, 2048 }, { 8, 1387, 2048 }, { 7, 1388, 2048 }, { 8, 1389, 2048 }, { 8, 1390, 2048 }, { 9, 1391, 2048 }, + { 6, 1392, 2048 }, { 7, 1393, 2048 }, { 7, 1394, 2048 }, { 8, 1395, 2048 }, { 7, 1396, 2048 }, { 8, 1397, 2048 }, { 8, 1398, 2048 }, { 9, 1399, 2048 }, + { 7, 1400, 2048 }, { 8, 1401, 2048 }, { 8, 1402, 2048 }, { 9, 1403, 2048 }, { 8, 1404, 2048 }, { 9, 1405, 2048 }, { 9, 1406, 2048 }, { 10, 1407, 2048 }, + { 4, 1408, 2048 }, { 5, 1409, 2048 }, { 5, 1410, 2048 }, { 6, 1411, 2048 }, { 5, 1412, 2048 }, { 6, 1413, 2048 }, { 6, 1414, 2048 }, { 7, 1415, 2048 }, + { 5, 1416, 2048 }, { 6, 1417, 2048 }, { 6, 1418, 2048 }, { 7, 1419, 2048 }, { 6, 1420, 2048 }, { 7, 1421, 2048 }, { 7, 1422, 2048 }, { 8, 1423, 2048 }, + { 5, 1424, 2048 }, { 6, 1425, 2048 }, { 6, 1426, 2048 }, { 7, 1427, 2048 }, { 6, 1428, 2048 }, { 7, 1429, 2048 }, { 7, 1430, 2048 }, { 8, 1431, 2048 }, + { 6, 1432, 2048 }, { 7, 1433, 2048 }, { 7, 1434, 2048 }, { 8, 1435, 2048 }, { 7, 1436, 2048 }, { 8, 1437, 2048 }, { 8, 1438, 2048 }, { 9, 1439, 2048 }, + { 5, 1440, 2048 }, { 6, 1441, 2048 }, { 6, 1442, 2048 }, { 7, 1443, 2048 }, { 6, 1444, 2048 }, { 7, 1445, 2048 }, { 7, 1446, 2048 }, { 8, 1447, 2048 }, + { 6, 1448, 2048 }, { 7, 1449, 2048 }, { 7, 1450, 2048 }, { 8, 1451, 2048 }, { 7, 1452, 2048 }, { 8, 1453, 2048 }, { 8, 1454, 2048 }, { 9, 1455, 2048 }, + { 6, 1456, 2048 }, { 7, 1457, 2048 }, { 7, 1458, 2048 }, { 8, 1459, 2048 }, { 7, 1460, 2048 }, { 8, 1461, 2048 }, { 8, 1462, 2048 }, { 9, 1463, 2048 }, + { 7, 1464, 2048 }, { 8, 1465, 2048 }, { 8, 1466, 2048 }, { 9, 1467, 2048 }, { 8, 1468, 2048 }, { 9, 1469, 2048 }, { 9, 1470, 2048 }, { 10, 1471, 2048 }, + { 5, 1472, 2048 }, { 6, 1473, 2048 }, { 6, 1474, 2048 }, { 7, 1475, 2048 }, { 6, 1476, 2048 }, { 7, 1477, 2048 }, { 7, 1478, 2048 }, { 8, 1479, 2048 }, + { 6, 1480, 2048 }, { 7, 1481, 2048 }, { 7, 1482, 2048 }, { 8, 1483, 2048 }, { 7, 1484, 2048 }, { 8, 1485, 2048 }, { 8, 1486, 2048 }, { 9, 1487, 2048 }, + { 6, 1488, 2048 }, { 7, 1489, 2048 }, { 7, 1490, 2048 }, { 8, 1491, 2048 }, { 7, 1492, 2048 }, { 8, 1493, 2048 }, { 8, 1494, 2048 }, { 9, 1495, 2048 }, + { 7, 1496, 2048 }, { 8, 1497, 2048 }, { 8, 1498, 2048 }, { 9, 1499, 2048 }, { 8, 1500, 2048 }, { 9, 1501, 2048 }, { 9, 1502, 2048 }, { 10, 1503, 2048 }, + { 6, 1504, 2048 }, { 7, 1505, 2048 }, { 7, 1506, 2048 }, { 8, 1507, 2048 }, { 7, 1508, 2048 }, { 8, 1509, 2048 }, { 8, 1510, 2048 }, { 9, 1511, 2048 }, + { 7, 1512, 2048 }, { 8, 1513, 2048 }, { 8, 1514, 2048 }, { 9, 1515, 2048 }, { 8, 1516, 2048 }, { 9, 1517, 2048 }, { 9, 1518, 2048 }, { 10, 1519, 2048 }, + { 7, 1520, 2048 }, { 8, 1521, 2048 }, { 8, 1522, 2048 }, { 9, 1523, 2048 }, { 8, 1524, 2048 }, { 9, 1525, 2048 }, { 9, 1526, 2048 }, { 10, 1527, 2048 }, + { 8, 1528, 2048 }, { 9, 1529, 2048 }, { 9, 1530, 2048 }, { 10, 1531, 2048 }, { 9, 1532, 2048 }, { 10, 1533, 2048 }, { 10, 1534, 2048 }, { 11, 1535, 2048 }, + { 3, 1536, 2048 }, { 4, 1537, 2048 }, { 4, 1538, 2048 }, { 5, 1539, 2048 }, { 4, 1540, 2048 }, { 5, 1541, 2048 }, { 5, 1542, 2048 }, { 6, 1543, 2048 }, + { 4, 1544, 2048 }, { 5, 1545, 2048 }, { 5, 1546, 2048 }, { 6, 1547, 2048 }, { 5, 1548, 2048 }, { 6, 1549, 2048 }, { 6, 1550, 2048 }, { 7, 1551, 2048 }, + { 4, 1552, 2048 }, { 5, 1553, 2048 }, { 5, 1554, 2048 }, { 6, 1555, 2048 }, { 5, 1556, 2048 }, { 6, 1557, 2048 }, { 6, 1558, 2048 }, { 7, 1559, 2048 }, + { 5, 1560, 2048 }, { 6, 1561, 2048 }, { 6, 1562, 2048 }, { 7, 1563, 2048 }, { 6, 1564, 2048 }, { 7, 1565, 2048 }, { 7, 1566, 2048 }, { 8, 1567, 2048 }, + { 4, 1568, 2048 }, { 5, 1569, 2048 }, { 5, 1570, 2048 }, { 6, 1571, 2048 }, { 5, 1572, 2048 }, { 6, 1573, 2048 }, { 6, 1574, 2048 }, { 7, 1575, 2048 }, + { 5, 1576, 2048 }, { 6, 1577, 2048 }, { 6, 1578, 2048 }, { 7, 1579, 2048 }, { 6, 1580, 2048 }, { 7, 1581, 2048 }, { 7, 1582, 2048 }, { 8, 1583, 2048 }, + { 5, 1584, 2048 }, { 6, 1585, 2048 }, { 6, 1586, 2048 }, { 7, 1587, 2048 }, { 6, 1588, 2048 }, { 7, 1589, 2048 }, { 7, 1590, 2048 }, { 8, 1591, 2048 }, + { 6, 1592, 2048 }, { 7, 1593, 2048 }, { 7, 1594, 2048 }, { 8, 1595, 2048 }, { 7, 1596, 2048 }, { 8, 1597, 2048 }, { 8, 1598, 2048 }, { 9, 1599, 2048 }, + { 4, 1600, 2048 }, { 5, 1601, 2048 }, { 5, 1602, 2048 }, { 6, 1603, 2048 }, { 5, 1604, 2048 }, { 6, 1605, 2048 }, { 6, 1606, 2048 }, { 7, 1607, 2048 }, + { 5, 1608, 2048 }, { 6, 1609, 2048 }, { 6, 1610, 2048 }, { 7, 1611, 2048 }, { 6, 1612, 2048 }, { 7, 1613, 2048 }, { 7, 1614, 2048 }, { 8, 1615, 2048 }, + { 5, 1616, 2048 }, { 6, 1617, 2048 }, { 6, 1618, 2048 }, { 7, 1619, 2048 }, { 6, 1620, 2048 }, { 7, 1621, 2048 }, { 7, 1622, 2048 }, { 8, 1623, 2048 }, + { 6, 1624, 2048 }, { 7, 1625, 2048 }, { 7, 1626, 2048 }, { 8, 1627, 2048 }, { 7, 1628, 2048 }, { 8, 1629, 2048 }, { 8, 1630, 2048 }, { 9, 1631, 2048 }, + { 5, 1632, 2048 }, { 6, 1633, 2048 }, { 6, 1634, 2048 }, { 7, 1635, 2048 }, { 6, 1636, 2048 }, { 7, 1637, 2048 }, { 7, 1638, 2048 }, { 8, 1639, 2048 }, + { 6, 1640, 2048 }, { 7, 1641, 2048 }, { 7, 1642, 2048 }, { 8, 1643, 2048 }, { 7, 1644, 2048 }, { 8, 1645, 2048 }, { 8, 1646, 2048 }, { 9, 1647, 2048 }, + { 6, 1648, 2048 }, { 7, 1649, 2048 }, { 7, 1650, 2048 }, { 8, 1651, 2048 }, { 7, 1652, 2048 }, { 8, 1653, 2048 }, { 8, 1654, 2048 }, { 9, 1655, 2048 }, + { 7, 1656, 2048 }, { 8, 1657, 2048 }, { 8, 1658, 2048 }, { 9, 1659, 2048 }, { 8, 1660, 2048 }, { 9, 1661, 2048 }, { 9, 1662, 2048 }, { 10, 1663, 2048 }, + { 4, 1664, 2048 }, { 5, 1665, 2048 }, { 5, 1666, 2048 }, { 6, 1667, 2048 }, { 5, 1668, 2048 }, { 6, 1669, 2048 }, { 6, 1670, 2048 }, { 7, 1671, 2048 }, + { 5, 1672, 2048 }, { 6, 1673, 2048 }, { 6, 1674, 2048 }, { 7, 1675, 2048 }, { 6, 1676, 2048 }, { 7, 1677, 2048 }, { 7, 1678, 2048 }, { 8, 1679, 2048 }, + { 5, 1680, 2048 }, { 6, 1681, 2048 }, { 6, 1682, 2048 }, { 7, 1683, 2048 }, { 6, 1684, 2048 }, { 7, 1685, 2048 }, { 7, 1686, 2048 }, { 8, 1687, 2048 }, + { 6, 1688, 2048 }, { 7, 1689, 2048 }, { 7, 1690, 2048 }, { 8, 1691, 2048 }, { 7, 1692, 2048 }, { 8, 1693, 2048 }, { 8, 1694, 2048 }, { 9, 1695, 2048 }, + { 5, 1696, 2048 }, { 6, 1697, 2048 }, { 6, 1698, 2048 }, { 7, 1699, 2048 }, { 6, 1700, 2048 }, { 7, 1701, 2048 }, { 7, 1702, 2048 }, { 8, 1703, 2048 }, + { 6, 1704, 2048 }, { 7, 1705, 2048 }, { 7, 1706, 2048 }, { 8, 1707, 2048 }, { 7, 1708, 2048 }, { 8, 1709, 2048 }, { 8, 1710, 2048 }, { 9, 1711, 2048 }, + { 6, 1712, 2048 }, { 7, 1713, 2048 }, { 7, 1714, 2048 }, { 8, 1715, 2048 }, { 7, 1716, 2048 }, { 8, 1717, 2048 }, { 8, 1718, 2048 }, { 9, 1719, 2048 }, + { 7, 1720, 2048 }, { 8, 1721, 2048 }, { 8, 1722, 2048 }, { 9, 1723, 2048 }, { 8, 1724, 2048 }, { 9, 1725, 2048 }, { 9, 1726, 2048 }, { 10, 1727, 2048 }, + { 5, 1728, 2048 }, { 6, 1729, 2048 }, { 6, 1730, 2048 }, { 7, 1731, 2048 }, { 6, 1732, 2048 }, { 7, 1733, 2048 }, { 7, 1734, 2048 }, { 8, 1735, 2048 }, + { 6, 1736, 2048 }, { 7, 1737, 2048 }, { 7, 1738, 2048 }, { 8, 1739, 2048 }, { 7, 1740, 2048 }, { 8, 1741, 2048 }, { 8, 1742, 2048 }, { 9, 1743, 2048 }, + { 6, 1744, 2048 }, { 7, 1745, 2048 }, { 7, 1746, 2048 }, { 8, 1747, 2048 }, { 7, 1748, 2048 }, { 8, 1749, 2048 }, { 8, 1750, 2048 }, { 9, 1751, 2048 }, + { 7, 1752, 2048 }, { 8, 1753, 2048 }, { 8, 1754, 2048 }, { 9, 1755, 2048 }, { 8, 1756, 2048 }, { 9, 1757, 2048 }, { 9, 1758, 2048 }, { 10, 1759, 2048 }, + { 6, 1760, 2048 }, { 7, 1761, 2048 }, { 7, 1762, 2048 }, { 8, 1763, 2048 }, { 7, 1764, 2048 }, { 8, 1765, 2048 }, { 8, 1766, 2048 }, { 9, 1767, 2048 }, + { 7, 1768, 2048 }, { 8, 1769, 2048 }, { 8, 1770, 2048 }, { 9, 1771, 2048 }, { 8, 1772, 2048 }, { 9, 1773, 2048 }, { 9, 1774, 2048 }, { 10, 1775, 2048 }, + { 7, 1776, 2048 }, { 8, 1777, 2048 }, { 8, 1778, 2048 }, { 9, 1779, 2048 }, { 8, 1780, 2048 }, { 9, 1781, 2048 }, { 9, 1782, 2048 }, { 10, 1783, 2048 }, + { 8, 1784, 2048 }, { 9, 1785, 2048 }, { 9, 1786, 2048 }, { 10, 1787, 2048 }, { 9, 1788, 2048 }, { 10, 1789, 2048 }, { 10, 1790, 2048 }, { 11, 1791, 2048 }, + { 4, 1792, 2048 }, { 5, 1793, 2048 }, { 5, 1794, 2048 }, { 6, 1795, 2048 }, { 5, 1796, 2048 }, { 6, 1797, 2048 }, { 6, 1798, 2048 }, { 7, 1799, 2048 }, + { 5, 1800, 2048 }, { 6, 1801, 2048 }, { 6, 1802, 2048 }, { 7, 1803, 2048 }, { 6, 1804, 2048 }, { 7, 1805, 2048 }, { 7, 1806, 2048 }, { 8, 1807, 2048 }, + { 5, 1808, 2048 }, { 6, 1809, 2048 }, { 6, 1810, 2048 }, { 7, 1811, 2048 }, { 6, 1812, 2048 }, { 7, 1813, 2048 }, { 7, 1814, 2048 }, { 8, 1815, 2048 }, + { 6, 1816, 2048 }, { 7, 1817, 2048 }, { 7, 1818, 2048 }, { 8, 1819, 2048 }, { 7, 1820, 2048 }, { 8, 1821, 2048 }, { 8, 1822, 2048 }, { 9, 1823, 2048 }, + { 5, 1824, 2048 }, { 6, 1825, 2048 }, { 6, 1826, 2048 }, { 7, 1827, 2048 }, { 6, 1828, 2048 }, { 7, 1829, 2048 }, { 7, 1830, 2048 }, { 8, 1831, 2048 }, + { 6, 1832, 2048 }, { 7, 1833, 2048 }, { 7, 1834, 2048 }, { 8, 1835, 2048 }, { 7, 1836, 2048 }, { 8, 1837, 2048 }, { 8, 1838, 2048 }, { 9, 1839, 2048 }, + { 6, 1840, 2048 }, { 7, 1841, 2048 }, { 7, 1842, 2048 }, { 8, 1843, 2048 }, { 7, 1844, 2048 }, { 8, 1845, 2048 }, { 8, 1846, 2048 }, { 9, 1847, 2048 }, + { 7, 1848, 2048 }, { 8, 1849, 2048 }, { 8, 1850, 2048 }, { 9, 1851, 2048 }, { 8, 1852, 2048 }, { 9, 1853, 2048 }, { 9, 1854, 2048 }, { 10, 1855, 2048 }, + { 5, 1856, 2048 }, { 6, 1857, 2048 }, { 6, 1858, 2048 }, { 7, 1859, 2048 }, { 6, 1860, 2048 }, { 7, 1861, 2048 }, { 7, 1862, 2048 }, { 8, 1863, 2048 }, + { 6, 1864, 2048 }, { 7, 1865, 2048 }, { 7, 1866, 2048 }, { 8, 1867, 2048 }, { 7, 1868, 2048 }, { 8, 1869, 2048 }, { 8, 1870, 2048 }, { 9, 1871, 2048 }, + { 6, 1872, 2048 }, { 7, 1873, 2048 }, { 7, 1874, 2048 }, { 8, 1875, 2048 }, { 7, 1876, 2048 }, { 8, 1877, 2048 }, { 8, 1878, 2048 }, { 9, 1879, 2048 }, + { 7, 1880, 2048 }, { 8, 1881, 2048 }, { 8, 1882, 2048 }, { 9, 1883, 2048 }, { 8, 1884, 2048 }, { 9, 1885, 2048 }, { 9, 1886, 2048 }, { 10, 1887, 2048 }, + { 6, 1888, 2048 }, { 7, 1889, 2048 }, { 7, 1890, 2048 }, { 8, 1891, 2048 }, { 7, 1892, 2048 }, { 8, 1893, 2048 }, { 8, 1894, 2048 }, { 9, 1895, 2048 }, + { 7, 1896, 2048 }, { 8, 1897, 2048 }, { 8, 1898, 2048 }, { 9, 1899, 2048 }, { 8, 1900, 2048 }, { 9, 1901, 2048 }, { 9, 1902, 2048 }, { 10, 1903, 2048 }, + { 7, 1904, 2048 }, { 8, 1905, 2048 }, { 8, 1906, 2048 }, { 9, 1907, 2048 }, { 8, 1908, 2048 }, { 9, 1909, 2048 }, { 9, 1910, 2048 }, { 10, 1911, 2048 }, + { 8, 1912, 2048 }, { 9, 1913, 2048 }, { 9, 1914, 2048 }, { 10, 1915, 2048 }, { 9, 1916, 2048 }, { 10, 1917, 2048 }, { 10, 1918, 2048 }, { 11, 1919, 2048 }, + { 5, 1920, 2048 }, { 6, 1921, 2048 }, { 6, 1922, 2048 }, { 7, 1923, 2048 }, { 6, 1924, 2048 }, { 7, 1925, 2048 }, { 7, 1926, 2048 }, { 8, 1927, 2048 }, + { 6, 1928, 2048 }, { 7, 1929, 2048 }, { 7, 1930, 2048 }, { 8, 1931, 2048 }, { 7, 1932, 2048 }, { 8, 1933, 2048 }, { 8, 1934, 2048 }, { 9, 1935, 2048 }, + { 6, 1936, 2048 }, { 7, 1937, 2048 }, { 7, 1938, 2048 }, { 8, 1939, 2048 }, { 7, 1940, 2048 }, { 8, 1941, 2048 }, { 8, 1942, 2048 }, { 9, 1943, 2048 }, + { 7, 1944, 2048 }, { 8, 1945, 2048 }, { 8, 1946, 2048 }, { 9, 1947, 2048 }, { 8, 1948, 2048 }, { 9, 1949, 2048 }, { 9, 1950, 2048 }, { 10, 1951, 2048 }, + { 6, 1952, 2048 }, { 7, 1953, 2048 }, { 7, 1954, 2048 }, { 8, 1955, 2048 }, { 7, 1956, 2048 }, { 8, 1957, 2048 }, { 8, 1958, 2048 }, { 9, 1959, 2048 }, + { 7, 1960, 2048 }, { 8, 1961, 2048 }, { 8, 1962, 2048 }, { 9, 1963, 2048 }, { 8, 1964, 2048 }, { 9, 1965, 2048 }, { 9, 1966, 2048 }, { 10, 1967, 2048 }, + { 7, 1968, 2048 }, { 8, 1969, 2048 }, { 8, 1970, 2048 }, { 9, 1971, 2048 }, { 8, 1972, 2048 }, { 9, 1973, 2048 }, { 9, 1974, 2048 }, { 10, 1975, 2048 }, + { 8, 1976, 2048 }, { 9, 1977, 2048 }, { 9, 1978, 2048 }, { 10, 1979, 2048 }, { 9, 1980, 2048 }, { 10, 1981, 2048 }, { 10, 1982, 2048 }, { 11, 1983, 2048 }, + { 6, 1984, 2048 }, { 7, 1985, 2048 }, { 7, 1986, 2048 }, { 8, 1987, 2048 }, { 7, 1988, 2048 }, { 8, 1989, 2048 }, { 8, 1990, 2048 }, { 9, 1991, 2048 }, + { 7, 1992, 2048 }, { 8, 1993, 2048 }, { 8, 1994, 2048 }, { 9, 1995, 2048 }, { 8, 1996, 2048 }, { 9, 1997, 2048 }, { 9, 1998, 2048 }, { 10, 1999, 2048 }, + { 7, 2000, 2048 }, { 8, 2001, 2048 }, { 8, 2002, 2048 }, { 9, 2003, 2048 }, { 8, 2004, 2048 }, { 9, 2005, 2048 }, { 9, 2006, 2048 }, { 10, 2007, 2048 }, + { 8, 2008, 2048 }, { 9, 2009, 2048 }, { 9, 2010, 2048 }, { 10, 2011, 2048 }, { 9, 2012, 2048 }, { 10, 2013, 2048 }, { 10, 2014, 2048 }, { 11, 2015, 2048 }, + { 7, 2016, 2048 }, { 8, 2017, 2048 }, { 8, 2018, 2048 }, { 9, 2019, 2048 }, { 8, 2020, 2048 }, { 9, 2021, 2048 }, { 9, 2022, 2048 }, { 10, 2023, 2048 }, + { 8, 2024, 2048 }, { 9, 2025, 2048 }, { 9, 2026, 2048 }, { 10, 2027, 2048 }, { 9, 2028, 2048 }, { 10, 2029, 2048 }, { 10, 2030, 2048 }, { 11, 2031, 2048 }, + { 8, 2032, 2048 }, { 9, 2033, 2048 }, { 9, 2034, 2048 }, { 10, 2035, 2048 }, { 9, 2036, 2048 }, { 10, 2037, 2048 }, { 10, 2038, 2048 }, { 11, 2039, 2048 }, + { 9, 2040, 2048 }, { 10, 2041, 2048 }, { 10, 2042, 2048 }, { 11, 2043, 2048 }, { 10, 2044, 2048 }, { 11, 2045, 2048 }, { 11, 2046, 2048 }, { 12, 2047, 2048 }, #endif #endif #endif @@ -3462,6 +8636,7 @@ static const struct { #endif }; + /* find a hole and free as required, return -1 if no hole found */ static int find_hole(void) { @@ -3484,10 +8659,10 @@ static int find_hole(void) /* free entry z */ if (z >= 0 && fp_cache[z].g) { mp_clear(&fp_cache[z].mu); - ecc_del_point(fp_cache[z].g); + wc_ecc_del_point(fp_cache[z].g); fp_cache[z].g = NULL; for (x = 0; x < (1U<<FP_LUT); x++) { - ecc_del_point(fp_cache[z].LUT[x]); + wc_ecc_del_point(fp_cache[z].LUT[x]); fp_cache[z].LUT[x] = NULL; } fp_cache[z].lru_count = 0; @@ -3500,9 +8675,9 @@ static int find_base(ecc_point* g) { int x; for (x = 0; x < FP_ENTRIES; x++) { - if (fp_cache[x].g != NULL && - mp_cmp(fp_cache[x].g->x, g->x) == MP_EQ && - mp_cmp(fp_cache[x].g->y, g->y) == MP_EQ && + if (fp_cache[x].g != NULL && + mp_cmp(fp_cache[x].g->x, g->x) == MP_EQ && + mp_cmp(fp_cache[x].g->y, g->y) == MP_EQ && mp_cmp(fp_cache[x].g->z, g->z) == MP_EQ) { break; } @@ -3519,7 +8694,7 @@ static int add_entry(int idx, ecc_point *g) unsigned x, y; /* allocate base and LUT */ - fp_cache[idx].g = ecc_new_point(); + fp_cache[idx].g = wc_ecc_new_point(); if (fp_cache[idx].g == NULL) { return GEN_MEM_ERR; } @@ -3528,38 +8703,42 @@ static int add_entry(int idx, ecc_point *g) if ((mp_copy(g->x, fp_cache[idx].g->x) != MP_OKAY) || (mp_copy(g->y, fp_cache[idx].g->y) != MP_OKAY) || (mp_copy(g->z, fp_cache[idx].g->z) != MP_OKAY)) { - ecc_del_point(fp_cache[idx].g); + wc_ecc_del_point(fp_cache[idx].g); fp_cache[idx].g = NULL; return GEN_MEM_ERR; - } + } for (x = 0; x < (1U<<FP_LUT); x++) { - fp_cache[idx].LUT[x] = ecc_new_point(); + fp_cache[idx].LUT[x] = wc_ecc_new_point(); if (fp_cache[idx].LUT[x] == NULL) { for (y = 0; y < x; y++) { - ecc_del_point(fp_cache[idx].LUT[y]); + wc_ecc_del_point(fp_cache[idx].LUT[y]); fp_cache[idx].LUT[y] = NULL; } - ecc_del_point(fp_cache[idx].g); + wc_ecc_del_point(fp_cache[idx].g); fp_cache[idx].g = NULL; fp_cache[idx].lru_count = 0; return GEN_MEM_ERR; } } - + fp_cache[idx].lru_count = 0; return MP_OKAY; } +#endif -/* build the LUT by spacing the bits of the input by #modulus/FP_LUT bits apart - * - * The algorithm builds patterns in increasing bit order by first making all +#ifndef WOLFSSL_SP_MATH +/* build the LUT by spacing the bits of the input by #modulus/FP_LUT bits apart + * + * The algorithm builds patterns in increasing bit order by first making all * single bit input patterns, then all two bit input patterns and so on */ -static int build_lut(int idx, mp_int* modulus, mp_digit* mp, mp_int* mu) -{ - unsigned x, y, err, bitlen, lut_gap; +static int build_lut(int idx, mp_int* a, mp_int* modulus, mp_digit mp, + mp_int* mu) +{ + int err; + unsigned x, y, bitlen, lut_gap; mp_int tmp; if (mp_init(&tmp) != MP_OKAY) @@ -3570,82 +8749,80 @@ static int build_lut(int idx, mp_int* modulus, mp_digit* mp, mp_int* mu) if ((sizeof(lut_orders) / sizeof(lut_orders[0])) < (1U<<FP_LUT)) { err = BAD_FUNC_ARG; } - else { + else { /* get bitlen and round up to next multiple of FP_LUT */ bitlen = mp_unsigned_bin_size(modulus) << 3; x = bitlen % FP_LUT; if (x) { bitlen += FP_LUT - x; - } + } lut_gap = bitlen / FP_LUT; /* init the mu */ err = mp_init_copy(&fp_cache[idx].mu, mu); } - + /* copy base */ if (err == MP_OKAY) { if ((mp_mulmod(fp_cache[idx].g->x, mu, modulus, - fp_cache[idx].LUT[1]->x) != MP_OKAY) || + fp_cache[idx].LUT[1]->x) != MP_OKAY) || (mp_mulmod(fp_cache[idx].g->y, mu, modulus, - fp_cache[idx].LUT[1]->y) != MP_OKAY) || + fp_cache[idx].LUT[1]->y) != MP_OKAY) || (mp_mulmod(fp_cache[idx].g->z, mu, modulus, fp_cache[idx].LUT[1]->z) != MP_OKAY)) { - err = MP_MULMOD_E; + err = MP_MULMOD_E; } } - + /* make all single bit entries */ for (x = 1; x < FP_LUT; x++) { if (err != MP_OKAY) break; if ((mp_copy(fp_cache[idx].LUT[1<<(x-1)]->x, - fp_cache[idx].LUT[1<<x]->x) != MP_OKAY) || + fp_cache[idx].LUT[1<<x]->x) != MP_OKAY) || (mp_copy(fp_cache[idx].LUT[1<<(x-1)]->y, - fp_cache[idx].LUT[1<<x]->y) != MP_OKAY) || + fp_cache[idx].LUT[1<<x]->y) != MP_OKAY) || (mp_copy(fp_cache[idx].LUT[1<<(x-1)]->z, fp_cache[idx].LUT[1<<x]->z) != MP_OKAY)){ err = MP_INIT_E; break; } else { - + /* now double it bitlen/FP_LUT times */ for (y = 0; y < lut_gap; y++) { if ((err = ecc_projective_dbl_point(fp_cache[idx].LUT[1<<x], - fp_cache[idx].LUT[1<<x], modulus, mp)) != MP_OKAY) { + fp_cache[idx].LUT[1<<x], a, modulus, mp)) != MP_OKAY) { break; } } } } - + /* now make all entries in increase order of hamming weight */ for (x = 2; x <= FP_LUT; x++) { if (err != MP_OKAY) break; for (y = 0; y < (1UL<<FP_LUT); y++) { - if (err != MP_OKAY) - break; if (lut_orders[y].ham != (int)x) continue; - + /* perform the add */ if ((err = ecc_projective_add_point( fp_cache[idx].LUT[lut_orders[y].terma], fp_cache[idx].LUT[lut_orders[y].termb], - fp_cache[idx].LUT[y], modulus, mp)) != MP_OKAY) { + fp_cache[idx].LUT[y], a, modulus, mp)) != MP_OKAY) { break; } } } - + /* now map all entries back to affine space to make point addition faster */ for (x = 1; x < (1UL<<FP_LUT); x++) { if (err != MP_OKAY) break; /* convert z to normal from montgomery */ - err = mp_montgomery_reduce(fp_cache[idx].LUT[x]->z, modulus, *mp); - + err = mp_montgomery_reduce(fp_cache[idx].LUT[x]->z, modulus, mp); + /* invert it */ if (err == MP_OKAY) err = mp_invmod(fp_cache[idx].LUT[x]->z, modulus, @@ -3654,7 +8831,7 @@ static int build_lut(int idx, mp_int* modulus, mp_digit* mp, mp_int* mu) if (err == MP_OKAY) /* now square it */ err = mp_sqrmod(fp_cache[idx].LUT[x]->z, modulus, &tmp); - + if (err == MP_OKAY) /* fix x */ err = mp_mulmod(fp_cache[idx].LUT[x]->x, &tmp, modulus, @@ -3673,6 +8850,7 @@ static int build_lut(int idx, mp_int* modulus, mp_digit* mp, mp_int* mu) /* free z */ mp_clear(fp_cache[idx].LUT[x]->z); } + mp_clear(&tmp); if (err == MP_OKAY) @@ -3680,107 +8858,99 @@ static int build_lut(int idx, mp_int* modulus, mp_digit* mp, mp_int* mu) /* err cleanup */ for (y = 0; y < (1U<<FP_LUT); y++) { - ecc_del_point(fp_cache[idx].LUT[y]); + wc_ecc_del_point(fp_cache[idx].LUT[y]); fp_cache[idx].LUT[y] = NULL; } - ecc_del_point(fp_cache[idx].g); + wc_ecc_del_point(fp_cache[idx].g); fp_cache[idx].g = NULL; fp_cache[idx].lru_count = 0; mp_clear(&fp_cache[idx].mu); - mp_clear(&tmp); return err; } /* perform a fixed point ECC mulmod */ -static int accel_fp_mul(int idx, mp_int* k, ecc_point *R, mp_int* modulus, - mp_digit* mp, int map) +static int accel_fp_mul(int idx, mp_int* k, ecc_point *R, mp_int* a, + mp_int* modulus, mp_digit mp, int map) { #define KB_SIZE 128 #ifdef WOLFSSL_SMALL_STACK - unsigned char* kb; + unsigned char* kb = NULL; #else - unsigned char kb[128]; + unsigned char kb[KB_SIZE]; #endif - int x; - unsigned y, z, err, bitlen, bitpos, lut_gap, first; - mp_int tk; + int x, err; + unsigned y, z = 0, bitlen, bitpos, lut_gap, first; + mp_int tk, order; - if (mp_init(&tk) != MP_OKAY) + if (mp_init_multi(&tk, &order, NULL, NULL, NULL, NULL) != MP_OKAY) return MP_INIT_E; /* if it's smaller than modulus we fine */ if (mp_unsigned_bin_size(k) > mp_unsigned_bin_size(modulus)) { - mp_int order; - if (mp_init(&order) != MP_OKAY) { - mp_clear(&tk); - return MP_INIT_E; - } - /* find order */ y = mp_unsigned_bin_size(modulus); for (x = 0; ecc_sets[x].size; x++) { if (y <= (unsigned)ecc_sets[x].size) break; } - + /* back off if we are on the 521 bit curve */ if (y == 66) --x; - - if ((err = mp_read_radix(&order, ecc_sets[x].order, 16)) != MP_OKAY) { - mp_clear(&order); - mp_clear(&tk); - return err; + + if ((err = mp_read_radix(&order, ecc_sets[x].order, + MP_RADIX_HEX)) != MP_OKAY) { + goto done; } /* k must be less than modulus */ if (mp_cmp(k, &order) != MP_LT) { if ((err = mp_mod(k, &order, &tk)) != MP_OKAY) { - mp_clear(&tk); - mp_clear(&order); - return err; + goto done; } } else { - mp_copy(k, &tk); + if ((err = mp_copy(k, &tk)) != MP_OKAY) { + goto done; + } } - mp_clear(&order); } else { - mp_copy(k, &tk); - } - + if ((err = mp_copy(k, &tk)) != MP_OKAY) { + goto done; + } + } + /* get bitlen and round up to next multiple of FP_LUT */ bitlen = mp_unsigned_bin_size(modulus) << 3; x = bitlen % FP_LUT; if (x) { bitlen += FP_LUT - x; - } + } lut_gap = bitlen / FP_LUT; - + /* get the k value */ if (mp_unsigned_bin_size(&tk) > (int)(KB_SIZE - 2)) { - mp_clear(&tk); - return BUFFER_E; + err = BUFFER_E; goto done; } - + /* store k */ #ifdef WOLFSSL_SMALL_STACK - kb = (unsigned char*)XMALLOC(KB_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (kb == NULL) - return MEMORY_E; + kb = (unsigned char*)XMALLOC(KB_SIZE, NULL, DYNAMIC_TYPE_ECC_BUFFER); + if (kb == NULL) { + err = MEMORY_E; goto done; + } #endif XMEMSET(kb, 0, KB_SIZE); - if ((err = mp_to_unsigned_bin(&tk, kb)) != MP_OKAY) { - mp_clear(&tk); - } - else { + if ((err = mp_to_unsigned_bin(&tk, kb)) == MP_OKAY) { /* let's reverse kb so it's little endian */ x = 0; - y = mp_unsigned_bin_size(&tk) - 1; - mp_clear(&tk); + y = mp_unsigned_bin_size(&tk); + if (y > 0) { + y -= 1; + } while ((unsigned)x < y) { - z = kb[x]; kb[x] = kb[y]; kb[y] = z; + z = kb[x]; kb[x] = kb[y]; kb[y] = (byte)z; ++x; --y; } @@ -3798,7 +8968,7 @@ static int accel_fp_mul(int idx, mp_int* k, ecc_point *R, mp_int* modulus, /* double if not first */ if (!first) { - if ((err = ecc_projective_dbl_point(R, R, modulus, + if ((err = ecc_projective_dbl_point(R, R, a, modulus, mp)) != MP_OKAY) { break; } @@ -3806,10 +8976,35 @@ static int accel_fp_mul(int idx, mp_int* k, ecc_point *R, mp_int* modulus, /* add if not first, otherwise copy */ if (!first && z) { - if ((err = ecc_projective_add_point(R, fp_cache[idx].LUT[z], R, + if ((err = ecc_projective_add_point(R, fp_cache[idx].LUT[z], R, a, modulus, mp)) != MP_OKAY) { break; } + if (mp_iszero(R->z)) { + /* When all zero then should have done an add */ + if (mp_iszero(R->x) && mp_iszero(R->y)) { + if ((err = ecc_projective_dbl_point(fp_cache[idx].LUT[z], + R, a, modulus, mp)) != MP_OKAY) { + break; + } + } + /* When only Z zero then result is infinity */ + else { + err = mp_set(R->x, 0); + if (err != MP_OKAY) { + break; + } + err = mp_set(R->y, 0); + if (err != MP_OKAY) { + break; + } + err = mp_copy(&fp_cache[idx].mu, R->z); + if (err != MP_OKAY) { + break; + } + first = 1; + } + } } else if (z) { if ((mp_copy(fp_cache[idx].LUT[z]->x, R->x) != MP_OKAY) || (mp_copy(fp_cache[idx].LUT[z]->y, R->y) != MP_OKAY) || @@ -3817,14 +9012,15 @@ static int accel_fp_mul(int idx, mp_int* k, ecc_point *R, mp_int* modulus, err = GEN_MEM_ERR; break; } - first = 0; + first = 0; } } } if (err == MP_OKAY) { - z = 0; + (void) z; /* Acknowledge the unused assignment */ ForceZero(kb, KB_SIZE); + /* map R back from projective space */ if (map) { err = ecc_map(R, modulus, mp); @@ -3833,35 +9029,41 @@ static int accel_fp_mul(int idx, mp_int* k, ecc_point *R, mp_int* modulus, } } +done: + /* cleanup */ + mp_clear(&order); + mp_clear(&tk); + #ifdef WOLFSSL_SMALL_STACK - XFREE(kb, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(kb, NULL, DYNAMIC_TYPE_ECC_BUFFER); #endif #undef KB_SIZE return err; } +#endif #ifdef ECC_SHAMIR +#ifndef WOLFSSL_SP_MATH /* perform a fixed point ECC mulmod */ -static int accel_fp_mul2add(int idx1, int idx2, +static int accel_fp_mul2add(int idx1, int idx2, mp_int* kA, mp_int* kB, - ecc_point *R, mp_int* modulus, mp_digit* mp) + ecc_point *R, mp_int* a, + mp_int* modulus, mp_digit mp) { #define KB_SIZE 128 #ifdef WOLFSSL_SMALL_STACK - unsigned char* kb[2]; + unsigned char* kb[2] = {NULL, NULL}; #else - unsigned char kb[2][128]; + unsigned char kb[2][KB_SIZE]; #endif - int x; - unsigned y, z, err, bitlen, bitpos, lut_gap, first, zA, zB; - mp_int tka; - mp_int tkb; - mp_int order; + int x, err; + unsigned y, z, bitlen, bitpos, lut_gap, first, zA, zB; + mp_int tka, tkb, order; - if (mp_init_multi(&tka, &tkb, 0, 0, 0, 0) != MP_OKAY) + if (mp_init_multi(&tka, &tkb, &order, NULL, NULL, NULL) != MP_OKAY) return MP_INIT_E; /* if it's smaller than modulus we fine */ @@ -3871,37 +9073,30 @@ static int accel_fp_mul2add(int idx1, int idx2, for (x = 0; ecc_sets[x].size; x++) { if (y <= (unsigned)ecc_sets[x].size) break; } - + /* back off if we are on the 521 bit curve */ if (y == 66) --x; - - if ((err = mp_init(&order)) != MP_OKAY) { - mp_clear(&tkb); - mp_clear(&tka); - return err; - } - if ((err = mp_read_radix(&order, ecc_sets[x].order, 16)) != MP_OKAY) { - mp_clear(&tkb); - mp_clear(&tka); - mp_clear(&order); - return err; + + if ((err = mp_read_radix(&order, ecc_sets[x].order, + MP_RADIX_HEX)) != MP_OKAY) { + goto done; } /* kA must be less than modulus */ if (mp_cmp(kA, &order) != MP_LT) { if ((err = mp_mod(kA, &order, &tka)) != MP_OKAY) { - mp_clear(&tkb); - mp_clear(&tka); - mp_clear(&order); - return err; + goto done; } } else { - mp_copy(kA, &tka); + if ((err = mp_copy(kA, &tka)) != MP_OKAY) { + goto done; + } } - mp_clear(&order); } else { - mp_copy(kA, &tka); - } + if ((err = mp_copy(kA, &tka)) != MP_OKAY) { + goto done; + } + } /* if it's smaller than modulus we fine */ if (mp_unsigned_bin_size(kB) > mp_unsigned_bin_size(modulus)) { @@ -3910,97 +9105,88 @@ static int accel_fp_mul2add(int idx1, int idx2, for (x = 0; ecc_sets[x].size; x++) { if (y <= (unsigned)ecc_sets[x].size) break; } - + /* back off if we are on the 521 bit curve */ if (y == 66) --x; - - if ((err = mp_init(&order)) != MP_OKAY) { - mp_clear(&tkb); - mp_clear(&tka); - return err; - } - if ((err = mp_read_radix(&order, ecc_sets[x].order, 16)) != MP_OKAY) { - mp_clear(&tkb); - mp_clear(&tka); - mp_clear(&order); - return err; + + if ((err = mp_read_radix(&order, ecc_sets[x].order, + MP_RADIX_HEX)) != MP_OKAY) { + goto done; } /* kB must be less than modulus */ if (mp_cmp(kB, &order) != MP_LT) { if ((err = mp_mod(kB, &order, &tkb)) != MP_OKAY) { - mp_clear(&tkb); - mp_clear(&tka); - mp_clear(&order); - return err; + goto done; } } else { - mp_copy(kB, &tkb); + if ((err = mp_copy(kB, &tkb)) != MP_OKAY) { + goto done; + } } - mp_clear(&order); } else { - mp_copy(kB, &tkb); - } + if ((err = mp_copy(kB, &tkb)) != MP_OKAY) { + goto done; + } + } /* get bitlen and round up to next multiple of FP_LUT */ bitlen = mp_unsigned_bin_size(modulus) << 3; x = bitlen % FP_LUT; if (x) { bitlen += FP_LUT - x; - } + } lut_gap = bitlen / FP_LUT; - + /* get the k value */ if ((mp_unsigned_bin_size(&tka) > (int)(KB_SIZE - 2)) || (mp_unsigned_bin_size(&tkb) > (int)(KB_SIZE - 2)) ) { - mp_clear(&tka); - mp_clear(&tkb); - return BUFFER_E; + err = BUFFER_E; goto done; } - + /* store k */ #ifdef WOLFSSL_SMALL_STACK - kb[0] = (unsigned char*)XMALLOC(KB_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (kb[0] == NULL) - return MEMORY_E; + kb[0] = (unsigned char*)XMALLOC(KB_SIZE, NULL, DYNAMIC_TYPE_ECC_BUFFER); + if (kb[0] == NULL) { + err = MEMORY_E; goto done; + } #endif XMEMSET(kb[0], 0, KB_SIZE); if ((err = mp_to_unsigned_bin(&tka, kb[0])) != MP_OKAY) { - mp_clear(&tka); - mp_clear(&tkb); - XFREE(kb[0], NULL, DYNAMIC_TYPE_TMP_BUFFER); - return err; + goto done; } - + /* let's reverse kb so it's little endian */ x = 0; - y = mp_unsigned_bin_size(&tka) - 1; + y = mp_unsigned_bin_size(&tka); + if (y > 0) { + y -= 1; + } mp_clear(&tka); while ((unsigned)x < y) { - z = kb[0][x]; kb[0][x] = kb[0][y]; kb[0][y] = z; + z = kb[0][x]; kb[0][x] = kb[0][y]; kb[0][y] = (byte)z; ++x; --y; - } - + } + /* store b */ #ifdef WOLFSSL_SMALL_STACK - kb[1] = (unsigned char*)XMALLOC(KB_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + kb[1] = (unsigned char*)XMALLOC(KB_SIZE, NULL, DYNAMIC_TYPE_ECC_BUFFER); if (kb[1] == NULL) { - XFREE(kb[0], NULL, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; + err = MEMORY_E; goto done; } #endif XMEMSET(kb[1], 0, KB_SIZE); - if ((err = mp_to_unsigned_bin(&tkb, kb[1])) != MP_OKAY) { - mp_clear(&tkb); - } - else { + if ((err = mp_to_unsigned_bin(&tkb, kb[1])) == MP_OKAY) { x = 0; - y = mp_unsigned_bin_size(&tkb) - 1; - mp_clear(&tkb); + y = mp_unsigned_bin_size(&tkb); + if (y > 0) { + y -= 1; + } + while ((unsigned)x < y) { - z = kb[1][x]; kb[1][x] = kb[1][y]; kb[1][y] = z; + z = kb[1][x]; kb[1][x] = kb[1][y]; kb[1][y] = (byte)z; ++x; --y; } @@ -4019,31 +9205,82 @@ static int accel_fp_mul2add(int idx1, int idx2, /* double if not first */ if (!first) { - if ((err = ecc_projective_dbl_point(R, R, modulus, + if ((err = ecc_projective_dbl_point(R, R, a, modulus, mp)) != MP_OKAY) { break; } - } - /* add if not first, otherwise copy */ - if (!first) { + /* add if not first, otherwise copy */ if (zA) { if ((err = ecc_projective_add_point(R, fp_cache[idx1].LUT[zA], - R, modulus, mp)) != MP_OKAY) { + R, a, modulus, mp)) != MP_OKAY) { break; } + if (mp_iszero(R->z)) { + /* When all zero then should have done an add */ + if (mp_iszero(R->x) && mp_iszero(R->y)) { + if ((err = ecc_projective_dbl_point( + fp_cache[idx1].LUT[zA], R, + a, modulus, mp)) != MP_OKAY) { + break; + } + } + /* When only Z zero then result is infinity */ + else { + err = mp_set(R->x, 0); + if (err != MP_OKAY) { + break; + } + err = mp_set(R->y, 0); + if (err != MP_OKAY) { + break; + } + err = mp_copy(&fp_cache[idx1].mu, R->z); + if (err != MP_OKAY) { + break; + } + first = 1; + } + } } + if (zB) { if ((err = ecc_projective_add_point(R, fp_cache[idx2].LUT[zB], - R, modulus, mp)) != MP_OKAY) { + R, a, modulus, mp)) != MP_OKAY) { break; } + if (mp_iszero(R->z)) { + /* When all zero then should have done an add */ + if (mp_iszero(R->x) && mp_iszero(R->y)) { + if ((err = ecc_projective_dbl_point( + fp_cache[idx2].LUT[zB], R, + a, modulus, mp)) != MP_OKAY) { + break; + } + } + /* When only Z zero then result is infinity */ + else { + err = mp_set(R->x, 0); + if (err != MP_OKAY) { + break; + } + err = mp_set(R->y, 0); + if (err != MP_OKAY) { + break; + } + err = mp_copy(&fp_cache[idx2].mu, R->z); + if (err != MP_OKAY) { + break; + } + first = 1; + } + } } } else { if (zA) { if ((mp_copy(fp_cache[idx1].LUT[zA]->x, R->x) != MP_OKAY) || - (mp_copy(fp_cache[idx1].LUT[zA]->y, R->y) != MP_OKAY) || - (mp_copy(&fp_cache[idx1].mu, R->z) != MP_OKAY)) { + (mp_copy(fp_cache[idx1].LUT[zA]->y, R->y) != MP_OKAY) || + (mp_copy(&fp_cache[idx1].mu, R->z) != MP_OKAY)) { err = GEN_MEM_ERR; break; } @@ -4052,14 +9289,40 @@ static int accel_fp_mul2add(int idx1, int idx2, if (zB && first == 0) { if (zB) { if ((err = ecc_projective_add_point(R, - fp_cache[idx2].LUT[zB], R, modulus, mp)) != MP_OKAY){ + fp_cache[idx2].LUT[zB], R, a, modulus, mp)) != MP_OKAY){ break; } + if (mp_iszero(R->z)) { + /* When all zero then should have done an add */ + if (mp_iszero(R->x) && mp_iszero(R->y)) { + if ((err = ecc_projective_dbl_point( + fp_cache[idx2].LUT[zB], R, + a, modulus, mp)) != MP_OKAY) { + break; + } + } + /* When only Z zero then result is infinity */ + else { + err = mp_set(R->x, 0); + if (err != MP_OKAY) { + break; + } + err = mp_set(R->y, 0); + if (err != MP_OKAY) { + break; + } + err = mp_copy(&fp_cache[idx2].mu, R->z); + if (err != MP_OKAY) { + break; + } + first = 1; + } + } } } else if (zB && first == 1) { if ((mp_copy(fp_cache[idx2].LUT[zB]->x, R->x) != MP_OKAY) || - (mp_copy(fp_cache[idx2].LUT[zB]->y, R->y) != MP_OKAY) || - (mp_copy(&fp_cache[idx2].mu, R->z) != MP_OKAY)) { + (mp_copy(fp_cache[idx2].LUT[zB]->y, R->y) != MP_OKAY) || + (mp_copy(&fp_cache[idx2].mu, R->z) != MP_OKAY)) { err = GEN_MEM_ERR; break; } @@ -4069,47 +9332,64 @@ static int accel_fp_mul2add(int idx1, int idx2, } } - ForceZero(kb[0], KB_SIZE); - ForceZero(kb[1], KB_SIZE); +done: + /* cleanup */ + mp_clear(&tkb); + mp_clear(&tka); + mp_clear(&order); + +#ifdef WOLFSSL_SMALL_STACK + if (kb[0]) +#endif + ForceZero(kb[0], KB_SIZE); +#ifdef WOLFSSL_SMALL_STACK + if (kb[1]) +#endif + ForceZero(kb[1], KB_SIZE); #ifdef WOLFSSL_SMALL_STACK - XFREE(kb[0], NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(kb[1], NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(kb[0], NULL, DYNAMIC_TYPE_ECC_BUFFER); + XFREE(kb[1], NULL, DYNAMIC_TYPE_ECC_BUFFER); #endif #undef KB_SIZE + if (err != MP_OKAY) + return err; + return ecc_map(R, modulus, mp); } -/** ECC Fixed Point mulmod global + +/** ECC Fixed Point mulmod global with heap hint used Computes kA*A + kB*B = C using Shamir's Trick A First point to multiply kA What to multiple A by B Second point to multiply kB What to multiple B by C [out] Destination point (can overlap with A or B) - modulus Modulus for curve + a ECC curve parameter a + modulus Modulus for curve return MP_OKAY on success -*/ +*/ int ecc_mul2add(ecc_point* A, mp_int* kA, ecc_point* B, mp_int* kB, - ecc_point* C, mp_int* modulus) + ecc_point* C, mp_int* a, mp_int* modulus, void* heap) { - int idx1 = -1, idx2 = -1, err = MP_OKAY, mpInit = 0; + int idx1 = -1, idx2 = -1, err, mpInit = 0; mp_digit mp; mp_int mu; - + err = mp_init(&mu); if (err != MP_OKAY) return err; #ifndef HAVE_THREAD_LS if (initMutex == 0) { - InitMutex(&ecc_fp_lock); + wc_InitMutex(&ecc_fp_lock); initMutex = 1; } - if (LockMutex(&ecc_fp_lock) != 0) + if (wc_LockMutex(&ecc_fp_lock) != 0) return BAD_MUTEX_E; #endif /* HAVE_THREAD_LS */ @@ -4128,11 +9408,10 @@ int ecc_mul2add(ecc_point* A, mp_int* kA, ++(fp_cache[idx1].lru_count); } - if (err == MP_OKAY) + if (err == MP_OKAY) { /* find point */ idx2 = find_base(B); - if (err == MP_OKAY) { /* no entry? */ if (idx2 == -1) { /* find hole and add it */ @@ -4156,10 +9435,10 @@ int ecc_mul2add(ecc_point* A, mp_int* kA, mpInit = 1; err = mp_montgomery_calc_normalization(&mu, modulus); } - + if (err == MP_OKAY) /* build the LUT */ - err = build_lut(idx1, modulus, &mp, &mu); + err = build_lut(idx1, a, modulus, mp, &mu); } } @@ -4174,10 +9453,10 @@ int ecc_mul2add(ecc_point* A, mp_int* kA, err = mp_montgomery_calc_normalization(&mu, modulus); } } - - if (err == MP_OKAY) + + if (err == MP_OKAY) /* build the LUT */ - err = build_lut(idx2, modulus, &mp, &mu); + err = build_lut(idx2, a, modulus, mp, &mu); } } @@ -4190,48 +9469,55 @@ int ecc_mul2add(ecc_point* A, mp_int* kA, err = mp_montgomery_setup(modulus, &mp); } if (err == MP_OKAY) - err = accel_fp_mul2add(idx1, idx2, kA, kB, C, modulus, &mp); + err = accel_fp_mul2add(idx1, idx2, kA, kB, C, a, modulus, mp); } else { - err = normal_ecc_mul2add(A, kA, B, kB, C, modulus); + err = normal_ecc_mul2add(A, kA, B, kB, C, a, modulus, heap); } } #ifndef HAVE_THREAD_LS - UnLockMutex(&ecc_fp_lock); + wc_UnLockMutex(&ecc_fp_lock); #endif /* HAVE_THREAD_LS */ mp_clear(&mu); return err; } #endif +#endif /* ECC_SHAMIR */ /** ECC Fixed Point mulmod global k The multiplicand G Base point to multiply R [out] Destination of product + a ECC curve parameter a modulus The modulus for the curve - map [boolean] If non-zero maps the point back to affine co-ordinates, + map [boolean] If non-zero maps the point back to affine coordinates, otherwise it's left in jacobian-montgomery form return MP_OKAY if successful -*/ -int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, - int map) +*/ +int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, + mp_int* modulus, int map, void* heap) { +#ifndef WOLFSSL_SP_MATH int idx, err = MP_OKAY; mp_digit mp; mp_int mu; int mpSetup = 0; + if (k == NULL || G == NULL || R == NULL || a == NULL || modulus == NULL) { + return ECC_BAD_ARG_E; + } + if (mp_init(&mu) != MP_OKAY) return MP_INIT_E; - + #ifndef HAVE_THREAD_LS if (initMutex == 0) { - InitMutex(&ecc_fp_lock); + wc_InitMutex(&ecc_fp_lock); initMutex = 1; } - - if (LockMutex(&ecc_fp_lock) != 0) + + if (wc_LockMutex(&ecc_fp_lock) != 0) return BAD_MUTEX_E; #endif /* HAVE_THREAD_LS */ @@ -4252,7 +9538,7 @@ int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, } - if (err == MP_OKAY) { + if (err == MP_OKAY) { /* if it's 2 build the LUT, if it's higher just use the LUT */ if (idx >= 0 && fp_cache[idx].lru_count == 2) { /* compute mp */ @@ -4263,34 +9549,52 @@ int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, mpSetup = 1; err = mp_montgomery_calc_normalization(&mu, modulus); } - - if (err == MP_OKAY) + + if (err == MP_OKAY) /* build the LUT */ - err = build_lut(idx, modulus, &mp, &mu); + err = build_lut(idx, a, modulus, mp, &mu); } } - if (err == MP_OKAY) { + if (err == MP_OKAY) { if (idx >= 0 && fp_cache[idx].lru_count >= 2) { if (mpSetup == 0) { /* compute mp */ err = mp_montgomery_setup(modulus, &mp); } if (err == MP_OKAY) - err = accel_fp_mul(idx, k, R, modulus, &mp, map); + err = accel_fp_mul(idx, k, R, a, modulus, mp, map); } else { - err = normal_ecc_mulmod(k, G, R, modulus, map); + err = normal_ecc_mulmod(k, G, R, a, modulus, map, heap); } } #ifndef HAVE_THREAD_LS - UnLockMutex(&ecc_fp_lock); + wc_UnLockMutex(&ecc_fp_lock); #endif /* HAVE_THREAD_LS */ mp_clear(&mu); return err; +#else + if (k == NULL || G == NULL || R == NULL || a == NULL || modulus == NULL) { + return ECC_BAD_ARG_E; + } + +#ifndef WOLFSSL_SP_NO_256 + if (mp_count_bits(modulus) == 256) { + return sp_ecc_mulmod_256(k, G, R, map, heap); + } +#endif +#ifdef WOLFSSL_SP_384 + if (mp_count_bits(modulus) == 384) { + return sp_ecc_mulmod_384(k, G, R, map, heap); + } +#endif + return WC_KEY_SIZE_E; +#endif } +#ifndef WOLFSSL_SP_MATH /* helper function for freeing the cache ... must be called with the cache mutex locked */ static void wc_ecc_fp_free_cache(void) @@ -4299,38 +9603,41 @@ static void wc_ecc_fp_free_cache(void) for (x = 0; x < FP_ENTRIES; x++) { if (fp_cache[x].g != NULL) { for (y = 0; y < (1U<<FP_LUT); y++) { - ecc_del_point(fp_cache[x].LUT[y]); + wc_ecc_del_point(fp_cache[x].LUT[y]); fp_cache[x].LUT[y] = NULL; } - ecc_del_point(fp_cache[x].g); + wc_ecc_del_point(fp_cache[x].g); fp_cache[x].g = NULL; mp_clear(&fp_cache[x].mu); fp_cache[x].lru_count = 0; fp_cache[x].lock = 0; - } + } } -} +} +#endif /** Free the Fixed Point cache */ void wc_ecc_fp_free(void) { +#ifndef WOLFSSL_SP_MATH #ifndef HAVE_THREAD_LS if (initMutex == 0) { - InitMutex(&ecc_fp_lock); + wc_InitMutex(&ecc_fp_lock); initMutex = 1; } - - if (LockMutex(&ecc_fp_lock) == 0) { + + if (wc_LockMutex(&ecc_fp_lock) == 0) { #endif /* HAVE_THREAD_LS */ wc_ecc_fp_free_cache(); #ifndef HAVE_THREAD_LS - UnLockMutex(&ecc_fp_lock); - FreeMutex(&ecc_fp_lock); + wc_UnLockMutex(&ecc_fp_lock); + wc_FreeMutex(&ecc_fp_lock); initMutex = 0; } #endif /* HAVE_THREAD_LS */ +#endif } @@ -4340,21 +9647,21 @@ void wc_ecc_fp_free(void) enum ecCliState { - ecCLI_INIT = 1, - ecCLI_SALT_GET = 2, - ecCLI_SALT_SET = 3, - ecCLI_SENT_REQ = 4, - ecCLI_RECV_RESP = 5, - ecCLI_BAD_STATE = 99 + ecCLI_INIT = 1, + ecCLI_SALT_GET = 2, + ecCLI_SALT_SET = 3, + ecCLI_SENT_REQ = 4, + ecCLI_RECV_RESP = 5, + ecCLI_BAD_STATE = 99 }; enum ecSrvState { - ecSRV_INIT = 1, - ecSRV_SALT_GET = 2, - ecSRV_SALT_SET = 3, - ecSRV_RECV_REQ = 4, - ecSRV_SENT_RESP = 5, - ecSRV_BAD_STATE = 99 + ecSRV_INIT = 1, + ecSRV_SALT_GET = 2, + ecSRV_SALT_SET = 3, + ecSRV_RECV_REQ = 4, + ecSRV_SENT_RESP = 5, + ecSRV_BAD_STATE = 99 }; @@ -4365,6 +9672,7 @@ struct ecEncCtx { word32 kdfSaltSz; /* size of kdfSalt */ word32 kdfInfoSz; /* size of kdfInfo */ word32 macSaltSz; /* size of macSalt */ + void* heap; /* heap hint for memory used */ byte clientSalt[EXCHANGE_SALT_SZ]; /* for msg exchange */ byte serverSalt[EXCHANGE_SALT_SZ]; /* for msg exchange */ byte encAlgo; /* which encryption type */ @@ -4435,7 +9743,7 @@ int wc_ecc_ctx_set_peer_salt(ecEncCtx* ctx, const byte* salt) ctx->cliSt = ecCLI_SALT_SET; else { ctx->cliSt = ecCLI_BAD_STATE; - return BAD_ENC_STATE_E; + return BAD_STATE_E; } } else { @@ -4444,7 +9752,7 @@ int wc_ecc_ctx_set_peer_salt(ecEncCtx* ctx, const byte* salt) ctx->srvSt = ecSRV_SALT_SET; else { ctx->srvSt = ecSRV_BAD_STATE; - return BAD_ENC_STATE_E; + return BAD_STATE_E; } } @@ -4470,11 +9778,11 @@ int wc_ecc_ctx_set_peer_salt(ecEncCtx* ctx, const byte* salt) } -static int ecc_ctx_set_salt(ecEncCtx* ctx, int flags, RNG* rng) +static int ecc_ctx_set_salt(ecEncCtx* ctx, int flags, WC_RNG* rng) { byte* saltBuffer = NULL; - if (ctx == NULL || rng == NULL || flags == 0) + if (ctx == NULL || rng == NULL || flags == 0) return BAD_FUNC_ARG; saltBuffer = (flags == REQ_RESP_CLIENT) ? ctx->clientSalt : ctx->serverSalt; @@ -4501,8 +9809,8 @@ static void ecc_ctx_init(ecEncCtx* ctx, int flags) } -/* allow ecc context reset so user doesn't have to init/free for resue */ -int wc_ecc_ctx_reset(ecEncCtx* ctx, RNG* rng) +/* allow ecc context reset so user doesn't have to init/free for reuse */ +int wc_ecc_ctx_reset(ecEncCtx* ctx, WC_RNG* rng) { if (ctx == NULL || rng == NULL) return BAD_FUNC_ARG; @@ -4512,14 +9820,16 @@ int wc_ecc_ctx_reset(ecEncCtx* ctx, RNG* rng) } -/* alloc/init and set defaults, return new Context */ -ecEncCtx* wc_ecc_ctx_new(int flags, RNG* rng) +ecEncCtx* wc_ecc_ctx_new_ex(int flags, WC_RNG* rng, void* heap) { int ret = 0; - ecEncCtx* ctx = (ecEncCtx*)XMALLOC(sizeof(ecEncCtx), 0, DYNAMIC_TYPE_ECC); + ecEncCtx* ctx = (ecEncCtx*)XMALLOC(sizeof(ecEncCtx), heap, + DYNAMIC_TYPE_ECC); - if (ctx) + if (ctx) { ctx->protocol = (byte)flags; + ctx->heap = heap; + } ret = wc_ecc_ctx_reset(ctx, rng); if (ret != 0) { @@ -4531,12 +9841,19 @@ ecEncCtx* wc_ecc_ctx_new(int flags, RNG* rng) } +/* alloc/init and set defaults, return new Context */ +ecEncCtx* wc_ecc_ctx_new(int flags, WC_RNG* rng) +{ + return wc_ecc_ctx_new_ex(flags, rng, NULL); +} + + /* free any resources, clear any keys */ void wc_ecc_ctx_free(ecEncCtx* ctx) { if (ctx) { ForceZero(ctx, sizeof(ecEncCtx)); - XFREE(ctx, 0, DYNAMIC_TYPE_ECC); + XFREE(ctx, ctx->heap, DYNAMIC_TYPE_ECC); } } @@ -4548,7 +9865,7 @@ static int ecc_get_key_sizes(ecEncCtx* ctx, int* encKeySz, int* ivSz, switch (ctx->encAlgo) { case ecAES_128_CBC: *encKeySz = KEY_SIZE_128; - *ivSz = IV_SIZE_64; + *ivSz = IV_SIZE_128; *blockSz = AES_BLOCK_SIZE; break; default: @@ -4557,7 +9874,7 @@ static int ecc_get_key_sizes(ecEncCtx* ctx, int* encKeySz, int* ivSz, switch (ctx->macAlgo) { case ecHMAC_SHA256: - *digestSz = SHA256_DIGEST_SIZE; + *digestSz = WC_SHA256_DIGEST_SIZE; break; default: return BAD_FUNC_ARG; @@ -4573,12 +9890,12 @@ static int ecc_get_key_sizes(ecEncCtx* ctx, int* encKeySz, int* ivSz, /* ecc encrypt with shared secret run through kdf ctx holds non default algos and inputs - msgSz should be the right size for encAlgo, i.e., already padded + msgSz should be the right size for encAlgo, i.e., already padded return 0 on success */ int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx) { - int ret; + int ret = 0; word32 blockSz; word32 digestSz; ecEncCtx localCtx; @@ -4604,9 +9921,9 @@ int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, if (ctx == NULL) { /* use defaults */ ecc_ctx_init(&localCtx, 0); - ctx = &localCtx; + ctx = &localCtx; } - + ret = ecc_get_key_sizes(ctx, &encKeySz, &ivSz, &keysLen, &digestSz, &blockSz); if (ret != 0) @@ -4617,20 +9934,20 @@ int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, keysLen *= 2; if (ctx->srvSt != ecSRV_RECV_REQ) - return BAD_ENC_STATE_E; + return BAD_STATE_E; ctx->srvSt = ecSRV_BAD_STATE; /* we're done no more ops allowed */ } else if (ctx->protocol == REQ_RESP_CLIENT) { if (ctx->cliSt != ecCLI_SALT_SET) - return BAD_ENC_STATE_E; + return BAD_STATE_E; ctx->cliSt = ecCLI_SENT_REQ; /* only do this once */ } - + if (keysLen > ECC_BUFSIZE) /* keys size */ return BUFFER_E; - + if ( (msgSz%blockSz) != 0) return BAD_PADDING_E; @@ -4638,23 +9955,29 @@ int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, return BUFFER_E; #ifdef WOLFSSL_SMALL_STACK - sharedSecret = (byte*)XMALLOC(ECC_MAXSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + sharedSecret = (byte*)XMALLOC(ECC_MAXSIZE, NULL, DYNAMIC_TYPE_ECC_BUFFER); if (sharedSecret == NULL) return MEMORY_E; - keys = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + keys = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_ECC_BUFFER); if (keys == NULL) { - XFREE(sharedSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sharedSecret, NULL, DYNAMIC_TYPE_ECC_BUFFER); return MEMORY_E; } #endif - ret = wc_ecc_shared_secret(privKey, pubKey, sharedSecret, &sharedSz); - + do { + #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + ret = wc_AsyncWait(ret, &privKey->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + break; + #endif + ret = wc_ecc_shared_secret(privKey, pubKey, sharedSecret, &sharedSz); + } while (ret == WC_PENDING_E); if (ret == 0) { switch (ctx->kdfAlgo) { case ecHKDF_SHA256 : - ret = wc_HKDF(SHA256, sharedSecret, sharedSz, ctx->kdfSalt, + ret = wc_HKDF(WC_SHA256, sharedSecret, sharedSz, ctx->kdfSalt, ctx->kdfSaltSz, ctx->kdfInfo, ctx->kdfInfoSz, keys, keysLen); break; @@ -4674,11 +9997,21 @@ int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, case ecAES_128_CBC: { Aes aes; - ret = wc_AesSetKey(&aes, encKey, KEY_SIZE_128, encIv, + ret = wc_AesInit(&aes, NULL, INVALID_DEVID); + if (ret == 0) { + ret = wc_AesSetKey(&aes, encKey, KEY_SIZE_128, encIv, AES_ENCRYPTION); + if (ret == 0) { + ret = wc_AesCbcEncrypt(&aes, out, msg, msgSz); + #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_AES) + ret = wc_AsyncWait(ret, &aes.asyncDev, + WC_ASYNC_FLAG_NONE); + #endif + } + wc_AesFree(&aes); + } if (ret != 0) - break; - ret = wc_AesCbcEncrypt(&aes, out, msg, msgSz); + break; } break; @@ -4693,16 +10026,17 @@ int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, case ecHMAC_SHA256: { Hmac hmac; - ret = wc_HmacSetKey(&hmac, SHA256, macKey, SHA256_DIGEST_SIZE); - if (ret != 0) - break; - ret = wc_HmacUpdate(&hmac, out, msgSz); - if (ret != 0) - break; - ret = wc_HmacUpdate(&hmac, ctx->macSalt, ctx->macSaltSz); - if (ret != 0) - break; - ret = wc_HmacFinal(&hmac, out+msgSz); + ret = wc_HmacInit(&hmac, NULL, INVALID_DEVID); + if (ret == 0) { + ret = wc_HmacSetKey(&hmac, WC_SHA256, macKey, WC_SHA256_DIGEST_SIZE); + if (ret == 0) + ret = wc_HmacUpdate(&hmac, out, msgSz); + if (ret == 0) + ret = wc_HmacUpdate(&hmac, ctx->macSalt, ctx->macSaltSz); + if (ret == 0) + ret = wc_HmacFinal(&hmac, out+msgSz); + wc_HmacFree(&hmac); + } } break; @@ -4716,8 +10050,8 @@ int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, *outSz = msgSz + digestSz; #ifdef WOLFSSL_SMALL_STACK - XFREE(sharedSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keys, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sharedSecret, NULL, DYNAMIC_TYPE_ECC_BUFFER); + XFREE(keys, NULL, DYNAMIC_TYPE_ECC_BUFFER); #endif return ret; @@ -4730,7 +10064,7 @@ int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx) { - int ret; + int ret = 0; word32 blockSz; word32 digestSz; ecEncCtx localCtx; @@ -4756,33 +10090,33 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, if (ctx == NULL) { /* use defaults */ ecc_ctx_init(&localCtx, 0); - ctx = &localCtx; + ctx = &localCtx; } - + ret = ecc_get_key_sizes(ctx, &encKeySz, &ivSz, &keysLen, &digestSz, &blockSz); if (ret != 0) return ret; - + if (ctx->protocol == REQ_RESP_CLIENT) { offset = keysLen; keysLen *= 2; if (ctx->cliSt != ecCLI_SENT_REQ) - return BAD_ENC_STATE_E; + return BAD_STATE_E; ctx->cliSt = ecSRV_BAD_STATE; /* we're done no more ops allowed */ } else if (ctx->protocol == REQ_RESP_SERVER) { if (ctx->srvSt != ecSRV_SALT_SET) - return BAD_ENC_STATE_E; + return BAD_STATE_E; ctx->srvSt = ecSRV_RECV_REQ; /* only do this once */ } - + if (keysLen > ECC_BUFSIZE) /* keys size */ return BUFFER_E; - + if ( ((msgSz-digestSz) % blockSz) != 0) return BAD_PADDING_E; @@ -4790,23 +10124,29 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, return BUFFER_E; #ifdef WOLFSSL_SMALL_STACK - sharedSecret = (byte*)XMALLOC(ECC_MAXSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + sharedSecret = (byte*)XMALLOC(ECC_MAXSIZE, NULL, DYNAMIC_TYPE_ECC_BUFFER); if (sharedSecret == NULL) return MEMORY_E; - keys = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + keys = (byte*)XMALLOC(ECC_BUFSIZE, NULL, DYNAMIC_TYPE_ECC_BUFFER); if (keys == NULL) { - XFREE(sharedSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sharedSecret, NULL, DYNAMIC_TYPE_ECC_BUFFER); return MEMORY_E; } #endif - ret = wc_ecc_shared_secret(privKey, pubKey, sharedSecret, &sharedSz); - + do { + #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) + ret = wc_AsyncWait(ret, &privKey->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + if (ret != 0) + break; + #endif + ret = wc_ecc_shared_secret(privKey, pubKey, sharedSecret, &sharedSz); + } while (ret == WC_PENDING_E); if (ret == 0) { switch (ctx->kdfAlgo) { case ecHKDF_SHA256 : - ret = wc_HKDF(SHA256, sharedSecret, sharedSz, ctx->kdfSalt, + ret = wc_HKDF(WC_SHA256, sharedSecret, sharedSz, ctx->kdfSalt, ctx->kdfSaltSz, ctx->kdfInfo, ctx->kdfInfoSz, keys, keysLen); break; @@ -4824,25 +10164,28 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, switch (ctx->macAlgo) { case ecHMAC_SHA256: - { - byte verify[SHA256_DIGEST_SIZE]; - Hmac hmac; - ret = wc_HmacSetKey(&hmac, SHA256, macKey, SHA256_DIGEST_SIZE); - if (ret != 0) - break; - ret = wc_HmacUpdate(&hmac, msg, msgSz-digestSz); - if (ret != 0) - break; - ret = wc_HmacUpdate(&hmac, ctx->macSalt, ctx->macSaltSz); - if (ret != 0) - break; - ret = wc_HmacFinal(&hmac, verify); - if (ret != 0) - break; - if (memcmp(verify, msg + msgSz - digestSz, digestSz) != 0) - ret = -1; + { + byte verify[WC_SHA256_DIGEST_SIZE]; + Hmac hmac; + + ret = wc_HmacInit(&hmac, NULL, INVALID_DEVID); + if (ret == 0) { + ret = wc_HmacSetKey(&hmac, WC_SHA256, macKey, WC_SHA256_DIGEST_SIZE); + if (ret == 0) + ret = wc_HmacUpdate(&hmac, msg, msgSz-digestSz); + if (ret == 0) + ret = wc_HmacUpdate(&hmac, ctx->macSalt, ctx->macSaltSz); + if (ret == 0) + ret = wc_HmacFinal(&hmac, verify); + if (ret == 0) { + if (XMEMCMP(verify, msg + msgSz - digestSz, digestSz) != 0) + ret = -1; + } + + wc_HmacFree(&hmac); } break; + } default: ret = BAD_FUNC_ARG; @@ -4852,6 +10195,7 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, if (ret == 0) { switch (ctx->encAlgo) { + #ifdef HAVE_AES_CBC case ecAES_128_CBC: { Aes aes; @@ -4860,9 +10204,12 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, if (ret != 0) break; ret = wc_AesCbcDecrypt(&aes, out, msg, msgSz-digestSz); + #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_AES) + ret = wc_AsyncWait(ret, &aes.asyncDev, WC_ASYNC_FLAG_NONE); + #endif } break; - + #endif default: ret = BAD_FUNC_ARG; break; @@ -4873,8 +10220,8 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, *outSz = msgSz - digestSz; #ifdef WOLFSSL_SMALL_STACK - XFREE(sharedSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keys, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sharedSecret, NULL, DYNAMIC_TYPE_ECC_BUFFER); + XFREE(keys, NULL, DYNAMIC_TYPE_ECC_BUFFER); #endif return ret; @@ -4885,25 +10232,36 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg, #ifdef HAVE_COMP_KEY +#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_CRYPTOCELL) -/* computes the jacobi c = (a | n) (or Legendre if n is prime) - * HAC pp. 73 Algorithm 2.149 - */ -int mp_jacobi(mp_int* a, mp_int* p, int* c) +#ifndef WOLFSSL_SP_MATH +int do_mp_jacobi(mp_int* a, mp_int* n, int* c); + +int do_mp_jacobi(mp_int* a, mp_int* n, int* c) { - mp_int a1, p1; - int k, s, r, res; + int k, s, res; + int r = 0; /* initialize to help static analysis out */ mp_digit residue; - /* if p <= 0 return MP_VAL */ - if (mp_cmp_d(p, 0) != MP_GT) { + /* if a < 0 return MP_VAL */ + if (mp_isneg(a) == MP_YES) { return MP_VAL; } - /* step 1. if a == 0, return 0 */ - if (mp_iszero (a) == 1) { - *c = 0; - return MP_OKAY; + /* if n <= 0 return MP_VAL */ + if (mp_cmp_d(n, 0) != MP_GT) { + return MP_VAL; + } + + /* step 1. handle case of a == 0 */ + if (mp_iszero (a) == MP_YES) { + /* special case of a == 0 and n == 1 */ + if (mp_cmp_d (n, 1) == MP_EQ) { + *c = 1; + } else { + *c = 0; + } + return MP_OKAY; } /* step 2. if a == 1, return 1 */ @@ -4915,19 +10273,9 @@ int mp_jacobi(mp_int* a, mp_int* p, int* c) /* default */ s = 0; - /* step 3. write a = a1 * 2**k */ - if ((res = mp_init_copy (&a1, a)) != MP_OKAY) { - return res; - } - - if ((res = mp_init (&p1)) != MP_OKAY) { - mp_clear(&a1); - return res; - } - /* divide out larger power of two */ - k = mp_cnt_lsb(&a1); - res = mp_div_2d(&a1, k, &a1, NULL); + k = mp_cnt_lsb(a); + res = mp_div_2d(a, k, a, NULL); if (res == MP_OKAY) { /* step 4. if e is even set s=1 */ @@ -4935,7 +10283,7 @@ int mp_jacobi(mp_int* a, mp_int* p, int* c) s = 1; } else { /* else set s=1 if p = 1/7 (mod 8) or s=-1 if p = 3/5 (mod 8) */ - residue = p->dp[0] & 7; + residue = n->dp[0] & 7; if (residue == 1 || residue == 7) { s = 1; @@ -4944,50 +10292,114 @@ int mp_jacobi(mp_int* a, mp_int* p, int* c) } } - /* step 5. if p == 3 (mod 4) *and* a1 == 3 (mod 4) then s = -s */ - if ( ((p->dp[0] & 3) == 3) && ((a1.dp[0] & 3) == 3)) { + /* step 5. if p == 3 (mod 4) *and* a == 3 (mod 4) then s = -s */ + if ( ((n->dp[0] & 3) == 3) && ((a->dp[0] & 3) == 3)) { s = -s; } } if (res == MP_OKAY) { - /* if a1 == 1 we're done */ - if (mp_cmp_d (&a1, 1) == MP_EQ) { + /* if a == 1 we're done */ + if (mp_cmp_d(a, 1) == MP_EQ) { *c = s; } else { - /* n1 = n mod a1 */ - res = mp_mod (p, &a1, &p1); + /* n1 = n mod a */ + res = mp_mod (n, a, n); if (res == MP_OKAY) - res = mp_jacobi (&p1, &a1, &r); + res = do_mp_jacobi(n, a, &r); if (res == MP_OKAY) - *c = s * r; + *c = s * r; } } - /* done */ - mp_clear (&p1); - mp_clear (&a1); + return res; +} + + +/* computes the jacobi c = (a | n) (or Legendre if n is prime) + * HAC pp. 73 Algorithm 2.149 + * HAC is wrong here, as the special case of (0 | 1) is not + * handled correctly. + */ +int mp_jacobi(mp_int* a, mp_int* n, int* c) +{ + mp_int a1, n1; + int res; + + /* step 3. write a = a1 * 2**k */ + if ((res = mp_init_multi(&a1, &n1, NULL, NULL, NULL, NULL)) != MP_OKAY) { + return res; + } + + if ((res = mp_copy(a, &a1)) != MP_OKAY) { + goto done; + } + + if ((res = mp_copy(n, &n1)) != MP_OKAY) { + goto done; + } + + res = do_mp_jacobi(&a1, &n1, c); + +done: + /* cleanup */ + mp_clear(&n1); + mp_clear(&a1); return res; } +/* Solves the modular equation x^2 = n (mod p) + * where prime number is greater than 2 (odd prime). + * The result is returned in the third argument x + * the function returns MP_OKAY on success, MP_VAL or another error on failure + */ int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret) { +#ifdef SQRTMOD_USE_MOD_EXP + int res; + + mp_int e; + + res = mp_init(&e); + if (res == MP_OKAY) + res = mp_add_d(prime, 1, &e); + if (res == MP_OKAY) + res = mp_div_2d(&e, 2, &e, NULL); + if (res == MP_OKAY) + res = mp_exptmod(n, &e, prime, ret); + + mp_clear(&e); + + return res; +#else int res, legendre, done = 0; mp_int t1, C, Q, S, Z, M, T, R, two; mp_digit i; - /* first handle the simple cases */ + /* first handle the simple cases n = 0 or n = 1 */ if (mp_cmp_d(n, 0) == MP_EQ) { mp_zero(ret); return MP_OKAY; } - if (mp_cmp_d(prime, 2) == MP_EQ) return MP_VAL; /* prime must be odd */ - /* TAO removed - if ((res = mp_jacobi(n, prime, &legendre)) != MP_OKAY) return res; - if (legendre == -1) return MP_VAL; */ /* quadratic non-residue mod prime */ + if (mp_cmp_d(n, 1) == MP_EQ) { + return mp_set(ret, 1); + } + + /* prime must be odd */ + if (mp_cmp_d(prime, 2) == MP_EQ) { + return MP_VAL; + } + + /* is quadratic non-residue mod prime */ + if ((res = mp_jacobi(n, prime, &legendre)) != MP_OKAY) { + return res; + } + if (legendre == -1) { + return MP_VAL; + } if ((res = mp_init_multi(&t1, &C, &Q, &S, &Z, &M)) != MP_OKAY) return res; @@ -5018,61 +10430,72 @@ int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret) } /* NOW: TonelliShanks algorithm */ + if (res == MP_OKAY && done == 0) { - if (res == MP_OKAY && done == 0) { - - /* factor out powers of 2 from prime-1, defining Q and S + /* factor out powers of 2 from prime-1, defining Q and S * as: prime-1 = Q*2^S */ + /* Q = prime - 1 */ res = mp_copy(prime, &Q); if (res == MP_OKAY) res = mp_sub_d(&Q, 1, &Q); - /* Q = prime - 1 */ + + /* S = 0 */ if (res == MP_OKAY) mp_zero(&S); - /* S = 0 */ - while (res == MP_OKAY && mp_iseven(&Q)) { - res = mp_div_2(&Q, &Q); + + while (res == MP_OKAY && mp_iseven(&Q) == MP_YES) { /* Q = Q / 2 */ + res = mp_div_2(&Q, &Q); + + /* S = S + 1 */ if (res == MP_OKAY) res = mp_add_d(&S, 1, &S); - /* S = S + 1 */ } /* find a Z such that the Legendre symbol (Z|prime) == -1 */ + /* Z = 2 */ if (res == MP_OKAY) res = mp_set_int(&Z, 2); - /* Z = 2 */ + while (res == MP_OKAY) { res = mp_jacobi(&Z, prime, &legendre); if (res == MP_OKAY && legendre == -1) break; + + /* Z = Z + 1 */ if (res == MP_OKAY) res = mp_add_d(&Z, 1, &Z); - /* Z = Z + 1 */ } + /* C = Z ^ Q mod prime */ if (res == MP_OKAY) res = mp_exptmod(&Z, &Q, prime, &C); - /* C = Z ^ Q mod prime */ + + /* t1 = (Q + 1) / 2 */ if (res == MP_OKAY) res = mp_add_d(&Q, 1, &t1); if (res == MP_OKAY) res = mp_div_2(&t1, &t1); - /* t1 = (Q + 1) / 2 */ + + /* R = n ^ ((Q + 1) / 2) mod prime */ if (res == MP_OKAY) res = mp_exptmod(n, &t1, prime, &R); - /* R = n ^ ((Q + 1) / 2) mod prime */ + + /* T = n ^ Q mod prime */ if (res == MP_OKAY) res = mp_exptmod(n, &Q, prime, &T); - /* T = n ^ Q mod prime */ + + /* M = S */ if (res == MP_OKAY) res = mp_copy(&S, &M); - /* M = S */ + if (res == MP_OKAY) res = mp_set_int(&two, 2); while (res == MP_OKAY && done == 0) { res = mp_copy(&T, &t1); + + /* reduce to 1 and count */ i = 0; while (res == MP_OKAY) { if (mp_cmp_d(&t1, 1) == MP_EQ) @@ -5082,34 +10505,38 @@ int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret) i++; } if (res == MP_OKAY && i == 0) { - mp_copy(&R, ret); - res = MP_OKAY; + res = mp_copy(&R, ret); done = 1; } if (done == 0) { + /* t1 = 2 ^ (M - i - 1) */ if (res == MP_OKAY) res = mp_sub_d(&M, i, &t1); if (res == MP_OKAY) res = mp_sub_d(&t1, 1, &t1); if (res == MP_OKAY) res = mp_exptmod(&two, &t1, prime, &t1); - /* t1 = 2 ^ (M - i - 1) */ - if (res == MP_OKAY) - res = mp_exptmod(&C, &t1, prime, &t1); + /* t1 = C ^ (2 ^ (M - i - 1)) mod prime */ if (res == MP_OKAY) - res = mp_sqrmod(&t1, prime, &C); + res = mp_exptmod(&C, &t1, prime, &t1); + /* C = (t1 * t1) mod prime */ if (res == MP_OKAY) - res = mp_mulmod(&R, &t1, prime, &R); + res = mp_sqrmod(&t1, prime, &C); + /* R = (R * t1) mod prime */ if (res == MP_OKAY) - res = mp_mulmod(&T, &C, prime, &T); + res = mp_mulmod(&R, &t1, prime, &R); + /* T = (T * C) mod prime */ if (res == MP_OKAY) - mp_set(&M, i); + res = mp_mulmod(&T, &C, prime, &T); + /* M = i */ + if (res == MP_OKAY) + res = mp_set(&M, i); } } } @@ -5126,19 +10553,22 @@ int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret) mp_clear(&two); return res; +#endif } +#endif +#endif /* !WOLFSSL_ATECC508A && !WOLFSSL_CRYPTOCELL */ /* export public ECC key in ANSI X9.63 format compressed */ -int wc_ecc_export_x963_compressed(ecc_key* key, byte* out, word32* outLen) +static int wc_ecc_export_x963_compressed(ecc_key* key, byte* out, word32* outLen) { word32 numlen; int ret = MP_OKAY; if (key == NULL || out == NULL || outLen == NULL) - return ECC_BAD_ARG_E; + return BAD_FUNC_ARG; - if (ecc_is_valid_idx(key->idx) == 0) { + if (wc_ecc_is_valid_idx(key->idx) == 0) { return ECC_BAD_ARG_E; } numlen = key->dp->size; @@ -5149,38 +10579,183 @@ int wc_ecc_export_x963_compressed(ecc_key* key, byte* out, word32* outLen) } /* store first byte */ - out[0] = mp_isodd(key->pubkey.y) ? 0x03 : 0x02; + out[0] = mp_isodd(key->pubkey.y) == MP_YES ? ECC_POINT_COMP_ODD : ECC_POINT_COMP_EVEN; /* pad and store x */ XMEMSET(out+1, 0, numlen); ret = mp_to_unsigned_bin(key->pubkey.x, out+1 + (numlen - mp_unsigned_bin_size(key->pubkey.x))); *outLen = 1 + numlen; + return ret; } +#endif /* HAVE_COMP_KEY */ + -/* d = a - b (mod c) */ -int mp_submod(mp_int* a, mp_int* b, mp_int* c, mp_int* d) +int wc_ecc_get_oid(word32 oidSum, const byte** oid, word32* oidSz) { - int res; - mp_int t; + int x; - if ((res = mp_init (&t)) != MP_OKAY) { - return res; - } + if (oidSum == 0) { + return BAD_FUNC_ARG; + } - if ((res = mp_sub (a, b, &t)) != MP_OKAY) { - mp_clear (&t); - return res; - } - res = mp_mod (&t, c, d); - mp_clear (&t); + /* find matching OID sum (based on encoded value) */ + for (x = 0; ecc_sets[x].size != 0; x++) { + if (ecc_sets[x].oidSum == oidSum) { + int ret; + #ifdef HAVE_OID_ENCODING + ret = 0; + /* check cache */ + oid_cache_t* o = &ecc_oid_cache[x]; + if (o->oidSz == 0) { + o->oidSz = sizeof(o->oid); + ret = EncodeObjectId(ecc_sets[x].oid, ecc_sets[x].oidSz, + o->oid, &o->oidSz); + } + if (oidSz) { + *oidSz = o->oidSz; + } + if (oid) { + *oid = o->oid; + } + /* on success return curve id */ + if (ret == 0) { + ret = ecc_sets[x].id; + } + #else + if (oidSz) { + *oidSz = ecc_sets[x].oidSz; + } + if (oid) { + *oid = ecc_sets[x].oid; + } + ret = ecc_sets[x].id; + #endif + return ret; + } + } - return res; + return NOT_COMPILED_IN; } +#ifdef WOLFSSL_CUSTOM_CURVES +int wc_ecc_set_custom_curve(ecc_key* key, const ecc_set_type* dp) +{ + if (key == NULL || dp == NULL) { + return BAD_FUNC_ARG; + } -#endif /* HAVE_COMP_KEY */ + key->idx = ECC_CUSTOM_IDX; + key->dp = dp; + + return 0; +} +#endif /* WOLFSSL_CUSTOM_CURVES */ + +#ifdef HAVE_X963_KDF + +static WC_INLINE void IncrementX963KdfCounter(byte* inOutCtr) +{ + int i; + + /* in network byte order so start at end and work back */ + for (i = 3; i >= 0; i--) { + if (++inOutCtr[i]) /* we're done unless we overflow */ + return; + } +} + +/* ASN X9.63 Key Derivation Function (SEC1) */ +int wc_X963_KDF(enum wc_HashType type, const byte* secret, word32 secretSz, + const byte* sinfo, word32 sinfoSz, byte* out, word32 outSz) +{ + int ret, i; + int digestSz, copySz; + int remaining = outSz; + byte* outIdx; + byte counter[4]; + byte tmp[WC_MAX_DIGEST_SIZE]; + +#ifdef WOLFSSL_SMALL_STACK + wc_HashAlg* hash; +#else + wc_HashAlg hash[1]; +#endif + + if (secret == NULL || secretSz == 0 || out == NULL) + return BAD_FUNC_ARG; + + /* X9.63 allowed algos only */ + if (type != WC_HASH_TYPE_SHA && type != WC_HASH_TYPE_SHA224 && + type != WC_HASH_TYPE_SHA256 && type != WC_HASH_TYPE_SHA384 && + type != WC_HASH_TYPE_SHA512) + return BAD_FUNC_ARG; + + digestSz = wc_HashGetDigestSize(type); + if (digestSz < 0) + return digestSz; + +#ifdef WOLFSSL_SMALL_STACK + hash = (wc_HashAlg*)XMALLOC(sizeof(wc_HashAlg), NULL, + DYNAMIC_TYPE_HASHES); + if (hash == NULL) + return MEMORY_E; +#endif + + ret = wc_HashInit(hash, type); + if (ret != 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(hash, NULL, DYNAMIC_TYPE_HASHES); +#endif + return ret; + } + + outIdx = out; + XMEMSET(counter, 0, sizeof(counter)); + + for (i = 1; remaining > 0; i++) { + + IncrementX963KdfCounter(counter); + + ret = wc_HashUpdate(hash, type, secret, secretSz); + if (ret != 0) { + break; + } + + ret = wc_HashUpdate(hash, type, counter, sizeof(counter)); + if (ret != 0) { + break; + } + + if (sinfo) { + ret = wc_HashUpdate(hash, type, sinfo, sinfoSz); + if (ret != 0) { + break; + } + } + + ret = wc_HashFinal(hash, type, tmp); + if (ret != 0) { + break; + } + + copySz = min(remaining, digestSz); + XMEMCPY(outIdx, tmp, copySz); + + remaining -= copySz; + outIdx += copySz; + } + + wc_HashFree(hash, type); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(hash, NULL, DYNAMIC_TYPE_HASHES); +#endif + + return ret; +} +#endif /* HAVE_X963_KDF */ #endif /* HAVE_ECC */ |