[
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2015, Yohanes Nugroho\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n"
  },
  {
    "path": "LICENSE-micro-ecc.txt",
    "content": "Copyright (c) 2014, Kenneth MacKay\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n * Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "teensy-u2f\n==========\n\nU2F implementation for Teensy LC. \n\nThis implementation is simple, works, but a bit insecure in the key handle generation part and user presence check. \n\nThe key handle is generated from private key  XOR-ed  with a simple fixed key (note: key handle generation is outside of U2F implementation scope). Attacker that knows the fixed key (or able to deduce it from multiple registrations request) can get the private key sign any authentication request although in practice its not that easy to perform this attack.\n\nBecause there is no user button in Teensy LC, I didn't actually implement any button handling logic for 'user-presence' check. On first request this implementation will assume button is not pressed, and on next request it will assume the user has pressed the button. When logging in to a website, you may need to unplug and replug the Teensy LC.\n\nFor the ECDSA key generation and signing this implementation uses the micro-ecc library:\n\n<https://github.com/kmackay/micro-ecc>\n\n\nLicense\n-------\n\nSee LICENSE.txt\n"
  },
  {
    "path": "u2f/Makefile.desktop",
    "content": "\nall: desktop_test\n\nuECC.o\t: uECC.c\n\tgcc -Wall -c uECC.c\n\ndesktop_test: desktop_test.cpp sha256.c u2f.ino uECC.o\n\t      g++ -Wall -DIS_DESKTOP_TEST=1 desktop_test.cpp sha256.c uECC.o  -o desktop_test \n\t      "
  },
  {
    "path": "u2f/asm_arm.h",
    "content": "/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */\n\n#ifndef _UECC_ASM_ARM_H_\n#define _UECC_ASM_ARM_H_\n\n#include \"asm_arm_mult_square.h\"\n\n#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)\n    #define uECC_MIN_WORDS 8\n#endif\n#if uECC_SUPPORTS_secp224r1\n    #undef uECC_MIN_WORDS\n    #define uECC_MIN_WORDS 7\n#endif\n#if uECC_SUPPORTS_secp192r1\n    #undef uECC_MIN_WORDS\n    #define uECC_MIN_WORDS 6\n#endif\n#if uECC_SUPPORTS_secp160r1\n    #undef uECC_MIN_WORDS\n    #define uECC_MIN_WORDS 5\n#endif\n\n#if (uECC_PLATFORM == uECC_arm_thumb)\n    #define REG_RW \"+l\"\n    #define REG_WRITE \"=l\"\n#else\n    #define REG_RW \"+r\"\n    #define REG_WRITE \"=r\"\n#endif\n\n#if (uECC_PLATFORM == uECC_arm_thumb || uECC_PLATFORM == uECC_arm_thumb2)\n    #define REG_RW_LO \"+l\"\n    #define REG_WRITE_LO \"=l\"\n#else\n    #define REG_RW_LO \"+r\"\n    #define REG_WRITE_LO \"=r\"\n#endif\n\n#if (uECC_PLATFORM == uECC_arm_thumb2)\n    #define RESUME_SYNTAX\n#else\n    #define RESUME_SYNTAX \".syntax divided \\n\\t\"\n#endif\n\n#if (uECC_OPTIMIZATION_LEVEL >= 2)\n\nuECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result,\n                                      const uECC_word_t *left,\n                                      const uECC_word_t *right,\n                                      wordcount_t num_words) {\n#if (uECC_MAX_WORDS != uECC_MIN_WORDS)\n  #if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2)\n    uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 2 + 1;\n  #else /* ARM */\n    uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 4;\n  #endif\n#endif\n    uint32_t carry;\n    uint32_t left_word;\n    uint32_t right_word;\n    \n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"movs %[carry], #0 \\n\\t\"\n    #if (uECC_MAX_WORDS != uECC_MIN_WORDS)\n        \"adr %[left], 1f \\n\\t\"\n        \".align 4 \\n\\t\"\n        \"adds %[jump], %[left] \\n\\t\"\n    #endif\n        \n        \"ldmia %[lptr]!, {%[left]} \\n\\t\"\n        \"ldmia %[rptr]!, {%[right]} \\n\\t\"\n        \"adds %[left], %[right] \\n\\t\"\n        \"stmia %[dptr]!, {%[left]} \\n\\t\"\n        \n    #if (uECC_MAX_WORDS != uECC_MIN_WORDS)\n        \"bx %[jump] \\n\\t\"\n    #endif\n        \"1: \\n\\t\"\n        REPEAT(DEC(uECC_MAX_WORDS),\n            \"ldmia %[lptr]!, {%[left]} \\n\\t\"\n            \"ldmia %[rptr]!, {%[right]} \\n\\t\"\n            \"adcs %[left], %[right] \\n\\t\"\n            \"stmia %[dptr]!, {%[left]} \\n\\t\")\n        \n        \"adcs %[carry], %[carry] \\n\\t\"\n        RESUME_SYNTAX\n        : [dptr] REG_RW_LO (result), [lptr] REG_RW_LO (left), [rptr] REG_RW_LO (right),\n    #if (uECC_MAX_WORDS != uECC_MIN_WORDS)\n          [jump] REG_RW_LO (jump),\n    #endif\n          [carry] REG_WRITE_LO (carry), [left] REG_WRITE_LO (left_word),\n          [right] REG_WRITE_LO (right_word)\n        :\n        : \"cc\", \"memory\"\n    );\n    return carry;\n}\n#define asm_add 1\n\nuECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result,\n                                      const uECC_word_t *left,\n                                      const uECC_word_t *right,\n                                      wordcount_t num_words) {\n#if (uECC_MAX_WORDS != uECC_MIN_WORDS)\n  #if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2)\n    uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 2 + 1;\n  #else /* ARM */\n    uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 4;\n  #endif\n#endif\n    uint32_t carry;\n    uint32_t left_word;\n    uint32_t right_word;\n    \n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"movs %[carry], #0 \\n\\t\"\n    #if (uECC_MAX_WORDS != uECC_MIN_WORDS)\n        \"adr %[left], 1f \\n\\t\"\n        \".align 4 \\n\\t\"\n        \"adds %[jump], %[left] \\n\\t\"\n    #endif\n        \n        \"ldmia %[lptr]!, {%[left]} \\n\\t\"\n        \"ldmia %[rptr]!, {%[right]} \\n\\t\"\n        \"subs %[left], %[right] \\n\\t\"\n        \"stmia %[dptr]!, {%[left]} \\n\\t\"\n        \n    #if (uECC_MAX_WORDS != uECC_MIN_WORDS)\n        \"bx %[jump] \\n\\t\"\n    #endif\n        \"1: \\n\\t\"\n        REPEAT(DEC(uECC_MAX_WORDS),\n            \"ldmia %[lptr]!, {%[left]} \\n\\t\"\n            \"ldmia %[rptr]!, {%[right]} \\n\\t\"\n            \"sbcs %[left], %[right] \\n\\t\"\n            \"stmia %[dptr]!, {%[left]} \\n\\t\")\n        \n        \"adcs %[carry], %[carry] \\n\\t\"\n        RESUME_SYNTAX\n        : [dptr] REG_RW_LO (result), [lptr] REG_RW_LO (left), [rptr] REG_RW_LO (right),\n    #if (uECC_MAX_WORDS != uECC_MIN_WORDS)\n          [jump] REG_RW_LO (jump),\n    #endif\n          [carry] REG_WRITE_LO (carry), [left] REG_WRITE_LO (left_word),\n          [right] REG_WRITE_LO (right_word)\n        :\n        : \"cc\", \"memory\"\n    );\n    return !carry; /* Note that on ARM, carry flag set means \"no borrow\" when subtracting\n                      (for some reason...) */\n}\n#define asm_sub 1\n\n#endif /* (uECC_OPTIMIZATION_LEVEL >= 2) */\n\n#if (uECC_OPTIMIZATION_LEVEL >= 3)\n\n#define FAST_MULT_ASM_5_TO_6                 \\\n    \"cmp r3, #5 \\n\\t\"                        \\\n    \"beq 1f \\n\\t\"                            \\\n                                             \\\n    /* r4 = left high, r5 = right high */    \\\n    \"ldr r4, [r1] \\n\\t\"                      \\\n    \"ldr r5, [r2] \\n\\t\"                      \\\n                                             \\\n    \"sub r0, #20 \\n\\t\"                       \\\n    \"sub r1, #20 \\n\\t\"                       \\\n    \"sub r2, #20 \\n\\t\"                       \\\n                                             \\\n    \"ldr r6, [r0] \\n\\t\"                      \\\n    \"ldr r7, [r1], #4 \\n\\t\"                  \\\n    \"ldr r8, [r2], #4 \\n\\t\"                  \\\n    \"mov r14, #0 \\n\\t\"                       \\\n    \"umull r9, r10, r4, r8 \\n\\t\"             \\\n    \"umull r11, r12, r5, r7 \\n\\t\"            \\\n    \"adds r9, r9, r6 \\n\\t\"                   \\\n    \"adc r10, r10, #0 \\n\\t\"                  \\\n    \"adds r9, r9, r11 \\n\\t\"                  \\\n    \"adcs r10, r10, r12 \\n\\t\"                \\\n    \"adc r14, r14, #0 \\n\\t\"                  \\\n    \"str r9, [r0], #4 \\n\\t\"                  \\\n                                             \\\n    \"ldr r6, [r0] \\n\\t\"                      \\\n    \"adds r10, r10, r6 \\n\\t\"                 \\\n    \"adcs r14, r14, #0 \\n\\t\"                 \\\n    \"ldr r7, [r1], #4 \\n\\t\"                  \\\n    \"ldr r8, [r2], #4 \\n\\t\"                  \\\n    \"mov r9, #0 \\n\\t\"                        \\\n    \"umull r11, r12, r4, r8 \\n\\t\"            \\\n    \"adds r10, r10, r11 \\n\\t\"                \\\n    \"adcs r14, r14, r12 \\n\\t\"                \\\n    \"adc r9, r9, #0 \\n\\t\"                    \\\n    \"umull r11, r12, r5, r7 \\n\\t\"            \\\n    \"adds r10, r10, r11 \\n\\t\"                \\\n    \"adcs r14, r14, r12 \\n\\t\"                \\\n    \"adc r9, r9, #0 \\n\\t\"                    \\\n    \"str r10, [r0], #4 \\n\\t\"                 \\\n                                             \\\n    \"ldr r6, [r0] \\n\\t\"                      \\\n    \"adds r14, r14, r6 \\n\\t\"                 \\\n    \"adcs r9, r9, #0 \\n\\t\"                   \\\n    \"ldr r7, [r1], #4 \\n\\t\"                  \\\n    \"ldr r8, [r2], #4 \\n\\t\"                  \\\n    \"mov r10, #0 \\n\\t\"                       \\\n    \"umull r11, r12, r4, r8 \\n\\t\"            \\\n    \"adds r14, r14, r11 \\n\\t\"                \\\n    \"adcs r9, r9, r12 \\n\\t\"                  \\\n    \"adc r10, r10, #0 \\n\\t\"                  \\\n    \"umull r11, r12, r5, r7 \\n\\t\"            \\\n    \"adds r14, r14, r11 \\n\\t\"                \\\n    \"adcs r9, r9, r12 \\n\\t\"                  \\\n    \"adc r10, r10, #0 \\n\\t\"                  \\\n    \"str r14, [r0], #4 \\n\\t\"                 \\\n                                             \\\n    \"ldr r6, [r0] \\n\\t\"                      \\\n    \"adds r9, r9, r6 \\n\\t\"                   \\\n    \"adcs r10, r10, #0 \\n\\t\"                 \\\n    \"ldr r7, [r1], #4 \\n\\t\"                  \\\n    \"ldr r8, [r2], #4 \\n\\t\"                  \\\n    \"mov r14, #0 \\n\\t\"                       \\\n    \"umull r11, r12, r4, r8 \\n\\t\"            \\\n    \"adds r9, r9, r11 \\n\\t\"                  \\\n    \"adcs r10, r10, r12 \\n\\t\"                \\\n    \"adc r14, r14, #0 \\n\\t\"                  \\\n    \"umull r11, r12, r5, r7 \\n\\t\"            \\\n    \"adds r9, r9, r11 \\n\\t\"                  \\\n    \"adcs r10, r10, r12 \\n\\t\"                \\\n    \"adc r14, r14, #0 \\n\\t\"                  \\\n    \"str r9, [r0], #4 \\n\\t\"                  \\\n                                             \\\n    \"ldr r6, [r0] \\n\\t\"                      \\\n    \"adds r10, r10, r6 \\n\\t\"                 \\\n    \"adcs r14, r14, #0 \\n\\t\"                 \\\n    /* skip past already-loaded (r4, r5) */  \\\n    \"ldr r7, [r1], #8 \\n\\t\"                  \\\n    \"ldr r8, [r2], #8 \\n\\t\"                  \\\n    \"mov r9, #0 \\n\\t\"                        \\\n    \"umull r11, r12, r4, r8 \\n\\t\"            \\\n    \"adds r10, r10, r11 \\n\\t\"                \\\n    \"adcs r14, r14, r12 \\n\\t\"                \\\n    \"adc r9, r9, #0 \\n\\t\"                    \\\n    \"umull r11, r12, r5, r7 \\n\\t\"            \\\n    \"adds r10, r10, r11 \\n\\t\"                \\\n    \"adcs r14, r14, r12 \\n\\t\"                \\\n    \"adc r9, r9, #0 \\n\\t\"                    \\\n    \"str r10, [r0], #4 \\n\\t\"                 \\\n                                             \\\n    \"umull r11, r12, r4, r5 \\n\\t\"            \\\n    \"adds r11, r11, r14 \\n\\t\"                \\\n    \"adc r12, r12, r9 \\n\\t\"                  \\\n    \"stmia r0!, {r11, r12} \\n\\t\"\n\n#define FAST_MULT_ASM_6_TO_7                    \\\n    \"cmp r3, #6 \\n\\t\"                           \\\n    \"beq 1f \\n\\t\"                               \\\n                                                \\\n    /* r4 = left high, r5 = right high */       \\\n    \"ldr r4, [r1] \\n\\t\"                         \\\n    \"ldr r5, [r2] \\n\\t\"                         \\\n                                                \\\n    \"sub r0, #24 \\n\\t\"                          \\\n    \"sub r1, #24 \\n\\t\"                          \\\n    \"sub r2, #24 \\n\\t\"                          \\\n                                                \\\n    \"ldr r6, [r0] \\n\\t\"                         \\\n    \"ldr r7, [r1], #4 \\n\\t\"                     \\\n    \"ldr r8, [r2], #4 \\n\\t\"                     \\\n    \"mov r14, #0 \\n\\t\"                          \\\n    \"umull r9, r10, r4, r8 \\n\\t\"                \\\n    \"umull r11, r12, r5, r7 \\n\\t\"               \\\n    \"adds r9, r9, r6 \\n\\t\"                      \\\n    \"adc r10, r10, #0 \\n\\t\"                     \\\n    \"adds r9, r9, r11 \\n\\t\"                     \\\n    \"adcs r10, r10, r12 \\n\\t\"                   \\\n    \"adc r14, r14, #0 \\n\\t\"                     \\\n    \"str r9, [r0], #4 \\n\\t\"                     \\\n                                                \\\n    \"ldr r6, [r0] \\n\\t\"                         \\\n    \"adds r10, r10, r6 \\n\\t\"                    \\\n    \"adcs r14, r14, #0 \\n\\t\"                    \\\n    \"ldr r7, [r1], #4 \\n\\t\"                     \\\n    \"ldr r8, [r2], #4 \\n\\t\"                     \\\n    \"mov r9, #0 \\n\\t\"                           \\\n    \"umull r11, r12, r4, r8 \\n\\t\"               \\\n    \"adds r10, r10, r11 \\n\\t\"                   \\\n    \"adcs r14, r14, r12 \\n\\t\"                   \\\n    \"adc r9, r9, #0 \\n\\t\"                       \\\n    \"umull r11, r12, r5, r7 \\n\\t\"               \\\n    \"adds r10, r10, r11 \\n\\t\"                   \\\n    \"adcs r14, r14, r12 \\n\\t\"                   \\\n    \"adc r9, r9, #0 \\n\\t\"                       \\\n    \"str r10, [r0], #4 \\n\\t\"                    \\\n                                                \\\n    \"ldr r6, [r0] \\n\\t\"                         \\\n    \"adds r14, r14, r6 \\n\\t\"                    \\\n    \"adcs r9, r9, #0 \\n\\t\"                      \\\n    \"ldr r7, [r1], #4 \\n\\t\"                     \\\n    \"ldr r8, [r2], #4 \\n\\t\"                     \\\n    \"mov r10, #0 \\n\\t\"                          \\\n    \"umull r11, r12, r4, r8 \\n\\t\"               \\\n    \"adds r14, r14, r11 \\n\\t\"                   \\\n    \"adcs r9, r9, r12 \\n\\t\"                     \\\n    \"adc r10, r10, #0 \\n\\t\"                     \\\n    \"umull r11, r12, r5, r7 \\n\\t\"               \\\n    \"adds r14, r14, r11 \\n\\t\"                   \\\n    \"adcs r9, r9, r12 \\n\\t\"                     \\\n    \"adc r10, r10, #0 \\n\\t\"                     \\\n    \"str r14, [r0], #4 \\n\\t\"                    \\\n                                                \\\n    \"ldr r6, [r0] \\n\\t\"                         \\\n    \"adds r9, r9, r6 \\n\\t\"                      \\\n    \"adcs r10, r10, #0 \\n\\t\"                    \\\n    \"ldr r7, [r1], #4 \\n\\t\"                     \\\n    \"ldr r8, [r2], #4 \\n\\t\"                     \\\n    \"mov r14, #0 \\n\\t\"                          \\\n    \"umull r11, r12, r4, r8 \\n\\t\"               \\\n    \"adds r9, r9, r11 \\n\\t\"                     \\\n    \"adcs r10, r10, r12 \\n\\t\"                   \\\n    \"adc r14, r14, #0 \\n\\t\"                     \\\n    \"umull r11, r12, r5, r7 \\n\\t\"               \\\n    \"adds r9, r9, r11 \\n\\t\"                     \\\n    \"adcs r10, r10, r12 \\n\\t\"                   \\\n    \"adc r14, r14, #0 \\n\\t\"                     \\\n    \"str r9, [r0], #4 \\n\\t\"                     \\\n                                                \\\n    \"ldr r6, [r0] \\n\\t\"                         \\\n    \"adds r10, r10, r6 \\n\\t\"                    \\\n    \"adcs r14, r14, #0 \\n\\t\"                    \\\n    \"ldr r7, [r1], #4 \\n\\t\"                     \\\n    \"ldr r8, [r2], #4 \\n\\t\"                     \\\n    \"mov r9, #0 \\n\\t\"                           \\\n    \"umull r11, r12, r4, r8 \\n\\t\"               \\\n    \"adds r10, r10, r11 \\n\\t\"                   \\\n    \"adcs r14, r14, r12 \\n\\t\"                   \\\n    \"adc r9, r9, #0 \\n\\t\"                       \\\n    \"umull r11, r12, r5, r7 \\n\\t\"               \\\n    \"adds r10, r10, r11 \\n\\t\"                   \\\n    \"adcs r14, r14, r12 \\n\\t\"                   \\\n    \"adc r9, r9, #0 \\n\\t\"                       \\\n    \"str r10, [r0], #4 \\n\\t\"                    \\\n                                                \\\n    \"ldr r6, [r0] \\n\\t\"                         \\\n    \"adds r14, r14, r6 \\n\\t\"                    \\\n    \"adcs r9, r9, #0 \\n\\t\"                      \\\n    /* skip past already-loaded (r4, r5) */     \\\n    \"ldr r7, [r1], #8 \\n\\t\"                     \\\n    \"ldr r8, [r2], #8 \\n\\t\"                     \\\n    \"mov r10, #0 \\n\\t\"                          \\\n    \"umull r11, r12, r4, r8 \\n\\t\"               \\\n    \"adds r14, r14, r11 \\n\\t\"                   \\\n    \"adcs r9, r9, r12 \\n\\t\"                     \\\n    \"adc r10, r10, #0 \\n\\t\"                     \\\n    \"umull r11, r12, r5, r7 \\n\\t\"               \\\n    \"adds r14, r14, r11 \\n\\t\"                   \\\n    \"adcs r9, r9, r12 \\n\\t\"                     \\\n    \"adc r10, r10, #0 \\n\\t\"                     \\\n    \"str r14, [r0], #4 \\n\\t\"                    \\\n                                                \\\n    \"umull r11, r12, r4, r5 \\n\\t\"               \\\n    \"adds r11, r11, r9 \\n\\t\"                    \\\n    \"adc r12, r12, r10 \\n\\t\"                    \\\n    \"stmia r0!, {r11, r12} \\n\\t\"\n\n#define FAST_MULT_ASM_7_TO_8                 \\\n    \"cmp r3, #7 \\n\\t\"                        \\\n    \"beq 1f \\n\\t\"                            \\\n                                             \\\n    /* r4 = left high, r5 = right high */    \\\n    \"ldr r4, [r1] \\n\\t\"                      \\\n    \"ldr r5, [r2] \\n\\t\"                      \\\n                                             \\\n    \"sub r0, #28 \\n\\t\"                       \\\n    \"sub r1, #28 \\n\\t\"                       \\\n    \"sub r2, #28 \\n\\t\"                       \\\n                                             \\\n    \"ldr r6, [r0] \\n\\t\"                      \\\n    \"ldr r7, [r1], #4 \\n\\t\"                  \\\n    \"ldr r8, [r2], #4 \\n\\t\"                  \\\n    \"mov r14, #0 \\n\\t\"                       \\\n    \"umull r9, r10, r4, r8 \\n\\t\"             \\\n    \"umull r11, r12, r5, r7 \\n\\t\"            \\\n    \"adds r9, r9, r6 \\n\\t\"                   \\\n    \"adc r10, r10, #0 \\n\\t\"                  \\\n    \"adds r9, r9, r11 \\n\\t\"                  \\\n    \"adcs r10, r10, r12 \\n\\t\"                \\\n    \"adc r14, r14, #0 \\n\\t\"                  \\\n    \"str r9, [r0], #4 \\n\\t\"                  \\\n                                             \\\n    \"ldr r6, [r0] \\n\\t\"                      \\\n    \"adds r10, r10, r6 \\n\\t\"                 \\\n    \"adcs r14, r14, #0 \\n\\t\"                 \\\n    \"ldr r7, [r1], #4 \\n\\t\"                  \\\n    \"ldr r8, [r2], #4 \\n\\t\"                  \\\n    \"mov r9, #0 \\n\\t\"                        \\\n    \"umull r11, r12, r4, r8 \\n\\t\"            \\\n    \"adds r10, r10, r11 \\n\\t\"                \\\n    \"adcs r14, r14, r12 \\n\\t\"                \\\n    \"adc r9, r9, #0 \\n\\t\"                    \\\n    \"umull r11, r12, r5, r7 \\n\\t\"            \\\n    \"adds r10, r10, r11 \\n\\t\"                \\\n    \"adcs r14, r14, r12 \\n\\t\"                \\\n    \"adc r9, r9, #0 \\n\\t\"                    \\\n    \"str r10, [r0], #4 \\n\\t\"                 \\\n                                             \\\n    \"ldr r6, [r0] \\n\\t\"                      \\\n    \"adds r14, r14, r6 \\n\\t\"                 \\\n    \"adcs r9, r9, #0 \\n\\t\"                   \\\n    \"ldr r7, [r1], #4 \\n\\t\"                  \\\n    \"ldr r8, [r2], #4 \\n\\t\"                  \\\n    \"mov r10, #0 \\n\\t\"                       \\\n    \"umull r11, r12, r4, r8 \\n\\t\"            \\\n    \"adds r14, r14, r11 \\n\\t\"                \\\n    \"adcs r9, r9, r12 \\n\\t\"                  \\\n    \"adc r10, r10, #0 \\n\\t\"                  \\\n    \"umull r11, r12, r5, r7 \\n\\t\"            \\\n    \"adds r14, r14, r11 \\n\\t\"                \\\n    \"adcs r9, r9, r12 \\n\\t\"                  \\\n    \"adc r10, r10, #0 \\n\\t\"                  \\\n    \"str r14, [r0], #4 \\n\\t\"                 \\\n                                             \\\n    \"ldr r6, [r0] \\n\\t\"                      \\\n    \"adds r9, r9, r6 \\n\\t\"                   \\\n    \"adcs r10, r10, #0 \\n\\t\"                 \\\n    \"ldr r7, [r1], #4 \\n\\t\"                  \\\n    \"ldr r8, [r2], #4 \\n\\t\"                  \\\n    \"mov r14, #0 \\n\\t\"                       \\\n    \"umull r11, r12, r4, r8 \\n\\t\"            \\\n    \"adds r9, r9, r11 \\n\\t\"                  \\\n    \"adcs r10, r10, r12 \\n\\t\"                \\\n    \"adc r14, r14, #0 \\n\\t\"                  \\\n    \"umull r11, r12, r5, r7 \\n\\t\"            \\\n    \"adds r9, r9, r11 \\n\\t\"                  \\\n    \"adcs r10, r10, r12 \\n\\t\"                \\\n    \"adc r14, r14, #0 \\n\\t\"                  \\\n    \"str r9, [r0], #4 \\n\\t\"                  \\\n                                             \\\n    \"ldr r6, [r0] \\n\\t\"                      \\\n    \"adds r10, r10, r6 \\n\\t\"                 \\\n    \"adcs r14, r14, #0 \\n\\t\"                 \\\n    \"ldr r7, [r1], #4 \\n\\t\"                  \\\n    \"ldr r8, [r2], #4 \\n\\t\"                  \\\n    \"mov r9, #0 \\n\\t\"                        \\\n    \"umull r11, r12, r4, r8 \\n\\t\"            \\\n    \"adds r10, r10, r11 \\n\\t\"                \\\n    \"adcs r14, r14, r12 \\n\\t\"                \\\n    \"adc r9, r9, #0 \\n\\t\"                    \\\n    \"umull r11, r12, r5, r7 \\n\\t\"            \\\n    \"adds r10, r10, r11 \\n\\t\"                \\\n    \"adcs r14, r14, r12 \\n\\t\"                \\\n    \"adc r9, r9, #0 \\n\\t\"                    \\\n    \"str r10, [r0], #4 \\n\\t\"                 \\\n                                             \\\n    \"ldr r6, [r0] \\n\\t\"                      \\\n    \"adds r14, r14, r6 \\n\\t\"                 \\\n    \"adcs r9, r9, #0 \\n\\t\"                   \\\n    \"ldr r7, [r1], #4 \\n\\t\"                  \\\n    \"ldr r8, [r2], #4 \\n\\t\"                  \\\n    \"mov r10, #0 \\n\\t\"                       \\\n    \"umull r11, r12, r4, r8 \\n\\t\"            \\\n    \"adds r14, r14, r11 \\n\\t\"                \\\n    \"adcs r9, r9, r12 \\n\\t\"                  \\\n    \"adc r10, r10, #0 \\n\\t\"                  \\\n    \"umull r11, r12, r5, r7 \\n\\t\"            \\\n    \"adds r14, r14, r11 \\n\\t\"                \\\n    \"adcs r9, r9, r12 \\n\\t\"                  \\\n    \"adc r10, r10, #0 \\n\\t\"                  \\\n    \"str r14, [r0], #4 \\n\\t\"                 \\\n                                             \\\n    \"ldr r6, [r0] \\n\\t\"                      \\\n    \"adds r9, r9, r6 \\n\\t\"                   \\\n    \"adcs r10, r10, #0 \\n\\t\"                 \\\n    /* skip past already-loaded (r4, r5) */  \\\n    \"ldr r7, [r1], #8 \\n\\t\"                  \\\n    \"ldr r8, [r2], #8 \\n\\t\"                  \\\n    \"mov r14, #0 \\n\\t\"                       \\\n    \"umull r11, r12, r4, r8 \\n\\t\"            \\\n    \"adds r9, r9, r11 \\n\\t\"                  \\\n    \"adcs r10, r10, r12 \\n\\t\"                \\\n    \"adc r14, r14, #0 \\n\\t\"                  \\\n    \"umull r11, r12, r5, r7 \\n\\t\"            \\\n    \"adds r9, r9, r11 \\n\\t\"                  \\\n    \"adcs r10, r10, r12 \\n\\t\"                \\\n    \"adc r14, r14, #0 \\n\\t\"                  \\\n    \"str r9, [r0], #4 \\n\\t\"                  \\\n                                             \\\n    \"umull r11, r12, r4, r5 \\n\\t\"            \\\n    \"adds r11, r11, r10 \\n\\t\"                \\\n    \"adc r12, r12, r14 \\n\\t\"                 \\\n    \"stmia r0!, {r11, r12} \\n\\t\"\n\n#if (uECC_PLATFORM != uECC_arm_thumb)\nuECC_VLI_API void uECC_vli_mult(uint32_t *result,\n                                const uint32_t *left,\n                                const uint32_t *right,\n                                wordcount_t num_words) {\n    register uint32_t *r0 __asm__(\"r0\") = result;\n    register const uint32_t *r1 __asm__(\"r1\") = left;\n    register const uint32_t *r2 __asm__(\"r2\") = right;\n    register uint32_t r3 __asm__(\"r3\") = num_words;\n    \n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"push {r3} \\n\\t\"\n    \n#if (uECC_MIN_WORDS == 5)\n        FAST_MULT_ASM_5\n        \"pop {r3} \\n\\t\"\n    #if (uECC_MAX_WORDS > 5)\n        FAST_MULT_ASM_5_TO_6\n    #endif\n    #if (uECC_MAX_WORDS > 6)\n        FAST_MULT_ASM_6_TO_7\n    #endif\n    #if (uECC_MAX_WORDS > 7)\n        FAST_MULT_ASM_7_TO_8\n    #endif\n#elif (uECC_MIN_WORDS == 6)\n        FAST_MULT_ASM_6\n        \"pop {r3} \\n\\t\"\n    #if (uECC_MAX_WORDS > 6)\n        FAST_MULT_ASM_6_TO_7\n    #endif\n    #if (uECC_MAX_WORDS > 7)\n        FAST_MULT_ASM_7_TO_8\n    #endif\n#elif (uECC_MIN_WORDS == 7)\n        FAST_MULT_ASM_7\n        \"pop {r3} \\n\\t\"\n    #if (uECC_MAX_WORDS > 7)\n        FAST_MULT_ASM_7_TO_8\n    #endif\n#elif (uECC_MIN_WORDS == 8)\n        FAST_MULT_ASM_8\n        \"pop {r3} \\n\\t\"\n#endif\n\n        \"1: \\n\\t\"\n        RESUME_SYNTAX\n        : \"+r\" (r0), \"+r\" (r1), \"+r\" (r2)\n        : \"r\" (r3)\n        : \"r4\", \"r5\", \"r6\", \"r7\", \"r8\", \"r9\", \"r10\", \"r11\", \"r12\", \"r14\", \"cc\", \"memory\"\n    );\n}\n#define asm_mult 1\n\n#if uECC_SQUARE_FUNC\n\n#define FAST_SQUARE_ASM_5_TO_6           \\\n    \"cmp r2, #5 \\n\\t\"                    \\\n    \"beq 1f \\n\\t\"                        \\\n                                         \\\n    /* r3 = high */                      \\\n    \"ldr r3, [r1] \\n\\t\"                  \\\n                                         \\\n    \"sub r0, #20 \\n\\t\"                   \\\n    \"sub r1, #20 \\n\\t\"                   \\\n                                         \\\n    /* Do off-center multiplication */   \\\n    \"ldr r14, [r1], #4 \\n\\t\"             \\\n    \"umull r4, r5, r3, r14 \\n\\t\"         \\\n    \"ldr r14, [r1], #4 \\n\\t\"             \\\n    \"umull r7, r6, r3, r14 \\n\\t\"         \\\n    \"adds r5, r5, r7 \\n\\t\"               \\\n    \"ldr r14, [r1], #4 \\n\\t\"             \\\n    \"umull r8, r7, r3, r14 \\n\\t\"         \\\n    \"adcs r6, r6, r8 \\n\\t\"               \\\n    \"ldr r14, [r1], #4 \\n\\t\"             \\\n    \"umull r9, r8, r3, r14 \\n\\t\"         \\\n    \"adcs r7, r7, r9 \\n\\t\"               \\\n    /* Skip already-loaded r3 */         \\\n    \"ldr r14, [r1], #8 \\n\\t\"             \\\n    \"umull r10, r9, r3, r14 \\n\\t\"        \\\n    \"adcs r8, r8, r10 \\n\\t\"              \\\n    \"adcs r9, r9, #0 \\n\\t\"               \\\n                                         \\\n    /* Multiply by 2 */                  \\\n    \"mov r10, #0 \\n\\t\"                   \\\n    \"adds r4, r4, r4 \\n\\t\"               \\\n    \"adcs r5, r5, r5 \\n\\t\"               \\\n    \"adcs r6, r6, r6 \\n\\t\"               \\\n    \"adcs r7, r7, r7 \\n\\t\"               \\\n    \"adcs r8, r8, r8 \\n\\t\"               \\\n    \"adcs r9, r9, r9 \\n\\t\"               \\\n    \"adcs r10, r10, #0 \\n\\t\"             \\\n                                         \\\n    /* Add into previous */              \\\n    \"ldr r14, [r0] \\n\\t\"                 \\\n    \"adds r4, r4, r14 \\n\\t\"              \\\n    \"str r4, [r0], #4 \\n\\t\"              \\\n    \"ldr r14, [r0] \\n\\t\"                 \\\n    \"adcs r5, r5, r14 \\n\\t\"              \\\n    \"str r5, [r0], #4 \\n\\t\"              \\\n    \"ldr r14, [r0] \\n\\t\"                 \\\n    \"adcs r6, r6, r14 \\n\\t\"              \\\n    \"str r6, [r0], #4 \\n\\t\"              \\\n    \"ldr r14, [r0] \\n\\t\"                 \\\n    \"adcs r7, r7, r14 \\n\\t\"              \\\n    \"str r7, [r0], #4 \\n\\t\"              \\\n    \"ldr r14, [r0] \\n\\t\"                 \\\n    \"adcs r8, r8, r14 \\n\\t\"              \\\n    \"str r8, [r0], #4 \\n\\t\"              \\\n    \"adcs r9, r9, #0 \\n\\t\"               \\\n    \"adcs r10, r10, #0 \\n\\t\"             \\\n                                         \\\n    /* Perform center multiplication */  \\\n    \"umull r4, r5, r3, r3 \\n\\t\"          \\\n    \"adds r4, r4, r9 \\n\\t\"               \\\n    \"adc r5, r5, r10 \\n\\t\"               \\\n    \"stmia r0!, {r4, r5} \\n\\t\"           \n\n#define FAST_SQUARE_ASM_6_TO_7               \\\n    \"cmp r2, #6 \\n\\t\"                        \\\n    \"beq 1f \\n\\t\"                            \\\n                                             \\\n    /* r3 = high */                          \\\n    \"ldr r3, [r1] \\n\\t\"                      \\\n                                             \\\n    \"sub r0, #24 \\n\\t\"                       \\\n    \"sub r1, #24 \\n\\t\"                       \\\n                                             \\\n    /* Do off-center multiplication */       \\\n    \"ldr r14, [r1], #4 \\n\\t\"                 \\\n    \"umull r4, r5, r3, r14 \\n\\t\"             \\\n    \"ldr r14, [r1], #4 \\n\\t\"                 \\\n    \"umull r7, r6, r3, r14 \\n\\t\"             \\\n    \"adds r5, r5, r7 \\n\\t\"                   \\\n    \"ldr r14, [r1], #4 \\n\\t\"                 \\\n    \"umull r8, r7, r3, r14 \\n\\t\"             \\\n    \"adcs r6, r6, r8 \\n\\t\"                   \\\n    \"ldr r14, [r1], #4 \\n\\t\"                 \\\n    \"umull r9, r8, r3, r14 \\n\\t\"             \\\n    \"adcs r7, r7, r9 \\n\\t\"                   \\\n    \"ldr r14, [r1], #4 \\n\\t\"                 \\\n    \"umull r10, r9, r3, r14 \\n\\t\"            \\\n    \"adcs r8, r8, r10 \\n\\t\"                  \\\n    /* Skip already-loaded r3 */             \\\n    \"ldr r14, [r1], #8 \\n\\t\"                 \\\n    \"umull r11, r10, r3, r14 \\n\\t\"           \\\n    \"adcs r9, r9, r11 \\n\\t\"                  \\\n    \"adcs r10, r10, #0 \\n\\t\"                 \\\n                                             \\\n    /* Multiply by 2 */                      \\\n    \"mov r11, #0 \\n\\t\"                       \\\n    \"adds r4, r4, r4 \\n\\t\"                   \\\n    \"adcs r5, r5, r5 \\n\\t\"                   \\\n    \"adcs r6, r6, r6 \\n\\t\"                   \\\n    \"adcs r7, r7, r7 \\n\\t\"                   \\\n    \"adcs r8, r8, r8 \\n\\t\"                   \\\n    \"adcs r9, r9, r9 \\n\\t\"                   \\\n    \"adcs r10, r10, r10 \\n\\t\"                \\\n    \"adcs r11, r11, #0 \\n\\t\"                 \\\n                                             \\\n    /* Add into previous */                  \\\n    \"ldr r14, [r0] \\n\\t\"                     \\\n    \"adds r4, r4, r14 \\n\\t\"                  \\\n    \"str r4, [r0], #4 \\n\\t\"                  \\\n    \"ldr r14, [r0] \\n\\t\"                     \\\n    \"adcs r5, r5, r14 \\n\\t\"                  \\\n    \"str r5, [r0], #4 \\n\\t\"                  \\\n    \"ldr r14, [r0] \\n\\t\"                     \\\n    \"adcs r6, r6, r14 \\n\\t\"                  \\\n    \"str r6, [r0], #4 \\n\\t\"                  \\\n    \"ldr r14, [r0] \\n\\t\"                     \\\n    \"adcs r7, r7, r14 \\n\\t\"                  \\\n    \"str r7, [r0], #4 \\n\\t\"                  \\\n    \"ldr r14, [r0] \\n\\t\"                     \\\n    \"adcs r8, r8, r14 \\n\\t\"                  \\\n    \"str r8, [r0], #4 \\n\\t\"                  \\\n    \"ldr r14, [r0] \\n\\t\"                     \\\n    \"adcs r9, r9, r14 \\n\\t\"                  \\\n    \"str r9, [r0], #4 \\n\\t\"                  \\\n    \"adcs r10, r10, #0 \\n\\t\"                 \\\n    \"adcs r11, r11, #0 \\n\\t\"                 \\\n                                             \\\n    /* Perform center multiplication */      \\\n    \"umull r4, r5, r3, r3 \\n\\t\"              \\\n    \"adds r4, r4, r10 \\n\\t\"                  \\\n    \"adc r5, r5, r11 \\n\\t\"                   \\\n    \"stmia r0!, {r4, r5} \\n\\t\"\n\n#define FAST_SQUARE_ASM_7_TO_8           \\\n    \"cmp r2, #7 \\n\\t\"                    \\\n    \"beq 1f \\n\\t\"                        \\\n                                         \\\n    /* r3 = high */                      \\\n    \"ldr r3, [r1] \\n\\t\"                  \\\n                                         \\\n    \"sub r0, #28 \\n\\t\"                   \\\n    \"sub r1, #28 \\n\\t\"                   \\\n                                         \\\n    /* Do off-center multiplication */   \\\n    \"ldr r14, [r1], #4 \\n\\t\"             \\\n    \"umull r4, r5, r3, r14 \\n\\t\"         \\\n    \"ldr r14, [r1], #4 \\n\\t\"             \\\n    \"umull r7, r6, r3, r14 \\n\\t\"         \\\n    \"adds r5, r5, r7 \\n\\t\"               \\\n    \"ldr r14, [r1], #4 \\n\\t\"             \\\n    \"umull r8, r7, r3, r14 \\n\\t\"         \\\n    \"adcs r6, r6, r8 \\n\\t\"               \\\n    \"ldr r14, [r1], #4 \\n\\t\"             \\\n    \"umull r9, r8, r3, r14 \\n\\t\"         \\\n    \"adcs r7, r7, r9 \\n\\t\"               \\\n    \"ldr r14, [r1], #4 \\n\\t\"             \\\n    \"umull r10, r9, r3, r14 \\n\\t\"        \\\n    \"adcs r8, r8, r10 \\n\\t\"              \\\n    \"ldr r14, [r1], #4 \\n\\t\"             \\\n    \"umull r11, r10, r3, r14 \\n\\t\"       \\\n    \"adcs r9, r9, r11 \\n\\t\"              \\\n    /* Skip already-loaded r3 */         \\\n    \"ldr r14, [r1], #8 \\n\\t\"             \\\n    \"umull r12, r11, r3, r14 \\n\\t\"       \\\n    \"adcs r10, r10, r12 \\n\\t\"            \\\n    \"adcs r11, r11, #0 \\n\\t\"             \\\n                                         \\\n    /* Multiply by 2 */                  \\\n    \"mov r12, #0 \\n\\t\"                   \\\n    \"adds r4, r4, r4 \\n\\t\"               \\\n    \"adcs r5, r5, r5 \\n\\t\"               \\\n    \"adcs r6, r6, r6 \\n\\t\"               \\\n    \"adcs r7, r7, r7 \\n\\t\"               \\\n    \"adcs r8, r8, r8 \\n\\t\"               \\\n    \"adcs r9, r9, r9 \\n\\t\"               \\\n    \"adcs r10, r10, r10 \\n\\t\"            \\\n    \"adcs r11, r11, r11 \\n\\t\"            \\\n    \"adcs r12, r12, #0 \\n\\t\"             \\\n                                         \\\n    /* Add into previous */              \\\n    \"ldr r14, [r0] \\n\\t\"                 \\\n    \"adds r4, r4, r14 \\n\\t\"              \\\n    \"str r4, [r0], #4 \\n\\t\"              \\\n    \"ldr r14, [r0] \\n\\t\"                 \\\n    \"adcs r5, r5, r14 \\n\\t\"              \\\n    \"str r5, [r0], #4 \\n\\t\"              \\\n    \"ldr r14, [r0] \\n\\t\"                 \\\n    \"adcs r6, r6, r14 \\n\\t\"              \\\n    \"str r6, [r0], #4 \\n\\t\"              \\\n    \"ldr r14, [r0] \\n\\t\"                 \\\n    \"adcs r7, r7, r14 \\n\\t\"              \\\n    \"str r7, [r0], #4 \\n\\t\"              \\\n    \"ldr r14, [r0] \\n\\t\"                 \\\n    \"adcs r8, r8, r14 \\n\\t\"              \\\n    \"str r8, [r0], #4 \\n\\t\"              \\\n    \"ldr r14, [r0] \\n\\t\"                 \\\n    \"adcs r9, r9, r14 \\n\\t\"              \\\n    \"str r9, [r0], #4 \\n\\t\"              \\\n    \"ldr r14, [r0] \\n\\t\"                 \\\n    \"adcs r10, r10, r14 \\n\\t\"            \\\n    \"str r10, [r0], #4 \\n\\t\"             \\\n    \"adcs r11, r11, #0 \\n\\t\"             \\\n    \"adcs r12, r12, #0 \\n\\t\"             \\\n                                         \\\n    /* Perform center multiplication */  \\\n    \"umull r4, r5, r3, r3 \\n\\t\"          \\\n    \"adds r4, r4, r11 \\n\\t\"              \\\n    \"adc r5, r5, r12 \\n\\t\"               \\\n    \"stmia r0!, {r4, r5} \\n\\t\"           \n\nuECC_VLI_API void uECC_vli_square(uECC_word_t *result,\n                                  const uECC_word_t *left,\n                                  wordcount_t num_words) {\n    register uint32_t *r0 __asm__(\"r0\") = result;\n    register const uint32_t *r1 __asm__(\"r1\") = left;\n    register uint32_t r2 __asm__(\"r2\") = num_words;\n    \n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"push {r1, r2} \\n\\t\"\n\n#if (uECC_MIN_WORDS == 5)\n        FAST_SQUARE_ASM_5\n        \"pop {r1, r2} \\n\\t\"\n    #if (uECC_MAX_WORDS > 5)\n        \"add r1, #20 \\n\\t\"\n        FAST_SQUARE_ASM_5_TO_6\n    #endif\n    #if (uECC_MAX_WORDS > 6)\n        FAST_SQUARE_ASM_6_TO_7\n    #endif\n    #if (uECC_MAX_WORDS > 7)\n        FAST_SQUARE_ASM_7_TO_8\n    #endif\n#elif (uECC_MIN_WORDS == 6)\n        FAST_SQUARE_ASM_6\n        \"pop {r1, r2} \\n\\t\"\n    #if (uECC_MAX_WORDS > 6)\n        \"add r1, #24 \\n\\t\"\n        FAST_SQUARE_ASM_6_TO_7\n    #endif\n    #if (uECC_MAX_WORDS > 7)\n        FAST_SQUARE_ASM_7_TO_8\n    #endif\n#elif (uECC_MIN_WORDS == 7)\n        FAST_SQUARE_ASM_7\n        \"pop {r1, r2} \\n\\t\"\n    #if (uECC_MAX_WORDS > 7)\n        \"add r1, #28 \\n\\t\"\n        FAST_SQUARE_ASM_7_TO_8\n    #endif\n#elif (uECC_MIN_WORDS == 8)\n        FAST_SQUARE_ASM_8\n        \"pop {r1, r2} \\n\\t\"\n#endif\n\n        \"1: \\n\\t\"\n        RESUME_SYNTAX\n        : \"+r\" (r0), \"+r\" (r1)\n        : \"r\" (r2)\n        : \"r3\", \"r4\", \"r5\", \"r6\", \"r7\", \"r8\", \"r9\", \"r10\", \"r11\", \"r12\", \"r14\", \"cc\", \"memory\"\n    );\n}\n#define asm_square 1\n#endif /* uECC_SQUARE_FUNC */\n\n#endif /* uECC_PLATFORM != uECC_arm_thumb */\n\n#endif /* (uECC_OPTIMIZATION_LEVEL >= 3) */\n\n/* ---- \"Small\" implementations ---- */\n\n#if !asm_add\nuECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result,\n                                      const uECC_word_t *left,\n                                      const uECC_word_t *right,\n                                      wordcount_t num_words) {\n    uint32_t carry = 0;\n    uint32_t left_word;\n    uint32_t right_word;\n    \n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"1: \\n\\t\"\n        \"ldmia %[lptr]!, {%[left]} \\n\\t\"  /* Load left word. */\n        \"ldmia %[rptr]!, {%[right]} \\n\\t\" /* Load right word. */\n        \"lsrs %[carry], #1 \\n\\t\"          /* Set up carry flag (carry = 0 after this). */\n        \"adcs %[left], %[left], %[right] \\n\\t\"   /* Add with carry. */\n        \"adcs %[carry], %[carry], %[carry] \\n\\t\" /* Store carry bit. */\n        \"stmia %[dptr]!, {%[left]} \\n\\t\"  /* Store result word. */\n        \"subs %[ctr], #1 \\n\\t\"            /* Decrement counter. */\n        \"bne 1b \\n\\t\"                     /* Loop until counter == 0. */\n        RESUME_SYNTAX\n        : [dptr] REG_RW (result), [lptr] REG_RW (left), [rptr] REG_RW (right),\n          [ctr] REG_RW (num_words), [carry] REG_RW (carry),\n          [left] REG_WRITE (left_word), [right] REG_WRITE (right_word)\n        :\n        : \"cc\", \"memory\"\n    );\n    return carry;\n}\n#define asm_add 1\n#endif\n\n#if !asm_sub\nuECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result,\n                                      const uECC_word_t *left,\n                                      const uECC_word_t *right,\n                                      wordcount_t num_words) {\n    uint32_t carry = 1; /* carry = 1 initially (means don't borrow) */\n    uint32_t left_word;\n    uint32_t right_word;\n    \n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"1: \\n\\t\"\n        \"ldmia %[lptr]!, {%[left]} \\n\\t\"  /* Load left word. */\n        \"ldmia %[rptr]!, {%[right]} \\n\\t\" /* Load right word. */\n        \"lsrs %[carry], #1 \\n\\t\"          /* Set up carry flag (carry = 0 after this). */\n        \"sbcs %[left], %[left], %[right] \\n\\t\"   /* Subtract with borrow. */\n        \"adcs %[carry], %[carry], %[carry] \\n\\t\" /* Store carry bit. */\n        \"stmia %[dptr]!, {%[left]} \\n\\t\"  /* Store result word. */\n        \"subs %[ctr], #1 \\n\\t\"            /* Decrement counter. */\n        \"bne 1b \\n\\t\"                     /* Loop until counter == 0. */\n        RESUME_SYNTAX\n        : [dptr] REG_RW (result), [lptr] REG_RW (left), [rptr] REG_RW (right),\n          [ctr] REG_RW (num_words), [carry] REG_RW (carry),\n          [left] REG_WRITE (left_word), [right] REG_WRITE (right_word)\n        :\n        : \"cc\", \"memory\"\n    );\n    return !carry;\n}\n#define asm_sub 1\n#endif\n\n#if !asm_mult\nuECC_VLI_API void uECC_vli_mult(uECC_word_t *result,\n                                const uECC_word_t *left,\n                                const uECC_word_t *right,\n                                wordcount_t num_words) {\n#if (uECC_PLATFORM != uECC_arm_thumb)\n    uint32_t c0 = 0;\n    uint32_t c1 = 0;\n    uint32_t c2 = 0;\n    uint32_t k = 0;\n    uint32_t i;\n    uint32_t t0, t1;\n    \n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \n        \"1: \\n\\t\" /* outer loop (k < num_words) */\n        \"movs %[i], #0 \\n\\t\" /* i = 0 */\n        \"b 3f \\n\\t\"\n        \n        \"2: \\n\\t\" /* outer loop (k >= num_words) */\n        \"movs %[i], %[k] \\n\\t\"         /* i = k */\n        \"subs %[i], %[last_word] \\n\\t\" /* i = k - (num_words - 1) (times 4) */\n        \n        \"3: \\n\\t\" /* inner loop */\n        \"subs %[t0], %[k], %[i] \\n\\t\" /* t0 = k-i */\n        \n        \"ldr %[t1], [%[right], %[t0]] \\n\\t\" /* t1 = right[k - i] */\n        \"ldr %[t0], [%[left], %[i]] \\n\\t\"   /* t0 = left[i] */\n        \n        \"umull %[t0], %[t1], %[t0], %[t1] \\n\\t\" /* (t0, t1) = left[i] * right[k - i] */\n        \n        \"adds %[c0], %[c0], %[t0] \\n\\t\" /* add low word to c0 */\n        \"adcs %[c1], %[c1], %[t1] \\n\\t\" /* add high word to c1, including carry */\n        \"adcs %[c2], %[c2], #0 \\n\\t\"    /* add carry to c2 */\n\n        \"adds %[i], #4 \\n\\t\"          /* i += 4 */\n        \"cmp %[i], %[last_word] \\n\\t\" /* i > (num_words - 1) (times 4)? */\n        \"bgt 4f \\n\\t\"                 /*   if so, exit the loop */\n        \"cmp %[i], %[k] \\n\\t\"         /* i <= k? */\n        \"ble 3b \\n\\t\"                 /*   if so, continue looping */\n        \n        \"4: \\n\\t\" /* end inner loop */\n        \n        \"str %[c0], [%[result], %[k]] \\n\\t\" /* result[k] = c0 */\n        \"mov %[c0], %[c1] \\n\\t\"       /* c0 = c1 */\n        \"mov %[c1], %[c2] \\n\\t\"       /* c1 = c2 */\n        \"movs %[c2], #0 \\n\\t\"         /* c2 = 0 */\n        \"adds %[k], #4 \\n\\t\"          /* k += 4 */\n        \"cmp %[k], %[last_word] \\n\\t\" /* k <= (num_words - 1) (times 4) ? */\n        \"ble 1b \\n\\t\"                 /*   if so, loop back, start with i = 0 */\n        \"cmp %[k], %[last_word], lsl #1 \\n\\t\" /* k <= (num_words * 2 - 2) (times 4) ? */\n        \"ble 2b \\n\\t\"                 /*   if so, loop back, start with i = (k + 1) - num_words */\n        /* end outer loop */\n        \n        \"str %[c0], [%[result], %[k]] \\n\\t\" /* result[num_words * 2 - 1] = c0 */\n        RESUME_SYNTAX\n        : [c0] \"+r\" (c0), [c1] \"+r\" (c1), [c2] \"+r\" (c2),\n          [k] \"+r\" (k), [i] \"=&r\" (i), [t0] \"=&r\" (t0), [t1] \"=&r\" (t1)\n        : [result] \"r\" (result), [left] \"r\" (left), [right] \"r\" (right),\n          [last_word] \"r\" ((num_words - 1) * 4)\n        : \"cc\", \"memory\"\n    );\n    \n#else /* Thumb-1 */\n    uint32_t r4, r5, r6, r7;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"subs %[r3], #1 \\n\\t\" /* r3 = num_words - 1 */\n        \"lsls %[r3], #2 \\n\\t\" /* r3 = (num_words - 1) * 4 */\n        \"mov r8, %[r3] \\n\\t\"  /* r8 = (num_words - 1) * 4 */\n        \"lsls %[r3], #1 \\n\\t\" /* r3 = (num_words - 1) * 8 */\n        \"mov r9, %[r3] \\n\\t\"  /* r9 = (num_words - 1) * 8 */\n        \"movs %[r3], #0 \\n\\t\" /* c0 = 0 */\n        \"movs %[r4], #0 \\n\\t\" /* c1 = 0 */\n        \"movs %[r5], #0 \\n\\t\" /* c2 = 0 */\n        \"movs %[r6], #0 \\n\\t\" /* k = 0 */\n        \n        \"push {%[r0]} \\n\\t\" /* keep result on the stack */\n        \n        \"1: \\n\\t\" /* outer loop (k < num_words) */\n        \"movs %[r7], #0 \\n\\t\" /* r7 = i = 0 */\n        \"b 3f \\n\\t\"\n        \n        \"2: \\n\\t\" /* outer loop (k >= num_words) */\n        \"movs %[r7], %[r6] \\n\\t\" /* r7 = k */\n        \"mov %[r0], r8 \\n\\t\"     /* r0 = (num_words - 1) * 4 */\n        \"subs %[r7], %[r0] \\n\\t\" /* r7 = i = k - (num_words - 1) (times 4) */\n        \n        \"3: \\n\\t\" /* inner loop */\n        \"push {%[r6]} \\n\\t\"\n        \"push {%[r5]} \\n\\t\"\n        \"push {%[r4]} \\n\\t\"\n        \"push {%[r3]} \\n\\t\" /* push things, r3 (c0) is at the top of stack. */\n        \"subs %[r0], %[r6], %[r7] \\n\\t\"          /* r0 = k - i */\n        \n        \"ldr %[r4], [%[r2], %[r0]] \\n\\t\" /* r4 = right[k - i] */\n        \"ldr %[r0], [%[r1], %[r7]] \\n\\t\" /* r0 = left[i] */\n        \n        \"lsrs %[r3], %[r0], #16 \\n\\t\" /* r3 = a1 */\n        \"uxth %[r0], %[r0] \\n\\t\"      /* r0 = a0 */\n        \n        \"lsrs %[r5], %[r4], #16 \\n\\t\" /* r5 = b1 */\n        \"uxth %[r4], %[r4] \\n\\t\"      /* r4 = b0 */\n        \n        \"movs %[r6], %[r3] \\n\\t\"        /* r6 = a1 */\n        \"muls %[r6], %[r5], %[r6] \\n\\t\" /* r6 = a1 * b1 */\n        \"muls %[r3], %[r4], %[r3] \\n\\t\" /* r3 = b0 * a1 */\n        \"muls %[r5], %[r0], %[r5] \\n\\t\" /* r5 = a0 * b1 */\n        \"muls %[r0], %[r4], %[r0] \\n\\t\" /* r0 = a0 * b0 */\n        \n        \"movs %[r4], #0 \\n\\t\"    /* r4 = 0 */\n        \"adds %[r3], %[r5] \\n\\t\" /* r3 = b0 * a1 + a0 * b1 */\n        \"adcs %[r4], %[r4] \\n\\t\" /* r4 = carry */\n        \"lsls %[r4], #16 \\n\\t\"   /* r4 = carry << 16 */\n        \"adds %[r6], %[r4] \\n\\t\" /* r6 = a1 * b1 + carry */\n        \n        \"lsls %[r4], %[r3], #16 \\n\\t\" /* r4 = (b0 * a1 + a0 * b1) << 16 */\n        \"lsrs %[r3], #16 \\n\\t\"        /* r3 = (b0 * a1 + a0 * b1) >> 16 */\n        \"adds %[r0], %[r4] \\n\\t\"      /* r0 = low word = a0 * b0 + ((b0 * a1 + a0 * b1) << 16) */\n        \"adcs %[r6], %[r3] \\n\\t\"      /* r6 = high word =\n                                              a1 * b1 + carry + ((b0 * a1 + a0 * b1) >> 16) */\n        \n        \"pop {%[r3]} \\n\\t\" /* r3 = c0 */\n        \"pop {%[r4]} \\n\\t\" /* r4 = c1 */\n        \"pop {%[r5]} \\n\\t\" /* r5 = c2 */\n        \"adds %[r3], %[r0] \\n\\t\"         /* add low word to c0 */\n        \"adcs %[r4], %[r6] \\n\\t\"         /* add high word to c1, including carry */\n        \"movs %[r0], #0 \\n\\t\"            /* r0 = 0 (does not affect carry bit) */\n        \"adcs %[r5], %[r0] \\n\\t\"         /* add carry to c2 */\n        \n        \"pop {%[r6]} \\n\\t\" /* r6 = k */\n\n        \"adds %[r7], #4 \\n\\t\"   /* i += 4 */\n        \"cmp %[r7], r8 \\n\\t\"    /* i > (num_words - 1) (times 4)? */\n        \"bgt 4f \\n\\t\"           /*   if so, exit the loop */\n        \"cmp %[r7], %[r6] \\n\\t\" /* i <= k? */\n        \"ble 3b \\n\\t\"           /*   if so, continue looping */\n        \n        \"4: \\n\\t\" /* end inner loop */\n        \n        \"ldr %[r0], [sp, #0] \\n\\t\" /* r0 = result */\n        \n        \"str %[r3], [%[r0], %[r6]] \\n\\t\" /* result[k] = c0 */\n        \"mov %[r3], %[r4] \\n\\t\"          /* c0 = c1 */\n        \"mov %[r4], %[r5] \\n\\t\"          /* c1 = c2 */\n        \"movs %[r5], #0 \\n\\t\"            /* c2 = 0 */\n        \"adds %[r6], #4 \\n\\t\"            /* k += 4 */\n        \"cmp %[r6], r8 \\n\\t\"             /* k <= (num_words - 1) (times 4) ? */\n        \"ble 1b \\n\\t\"                    /*   if so, loop back, start with i = 0 */\n        \"cmp %[r6], r9 \\n\\t\"             /* k <= (num_words * 2 - 2) (times 4) ? */\n        \"ble 2b \\n\\t\"                    /*   if so, loop back, with i = (k + 1) - num_words */\n        /* end outer loop */\n        \n        \"str %[r3], [%[r0], %[r6]] \\n\\t\" /* result[num_words * 2 - 1] = c0 */\n        \"pop {%[r0]} \\n\\t\"               /* pop result off the stack */\n        \n        \".syntax divided \\n\\t\"\n        : [r3] \"+l\" (num_words), [r4] \"=&l\" (r4),\n          [r5] \"=&l\" (r5), [r6] \"=&l\" (r6), [r7] \"=&l\" (r7)\n        : [r0] \"l\" (result), [r1] \"l\" (left), [r2] \"l\" (right)\n        : \"r8\", \"r9\", \"cc\", \"memory\"\n    );\n#endif\n}\n#define asm_mult 1\n#endif\n\n#if uECC_SQUARE_FUNC\n#if !asm_square\nuECC_VLI_API void uECC_vli_square(uECC_word_t *result,\n                                  const uECC_word_t *left,\n                                  wordcount_t num_words) {\n#if (uECC_PLATFORM != uECC_arm_thumb)\n    uint32_t c0 = 0;\n    uint32_t c1 = 0;\n    uint32_t c2 = 0;\n    uint32_t k = 0;\n    uint32_t i, tt;\n    uint32_t t0, t1;\n    \n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \n        \"1: \\n\\t\" /* outer loop (k < num_words) */\n        \"movs %[i], #0 \\n\\t\" /* i = 0 */\n        \"b 3f \\n\\t\"\n        \n        \"2: \\n\\t\" /* outer loop (k >= num_words) */\n        \"movs %[i], %[k] \\n\\t\"         /* i = k */\n        \"subs %[i], %[last_word] \\n\\t\" /* i = k - (num_words - 1) (times 4) */\n        \n        \"3: \\n\\t\" /* inner loop */\n        \"subs %[tt], %[k], %[i] \\n\\t\" /* tt = k-i */\n        \n        \"ldr %[t1], [%[left], %[tt]] \\n\\t\" /* t1 = left[k - i] */\n        \"ldr %[t0], [%[left], %[i]] \\n\\t\"  /* t0 = left[i] */\n        \n        \"umull %[t0], %[t1], %[t0], %[t1] \\n\\t\" /* (t0, t1) = left[i] * right[k - i] */\n        \n        \"cmp %[i], %[tt] \\n\\t\"      /* (i < k - i) ? */\n        \"bge 4f \\n\\t\"               /*   if i >= k - i, skip */\n        \"lsls %[t1], #1 \\n\\t\"       /* high word << 1 */\n        \"adc %[c2], %[c2], #0 \\n\\t\" /* add carry bit to c2 */\n        \"lsls %[t0], #1 \\n\\t\"       /* low word << 1 */\n        \"adc %[t1], %[t1], #0 \\n\\t\" /* add carry bit to high word */\n        \n        \"4: \\n\\t\"\n\n        \"adds %[c0], %[c0], %[t0] \\n\\t\" /* add low word to c0 */\n        \"adcs %[c1], %[c1], %[t1] \\n\\t\" /* add high word to c1, including carry */\n        \"adcs %[c2], %[c2], #0 \\n\\t\"    /* add carry to c2 */\n        \n        \"adds %[i], #4 \\n\\t\"          /* i += 4 */\n        \"cmp %[i], %[k] \\n\\t\"         /* i >= k? */\n        \"bge 5f \\n\\t\"                 /*   if so, exit the loop */\n        \"subs %[tt], %[k], %[i] \\n\\t\" /* tt = k - i */\n        \"cmp %[i], %[tt] \\n\\t\"        /* i <= k - i? */\n        \"ble 3b \\n\\t\"                 /*   if so, continue looping */\n        \n        \"5: \\n\\t\" /* end inner loop */\n        \n        \"str %[c0], [%[result], %[k]] \\n\\t\" /* result[k] = c0 */\n        \"mov %[c0], %[c1] \\n\\t\"       /* c0 = c1 */\n        \"mov %[c1], %[c2] \\n\\t\"       /* c1 = c2 */\n        \"movs %[c2], #0 \\n\\t\"         /* c2 = 0 */\n        \"adds %[k], #4 \\n\\t\"          /* k += 4 */\n        \"cmp %[k], %[last_word] \\n\\t\" /* k <= (num_words - 1) (times 4) ? */\n        \"ble 1b \\n\\t\"                 /*   if so, loop back, start with i = 0 */\n        \"cmp %[k], %[last_word], lsl #1 \\n\\t\" /* k <= (num_words * 2 - 2) (times 4) ? */\n        \"ble 2b \\n\\t\"                 /*   if so, loop back, start with i = (k + 1) - num_words */\n        /* end outer loop */\n        \n        \"str %[c0], [%[result], %[k]] \\n\\t\" /* result[num_words * 2 - 1] = c0 */\n        RESUME_SYNTAX\n        : [c0] \"+r\" (c0), [c1] \"+r\" (c1), [c2] \"+r\" (c2),\n          [k] \"+r\" (k), [i] \"=&r\" (i), [tt] \"=&r\" (tt), [t0] \"=&r\" (t0), [t1] \"=&r\" (t1)\n        : [result] \"r\" (result), [left] \"r\" (left), [last_word] \"r\" ((num_words - 1) * 4)\n        : \"cc\", \"memory\"\n    );\n    \n#else\n    uint32_t r3, r4, r5, r6, r7;\n\n    __asm__ volatile (\n        \".syntax unified \\n\\t\"\n        \"subs %[r2], #1 \\n\\t\" /* r2 = num_words - 1 */\n        \"lsls %[r2], #2 \\n\\t\" /* r2 = (num_words - 1) * 4 */\n        \"mov r8, %[r2] \\n\\t\"  /* r8 = (num_words - 1) * 4 */\n        \"lsls %[r2], #1 \\n\\t\" /* r2 = (num_words - 1) * 8 */\n        \"mov r9, %[r2] \\n\\t\"  /* r9 = (num_words - 1) * 8 */\n        \"movs %[r2], #0 \\n\\t\" /* c0 = 0 */\n        \"movs %[r3], #0 \\n\\t\" /* c1 = 0 */\n        \"movs %[r4], #0 \\n\\t\" /* c2 = 0 */\n        \"movs %[r5], #0 \\n\\t\" /* k = 0 */\n        \n        \"push {%[r0]} \\n\\t\" /* keep result on the stack */\n        \n        \"1: \\n\\t\" /* outer loop (k < num_words) */\n        \"movs %[r6], #0 \\n\\t\" /* r6 = i = 0 */\n        \"b 3f \\n\\t\"\n        \n        \"2: \\n\\t\" /* outer loop (k >= num_words) */\n        \"movs %[r6], %[r5] \\n\\t\" /* r6 = k */\n        \"mov %[r0], r8 \\n\\t\"     /* r0 = (num_words - 1) * 4 */\n        \"subs %[r6], %[r0] \\n\\t\" /* r6 = i = k - (num_words - 1) (times 4) */\n        \n        \"3: \\n\\t\" /* inner loop */\n        \"push {%[r5]} \\n\\t\"\n        \"push {%[r4]} \\n\\t\"\n        \"push {%[r3]} \\n\\t\"\n        \"push {%[r2]} \\n\\t\" /* push things, r2 (c0) is at the top of stack. */\n        \"subs %[r7], %[r5], %[r6] \\n\\t\"          /* r7 = k - i */\n        \n        \"ldr %[r3], [%[r1], %[r7]] \\n\\t\" /* r3 = left[k - i] */\n        \"ldr %[r0], [%[r1], %[r6]] \\n\\t\" /* r0 = left[i] */\n        \n        \"lsrs %[r2], %[r0], #16 \\n\\t\" /* r2 = a1 */\n        \"uxth %[r0], %[r0] \\n\\t\"      /* r0 = a0 */\n        \n        \"lsrs %[r4], %[r3], #16 \\n\\t\" /* r4 = b1 */\n        \"uxth %[r3], %[r3] \\n\\t\"      /* r3 = b0 */\n        \n        \"movs %[r5], %[r2] \\n\\t\"        /* r5 = a1 */\n        \"muls %[r5], %[r4], %[r5] \\n\\t\" /* r5 = a1 * b1 */\n        \"muls %[r2], %[r3], %[r2] \\n\\t\" /* r2 = b0 * a1 */\n        \"muls %[r4], %[r0], %[r4] \\n\\t\" /* r4 = a0 * b1 */\n        \"muls %[r0], %[r3], %[r0] \\n\\t\" /* r0 = a0 * b0 */\n        \n        \"movs %[r3], #0 \\n\\t\"    /* r3 = 0 */\n        \"adds %[r2], %[r4] \\n\\t\" /* r2 = b0 * a1 + a0 * b1 */\n        \"adcs %[r3], %[r3] \\n\\t\" /* r3 = carry */\n        \"lsls %[r3], #16 \\n\\t\"   /* r3 = carry << 16 */\n        \"adds %[r5], %[r3] \\n\\t\" /* r5 = a1 * b1 + carry */\n        \n        \"lsls %[r3], %[r2], #16 \\n\\t\" /* r3 = (b0 * a1 + a0 * b1) << 16 */\n        \"lsrs %[r2], #16 \\n\\t\"        /* r2 = (b0 * a1 + a0 * b1) >> 16 */\n        \"adds %[r0], %[r3] \\n\\t\"      /* r0 = low word = a0 * b0 + ((b0 * a1 + a0 * b1) << 16) */\n        \"adcs %[r5], %[r2] \\n\\t\"      /* r5 = high word = \n                                              a1 * b1 + carry + ((b0 * a1 + a0 * b1) >> 16) */\n    \n        \"movs %[r3], #0 \\n\\t\"    /* r3 = 0 */\n        \"cmp %[r6], %[r7] \\n\\t\"  /* (i < k - i) ? */\n        \"mov %[r7], %[r3] \\n\\t\"  /* r7 = 0 (does not affect condition) */\n        \"bge 4f \\n\\t\"            /*   if i >= k - i, skip */\n        \"lsls %[r5], #1 \\n\\t\"    /* high word << 1 */\n        \"adcs %[r7], %[r3] \\n\\t\" /* r7 = carry bit for c2 */\n        \"lsls %[r0], #1 \\n\\t\"    /* low word << 1 */\n        \"adcs %[r5], %[r3] \\n\\t\" /* add carry from shift to high word */\n        \n        \"4: \\n\\t\"\n        \"pop {%[r2]} \\n\\t\" /* r2 = c0 */\n        \"pop {%[r3]} \\n\\t\" /* r3 = c1 */\n        \"pop {%[r4]} \\n\\t\" /* r4 = c2 */\n        \"adds %[r2], %[r0] \\n\\t\"         /* add low word to c0 */\n        \"adcs %[r3], %[r5] \\n\\t\"         /* add high word to c1, including carry */\n        \"movs %[r0], #0 \\n\\t\"            /* r0 = 0 (does not affect carry bit) */\n        \"adcs %[r4], %[r0] \\n\\t\"         /* add carry to c2 */\n        \"adds %[r4], %[r7] \\n\\t\"         /* add carry from doubling (if any) */\n        \n        \"pop {%[r5]} \\n\\t\" /* r5 = k */\n        \n        \"adds %[r6], #4 \\n\\t\"           /* i += 4 */\n        \"cmp %[r6], %[r5] \\n\\t\"         /* i >= k? */\n        \"bge 5f \\n\\t\"                   /*   if so, exit the loop */\n        \"subs %[r7], %[r5], %[r6] \\n\\t\" /* r7 = k - i */\n        \"cmp %[r6], %[r7] \\n\\t\"         /* i <= k - i? */\n        \"ble 3b \\n\\t\"                   /*   if so, continue looping */\n        \n        \"5: \\n\\t\" /* end inner loop */\n        \n        \"ldr %[r0], [sp, #0] \\n\\t\" /* r0 = result */\n        \n        \"str %[r2], [%[r0], %[r5]] \\n\\t\" /* result[k] = c0 */\n        \"mov %[r2], %[r3] \\n\\t\"          /* c0 = c1 */\n        \"mov %[r3], %[r4] \\n\\t\"          /* c1 = c2 */\n        \"movs %[r4], #0 \\n\\t\"            /* c2 = 0 */\n        \"adds %[r5], #4 \\n\\t\"            /* k += 4 */\n        \"cmp %[r5], r8 \\n\\t\"             /* k <= (num_words - 1) (times 4) ? */\n        \"ble 1b \\n\\t\"                    /*   if so, loop back, start with i = 0 */\n        \"cmp %[r5], r9 \\n\\t\"             /* k <= (num_words * 2 - 2) (times 4) ? */\n        \"ble 2b \\n\\t\"                    /*   if so, loop back, with i = (k + 1) - num_words */\n        /* end outer loop */\n        \n        \"str %[r2], [%[r0], %[r5]] \\n\\t\" /* result[num_words * 2 - 1] = c0 */\n        \"pop {%[r0]} \\n\\t\"               /* pop result off the stack */\n\n        \".syntax divided \\n\\t\"\n        : [r2] \"+l\" (num_words), [r3] \"=&l\" (r3), [r4] \"=&l\" (r4),\n          [r5] \"=&l\" (r5), [r6] \"=&l\" (r6), [r7] \"=&l\" (r7)\n        : [r0] \"l\" (result), [r1] \"l\" (left)\n        : \"r8\", \"r9\", \"cc\", \"memory\"\n    );\n#endif\n}\n#define asm_square 1\n#endif\n#endif /* uECC_SQUARE_FUNC */\n\n#endif /* _UECC_ASM_ARM_H_ */\n"
  },
  {
    "path": "u2f/asm_arm_mult_square.h",
    "content": "/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */\n\n#ifndef _UECC_ASM_ARM_MULT_SQUARE_H_\n#define _UECC_ASM_ARM_MULT_SQUARE_H_\n\n#define FAST_MULT_ASM_5                \\\n    \"add r0, 12 \\n\\t\"                  \\\n    \"add r2, 12 \\n\\t\"                  \\\n    \"ldmia r1!, {r3,r4} \\n\\t\"          \\\n    \"ldmia r2!, {r6,r7} \\n\\t\"          \\\n                                       \\\n    \"umull r11, r12, r3, r6 \\n\\t\"      \\\n    \"stmia r0!, {r11} \\n\\t\"            \\\n                                       \\\n    \"mov r10, #0 \\n\\t\"                 \\\n    \"umull r11, r9, r3, r7 \\n\\t\"       \\\n    \"adds r12, r12, r11 \\n\\t\"          \\\n    \"adc r9, r9, #0 \\n\\t\"              \\\n    \"umull r11, r14, r4, r6 \\n\\t\"      \\\n    \"adds r12, r12, r11 \\n\\t\"          \\\n    \"adcs r9, r9, r14 \\n\\t\"            \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"stmia r0!, {r12} \\n\\t\"            \\\n                                       \\\n    \"umull r12, r14, r4, r7 \\n\\t\"      \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adc r10, r10, r14 \\n\\t\"           \\\n    \"stmia r0!, {r9, r10} \\n\\t\"        \\\n                                       \\\n    \"sub r0, 28 \\n\\t\"                  \\\n    \"sub r2, 20 \\n\\t\"                  \\\n    \"ldmia r2!, {r6,r7,r8} \\n\\t\"       \\\n    \"ldmia r1!, {r5} \\n\\t\"             \\\n                                       \\\n    \"umull r11, r12, r3, r6 \\n\\t\"      \\\n    \"stmia r0!, {r11} \\n\\t\"            \\\n                                       \\\n    \"mov r10, #0 \\n\\t\"                 \\\n    \"umull r11, r9, r3, r7 \\n\\t\"       \\\n    \"adds r12, r12, r11 \\n\\t\"          \\\n    \"adc r9, r9, #0 \\n\\t\"              \\\n    \"umull r11, r14, r4, r6 \\n\\t\"      \\\n    \"adds r12, r12, r11 \\n\\t\"          \\\n    \"adcs r9, r9, r14 \\n\\t\"            \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"stmia r0!, {r12} \\n\\t\"            \\\n                                       \\\n    \"mov r11, #0 \\n\\t\"                 \\\n    \"umull r12, r14, r3, r8 \\n\\t\"      \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, r14 \\n\\t\"          \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"umull r12, r14, r4, r7 \\n\\t\"      \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, r14 \\n\\t\"          \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"umull r12, r14, r5, r6 \\n\\t\"      \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, r14 \\n\\t\"          \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"stmia r0!, {r9} \\n\\t\"             \\\n                                       \\\n    \"ldmia r1!, {r3} \\n\\t\"             \\\n    \"mov r12, #0 \\n\\t\"                 \\\n    \"umull r14, r9, r4, r8 \\n\\t\"       \\\n    \"adds r10, r10, r14 \\n\\t\"          \\\n    \"adcs r11, r11, r9 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"            \\\n    \"umull r14, r9, r5, r7 \\n\\t\"       \\\n    \"adds r10, r10, r14 \\n\\t\"          \\\n    \"adcs r11, r11, r9 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"            \\\n    \"umull r14, r9, r3, r6 \\n\\t\"       \\\n    \"adds r10, r10, r14 \\n\\t\"          \\\n    \"adcs r11, r11, r9 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"            \\\n    \"ldr r14, [r0] \\n\\t\"               \\\n    \"adds r10, r10, r14 \\n\\t\"          \\\n    \"adcs r11, r11, #0 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"            \\\n    \"stmia r0!, {r10} \\n\\t\"            \\\n                                       \\\n    \"ldmia r1!, {r4} \\n\\t\"             \\\n    \"mov r14, #0 \\n\\t\"                 \\\n    \"umull r9, r10, r5, r8 \\n\\t\"       \\\n    \"adds r11, r11, r9 \\n\\t\"           \\\n    \"adcs r12, r12, r10 \\n\\t\"          \\\n    \"adc r14, r14, #0 \\n\\t\"            \\\n    \"umull r9, r10, r3, r7 \\n\\t\"       \\\n    \"adds r11, r11, r9 \\n\\t\"           \\\n    \"adcs r12, r12, r10 \\n\\t\"          \\\n    \"adc r14, r14, #0 \\n\\t\"            \\\n    \"umull r9, r10, r4, r6 \\n\\t\"       \\\n    \"adds r11, r11, r9 \\n\\t\"           \\\n    \"adcs r12, r12, r10 \\n\\t\"          \\\n    \"adc r14, r14, #0 \\n\\t\"            \\\n    \"ldr r9, [r0] \\n\\t\"                \\\n    \"adds r11, r11, r9 \\n\\t\"           \\\n    \"adcs r12, r12, #0 \\n\\t\"           \\\n    \"adc r14, r14, #0 \\n\\t\"            \\\n    \"stmia r0!, {r11} \\n\\t\"            \\\n                                       \\\n    \"ldmia r2!, {r6} \\n\\t\"             \\\n    \"mov r9, #0 \\n\\t\"                  \\\n    \"umull r10, r11, r5, r6 \\n\\t\"      \\\n    \"adds r12, r12, r10 \\n\\t\"          \\\n    \"adcs r14, r14, r11 \\n\\t\"          \\\n    \"adc r9, r9, #0 \\n\\t\"              \\\n    \"umull r10, r11, r3, r8 \\n\\t\"      \\\n    \"adds r12, r12, r10 \\n\\t\"          \\\n    \"adcs r14, r14, r11 \\n\\t\"          \\\n    \"adc r9, r9, #0 \\n\\t\"              \\\n    \"umull r10, r11, r4, r7 \\n\\t\"      \\\n    \"adds r12, r12, r10 \\n\\t\"          \\\n    \"adcs r14, r14, r11 \\n\\t\"          \\\n    \"adc r9, r9, #0 \\n\\t\"              \\\n    \"ldr r10, [r0] \\n\\t\"               \\\n    \"adds r12, r12, r10 \\n\\t\"          \\\n    \"adcs r14, r14, #0 \\n\\t\"           \\\n    \"adc r9, r9, #0 \\n\\t\"              \\\n    \"stmia r0!, {r12} \\n\\t\"            \\\n                                       \\\n    \"ldmia r2!, {r7} \\n\\t\"             \\\n    \"mov r10, #0 \\n\\t\"                 \\\n    \"umull r11, r12, r5, r7 \\n\\t\"      \\\n    \"adds r14, r14, r11 \\n\\t\"          \\\n    \"adcs r9, r9, r12 \\n\\t\"            \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"umull r11, r12, r3, r6 \\n\\t\"      \\\n    \"adds r14, r14, r11 \\n\\t\"          \\\n    \"adcs r9, r9, r12 \\n\\t\"            \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"umull r11, r12, r4, r8 \\n\\t\"      \\\n    \"adds r14, r14, r11 \\n\\t\"          \\\n    \"adcs r9, r9, r12 \\n\\t\"            \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"ldr r11, [r0] \\n\\t\"               \\\n    \"adds r14, r14, r11 \\n\\t\"          \\\n    \"adcs r9, r9, #0 \\n\\t\"             \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"stmia r0!, {r14} \\n\\t\"            \\\n                                       \\\n    \"mov r11, #0 \\n\\t\"                 \\\n    \"umull r12, r14, r3, r7 \\n\\t\"      \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, r14 \\n\\t\"          \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"umull r12, r14, r4, r6 \\n\\t\"      \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, r14 \\n\\t\"          \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"stmia r0!, {r9} \\n\\t\"             \\\n                                       \\\n    \"umull r14, r9, r4, r7 \\n\\t\"       \\\n    \"adds r10, r10, r14 \\n\\t\"          \\\n    \"adc r11, r11, r9 \\n\\t\"            \\\n    \"stmia r0!, {r10, r11} \\n\\t\"\n\n#define FAST_MULT_ASM_6             \\\n    \"add r0, 12 \\n\\t\"               \\\n    \"add r2, 12 \\n\\t\"               \\\n    \"ldmia r1!, {r3,r4,r5} \\n\\t\"    \\\n    \"ldmia r2!, {r6,r7,r8} \\n\\t\"    \\\n                                    \\\n    \"umull r11, r12, r3, r6 \\n\\t\"   \\\n    \"stmia r0!, {r11} \\n\\t\"         \\\n                                    \\\n    \"mov r10, #0 \\n\\t\"              \\\n    \"umull r11, r9, r3, r7 \\n\\t\"    \\\n    \"adds r12, r12, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"umull r11, r14, r4, r6 \\n\\t\"   \\\n    \"adds r12, r12, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r14 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"stmia r0!, {r12} \\n\\t\"         \\\n                                    \\\n    \"mov r11, #0 \\n\\t\"              \\\n    \"umull r12, r14, r3, r8 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"umull r12, r14, r4, r7 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"umull r12, r14, r5, r6 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"stmia r0!, {r9} \\n\\t\"          \\\n                                    \\\n    \"mov r12, #0 \\n\\t\"              \\\n    \"umull r14, r9, r4, r8 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"umull r14, r9, r5, r7 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"stmia r0!, {r10} \\n\\t\"         \\\n                                    \\\n    \"umull r9, r10, r5, r8 \\n\\t\"    \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, r10 \\n\\t\"        \\\n    \"stmia r0!, {r11, r12} \\n\\t\"    \\\n                                    \\\n    \"sub r0, 36 \\n\\t\"               \\\n    \"sub r2, 24 \\n\\t\"               \\\n    \"ldmia r2!, {r6,r7,r8} \\n\\t\"    \\\n                                    \\\n    \"umull r11, r12, r3, r6 \\n\\t\"   \\\n    \"stmia r0!, {r11} \\n\\t\"         \\\n                                    \\\n    \"mov r10, #0 \\n\\t\"              \\\n    \"umull r11, r9, r3, r7 \\n\\t\"    \\\n    \"adds r12, r12, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"umull r11, r14, r4, r6 \\n\\t\"   \\\n    \"adds r12, r12, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r14 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"stmia r0!, {r12} \\n\\t\"         \\\n                                    \\\n    \"mov r11, #0 \\n\\t\"              \\\n    \"umull r12, r14, r3, r8 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"umull r12, r14, r4, r7 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"umull r12, r14, r5, r6 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"stmia r0!, {r9} \\n\\t\"          \\\n                                    \\\n    \"ldmia r1!, {r3} \\n\\t\"          \\\n    \"mov r12, #0 \\n\\t\"              \\\n    \"umull r14, r9, r4, r8 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"umull r14, r9, r5, r7 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"umull r14, r9, r3, r6 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"ldr r14, [r0] \\n\\t\"            \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, #0 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"stmia r0!, {r10} \\n\\t\"         \\\n                                    \\\n    \"ldmia r1!, {r4} \\n\\t\"          \\\n    \"mov r14, #0 \\n\\t\"              \\\n    \"umull r9, r10, r5, r8 \\n\\t\"    \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, r10 \\n\\t\"       \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"umull r9, r10, r3, r7 \\n\\t\"    \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, r10 \\n\\t\"       \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"umull r9, r10, r4, r6 \\n\\t\"    \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, r10 \\n\\t\"       \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"ldr r9, [r0] \\n\\t\"             \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, #0 \\n\\t\"        \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"stmia r0!, {r11} \\n\\t\"         \\\n                                    \\\n    \"ldmia r1!, {r5} \\n\\t\"          \\\n    \"mov r9, #0 \\n\\t\"               \\\n    \"umull r10, r11, r3, r8 \\n\\t\"   \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adcs r14, r14, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"umull r10, r11, r4, r7 \\n\\t\"   \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adcs r14, r14, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"umull r10, r11, r5, r6 \\n\\t\"   \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adcs r14, r14, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"ldr r10, [r0] \\n\\t\"            \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adcs r14, r14, #0 \\n\\t\"        \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"stmia r0!, {r12} \\n\\t\"         \\\n                                    \\\n    \"ldmia r2!, {r6} \\n\\t\"          \\\n    \"mov r10, #0 \\n\\t\"              \\\n    \"umull r11, r12, r3, r6 \\n\\t\"   \\\n    \"adds r14, r14, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r12 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"umull r11, r12, r4, r8 \\n\\t\"   \\\n    \"adds r14, r14, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r12 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"umull r11, r12, r5, r7 \\n\\t\"   \\\n    \"adds r14, r14, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r12 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"ldr r11, [r0] \\n\\t\"            \\\n    \"adds r14, r14, r11 \\n\\t\"       \\\n    \"adcs r9, r9, #0 \\n\\t\"          \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"stmia r0!, {r14} \\n\\t\"         \\\n                                    \\\n    \"ldmia r2!, {r7} \\n\\t\"          \\\n    \"mov r11, #0 \\n\\t\"              \\\n    \"umull r12, r14, r3, r7 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"umull r12, r14, r4, r6 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"umull r12, r14, r5, r8 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"ldr r12, [r0] \\n\\t\"            \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, #0 \\n\\t\"        \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"stmia r0!, {r9} \\n\\t\"          \\\n                                    \\\n    \"ldmia r2!, {r8} \\n\\t\"          \\\n    \"mov r12, #0 \\n\\t\"              \\\n    \"umull r14, r9, r3, r8 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"umull r14, r9, r4, r7 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"umull r14, r9, r5, r6 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"ldr r14, [r0] \\n\\t\"            \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, #0 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"stmia r0!, {r10} \\n\\t\"         \\\n                                    \\\n    \"mov r14, #0 \\n\\t\"              \\\n    \"umull r9, r10, r4, r8 \\n\\t\"    \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, r10 \\n\\t\"       \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"umull r9, r10, r5, r7 \\n\\t\"    \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, r10 \\n\\t\"       \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"stmia r0!, {r11} \\n\\t\"         \\\n                                    \\\n    \"umull r10, r11, r5, r8 \\n\\t\"   \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adc r14, r14, r11 \\n\\t\"        \\\n    \"stmia r0!, {r12, r14} \\n\\t\"\n\n#define FAST_MULT_ASM_7                \\\n    \"add r0, 24 \\n\\t\"                  \\\n    \"add r2, 24 \\n\\t\"                  \\\n    \"ldmia r1!, {r3} \\n\\t\"             \\\n    \"ldmia r2!, {r6} \\n\\t\"             \\\n                                       \\\n    \"umull r9, r10, r3, r6 \\n\\t\"       \\\n    \"stmia r0!, {r9, r10} \\n\\t\"        \\\n                                       \\\n    \"sub r0, 20 \\n\\t\"                  \\\n    \"sub r2, 16 \\n\\t\"                  \\\n    \"ldmia r2!, {r6, r7, r8} \\n\\t\"     \\\n    \"ldmia r1!, {r4, r5} \\n\\t\"         \\\n                                       \\\n    \"umull r9, r10, r3, r6 \\n\\t\"       \\\n    \"stmia r0!, {r9} \\n\\t\"             \\\n                                       \\\n    \"mov r14, #0 \\n\\t\"                 \\\n    \"umull r9, r12, r3, r7 \\n\\t\"       \\\n    \"adds r10, r10, r9 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"            \\\n    \"umull r9, r11, r4, r6 \\n\\t\"       \\\n    \"adds r10, r10, r9 \\n\\t\"           \\\n    \"adcs r12, r12, r11 \\n\\t\"          \\\n    \"adc r14, r14, #0 \\n\\t\"            \\\n    \"stmia r0!, {r10} \\n\\t\"            \\\n                                       \\\n    \"mov r9, #0 \\n\\t\"                  \\\n    \"umull r10, r11, r3, r8 \\n\\t\"      \\\n    \"adds r12, r12, r10 \\n\\t\"          \\\n    \"adcs r14, r14, r11 \\n\\t\"          \\\n    \"adc r9, r9, #0 \\n\\t\"              \\\n    \"umull r10, r11, r4, r7 \\n\\t\"      \\\n    \"adds r12, r12, r10 \\n\\t\"          \\\n    \"adcs r14, r14, r11 \\n\\t\"          \\\n    \"adc r9, r9, #0 \\n\\t\"              \\\n    \"umull r10, r11, r5, r6 \\n\\t\"      \\\n    \"adds r12, r12, r10 \\n\\t\"          \\\n    \"adcs r14, r14, r11 \\n\\t\"          \\\n    \"adc r9, r9, #0 \\n\\t\"              \\\n    \"stmia r0!, {r12} \\n\\t\"            \\\n                                       \\\n    \"ldmia r1!, {r3} \\n\\t\"             \\\n    \"mov r10, #0 \\n\\t\"                 \\\n    \"umull r11, r12, r4, r8 \\n\\t\"      \\\n    \"adds r14, r14, r11 \\n\\t\"          \\\n    \"adcs r9, r9, r12 \\n\\t\"            \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"umull r11, r12, r5, r7 \\n\\t\"      \\\n    \"adds r14, r14, r11 \\n\\t\"          \\\n    \"adcs r9, r9, r12 \\n\\t\"            \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"umull r11, r12, r3, r6 \\n\\t\"      \\\n    \"adds r14, r14, r11 \\n\\t\"          \\\n    \"adcs r9, r9, r12 \\n\\t\"            \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"ldr r11, [r0] \\n\\t\"               \\\n    \"adds r14, r14, r11 \\n\\t\"          \\\n    \"adcs r9, r9, #0 \\n\\t\"             \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"stmia r0!, {r14} \\n\\t\"            \\\n                                       \\\n    \"ldmia r2!, {r6} \\n\\t\"             \\\n    \"mov r11, #0 \\n\\t\"                 \\\n    \"umull r12, r14, r4, r6 \\n\\t\"      \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, r14 \\n\\t\"          \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"umull r12, r14, r5, r8 \\n\\t\"      \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, r14 \\n\\t\"          \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"umull r12, r14, r3, r7 \\n\\t\"      \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, r14 \\n\\t\"          \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"ldr r12, [r0] \\n\\t\"               \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, #0 \\n\\t\"           \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"stmia r0!, {r9} \\n\\t\"             \\\n                                       \\\n    \"mov r12, #0 \\n\\t\"                 \\\n    \"umull r14, r9, r5, r6 \\n\\t\"       \\\n    \"adds r10, r10, r14 \\n\\t\"          \\\n    \"adcs r11, r11, r9 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"            \\\n    \"umull r14, r9, r3, r8 \\n\\t\"       \\\n    \"adds r10, r10, r14 \\n\\t\"          \\\n    \"adcs r11, r11, r9 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"            \\\n    \"stmia r0!, {r10} \\n\\t\"            \\\n                                       \\\n    \"umull r9, r10, r3, r6 \\n\\t\"       \\\n    \"adds r11, r11, r9 \\n\\t\"           \\\n    \"adc r12, r12, r10 \\n\\t\"           \\\n    \"stmia r0!, {r11, r12} \\n\\t\"       \\\n                                       \\\n    \"sub r0, 44 \\n\\t\"                  \\\n    \"sub r1, 16 \\n\\t\"                  \\\n    \"sub r2, 28 \\n\\t\"                  \\\n    \"ldmia r1!, {r3,r4,r5} \\n\\t\"       \\\n    \"ldmia r2!, {r6,r7,r8} \\n\\t\"       \\\n                                       \\\n    \"umull r9, r10, r3, r6 \\n\\t\"       \\\n    \"stmia r0!, {r9} \\n\\t\"             \\\n                                       \\\n    \"mov r14, #0 \\n\\t\"                 \\\n    \"umull r9, r12, r3, r7 \\n\\t\"       \\\n    \"adds r10, r10, r9 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"            \\\n    \"umull r9, r11, r4, r6 \\n\\t\"       \\\n    \"adds r10, r10, r9 \\n\\t\"           \\\n    \"adcs r12, r12, r11 \\n\\t\"          \\\n    \"adc r14, r14, #0 \\n\\t\"            \\\n    \"stmia r0!, {r10} \\n\\t\"            \\\n                                       \\\n    \"mov r9, #0 \\n\\t\"                  \\\n    \"umull r10, r11, r3, r8 \\n\\t\"      \\\n    \"adds r12, r12, r10 \\n\\t\"          \\\n    \"adcs r14, r14, r11 \\n\\t\"          \\\n    \"adc r9, r9, #0 \\n\\t\"              \\\n    \"umull r10, r11, r4, r7 \\n\\t\"      \\\n    \"adds r12, r12, r10 \\n\\t\"          \\\n    \"adcs r14, r14, r11 \\n\\t\"          \\\n    \"adc r9, r9, #0 \\n\\t\"              \\\n    \"umull r10, r11, r5, r6 \\n\\t\"      \\\n    \"adds r12, r12, r10 \\n\\t\"          \\\n    \"adcs r14, r14, r11 \\n\\t\"          \\\n    \"adc r9, r9, #0 \\n\\t\"              \\\n    \"stmia r0!, {r12} \\n\\t\"            \\\n                                       \\\n    \"ldmia r1!, {r3} \\n\\t\"             \\\n    \"mov r10, #0 \\n\\t\"                 \\\n    \"umull r11, r12, r4, r8 \\n\\t\"      \\\n    \"adds r14, r14, r11 \\n\\t\"          \\\n    \"adcs r9, r9, r12 \\n\\t\"            \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"umull r11, r12, r5, r7 \\n\\t\"      \\\n    \"adds r14, r14, r11 \\n\\t\"          \\\n    \"adcs r9, r9, r12 \\n\\t\"            \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"umull r11, r12, r3, r6 \\n\\t\"      \\\n    \"adds r14, r14, r11 \\n\\t\"          \\\n    \"adcs r9, r9, r12 \\n\\t\"            \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"ldr r11, [r0] \\n\\t\"               \\\n    \"adds r14, r14, r11 \\n\\t\"          \\\n    \"adcs r9, r9, #0 \\n\\t\"             \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"stmia r0!, {r14} \\n\\t\"            \\\n                                       \\\n    \"ldmia r1!, {r4} \\n\\t\"             \\\n    \"mov r11, #0 \\n\\t\"                 \\\n    \"umull r12, r14, r5, r8 \\n\\t\"      \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, r14 \\n\\t\"          \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"umull r12, r14, r3, r7 \\n\\t\"      \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, r14 \\n\\t\"          \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"umull r12, r14, r4, r6 \\n\\t\"      \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, r14 \\n\\t\"          \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"ldr r12, [r0] \\n\\t\"               \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, #0 \\n\\t\"           \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"stmia r0!, {r9} \\n\\t\"             \\\n                                       \\\n    \"ldmia r1!, {r5} \\n\\t\"             \\\n    \"mov r12, #0 \\n\\t\"                 \\\n    \"umull r14, r9, r3, r8 \\n\\t\"       \\\n    \"adds r10, r10, r14 \\n\\t\"          \\\n    \"adcs r11, r11, r9 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"            \\\n    \"umull r14, r9, r4, r7 \\n\\t\"       \\\n    \"adds r10, r10, r14 \\n\\t\"          \\\n    \"adcs r11, r11, r9 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"            \\\n    \"umull r14, r9, r5, r6 \\n\\t\"       \\\n    \"adds r10, r10, r14 \\n\\t\"          \\\n    \"adcs r11, r11, r9 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"            \\\n    \"ldr r14, [r0] \\n\\t\"               \\\n    \"adds r10, r10, r14 \\n\\t\"          \\\n    \"adcs r11, r11, #0 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"            \\\n    \"stmia r0!, {r10} \\n\\t\"            \\\n                                       \\\n    \"ldmia r1!, {r3} \\n\\t\"             \\\n    \"mov r14, #0 \\n\\t\"                 \\\n    \"umull r9, r10, r4, r8 \\n\\t\"       \\\n    \"adds r11, r11, r9 \\n\\t\"           \\\n    \"adcs r12, r12, r10 \\n\\t\"          \\\n    \"adc r14, r14, #0 \\n\\t\"            \\\n    \"umull r9, r10, r5, r7 \\n\\t\"       \\\n    \"adds r11, r11, r9 \\n\\t\"           \\\n    \"adcs r12, r12, r10 \\n\\t\"          \\\n    \"adc r14, r14, #0 \\n\\t\"            \\\n    \"umull r9, r10, r3, r6 \\n\\t\"       \\\n    \"adds r11, r11, r9 \\n\\t\"           \\\n    \"adcs r12, r12, r10 \\n\\t\"          \\\n    \"adc r14, r14, #0 \\n\\t\"            \\\n    \"ldr r9, [r0] \\n\\t\"                \\\n    \"adds r11, r11, r9 \\n\\t\"           \\\n    \"adcs r12, r12, #0 \\n\\t\"           \\\n    \"adc r14, r14, #0 \\n\\t\"            \\\n    \"stmia r0!, {r11} \\n\\t\"            \\\n                                       \\\n    \"ldmia r2!, {r6} \\n\\t\"             \\\n    \"mov r9, #0 \\n\\t\"                  \\\n    \"umull r10, r11, r4, r6 \\n\\t\"      \\\n    \"adds r12, r12, r10 \\n\\t\"          \\\n    \"adcs r14, r14, r11 \\n\\t\"          \\\n    \"adc r9, r9, #0 \\n\\t\"              \\\n    \"umull r10, r11, r5, r8 \\n\\t\"      \\\n    \"adds r12, r12, r10 \\n\\t\"          \\\n    \"adcs r14, r14, r11 \\n\\t\"          \\\n    \"adc r9, r9, #0 \\n\\t\"              \\\n    \"umull r10, r11, r3, r7 \\n\\t\"      \\\n    \"adds r12, r12, r10 \\n\\t\"          \\\n    \"adcs r14, r14, r11 \\n\\t\"          \\\n    \"adc r9, r9, #0 \\n\\t\"              \\\n    \"ldr r10, [r0] \\n\\t\"               \\\n    \"adds r12, r12, r10 \\n\\t\"          \\\n    \"adcs r14, r14, #0 \\n\\t\"           \\\n    \"adc r9, r9, #0 \\n\\t\"              \\\n    \"stmia r0!, {r12} \\n\\t\"            \\\n                                       \\\n    \"ldmia r2!, {r7} \\n\\t\"             \\\n    \"mov r10, #0 \\n\\t\"                 \\\n    \"umull r11, r12, r4, r7 \\n\\t\"      \\\n    \"adds r14, r14, r11 \\n\\t\"          \\\n    \"adcs r9, r9, r12 \\n\\t\"            \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"umull r11, r12, r5, r6 \\n\\t\"      \\\n    \"adds r14, r14, r11 \\n\\t\"          \\\n    \"adcs r9, r9, r12 \\n\\t\"            \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"umull r11, r12, r3, r8 \\n\\t\"      \\\n    \"adds r14, r14, r11 \\n\\t\"          \\\n    \"adcs r9, r9, r12 \\n\\t\"            \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"ldr r11, [r0] \\n\\t\"               \\\n    \"adds r14, r14, r11 \\n\\t\"          \\\n    \"adcs r9, r9, #0 \\n\\t\"             \\\n    \"adc r10, r10, #0 \\n\\t\"            \\\n    \"stmia r0!, {r14} \\n\\t\"            \\\n                                       \\\n    \"ldmia r2!, {r8} \\n\\t\"             \\\n    \"mov r11, #0 \\n\\t\"                 \\\n    \"umull r12, r14, r4, r8 \\n\\t\"      \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, r14 \\n\\t\"          \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"umull r12, r14, r5, r7 \\n\\t\"      \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, r14 \\n\\t\"          \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"umull r12, r14, r3, r6 \\n\\t\"      \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, r14 \\n\\t\"          \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"ldr r12, [r0] \\n\\t\"               \\\n    \"adds r9, r9, r12 \\n\\t\"            \\\n    \"adcs r10, r10, #0 \\n\\t\"           \\\n    \"adc r11, r11, #0 \\n\\t\"            \\\n    \"stmia r0!, {r9} \\n\\t\"             \\\n                                       \\\n    \"ldmia r2!, {r6} \\n\\t\"             \\\n    \"mov r12, #0 \\n\\t\"                 \\\n    \"umull r14, r9, r4, r6 \\n\\t\"       \\\n    \"adds r10, r10, r14 \\n\\t\"          \\\n    \"adcs r11, r11, r9 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"            \\\n    \"umull r14, r9, r5, r8 \\n\\t\"       \\\n    \"adds r10, r10, r14 \\n\\t\"          \\\n    \"adcs r11, r11, r9 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"            \\\n    \"umull r14, r9, r3, r7 \\n\\t\"       \\\n    \"adds r10, r10, r14 \\n\\t\"          \\\n    \"adcs r11, r11, r9 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"            \\\n    \"ldr r14, [r0] \\n\\t\"               \\\n    \"adds r10, r10, r14 \\n\\t\"          \\\n    \"adcs r11, r11, #0 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"            \\\n    \"stmia r0!, {r10} \\n\\t\"            \\\n                                       \\\n    \"mov r14, #0 \\n\\t\"                 \\\n    \"umull r9, r10, r5, r6 \\n\\t\"       \\\n    \"adds r11, r11, r9 \\n\\t\"           \\\n    \"adcs r12, r12, r10 \\n\\t\"          \\\n    \"adc r14, r14, #0 \\n\\t\"            \\\n    \"umull r9, r10, r3, r8 \\n\\t\"       \\\n    \"adds r11, r11, r9 \\n\\t\"           \\\n    \"adcs r12, r12, r10 \\n\\t\"          \\\n    \"adc r14, r14, #0 \\n\\t\"            \\\n    \"stmia r0!, {r11} \\n\\t\"            \\\n                                       \\\n    \"umull r10, r11, r3, r6 \\n\\t\"      \\\n    \"adds r12, r12, r10 \\n\\t\"          \\\n    \"adc r14, r14, r11 \\n\\t\"           \\\n    \"stmia r0!, {r12, r14} \\n\\t\"\n\n#define FAST_MULT_ASM_8             \\\n    \"add r0, 24 \\n\\t\"               \\\n    \"add r2, 24 \\n\\t\"               \\\n    \"ldmia r1!, {r3,r4} \\n\\t\"       \\\n    \"ldmia r2!, {r6,r7} \\n\\t\"       \\\n                                    \\\n    \"umull r11, r12, r3, r6 \\n\\t\"   \\\n    \"stmia r0!, {r11} \\n\\t\"         \\\n                                    \\\n    \"mov r10, #0 \\n\\t\"              \\\n    \"umull r11, r9, r3, r7 \\n\\t\"    \\\n    \"adds r12, r12, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"umull r11, r14, r4, r6 \\n\\t\"   \\\n    \"adds r12, r12, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r14 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"stmia r0!, {r12} \\n\\t\"         \\\n                                    \\\n    \"umull r12, r14, r4, r7 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adc r10, r10, r14 \\n\\t\"        \\\n    \"stmia r0!, {r9, r10} \\n\\t\"     \\\n                                    \\\n    \"sub r0, 28 \\n\\t\"               \\\n    \"sub r2, 20 \\n\\t\"               \\\n    \"ldmia r2!, {r6,r7,r8} \\n\\t\"    \\\n    \"ldmia r1!, {r5} \\n\\t\"          \\\n                                    \\\n    \"umull r11, r12, r3, r6 \\n\\t\"   \\\n    \"stmia r0!, {r11} \\n\\t\"         \\\n                                    \\\n    \"mov r10, #0 \\n\\t\"              \\\n    \"umull r11, r9, r3, r7 \\n\\t\"    \\\n    \"adds r12, r12, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"umull r11, r14, r4, r6 \\n\\t\"   \\\n    \"adds r12, r12, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r14 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"stmia r0!, {r12} \\n\\t\"         \\\n                                    \\\n    \"mov r11, #0 \\n\\t\"              \\\n    \"umull r12, r14, r3, r8 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"umull r12, r14, r4, r7 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"umull r12, r14, r5, r6 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"stmia r0!, {r9} \\n\\t\"          \\\n                                    \\\n    \"ldmia r1!, {r3} \\n\\t\"          \\\n    \"mov r12, #0 \\n\\t\"              \\\n    \"umull r14, r9, r4, r8 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"umull r14, r9, r5, r7 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"umull r14, r9, r3, r6 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"ldr r14, [r0] \\n\\t\"            \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, #0 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"stmia r0!, {r10} \\n\\t\"         \\\n                                    \\\n    \"ldmia r1!, {r4} \\n\\t\"          \\\n    \"mov r14, #0 \\n\\t\"              \\\n    \"umull r9, r10, r5, r8 \\n\\t\"    \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, r10 \\n\\t\"       \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"umull r9, r10, r3, r7 \\n\\t\"    \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, r10 \\n\\t\"       \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"umull r9, r10, r4, r6 \\n\\t\"    \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, r10 \\n\\t\"       \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"ldr r9, [r0] \\n\\t\"             \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, #0 \\n\\t\"        \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"stmia r0!, {r11} \\n\\t\"         \\\n                                    \\\n    \"ldmia r2!, {r6} \\n\\t\"          \\\n    \"mov r9, #0 \\n\\t\"               \\\n    \"umull r10, r11, r5, r6 \\n\\t\"   \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adcs r14, r14, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"umull r10, r11, r3, r8 \\n\\t\"   \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adcs r14, r14, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"umull r10, r11, r4, r7 \\n\\t\"   \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adcs r14, r14, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"ldr r10, [r0] \\n\\t\"            \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adcs r14, r14, #0 \\n\\t\"        \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"stmia r0!, {r12} \\n\\t\"         \\\n                                    \\\n    \"ldmia r2!, {r7} \\n\\t\"          \\\n    \"mov r10, #0 \\n\\t\"              \\\n    \"umull r11, r12, r5, r7 \\n\\t\"   \\\n    \"adds r14, r14, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r12 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"umull r11, r12, r3, r6 \\n\\t\"   \\\n    \"adds r14, r14, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r12 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"umull r11, r12, r4, r8 \\n\\t\"   \\\n    \"adds r14, r14, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r12 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"ldr r11, [r0] \\n\\t\"            \\\n    \"adds r14, r14, r11 \\n\\t\"       \\\n    \"adcs r9, r9, #0 \\n\\t\"          \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"stmia r0!, {r14} \\n\\t\"         \\\n                                    \\\n    \"mov r11, #0 \\n\\t\"              \\\n    \"umull r12, r14, r3, r7 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"umull r12, r14, r4, r6 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"stmia r0!, {r9} \\n\\t\"          \\\n                                    \\\n    \"umull r14, r9, r4, r7 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, r9 \\n\\t\"         \\\n    \"stmia r0!, {r10, r11} \\n\\t\"    \\\n                                    \\\n    \"sub r0, 52 \\n\\t\"               \\\n    \"sub r1, 20 \\n\\t\"               \\\n    \"sub r2, 32 \\n\\t\"               \\\n    \"ldmia r1!, {r3,r4,r5} \\n\\t\"    \\\n    \"ldmia r2!, {r6,r7,r8} \\n\\t\"    \\\n                                    \\\n    \"umull r11, r12, r3, r6 \\n\\t\"   \\\n    \"stmia r0!, {r11} \\n\\t\"         \\\n                                    \\\n    \"mov r10, #0 \\n\\t\"              \\\n    \"umull r11, r9, r3, r7 \\n\\t\"    \\\n    \"adds r12, r12, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"umull r11, r14, r4, r6 \\n\\t\"   \\\n    \"adds r12, r12, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r14 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"stmia r0!, {r12} \\n\\t\"         \\\n                                    \\\n    \"mov r11, #0 \\n\\t\"              \\\n    \"umull r12, r14, r3, r8 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"umull r12, r14, r4, r7 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"umull r12, r14, r5, r6 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"stmia r0!, {r9} \\n\\t\"          \\\n                                    \\\n    \"ldmia r1!, {r3} \\n\\t\"          \\\n    \"mov r12, #0 \\n\\t\"              \\\n    \"umull r14, r9, r4, r8 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"umull r14, r9, r5, r7 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"umull r14, r9, r3, r6 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"ldr r14, [r0] \\n\\t\"            \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, #0 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"stmia r0!, {r10} \\n\\t\"         \\\n                                    \\\n    \"ldmia r1!, {r4} \\n\\t\"          \\\n    \"mov r14, #0 \\n\\t\"              \\\n    \"umull r9, r10, r5, r8 \\n\\t\"    \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, r10 \\n\\t\"       \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"umull r9, r10, r3, r7 \\n\\t\"    \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, r10 \\n\\t\"       \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"umull r9, r10, r4, r6 \\n\\t\"    \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, r10 \\n\\t\"       \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"ldr r9, [r0] \\n\\t\"             \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, #0 \\n\\t\"        \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"stmia r0!, {r11} \\n\\t\"         \\\n                                    \\\n    \"ldmia r1!, {r5} \\n\\t\"          \\\n    \"mov r9, #0 \\n\\t\"               \\\n    \"umull r10, r11, r3, r8 \\n\\t\"   \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adcs r14, r14, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"umull r10, r11, r4, r7 \\n\\t\"   \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adcs r14, r14, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"umull r10, r11, r5, r6 \\n\\t\"   \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adcs r14, r14, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"ldr r10, [r0] \\n\\t\"            \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adcs r14, r14, #0 \\n\\t\"        \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"stmia r0!, {r12} \\n\\t\"         \\\n                                    \\\n    \"ldmia r1!, {r3} \\n\\t\"          \\\n    \"mov r10, #0 \\n\\t\"              \\\n    \"umull r11, r12, r4, r8 \\n\\t\"   \\\n    \"adds r14, r14, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r12 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"umull r11, r12, r5, r7 \\n\\t\"   \\\n    \"adds r14, r14, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r12 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"umull r11, r12, r3, r6 \\n\\t\"   \\\n    \"adds r14, r14, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r12 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"ldr r11, [r0] \\n\\t\"            \\\n    \"adds r14, r14, r11 \\n\\t\"       \\\n    \"adcs r9, r9, #0 \\n\\t\"          \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"stmia r0!, {r14} \\n\\t\"         \\\n                                    \\\n    \"ldmia r1!, {r4} \\n\\t\"          \\\n    \"mov r11, #0 \\n\\t\"              \\\n    \"umull r12, r14, r5, r8 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"umull r12, r14, r3, r7 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"umull r12, r14, r4, r6 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"ldr r12, [r0] \\n\\t\"            \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, #0 \\n\\t\"        \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"stmia r0!, {r9} \\n\\t\"          \\\n                                    \\\n    \"ldmia r2!, {r6} \\n\\t\"          \\\n    \"mov r12, #0 \\n\\t\"              \\\n    \"umull r14, r9, r5, r6 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"umull r14, r9, r3, r8 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"umull r14, r9, r4, r7 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"ldr r14, [r0] \\n\\t\"            \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, #0 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"stmia r0!, {r10} \\n\\t\"         \\\n                                    \\\n    \"ldmia r2!, {r7} \\n\\t\"          \\\n    \"mov r14, #0 \\n\\t\"              \\\n    \"umull r9, r10, r5, r7 \\n\\t\"    \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, r10 \\n\\t\"       \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"umull r9, r10, r3, r6 \\n\\t\"    \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, r10 \\n\\t\"       \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"umull r9, r10, r4, r8 \\n\\t\"    \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, r10 \\n\\t\"       \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"ldr r9, [r0] \\n\\t\"             \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adcs r12, r12, #0 \\n\\t\"        \\\n    \"adc r14, r14, #0 \\n\\t\"         \\\n    \"stmia r0!, {r11} \\n\\t\"         \\\n                                    \\\n    \"ldmia r2!, {r8} \\n\\t\"          \\\n    \"mov r9, #0 \\n\\t\"               \\\n    \"umull r10, r11, r5, r8 \\n\\t\"   \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adcs r14, r14, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"umull r10, r11, r3, r7 \\n\\t\"   \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adcs r14, r14, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"umull r10, r11, r4, r6 \\n\\t\"   \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adcs r14, r14, r11 \\n\\t\"       \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"ldr r10, [r0] \\n\\t\"            \\\n    \"adds r12, r12, r10 \\n\\t\"       \\\n    \"adcs r14, r14, #0 \\n\\t\"        \\\n    \"adc r9, r9, #0 \\n\\t\"           \\\n    \"stmia r0!, {r12} \\n\\t\"         \\\n                                    \\\n    \"ldmia r2!, {r6} \\n\\t\"          \\\n    \"mov r10, #0 \\n\\t\"              \\\n    \"umull r11, r12, r5, r6 \\n\\t\"   \\\n    \"adds r14, r14, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r12 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"umull r11, r12, r3, r8 \\n\\t\"   \\\n    \"adds r14, r14, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r12 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"umull r11, r12, r4, r7 \\n\\t\"   \\\n    \"adds r14, r14, r11 \\n\\t\"       \\\n    \"adcs r9, r9, r12 \\n\\t\"         \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"ldr r11, [r0] \\n\\t\"            \\\n    \"adds r14, r14, r11 \\n\\t\"       \\\n    \"adcs r9, r9, #0 \\n\\t\"          \\\n    \"adc r10, r10, #0 \\n\\t\"         \\\n    \"stmia r0!, {r14} \\n\\t\"         \\\n                                    \\\n    \"ldmia r2!, {r7} \\n\\t\"          \\\n    \"mov r11, #0 \\n\\t\"              \\\n    \"umull r12, r14, r5, r7 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"umull r12, r14, r3, r6 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"umull r12, r14, r4, r8 \\n\\t\"   \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, r14 \\n\\t\"       \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"ldr r12, [r0] \\n\\t\"            \\\n    \"adds r9, r9, r12 \\n\\t\"         \\\n    \"adcs r10, r10, #0 \\n\\t\"        \\\n    \"adc r11, r11, #0 \\n\\t\"         \\\n    \"stmia r0!, {r9} \\n\\t\"          \\\n                                    \\\n    \"mov r12, #0 \\n\\t\"              \\\n    \"umull r14, r9, r3, r7 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"umull r14, r9, r4, r6 \\n\\t\"    \\\n    \"adds r10, r10, r14 \\n\\t\"       \\\n    \"adcs r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, #0 \\n\\t\"         \\\n    \"stmia r0!, {r10} \\n\\t\"         \\\n                                    \\\n    \"umull r9, r10, r4, r7 \\n\\t\"    \\\n    \"adds r11, r11, r9 \\n\\t\"        \\\n    \"adc r12, r12, r10 \\n\\t\"        \\\n    \"stmia r0!, {r11, r12} \\n\\t\"\n\n#define FAST_SQUARE_ASM_5               \\\n    \"ldmia r1!, {r2,r3,r4,r5,r6} \\n\\t\"  \\\n                                        \\\n    \"umull r11, r12, r2, r2 \\n\\t\"       \\\n    \"stmia r0!, {r11} \\n\\t\"             \\\n                                        \\\n    \"mov r9, #0 \\n\\t\"                   \\\n    \"umull r10, r11, r2, r3 \\n\\t\"       \\\n    \"adds r12, r12, r10 \\n\\t\"           \\\n    \"adcs r8, r11, #0 \\n\\t\"             \\\n    \"adc r9, r9, #0 \\n\\t\"               \\\n    \"adds r12, r12, r10 \\n\\t\"           \\\n    \"adcs r8, r8, r11 \\n\\t\"             \\\n    \"adc r9, r9, #0 \\n\\t\"               \\\n    \"stmia r0!, {r12} \\n\\t\"             \\\n                                        \\\n    \"mov r10, #0 \\n\\t\"                  \\\n    \"umull r11, r12, r2, r4 \\n\\t\"       \\\n    \"adds r11, r11, r11 \\n\\t\"           \\\n    \"adcs r12, r12, r12 \\n\\t\"           \\\n    \"adc r10, r10, #0 \\n\\t\"             \\\n    \"adds r8, r8, r11 \\n\\t\"             \\\n    \"adcs r9, r9, r12 \\n\\t\"             \\\n    \"adc r10, r10, #0 \\n\\t\"             \\\n    \"umull r11, r12, r3, r3 \\n\\t\"       \\\n    \"adds r8, r8, r11 \\n\\t\"             \\\n    \"adcs r9, r9, r12 \\n\\t\"             \\\n    \"adc r10, r10, #0 \\n\\t\"             \\\n    \"stmia r0!, {r8} \\n\\t\"              \\\n                                        \\\n    \"mov r12, #0 \\n\\t\"                  \\\n    \"umull r8, r11, r2, r5 \\n\\t\"        \\\n    \"umull r1, r14, r3, r4 \\n\\t\"        \\\n    \"adds r8, r8, r1 \\n\\t\"              \\\n    \"adcs r11, r11, r14 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"             \\\n    \"adds r8, r8, r8 \\n\\t\"              \\\n    \"adcs r11, r11, r11 \\n\\t\"           \\\n    \"adc r12, r12, r12 \\n\\t\"            \\\n    \"adds r8, r8, r9 \\n\\t\"              \\\n    \"adcs r11, r11, r10 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"             \\\n    \"stmia r0!, {r8} \\n\\t\"              \\\n                                        \\\n    \"mov r10, #0 \\n\\t\"                  \\\n    \"umull r8, r9, r2, r6 \\n\\t\"         \\\n    \"umull r1, r14, r3, r5 \\n\\t\"        \\\n    \"adds r8, r8, r1 \\n\\t\"              \\\n    \"adcs r9, r9, r14 \\n\\t\"             \\\n    \"adc r10, r10, #0 \\n\\t\"             \\\n    \"adds r8, r8, r8 \\n\\t\"              \\\n    \"adcs r9, r9, r9 \\n\\t\"              \\\n    \"adc r10, r10, r10 \\n\\t\"            \\\n    \"umull r1, r14, r4, r4 \\n\\t\"        \\\n    \"adds r8, r8, r1 \\n\\t\"              \\\n    \"adcs r9, r9, r14 \\n\\t\"             \\\n    \"adc r10, r10, #0 \\n\\t\"             \\\n    \"adds r8, r8, r11 \\n\\t\"             \\\n    \"adcs r9, r9, r12 \\n\\t\"             \\\n    \"adc r10, r10, #0 \\n\\t\"             \\\n    \"stmia r0!, {r8} \\n\\t\"              \\\n                                        \\\n    \"mov r12, #0 \\n\\t\"                  \\\n    \"umull r8, r11, r3, r6 \\n\\t\"        \\\n    \"umull r1, r14, r4, r5 \\n\\t\"        \\\n    \"adds r8, r8, r1 \\n\\t\"              \\\n    \"adcs r11, r11, r14 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"             \\\n    \"adds r8, r8, r8 \\n\\t\"              \\\n    \"adcs r11, r11, r11 \\n\\t\"           \\\n    \"adc r12, r12, r12 \\n\\t\"            \\\n    \"adds r8, r8, r9 \\n\\t\"              \\\n    \"adcs r11, r11, r10 \\n\\t\"           \\\n    \"adc r12, r12, #0 \\n\\t\"             \\\n    \"stmia r0!, {r8} \\n\\t\"              \\\n                                        \\\n    \"mov r8, #0 \\n\\t\"                   \\\n    \"umull r1, r10, r4, r6 \\n\\t\"        \\\n    \"adds r1, r1, r1 \\n\\t\"              \\\n    \"adcs r10, r10, r10 \\n\\t\"           \\\n    \"adc r8, r8, #0 \\n\\t\"               \\\n    \"adds r11, r11, r1 \\n\\t\"            \\\n    \"adcs r12, r12, r10 \\n\\t\"           \\\n    \"adc r8, r8, #0 \\n\\t\"               \\\n    \"umull r1, r10, r5, r5 \\n\\t\"        \\\n    \"adds r11, r11, r1 \\n\\t\"            \\\n    \"adcs r12, r12, r10 \\n\\t\"           \\\n    \"adc r8, r8, #0 \\n\\t\"               \\\n    \"stmia r0!, {r11} \\n\\t\"             \\\n                                        \\\n    \"mov r11, #0 \\n\\t\"                  \\\n    \"umull r1, r10, r5, r6 \\n\\t\"        \\\n    \"adds r1, r1, r1 \\n\\t\"              \\\n    \"adcs r10, r10, r10 \\n\\t\"           \\\n    \"adc r11, r11, #0 \\n\\t\"             \\\n    \"adds r12, r12, r1 \\n\\t\"            \\\n    \"adcs r8, r8, r10 \\n\\t\"             \\\n    \"adc r11, r11, #0 \\n\\t\"             \\\n    \"stmia r0!, {r12} \\n\\t\"             \\\n                                        \\\n    \"umull r1, r10, r6, r6 \\n\\t\"        \\\n    \"adds r8, r8, r1 \\n\\t\"              \\\n    \"adcs r11, r11, r10 \\n\\t\"           \\\n    \"stmia r0!, {r8, r11} \\n\\t\"\n\n#define FAST_SQUARE_ASM_6                  \\\n    \"ldmia r1!, {r2,r3,r4,r5,r6,r7} \\n\\t\"  \\\n                                           \\\n    \"umull r11, r12, r2, r2 \\n\\t\"          \\\n    \"stmia r0!, {r11} \\n\\t\"                \\\n                                           \\\n    \"mov r9, #0 \\n\\t\"                      \\\n    \"umull r10, r11, r2, r3 \\n\\t\"          \\\n    \"adds r12, r12, r10 \\n\\t\"              \\\n    \"adcs r8, r11, #0 \\n\\t\"                \\\n    \"adc r9, r9, #0 \\n\\t\"                  \\\n    \"adds r12, r12, r10 \\n\\t\"              \\\n    \"adcs r8, r8, r11 \\n\\t\"                \\\n    \"adc r9, r9, #0 \\n\\t\"                  \\\n    \"stmia r0!, {r12} \\n\\t\"                \\\n                                           \\\n    \"mov r10, #0 \\n\\t\"                     \\\n    \"umull r11, r12, r2, r4 \\n\\t\"          \\\n    \"adds r11, r11, r11 \\n\\t\"              \\\n    \"adcs r12, r12, r12 \\n\\t\"              \\\n    \"adc r10, r10, #0 \\n\\t\"                \\\n    \"adds r8, r8, r11 \\n\\t\"                \\\n    \"adcs r9, r9, r12 \\n\\t\"                \\\n    \"adc r10, r10, #0 \\n\\t\"                \\\n    \"umull r11, r12, r3, r3 \\n\\t\"          \\\n    \"adds r8, r8, r11 \\n\\t\"                \\\n    \"adcs r9, r9, r12 \\n\\t\"                \\\n    \"adc r10, r10, #0 \\n\\t\"                \\\n    \"stmia r0!, {r8} \\n\\t\"                 \\\n                                           \\\n    \"mov r12, #0 \\n\\t\"                     \\\n    \"umull r8, r11, r2, r5 \\n\\t\"           \\\n    \"umull r1, r14, r3, r4 \\n\\t\"           \\\n    \"adds r8, r8, r1 \\n\\t\"                 \\\n    \"adcs r11, r11, r14 \\n\\t\"              \\\n    \"adc r12, r12, #0 \\n\\t\"                \\\n    \"adds r8, r8, r8 \\n\\t\"                 \\\n    \"adcs r11, r11, r11 \\n\\t\"              \\\n    \"adc r12, r12, r12 \\n\\t\"               \\\n    \"adds r8, r8, r9 \\n\\t\"                 \\\n    \"adcs r11, r11, r10 \\n\\t\"              \\\n    \"adc r12, r12, #0 \\n\\t\"                \\\n    \"stmia r0!, {r8} \\n\\t\"                 \\\n                                           \\\n    \"mov r10, #0 \\n\\t\"                     \\\n    \"umull r8, r9, r2, r6 \\n\\t\"            \\\n    \"umull r1, r14, r3, r5 \\n\\t\"           \\\n    \"adds r8, r8, r1 \\n\\t\"                 \\\n    \"adcs r9, r9, r14 \\n\\t\"                \\\n    \"adc r10, r10, #0 \\n\\t\"                \\\n    \"adds r8, r8, r8 \\n\\t\"                 \\\n    \"adcs r9, r9, r9 \\n\\t\"                 \\\n    \"adc r10, r10, r10 \\n\\t\"               \\\n    \"umull r1, r14, r4, r4 \\n\\t\"           \\\n    \"adds r8, r8, r1 \\n\\t\"                 \\\n    \"adcs r9, r9, r14 \\n\\t\"                \\\n    \"adc r10, r10, #0 \\n\\t\"                \\\n    \"adds r8, r8, r11 \\n\\t\"                \\\n    \"adcs r9, r9, r12 \\n\\t\"                \\\n    \"adc r10, r10, #0 \\n\\t\"                \\\n    \"stmia r0!, {r8} \\n\\t\"                 \\\n                                           \\\n    \"mov r12, #0 \\n\\t\"                     \\\n    \"umull r8, r11, r2, r7 \\n\\t\"           \\\n    \"umull r1, r14, r3, r6 \\n\\t\"           \\\n    \"adds r8, r8, r1 \\n\\t\"                 \\\n    \"adcs r11, r11, r14 \\n\\t\"              \\\n    \"adc r12, r12, #0 \\n\\t\"                \\\n    \"umull r1, r14, r4, r5 \\n\\t\"           \\\n    \"adds r8, r8, r1 \\n\\t\"                 \\\n    \"adcs r11, r11, r14 \\n\\t\"              \\\n    \"adc r12, r12, #0 \\n\\t\"                \\\n    \"adds r8, r8, r8 \\n\\t\"                 \\\n    \"adcs r11, r11, r11 \\n\\t\"              \\\n    \"adc r12, r12, r12 \\n\\t\"               \\\n    \"adds r8, r8, r9 \\n\\t\"                 \\\n    \"adcs r11, r11, r10 \\n\\t\"              \\\n    \"adc r12, r12, #0 \\n\\t\"                \\\n    \"stmia r0!, {r8} \\n\\t\"                 \\\n                                           \\\n    \"mov r10, #0 \\n\\t\"                     \\\n    \"umull r8, r9, r3, r7 \\n\\t\"            \\\n    \"umull r1, r14, r4, r6 \\n\\t\"           \\\n    \"adds r8, r8, r1 \\n\\t\"                 \\\n    \"adcs r9, r9, r14 \\n\\t\"                \\\n    \"adc r10, r10, #0 \\n\\t\"                \\\n    \"adds r8, r8, r8 \\n\\t\"                 \\\n    \"adcs r9, r9, r9 \\n\\t\"                 \\\n    \"adc r10, r10, r10 \\n\\t\"               \\\n    \"umull r1, r14, r5, r5 \\n\\t\"           \\\n    \"adds r8, r8, r1 \\n\\t\"                 \\\n    \"adcs r9, r9, r14 \\n\\t\"                \\\n    \"adc r10, r10, #0 \\n\\t\"                \\\n    \"adds r8, r8, r11 \\n\\t\"                \\\n    \"adcs r9, r9, r12 \\n\\t\"                \\\n    \"adc r10, r10, #0 \\n\\t\"                \\\n    \"stmia r0!, {r8} \\n\\t\"                 \\\n                                           \\\n    \"mov r12, #0 \\n\\t\"                     \\\n    \"umull r8, r11, r4, r7 \\n\\t\"           \\\n    \"umull r1, r14, r5, r6 \\n\\t\"           \\\n    \"adds r8, r8, r1 \\n\\t\"                 \\\n    \"adcs r11, r11, r14 \\n\\t\"              \\\n    \"adc r12, r12, #0 \\n\\t\"                \\\n    \"adds r8, r8, r8 \\n\\t\"                 \\\n    \"adcs r11, r11, r11 \\n\\t\"              \\\n    \"adc r12, r12, r12 \\n\\t\"               \\\n    \"adds r8, r8, r9 \\n\\t\"                 \\\n    \"adcs r11, r11, r10 \\n\\t\"              \\\n    \"adc r12, r12, #0 \\n\\t\"                \\\n    \"stmia r0!, {r8} \\n\\t\"                 \\\n                                           \\\n    \"mov r8, #0 \\n\\t\"                      \\\n    \"umull r1, r10, r5, r7 \\n\\t\"           \\\n    \"adds r1, r1, r1 \\n\\t\"                 \\\n    \"adcs r10, r10, r10 \\n\\t\"              \\\n    \"adc r8, r8, #0 \\n\\t\"                  \\\n    \"adds r11, r11, r1 \\n\\t\"               \\\n    \"adcs r12, r12, r10 \\n\\t\"              \\\n    \"adc r8, r8, #0 \\n\\t\"                  \\\n    \"umull r1, r10, r6, r6 \\n\\t\"           \\\n    \"adds r11, r11, r1 \\n\\t\"               \\\n    \"adcs r12, r12, r10 \\n\\t\"              \\\n    \"adc r8, r8, #0 \\n\\t\"                  \\\n    \"stmia r0!, {r11} \\n\\t\"                \\\n                                           \\\n    \"mov r11, #0 \\n\\t\"                     \\\n    \"umull r1, r10, r6, r7 \\n\\t\"           \\\n    \"adds r1, r1, r1 \\n\\t\"                 \\\n    \"adcs r10, r10, r10 \\n\\t\"              \\\n    \"adc r11, r11, #0 \\n\\t\"                \\\n    \"adds r12, r12, r1 \\n\\t\"               \\\n    \"adcs r8, r8, r10 \\n\\t\"                \\\n    \"adc r11, r11, #0 \\n\\t\"                \\\n    \"stmia r0!, {r12} \\n\\t\"                \\\n                                           \\\n    \"umull r1, r10, r7, r7 \\n\\t\"           \\\n    \"adds r8, r8, r1 \\n\\t\"                 \\\n    \"adcs r11, r11, r10 \\n\\t\"              \\\n    \"stmia r0!, {r8, r11} \\n\\t\"\n\n#define FAST_SQUARE_ASM_7                      \\\n    \"ldmia r1!, {r2} \\n\\t\"                     \\\n    \"add r1, 20 \\n\\t\"                          \\\n    \"ldmia r1!, {r5} \\n\\t\"                     \\\n    \"add r0, 24 \\n\\t\"                          \\\n    \"umull r8, r9, r2, r5 \\n\\t\"                \\\n    \"stmia r0!, {r8, r9} \\n\\t\"                 \\\n    \"sub r0, 32 \\n\\t\"                          \\\n    \"sub r1, 28 \\n\\t\"                          \\\n                                               \\\n    \"ldmia r1!, {r2, r3, r4, r5, r6, r7} \\n\\t\" \\\n                                               \\\n    \"umull r11, r12, r2, r2 \\n\\t\"              \\\n    \"stmia r0!, {r11} \\n\\t\"                    \\\n                                               \\\n    \"mov r9, #0 \\n\\t\"                          \\\n    \"umull r10, r11, r2, r3 \\n\\t\"              \\\n    \"adds r12, r12, r10 \\n\\t\"                  \\\n    \"adcs r8, r11, #0 \\n\\t\"                    \\\n    \"adc r9, r9, #0 \\n\\t\"                      \\\n    \"adds r12, r12, r10 \\n\\t\"                  \\\n    \"adcs r8, r8, r11 \\n\\t\"                    \\\n    \"adc r9, r9, #0 \\n\\t\"                      \\\n    \"stmia r0!, {r12} \\n\\t\"                    \\\n                                               \\\n    \"mov r10, #0 \\n\\t\"                         \\\n    \"umull r11, r12, r2, r4 \\n\\t\"              \\\n    \"adds r11, r11, r11 \\n\\t\"                  \\\n    \"adcs r12, r12, r12 \\n\\t\"                  \\\n    \"adc r10, r10, #0 \\n\\t\"                    \\\n    \"adds r8, r8, r11 \\n\\t\"                    \\\n    \"adcs r9, r9, r12 \\n\\t\"                    \\\n    \"adc r10, r10, #0 \\n\\t\"                    \\\n    \"umull r11, r12, r3, r3 \\n\\t\"              \\\n    \"adds r8, r8, r11 \\n\\t\"                    \\\n    \"adcs r9, r9, r12 \\n\\t\"                    \\\n    \"adc r10, r10, #0 \\n\\t\"                    \\\n    \"stmia r0!, {r8} \\n\\t\"                     \\\n                                               \\\n    \"mov r12, #0 \\n\\t\"                         \\\n    \"umull r8, r11, r2, r5 \\n\\t\"               \\\n    \"mov r14, r11 \\n\\t\"                        \\\n    \"umlal r8, r11, r3, r4 \\n\\t\"               \\\n    \"cmp r14, r11 \\n\\t\"                        \\\n    \"it hi \\n\\t\"                               \\\n    \"adchi r12, r12, #0 \\n\\t\"                  \\\n    \"adds r8, r8, r8 \\n\\t\"                     \\\n    \"adcs r11, r11, r11 \\n\\t\"                  \\\n    \"adc r12, r12, r12 \\n\\t\"                   \\\n    \"adds r8, r8, r9 \\n\\t\"                     \\\n    \"adcs r11, r11, r10 \\n\\t\"                  \\\n    \"adc r12, r12, #0 \\n\\t\"                    \\\n    \"stmia r0!, {r8} \\n\\t\"                     \\\n                                               \\\n    \"mov r10, #0 \\n\\t\"                         \\\n    \"umull r8, r9, r2, r6 \\n\\t\"                \\\n    \"mov r14, r9 \\n\\t\"                         \\\n    \"umlal r8, r9, r3, r5 \\n\\t\"                \\\n    \"cmp r14, r9 \\n\\t\"                         \\\n    \"it hi \\n\\t\"                               \\\n    \"adchi r10, r10, #0 \\n\\t\"                  \\\n    \"adds r8, r8, r8 \\n\\t\"                     \\\n    \"adcs r9, r9, r9 \\n\\t\"                     \\\n    \"adc r10, r10, r10 \\n\\t\"                   \\\n    \"mov r14, r9 \\n\\t\"                         \\\n    \"umlal r8, r9, r4, r4 \\n\\t\"                \\\n    \"cmp r14, r9 \\n\\t\"                         \\\n    \"it hi \\n\\t\"                               \\\n    \"adchi r10, r10, #0 \\n\\t\"                  \\\n    \"adds r8, r8, r11 \\n\\t\"                    \\\n    \"adcs r9, r9, r12 \\n\\t\"                    \\\n    \"adc r10, r10, #0 \\n\\t\"                    \\\n    \"stmia r0!, {r8} \\n\\t\"                     \\\n                                               \\\n    \"mov r12, #0 \\n\\t\"                         \\\n    \"umull r8, r11, r2, r7 \\n\\t\"               \\\n    \"mov r14, r11 \\n\\t\"                        \\\n    \"umlal r8, r11, r3, r6 \\n\\t\"               \\\n    \"cmp r14, r11 \\n\\t\"                        \\\n    \"it hi \\n\\t\"                               \\\n    \"adchi r12, r12, #0 \\n\\t\"                  \\\n    \"mov r14, r11 \\n\\t\"                        \\\n    \"umlal r8, r11, r4, r5 \\n\\t\"               \\\n    \"cmp r14, r11 \\n\\t\"                        \\\n    \"it hi \\n\\t\"                               \\\n    \"adchi r12, r12, #0 \\n\\t\"                  \\\n    \"adds r8, r8, r8 \\n\\t\"                     \\\n    \"adcs r11, r11, r11 \\n\\t\"                  \\\n    \"adc r12, r12, r12 \\n\\t\"                   \\\n    \"adds r8, r8, r9 \\n\\t\"                     \\\n    \"adcs r11, r11, r10 \\n\\t\"                  \\\n    \"adc r12, r12, #0 \\n\\t\"                    \\\n    \"stmia r0!, {r8} \\n\\t\"                     \\\n                                               \\\n    \"ldmia r1!, {r2} \\n\\t\"                     \\\n    \"mov r10, #0 \\n\\t\"                         \\\n    \"umull r8, r9, r3, r7 \\n\\t\"                \\\n    \"mov r14, r9 \\n\\t\"                         \\\n    \"umlal r8, r9, r4, r6 \\n\\t\"                \\\n    \"cmp r14, r9 \\n\\t\"                         \\\n    \"it hi \\n\\t\"                               \\\n    \"adchi r10, r10, #0 \\n\\t\"                  \\\n    \"ldr r14, [r0] \\n\\t\"                       \\\n    \"adds r8, r8, r14 \\n\\t\"                    \\\n    \"adcs r9, r9, #0 \\n\\t\"                     \\\n    \"adc r10, r10, #0 \\n\\t\"                    \\\n    \"adds r8, r8, r8 \\n\\t\"                     \\\n    \"adcs r9, r9, r9 \\n\\t\"                     \\\n    \"adc r10, r10, r10 \\n\\t\"                   \\\n    \"mov r14, r9 \\n\\t\"                         \\\n    \"umlal r8, r9, r5, r5 \\n\\t\"                \\\n    \"cmp r14, r9 \\n\\t\"                         \\\n    \"it hi \\n\\t\"                               \\\n    \"adchi r10, r10, #0 \\n\\t\"                  \\\n    \"adds r8, r8, r11 \\n\\t\"                    \\\n    \"adcs r9, r9, r12 \\n\\t\"                    \\\n    \"adc r10, r10, #0 \\n\\t\"                    \\\n    \"stmia r0!, {r8} \\n\\t\"                     \\\n                                               \\\n    \"mov r12, #0 \\n\\t\"                         \\\n    \"umull r8, r11, r3, r2 \\n\\t\"               \\\n    \"mov r14, r11 \\n\\t\"                        \\\n    \"umlal r8, r11, r4, r7 \\n\\t\"               \\\n    \"cmp r14, r11 \\n\\t\"                        \\\n    \"it hi \\n\\t\"                               \\\n    \"adchi r12, r12, #0 \\n\\t\"                  \\\n    \"mov r14, r11 \\n\\t\"                        \\\n    \"umlal r8, r11, r5, r6 \\n\\t\"               \\\n    \"cmp r14, r11 \\n\\t\"                        \\\n    \"it hi \\n\\t\"                               \\\n    \"adchi r12, r12, #0 \\n\\t\"                  \\\n    \"ldr r14, [r0] \\n\\t\"                       \\\n    \"adds r8, r8, r14 \\n\\t\"                    \\\n    \"adcs r11, r11, #0 \\n\\t\"                   \\\n    \"adc r12, r12, #0 \\n\\t\"                    \\\n    \"adds r8, r8, r8 \\n\\t\"                     \\\n    \"adcs r11, r11, r11 \\n\\t\"                  \\\n    \"adc r12, r12, r12 \\n\\t\"                   \\\n    \"adds r8, r8, r9 \\n\\t\"                     \\\n    \"adcs r11, r11, r10 \\n\\t\"                  \\\n    \"adc r12, r12, #0 \\n\\t\"                    \\\n    \"stmia r0!, {r8} \\n\\t\"                     \\\n                                               \\\n    \"mov r10, #0 \\n\\t\"                         \\\n    \"umull r8, r9, r4, r2 \\n\\t\"                \\\n    \"mov r14, r9 \\n\\t\"                         \\\n    \"umlal r8, r9, r5, r7 \\n\\t\"                \\\n    \"cmp r14, r9 \\n\\t\"                         \\\n    \"it hi \\n\\t\"                               \\\n    \"adchi r10, r10, #0 \\n\\t\"                  \\\n    \"adds r8, r8, r8 \\n\\t\"                     \\\n    \"adcs r9, r9, r9 \\n\\t\"                     \\\n    \"adc r10, r10, r10 \\n\\t\"                   \\\n    \"mov r14, r9 \\n\\t\"                         \\\n    \"umlal r8, r9, r6, r6 \\n\\t\"                \\\n    \"cmp r14, r9 \\n\\t\"                         \\\n    \"it hi \\n\\t\"                               \\\n    \"adchi r10, r10, #0 \\n\\t\"                  \\\n    \"adds r8, r8, r11 \\n\\t\"                    \\\n    \"adcs r9, r9, r12 \\n\\t\"                    \\\n    \"adc r10, r10, #0 \\n\\t\"                    \\\n    \"stmia r0!, {r8} \\n\\t\"                     \\\n                                               \\\n    \"mov r12, #0 \\n\\t\"                         \\\n    \"umull r8, r11, r5, r2 \\n\\t\"               \\\n    \"mov r14, r11 \\n\\t\"                        \\\n    \"umlal r8, r11, r6, r7 \\n\\t\"               \\\n    \"cmp r14, r11 \\n\\t\"                        \\\n    \"it hi \\n\\t\"                               \\\n    \"adchi r12, r12, #0 \\n\\t\"                  \\\n    \"adds r8, r8, r8 \\n\\t\"                     \\\n    \"adcs r11, r11, r11 \\n\\t\"                  \\\n    \"adc r12, r12, r12 \\n\\t\"                   \\\n    \"adds r8, r8, r9 \\n\\t\"                     \\\n    \"adcs r11, r11, r10 \\n\\t\"                  \\\n    \"adc r12, r12, #0 \\n\\t\"                    \\\n    \"stmia r0!, {r8} \\n\\t\"                     \\\n                                               \\\n    \"mov r8, #0 \\n\\t\"                          \\\n    \"umull r1, r10, r6, r2 \\n\\t\"               \\\n    \"adds r1, r1, r1 \\n\\t\"                     \\\n    \"adcs r10, r10, r10 \\n\\t\"                  \\\n    \"adc r8, r8, #0 \\n\\t\"                      \\\n    \"adds r11, r11, r1 \\n\\t\"                   \\\n    \"adcs r12, r12, r10 \\n\\t\"                  \\\n    \"adc r8, r8, #0 \\n\\t\"                      \\\n    \"umull r1, r10, r7, r7 \\n\\t\"               \\\n    \"adds r11, r11, r1 \\n\\t\"                   \\\n    \"adcs r12, r12, r10 \\n\\t\"                  \\\n    \"adc r8, r8, #0 \\n\\t\"                      \\\n    \"stmia r0!, {r11} \\n\\t\"                    \\\n                                               \\\n    \"mov r11, #0 \\n\\t\"                         \\\n    \"umull r1, r10, r7, r2 \\n\\t\"               \\\n    \"adds r1, r1, r1 \\n\\t\"                     \\\n    \"adcs r10, r10, r10 \\n\\t\"                  \\\n    \"adc r11, r11, #0 \\n\\t\"                    \\\n    \"adds r12, r12, r1 \\n\\t\"                   \\\n    \"adcs r8, r8, r10 \\n\\t\"                    \\\n    \"adc r11, r11, #0 \\n\\t\"                    \\\n    \"stmia r0!, {r12} \\n\\t\"                    \\\n                                               \\\n    \"umull r1, r10, r2, r2 \\n\\t\"               \\\n    \"adds r8, r8, r1 \\n\\t\"                     \\\n    \"adcs r11, r11, r10 \\n\\t\"                  \\\n    \"stmia r0!, {r8, r11} \\n\\t\"\n\n#define FAST_SQUARE_ASM_8                   \\\n    \"ldmia r1!, {r2, r3} \\n\\t\"              \\\n    \"add r1, 16 \\n\\t\"                       \\\n    \"ldmia r1!, {r5, r6} \\n\\t\"              \\\n    \"add r0, 24 \\n\\t\"                       \\\n                                            \\\n    \"umull r8, r9, r2, r5 \\n\\t\"             \\\n    \"stmia r0!, {r8} \\n\\t\"                  \\\n                                            \\\n    \"umull r12, r10, r2, r6 \\n\\t\"           \\\n    \"adds r9, r9, r12 \\n\\t\"                 \\\n    \"adc r10, r10, #0 \\n\\t\"                 \\\n    \"stmia r0!, {r9} \\n\\t\"                  \\\n                                            \\\n    \"umull r8, r9, r3, r6 \\n\\t\"             \\\n    \"adds r10, r10, r8 \\n\\t\"                \\\n    \"adc r11, r9, #0 \\n\\t\"                  \\\n    \"stmia r0!, {r10, r11} \\n\\t\"            \\\n                                            \\\n    \"sub r0, 40 \\n\\t\"                       \\\n    \"sub r1, 32 \\n\\t\"                       \\\n    \"ldmia r1!, {r2,r3,r4,r5,r6,r7} \\n\\t\"   \\\n                                            \\\n    \"umull r11, r12, r2, r2 \\n\\t\"           \\\n    \"stmia r0!, {r11} \\n\\t\"                 \\\n                                            \\\n    \"mov r9, #0 \\n\\t\"                       \\\n    \"umull r10, r11, r2, r3 \\n\\t\"           \\\n    \"adds r12, r12, r10 \\n\\t\"               \\\n    \"adcs r8, r11, #0 \\n\\t\"                 \\\n    \"adc r9, r9, #0 \\n\\t\"                   \\\n    \"adds r12, r12, r10 \\n\\t\"               \\\n    \"adcs r8, r8, r11 \\n\\t\"                 \\\n    \"adc r9, r9, #0 \\n\\t\"                   \\\n    \"stmia r0!, {r12} \\n\\t\"                 \\\n                                            \\\n    \"mov r10, #0 \\n\\t\"                      \\\n    \"umull r11, r12, r2, r4 \\n\\t\"           \\\n    \"adds r11, r11, r11 \\n\\t\"               \\\n    \"adcs r12, r12, r12 \\n\\t\"               \\\n    \"adc r10, r10, #0 \\n\\t\"                 \\\n    \"adds r8, r8, r11 \\n\\t\"                 \\\n    \"adcs r9, r9, r12 \\n\\t\"                 \\\n    \"adc r10, r10, #0 \\n\\t\"                 \\\n    \"umull r11, r12, r3, r3 \\n\\t\"           \\\n    \"adds r8, r8, r11 \\n\\t\"                 \\\n    \"adcs r9, r9, r12 \\n\\t\"                 \\\n    \"adc r10, r10, #0 \\n\\t\"                 \\\n    \"stmia r0!, {r8} \\n\\t\"                  \\\n                                            \\\n    \"mov r12, #0 \\n\\t\"                      \\\n    \"umull r8, r11, r2, r5 \\n\\t\"            \\\n    \"mov r14, r11 \\n\\t\"                     \\\n    \"umlal r8, r11, r3, r4 \\n\\t\"            \\\n    \"cmp r14, r11 \\n\\t\"                     \\\n    \"it hi \\n\\t\"                            \\\n    \"adchi r12, r12, #0 \\n\\t\"               \\\n    \"adds r8, r8, r8 \\n\\t\"                  \\\n    \"adcs r11, r11, r11 \\n\\t\"               \\\n    \"adc r12, r12, r12 \\n\\t\"                \\\n    \"adds r8, r8, r9 \\n\\t\"                  \\\n    \"adcs r11, r11, r10 \\n\\t\"               \\\n    \"adc r12, r12, #0 \\n\\t\"                 \\\n    \"stmia r0!, {r8} \\n\\t\"                  \\\n                                            \\\n    \"mov r10, #0 \\n\\t\"                      \\\n    \"umull r8, r9, r2, r6 \\n\\t\"             \\\n    \"mov r14, r9 \\n\\t\"                      \\\n    \"umlal r8, r9, r3, r5 \\n\\t\"             \\\n    \"cmp r14, r9 \\n\\t\"                      \\\n    \"it hi \\n\\t\"                            \\\n    \"adchi r10, r10, #0 \\n\\t\"               \\\n    \"adds r8, r8, r8 \\n\\t\"                  \\\n    \"adcs r9, r9, r9 \\n\\t\"                  \\\n    \"adc r10, r10, r10 \\n\\t\"                \\\n    \"mov r14, r9 \\n\\t\"                      \\\n    \"umlal r8, r9, r4, r4 \\n\\t\"             \\\n    \"cmp r14, r9 \\n\\t\"                      \\\n    \"it hi \\n\\t\"                            \\\n    \"adchi r10, r10, #0 \\n\\t\"               \\\n    \"adds r8, r8, r11 \\n\\t\"                 \\\n    \"adcs r9, r9, r12 \\n\\t\"                 \\\n    \"adc r10, r10, #0 \\n\\t\"                 \\\n    \"stmia r0!, {r8} \\n\\t\"                  \\\n                                            \\\n    \"mov r12, #0 \\n\\t\"                      \\\n    \"umull r8, r11, r2, r7 \\n\\t\"            \\\n    \"mov r14, r11 \\n\\t\"                     \\\n    \"umlal r8, r11, r3, r6 \\n\\t\"            \\\n    \"cmp r14, r11 \\n\\t\"                     \\\n    \"it hi \\n\\t\"                            \\\n    \"adchi r12, r12, #0 \\n\\t\"               \\\n    \"mov r14, r11 \\n\\t\"                     \\\n    \"umlal r8, r11, r4, r5 \\n\\t\"            \\\n    \"cmp r14, r11 \\n\\t\"                     \\\n    \"it hi \\n\\t\"                            \\\n    \"adchi r12, r12, #0 \\n\\t\"               \\\n    \"adds r8, r8, r8 \\n\\t\"                  \\\n    \"adcs r11, r11, r11 \\n\\t\"               \\\n    \"adc r12, r12, r12 \\n\\t\"                \\\n    \"adds r8, r8, r9 \\n\\t\"                  \\\n    \"adcs r11, r11, r10 \\n\\t\"               \\\n    \"adc r12, r12, #0 \\n\\t\"                 \\\n    \"stmia r0!, {r8} \\n\\t\"                  \\\n                                            \\\n    \"ldmia r1!, {r2} \\n\\t\"                  \\\n    \"mov r10, #0 \\n\\t\"                      \\\n    \"umull r8, r9, r3, r7 \\n\\t\"             \\\n    \"mov r14, r9 \\n\\t\"                      \\\n    \"umlal r8, r9, r4, r6 \\n\\t\"             \\\n    \"cmp r14, r9 \\n\\t\"                      \\\n    \"it hi \\n\\t\"                            \\\n    \"adchi r10, r10, #0 \\n\\t\"               \\\n    \"ldr r14, [r0] \\n\\t\"                    \\\n    \"adds r8, r8, r14 \\n\\t\"                 \\\n    \"adcs r9, r9, #0 \\n\\t\"                  \\\n    \"adc r10, r10, #0 \\n\\t\"                 \\\n    \"adds r8, r8, r8 \\n\\t\"                  \\\n    \"adcs r9, r9, r9 \\n\\t\"                  \\\n    \"adc r10, r10, r10 \\n\\t\"                \\\n    \"mov r14, r9 \\n\\t\"                      \\\n    \"umlal r8, r9, r5, r5 \\n\\t\"             \\\n    \"cmp r14, r9 \\n\\t\"                      \\\n    \"it hi \\n\\t\"                            \\\n    \"adchi r10, r10, #0 \\n\\t\"               \\\n    \"adds r8, r8, r11 \\n\\t\"                 \\\n    \"adcs r9, r9, r12 \\n\\t\"                 \\\n    \"adc r10, r10, #0 \\n\\t\"                 \\\n    \"stmia r0!, {r8} \\n\\t\"                  \\\n                                            \\\n    \"mov r12, #0 \\n\\t\"                      \\\n    \"umull r8, r11, r3, r2 \\n\\t\"            \\\n    \"mov r14, r11 \\n\\t\"                     \\\n    \"umlal r8, r11, r4, r7 \\n\\t\"            \\\n    \"cmp r14, r11 \\n\\t\"                     \\\n    \"it hi \\n\\t\"                            \\\n    \"adchi r12, r12, #0 \\n\\t\"               \\\n    \"mov r14, r11 \\n\\t\"                     \\\n    \"umlal r8, r11, r5, r6 \\n\\t\"            \\\n    \"cmp r14, r11 \\n\\t\"                     \\\n    \"it hi \\n\\t\"                            \\\n    \"adchi r12, r12, #0 \\n\\t\"               \\\n    \"ldr r14, [r0] \\n\\t\"                    \\\n    \"adds r8, r8, r14 \\n\\t\"                 \\\n    \"adcs r11, r11, #0 \\n\\t\"                \\\n    \"adc r12, r12, #0 \\n\\t\"                 \\\n    \"adds r8, r8, r8 \\n\\t\"                  \\\n    \"adcs r11, r11, r11 \\n\\t\"               \\\n    \"adc r12, r12, r12 \\n\\t\"                \\\n    \"adds r8, r8, r9 \\n\\t\"                  \\\n    \"adcs r11, r11, r10 \\n\\t\"               \\\n    \"adc r12, r12, #0 \\n\\t\"                 \\\n    \"stmia r0!, {r8} \\n\\t\"                  \\\n                                            \\\n    \"ldmia r1!, {r3} \\n\\t\"                  \\\n    \"mov r10, #0 \\n\\t\"                      \\\n    \"umull r8, r9, r4, r2 \\n\\t\"             \\\n    \"mov r14, r9 \\n\\t\"                      \\\n    \"umlal r8, r9, r5, r7 \\n\\t\"             \\\n    \"cmp r14, r9 \\n\\t\"                      \\\n    \"it hi \\n\\t\"                            \\\n    \"adchi r10, r10, #0 \\n\\t\"               \\\n    \"ldr r14, [r0] \\n\\t\"                    \\\n    \"adds r8, r8, r14 \\n\\t\"                 \\\n    \"adcs r9, r9, #0 \\n\\t\"                  \\\n    \"adc r10, r10, #0 \\n\\t\"                 \\\n    \"adds r8, r8, r8 \\n\\t\"                  \\\n    \"adcs r9, r9, r9 \\n\\t\"                  \\\n    \"adc r10, r10, r10 \\n\\t\"                \\\n    \"mov r14, r9 \\n\\t\"                      \\\n    \"umlal r8, r9, r6, r6 \\n\\t\"             \\\n    \"cmp r14, r9 \\n\\t\"                      \\\n    \"it hi \\n\\t\"                            \\\n    \"adchi r10, r10, #0 \\n\\t\"               \\\n    \"adds r8, r8, r11 \\n\\t\"                 \\\n    \"adcs r9, r9, r12 \\n\\t\"                 \\\n    \"adc r10, r10, #0 \\n\\t\"                 \\\n    \"stmia r0!, {r8} \\n\\t\"                  \\\n                                            \\\n    \"mov r12, #0 \\n\\t\"                      \\\n    \"umull r8, r11, r4, r3 \\n\\t\"            \\\n    \"mov r14, r11 \\n\\t\"                     \\\n    \"umlal r8, r11, r5, r2 \\n\\t\"            \\\n    \"cmp r14, r11 \\n\\t\"                     \\\n    \"it hi \\n\\t\"                            \\\n    \"adchi r12, r12, #0 \\n\\t\"               \\\n    \"mov r14, r11 \\n\\t\"                     \\\n    \"umlal r8, r11, r6, r7 \\n\\t\"            \\\n    \"cmp r14, r11 \\n\\t\"                     \\\n    \"it hi \\n\\t\"                            \\\n    \"adchi r12, r12, #0 \\n\\t\"               \\\n    \"ldr r14, [r0] \\n\\t\"                    \\\n    \"adds r8, r8, r14 \\n\\t\"                 \\\n    \"adcs r11, r11, #0 \\n\\t\"                \\\n    \"adc r12, r12, #0 \\n\\t\"                 \\\n    \"adds r8, r8, r8 \\n\\t\"                  \\\n    \"adcs r11, r11, r11 \\n\\t\"               \\\n    \"adc r12, r12, r12 \\n\\t\"                \\\n    \"adds r8, r8, r9 \\n\\t\"                  \\\n    \"adcs r11, r11, r10 \\n\\t\"               \\\n    \"adc r12, r12, #0 \\n\\t\"                 \\\n    \"stmia r0!, {r8} \\n\\t\"                  \\\n                                            \\\n    \"mov r10, #0 \\n\\t\"                      \\\n    \"umull r8, r9, r5, r3 \\n\\t\"             \\\n    \"mov r14, r9 \\n\\t\"                      \\\n    \"umlal r8, r9, r6, r2 \\n\\t\"             \\\n    \"cmp r14, r9 \\n\\t\"                      \\\n    \"it hi \\n\\t\"                            \\\n    \"adchi r10, r10, #0 \\n\\t\"               \\\n    \"adds r8, r8, r8 \\n\\t\"                  \\\n    \"adcs r9, r9, r9 \\n\\t\"                  \\\n    \"adc r10, r10, r10 \\n\\t\"                \\\n    \"mov r14, r9 \\n\\t\"                      \\\n    \"umlal r8, r9, r7, r7 \\n\\t\"             \\\n    \"cmp r14, r9 \\n\\t\"                      \\\n    \"it hi \\n\\t\"                            \\\n    \"adchi r10, r10, #0 \\n\\t\"               \\\n    \"adds r8, r8, r11 \\n\\t\"                 \\\n    \"adcs r9, r9, r12 \\n\\t\"                 \\\n    \"adc r10, r10, #0 \\n\\t\"                 \\\n    \"stmia r0!, {r8} \\n\\t\"                  \\\n                                            \\\n    \"mov r12, #0 \\n\\t\"                      \\\n    \"umull r8, r11, r6, r3 \\n\\t\"            \\\n    \"mov r14, r11 \\n\\t\"                     \\\n    \"umlal r8, r11, r7, r2 \\n\\t\"            \\\n    \"cmp r14, r11 \\n\\t\"                     \\\n    \"it hi \\n\\t\"                            \\\n    \"adchi r12, r12, #0 \\n\\t\"               \\\n    \"adds r8, r8, r8 \\n\\t\"                  \\\n    \"adcs r11, r11, r11 \\n\\t\"               \\\n    \"adc r12, r12, r12 \\n\\t\"                \\\n    \"adds r8, r8, r9 \\n\\t\"                  \\\n    \"adcs r11, r11, r10 \\n\\t\"               \\\n    \"adc r12, r12, #0 \\n\\t\"                 \\\n    \"stmia r0!, {r8} \\n\\t\"                  \\\n                                            \\\n    \"mov r8, #0 \\n\\t\"                       \\\n    \"umull r1, r10, r7, r3 \\n\\t\"            \\\n    \"adds r1, r1, r1 \\n\\t\"                  \\\n    \"adcs r10, r10, r10 \\n\\t\"               \\\n    \"adc r8, r8, #0 \\n\\t\"                   \\\n    \"adds r11, r11, r1 \\n\\t\"                \\\n    \"adcs r12, r12, r10 \\n\\t\"               \\\n    \"adc r8, r8, #0 \\n\\t\"                   \\\n    \"umull r1, r10, r2, r2 \\n\\t\"            \\\n    \"adds r11, r11, r1 \\n\\t\"                \\\n    \"adcs r12, r12, r10 \\n\\t\"               \\\n    \"adc r8, r8, #0 \\n\\t\"                   \\\n    \"stmia r0!, {r11} \\n\\t\"                 \\\n                                            \\\n    \"mov r11, #0 \\n\\t\"                      \\\n    \"umull r1, r10, r2, r3 \\n\\t\"            \\\n    \"adds r1, r1, r1 \\n\\t\"                  \\\n    \"adcs r10, r10, r10 \\n\\t\"               \\\n    \"adc r11, r11, #0 \\n\\t\"                 \\\n    \"adds r12, r12, r1 \\n\\t\"                \\\n    \"adcs r8, r8, r10 \\n\\t\"                 \\\n    \"adc r11, r11, #0 \\n\\t\"                 \\\n    \"stmia r0!, {r12} \\n\\t\"                 \\\n                                            \\\n    \"umull r1, r10, r3, r3 \\n\\t\"            \\\n    \"adds r8, r8, r1 \\n\\t\"                  \\\n    \"adcs r11, r11, r10 \\n\\t\"               \\\n    \"stmia r0!, {r8, r11} \\n\\t\"\n\n#endif /* _UECC_ASM_ARM_MULT_SQUARE_H_ */\n"
  },
  {
    "path": "u2f/curve-specific.h",
    "content": "/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */\n\n#ifndef _UECC_CURVE_SPECIFIC_H_\n#define _UECC_CURVE_SPECIFIC_H_\n\n#define num_bytes_secp160r1 20\n#define num_bytes_secp192r1 24\n#define num_bytes_secp224r1 28\n#define num_bytes_secp256r1 32\n#define num_bytes_secp256k1 32\n\n#if (uECC_WORD_SIZE == 1)\n\n#define num_words_secp160r1 20\n#define num_words_secp192r1 24\n#define num_words_secp224r1 28\n#define num_words_secp256r1 32\n#define num_words_secp256k1 32\n\n#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) \\\n    0x##a, 0x##b, 0x##c, 0x##d, 0x##e, 0x##f, 0x##g, 0x##h\n#define BYTES_TO_WORDS_4(a, b, c, d) 0x##a, 0x##b, 0x##c, 0x##d\n\n#elif (uECC_WORD_SIZE == 4)\n\n#define num_words_secp160r1 5\n#define num_words_secp192r1 6\n#define num_words_secp224r1 7\n#define num_words_secp256r1 8\n#define num_words_secp256k1 8\n\n#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##d##c##b##a, 0x##h##g##f##e\n#define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a\n\n#elif (uECC_WORD_SIZE == 8)\n\n#define num_words_secp160r1 3\n#define num_words_secp192r1 3\n#define num_words_secp224r1 4\n#define num_words_secp256r1 4\n#define num_words_secp256k1 4\n\n#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##h##g##f##e##d##c##b##a##ull\n#define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a##ull\n\n#endif /* uECC_WORD_SIZE */\n\n#if uECC_SUPPORTS_secp160r1 || uECC_SUPPORTS_secp192r1 || \\\n    uECC_SUPPORTS_secp224r1 || uECC_SUPPORTS_secp256r1\nstatic void double_jacobian_default(uECC_word_t * X1,\n                                    uECC_word_t * Y1,\n                                    uECC_word_t * Z1,\n                                    uECC_Curve curve) {\n    /* t1 = X, t2 = Y, t3 = Z */\n    uECC_word_t t4[uECC_MAX_WORDS];\n    uECC_word_t t5[uECC_MAX_WORDS];\n    wordcount_t num_words = curve->num_words;\n\n    if (uECC_vli_isZero(Z1, num_words)) {\n        return;\n    }\n\n    uECC_vli_modSquare_fast(t4, Y1, curve);   /* t4 = y1^2 */\n    uECC_vli_modMult_fast(t5, X1, t4, curve); /* t5 = x1*y1^2 = A */\n    uECC_vli_modSquare_fast(t4, t4, curve);   /* t4 = y1^4 */\n    uECC_vli_modMult_fast(Y1, Y1, Z1, curve); /* t2 = y1*z1 = z3 */\n    uECC_vli_modSquare_fast(Z1, Z1, curve);   /* t3 = z1^2 */\n\n    uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = x1 + z1^2 */\n    uECC_vli_modAdd(Z1, Z1, Z1, curve->p, num_words); /* t3 = 2*z1^2 */\n    uECC_vli_modSub(Z1, X1, Z1, curve->p, num_words); /* t3 = x1 - z1^2 */\n    uECC_vli_modMult_fast(X1, X1, Z1, curve);                /* t1 = x1^2 - z1^4 */\n\n    uECC_vli_modAdd(Z1, X1, X1, curve->p, num_words); /* t3 = 2*(x1^2 - z1^4) */\n    uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = 3*(x1^2 - z1^4) */\n    if (uECC_vli_testBit(X1, 0)) {\n        uECC_word_t l_carry = uECC_vli_add(X1, X1, curve->p, num_words);\n        uECC_vli_rshift1(X1, num_words);\n        X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1);\n    } else {\n        uECC_vli_rshift1(X1, num_words);\n    }\n    /* t1 = 3/2*(x1^2 - z1^4) = B */\n\n    uECC_vli_modSquare_fast(Z1, X1, curve);                  /* t3 = B^2 */\n    uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - A */\n    uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - 2A = x3 */\n    uECC_vli_modSub(t5, t5, Z1, curve->p, num_words); /* t5 = A - x3 */\n    uECC_vli_modMult_fast(X1, X1, t5, curve);                /* t1 = B * (A - x3) */\n    uECC_vli_modSub(t4, X1, t4, curve->p, num_words); /* t4 = B * (A - x3) - y1^4 = y3 */\n\n    uECC_vli_set(X1, Z1, num_words);\n    uECC_vli_set(Z1, Y1, num_words);\n    uECC_vli_set(Y1, t4, num_words);\n}\n\n/* Computes result = x^3 + ax + b. result must not overlap x. */\nstatic void x_side_default(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) {\n    uECC_word_t _3[uECC_MAX_WORDS] = {3}; /* -a = 3 */\n    wordcount_t num_words = curve->num_words;\n\n    uECC_vli_modSquare_fast(result, x, curve);                             /* r = x^2 */\n    uECC_vli_modSub(result, result, _3, curve->p, num_words);       /* r = x^2 - 3 */\n    uECC_vli_modMult_fast(result, result, x, curve);                       /* r = x^3 - 3x */\n    uECC_vli_modAdd(result, result, curve->b, curve->p, num_words); /* r = x^3 - 3x + b */\n}\n#endif /* uECC_SUPPORTS_secp... */\n\n#if uECC_SUPPORT_COMPRESSED_POINT\n#if uECC_SUPPORTS_secp160r1 || uECC_SUPPORTS_secp192r1 || \\\n    uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1\n/* Compute a = sqrt(a) (mod curve_p). */\nstatic void mod_sqrt_default(uECC_word_t *a, uECC_Curve curve) {\n    bitcount_t i;\n    uECC_word_t p1[uECC_MAX_WORDS] = {1};\n    uECC_word_t l_result[uECC_MAX_WORDS] = {1};\n    wordcount_t num_words = curve->num_words;\n    \n    /* When curve->p == 3 (mod 4), we can compute\n       sqrt(a) = a^((curve->p + 1) / 4) (mod curve->p). */\n    uECC_vli_add(p1, curve->p, p1, num_words); /* p1 = curve_p + 1 */\n    for (i = uECC_vli_numBits(p1, num_words) - 1; i > 1; --i) {\n        uECC_vli_modSquare_fast(l_result, l_result, curve);\n        if (uECC_vli_testBit(p1, i)) {\n            uECC_vli_modMult_fast(l_result, l_result, a, curve);\n        }\n    }\n    uECC_vli_set(a, l_result, num_words);\n}\n#endif /* uECC_SUPPORTS_secp... */\n#endif /* uECC_SUPPORT_COMPRESSED_POINT */\n\n#if uECC_SUPPORTS_secp160r1\n\n#if (uECC_OPTIMIZATION_LEVEL > 0)\nstatic void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product);\n#endif\n\nstatic const struct uECC_Curve_t curve_secp160r1 = {\n    num_words_secp160r1,\n    num_bytes_secp160r1,\n    161, /* num_n_bits */\n    { BYTES_TO_WORDS_8(FF, FF, FF, 7F, FF, FF, FF, FF),\n        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),\n        BYTES_TO_WORDS_4(FF, FF, FF, FF) },\n    { BYTES_TO_WORDS_8(57, 22, 75, CA, D3, AE, 27, F9),\n        BYTES_TO_WORDS_8(C8, F4, 01, 00, 00, 00, 00, 00),\n        BYTES_TO_WORDS_8(00, 00, 00, 00, 01, 00, 00, 00) },\n    { BYTES_TO_WORDS_8(82, FC, CB, 13, B9, 8B, C3, 68),\n        BYTES_TO_WORDS_8(89, 69, 64, 46, 28, 73, F5, 8E),\n        BYTES_TO_WORDS_4(68, B5, 96, 4A),\n\n        BYTES_TO_WORDS_8(32, FB, C5, 7A, 37, 51, 23, 04),\n        BYTES_TO_WORDS_8(12, C9, DC, 59, 7D, 94, 68, 31),\n        BYTES_TO_WORDS_4(55, 28, A6, 23) },\n    { BYTES_TO_WORDS_8(45, FA, 65, C5, AD, D4, D4, 81),\n        BYTES_TO_WORDS_8(9F, F8, AC, 65, 8B, 7A, BD, 54),\n        BYTES_TO_WORDS_4(FC, BE, 97, 1C) },\n    &double_jacobian_default,\n#if uECC_SUPPORT_COMPRESSED_POINT\n    &mod_sqrt_default,\n#endif\n    &x_side_default,\n#if (uECC_OPTIMIZATION_LEVEL > 0)\n    &vli_mmod_fast_secp160r1\n#endif\n};\n\nuECC_Curve uECC_secp160r1(void) { return &curve_secp160r1; }\n\n#if (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp160r1)\n/* Computes result = product % curve_p\n    see http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf page 354\n    \n    Note that this only works if log2(omega) < log2(p) / 2 */\nstatic void omega_mult_secp160r1(uECC_word_t *result, const uECC_word_t *right);\n#if uECC_WORD_SIZE == 8\nstatic void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product) {\n    uECC_word_t tmp[2 * num_words_secp160r1];\n    uECC_word_t copy;\n    \n    uECC_vli_clear(tmp, num_words_secp160r1);\n    uECC_vli_clear(tmp + num_words_secp160r1, num_words_secp160r1);\n\n    omega_mult_secp160r1(tmp, product + num_words_secp160r1 - 1); /* (Rq, q) = q * c */\n    \n    product[num_words_secp160r1 - 1] &= 0xffffffff;\n    copy = tmp[num_words_secp160r1 - 1];\n    tmp[num_words_secp160r1 - 1] &= 0xffffffff;\n    uECC_vli_add(result, product, tmp, num_words_secp160r1); /* (C, r) = r + q */\n    uECC_vli_clear(product, num_words_secp160r1);\n    tmp[num_words_secp160r1 - 1] = copy;\n    omega_mult_secp160r1(product, tmp + num_words_secp160r1 - 1); /* Rq*c */\n    uECC_vli_add(result, result, product, num_words_secp160r1); /* (C1, r) = r + Rq*c */\n\n    while (uECC_vli_cmp_unsafe(result, curve_secp160r1.p, num_words_secp160r1) > 0) {\n        uECC_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1);\n    }\n}\n\nstatic void omega_mult_secp160r1(uint64_t *result, const uint64_t *right) {\n    uint32_t carry;\n    unsigned i;\n    \n    /* Multiply by (2^31 + 1). */\n    carry = 0;\n    for (i = 0; i < num_words_secp160r1; ++i) {\n        uint64_t tmp = (right[i] >> 32) | (right[i + 1] << 32);\n        result[i] = (tmp << 31) + tmp + carry;\n        carry = (tmp >> 33) + (result[i] < tmp || (carry && result[i] == tmp));\n    }\n    result[i] = carry;\n}\n#else\nstatic void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product) {\n    uECC_word_t tmp[2 * num_words_secp160r1];\n    uECC_word_t carry;\n    \n    uECC_vli_clear(tmp, num_words_secp160r1);\n    uECC_vli_clear(tmp + num_words_secp160r1, num_words_secp160r1);\n\n    omega_mult_secp160r1(tmp, product + num_words_secp160r1); /* (Rq, q) = q * c */\n    \n    carry = uECC_vli_add(result, product, tmp, num_words_secp160r1); /* (C, r) = r + q */\n    uECC_vli_clear(product, num_words_secp160r1);\n    omega_mult_secp160r1(product, tmp + num_words_secp160r1); /* Rq*c */\n    carry += uECC_vli_add(result, result, product, num_words_secp160r1); /* (C1, r) = r + Rq*c */\n\n    while (carry > 0) {\n        --carry;\n        uECC_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1);\n    }\n    if (uECC_vli_cmp_unsafe(result, curve_secp160r1.p, num_words_secp160r1) > 0) {\n        uECC_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1);\n    }\n}\n#endif\n\n#if uECC_WORD_SIZE == 1\nstatic void omega_mult_secp160r1(uint8_t *result, const uint8_t *right) {\n    uint8_t carry;\n    uint8_t i;\n    \n    /* Multiply by (2^31 + 1). */\n    uECC_vli_set(result + 4, right, num_words_secp160r1); /* 2^32 */\n    uECC_vli_rshift1(result + 4, num_words_secp160r1); /* 2^31 */\n    result[3] = right[0] << 7; /* get last bit from shift */\n    \n    carry = uECC_vli_add(result, result, right, num_words_secp160r1); /* 2^31 + 1 */\n    for (i = num_words_secp160r1; carry; ++i) {\n        uint16_t sum = (uint16_t)result[i] + carry;\n        result[i] = (uint8_t)sum;\n        carry = sum >> 8;\n    }\n}\n#elif uECC_WORD_SIZE == 4\nstatic void omega_mult_secp160r1(uint32_t *result, const uint32_t *right) {\n    uint32_t carry;\n    unsigned i;\n    \n    /* Multiply by (2^31 + 1). */\n    uECC_vli_set(result + 1, right, num_words_secp160r1); /* 2^32 */\n    uECC_vli_rshift1(result + 1, num_words_secp160r1); /* 2^31 */\n    result[0] = right[0] << 31; /* get last bit from shift */\n    \n    carry = uECC_vli_add(result, result, right, num_words_secp160r1); /* 2^31 + 1 */\n    for (i = num_words_secp160r1; carry; ++i) {\n        uint64_t sum = (uint64_t)result[i] + carry;\n        result[i] = (uint32_t)sum;\n        carry = sum >> 32;\n    }\n}\n#endif /* uECC_WORD_SIZE */\n#endif /* (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp160r1) */\n\n#endif /* uECC_SUPPORTS_secp160r1 */\n\n#if uECC_SUPPORTS_secp192r1\n\n#if (uECC_OPTIMIZATION_LEVEL > 0)\nstatic void vli_mmod_fast_secp192r1(uECC_word_t *result, uECC_word_t *product);\n#endif\n\nstatic const struct uECC_Curve_t curve_secp192r1 = {\n    num_words_secp192r1,\n    num_bytes_secp192r1,\n    192, /* num_n_bits */\n    { BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),\n        BYTES_TO_WORDS_8(FE, FF, FF, FF, FF, FF, FF, FF),\n        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) },\n    { BYTES_TO_WORDS_8(31, 28, D2, B4, B1, C9, 6B, 14),\n        BYTES_TO_WORDS_8(36, F8, DE, 99, FF, FF, FF, FF),\n        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) },\n    { BYTES_TO_WORDS_8(12, 10, FF, 82, FD, 0A, FF, F4),\n        BYTES_TO_WORDS_8(00, 88, A1, 43, EB, 20, BF, 7C),\n        BYTES_TO_WORDS_8(F6, 90, 30, B0, 0E, A8, 8D, 18),\n\n        BYTES_TO_WORDS_8(11, 48, 79, 1E, A1, 77, F9, 73),\n        BYTES_TO_WORDS_8(D5, CD, 24, 6B, ED, 11, 10, 63),\n        BYTES_TO_WORDS_8(78, DA, C8, FF, 95, 2B, 19, 07) },\n    { BYTES_TO_WORDS_8(B1, B9, 46, C1, EC, DE, B8, FE),\n        BYTES_TO_WORDS_8(49, 30, 24, 72, AB, E9, A7, 0F),\n        BYTES_TO_WORDS_8(E7, 80, 9C, E5, 19, 05, 21, 64) },\n    &double_jacobian_default,\n#if uECC_SUPPORT_COMPRESSED_POINT\n    &mod_sqrt_default,\n#endif\n    &x_side_default,\n#if (uECC_OPTIMIZATION_LEVEL > 0)\n    &vli_mmod_fast_secp192r1\n#endif\n};\n\nuECC_Curve uECC_secp192r1(void) { return &curve_secp192r1; }\n\n#if (uECC_OPTIMIZATION_LEVEL > 0)\n/* Computes result = product % curve_p.\n   See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf */\n#if uECC_WORD_SIZE == 1\nstatic void vli_mmod_fast_secp192r1(uint8_t *result, uint8_t *product) {\n    uint8_t tmp[num_words_secp192r1];\n    uint8_t carry;\n    \n    uECC_vli_set(result, product, num_words_secp192r1);\n    \n    uECC_vli_set(tmp, &product[24], num_words_secp192r1);\n    carry = uECC_vli_add(result, result, tmp, num_words_secp192r1);\n    \n    tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;\n    tmp[8] = product[24]; tmp[9] = product[25]; tmp[10] = product[26]; tmp[11] = product[27];\n    tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31];\n    tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35];\n    tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39];\n    carry += uECC_vli_add(result, result, tmp, num_words_secp192r1);\n    \n    tmp[0] = tmp[8] = product[40];\n    tmp[1] = tmp[9] = product[41];\n    tmp[2] = tmp[10] = product[42];\n    tmp[3] = tmp[11] = product[43];\n    tmp[4] = tmp[12] = product[44];\n    tmp[5] = tmp[13] = product[45];\n    tmp[6] = tmp[14] = product[46];\n    tmp[7] = tmp[15] = product[47];\n    tmp[16] = tmp[17] = tmp[18] = tmp[19] = tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;\n    carry += uECC_vli_add(result, result, tmp, num_words_secp192r1);\n    \n    while (carry || uECC_vli_cmp_unsafe(curve_secp192r1.p, result, num_words_secp192r1) != 1) {\n        carry -= uECC_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1);\n    }\n}\n#elif uECC_WORD_SIZE == 4\nstatic void vli_mmod_fast_secp192r1(uint32_t *result, uint32_t *product) {\n    uint32_t tmp[num_words_secp192r1];\n    int carry;\n    \n    uECC_vli_set(result, product, num_words_secp192r1);\n    \n    uECC_vli_set(tmp, &product[6], num_words_secp192r1);\n    carry = uECC_vli_add(result, result, tmp, num_words_secp192r1);\n    \n    tmp[0] = tmp[1] = 0;\n    tmp[2] = product[6];\n    tmp[3] = product[7];\n    tmp[4] = product[8];\n    tmp[5] = product[9];\n    carry += uECC_vli_add(result, result, tmp, num_words_secp192r1);\n    \n    tmp[0] = tmp[2] = product[10];\n    tmp[1] = tmp[3] = product[11];\n    tmp[4] = tmp[5] = 0;\n    carry += uECC_vli_add(result, result, tmp, num_words_secp192r1);\n    \n    while (carry || uECC_vli_cmp_unsafe(curve_secp192r1.p, result, num_words_secp192r1) != 1) {\n        carry -= uECC_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1);\n    }\n}\n#else\nstatic void vli_mmod_fast_secp192r1(uint64_t *result, uint64_t *product) {\n    uint64_t tmp[num_words_secp192r1];\n    int carry;\n    \n    uECC_vli_set(result, product, num_words_secp192r1);\n    \n    uECC_vli_set(tmp, &product[3], num_words_secp192r1);\n    carry = (int)uECC_vli_add(result, result, tmp, num_words_secp192r1);\n    \n    tmp[0] = 0;\n    tmp[1] = product[3];\n    tmp[2] = product[4];\n    carry += uECC_vli_add(result, result, tmp, num_words_secp192r1);\n    \n    tmp[0] = tmp[1] = product[5];\n    tmp[2] = 0;\n    carry += uECC_vli_add(result, result, tmp, num_words_secp192r1);\n    \n    while (carry || uECC_vli_cmp_unsafe(curve_secp192r1.p, result, num_words_secp192r1) != 1) {\n        carry -= uECC_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1);\n    }\n}\n#endif /* uECC_WORD_SIZE */\n#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */\n\n#endif /* uECC_SUPPORTS_secp192r1 */\n\n#if uECC_SUPPORTS_secp224r1\n\n#if uECC_SUPPORT_COMPRESSED_POINT\nstatic void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve);\n#endif\n#if (uECC_OPTIMIZATION_LEVEL > 0)\nstatic void vli_mmod_fast_secp224r1(uECC_word_t *result, uECC_word_t *product);\n#endif\n\nstatic const struct uECC_Curve_t curve_secp224r1 = {\n    num_words_secp224r1,\n    num_bytes_secp224r1,\n    224, /* num_n_bits */\n    { BYTES_TO_WORDS_8(01, 00, 00, 00, 00, 00, 00, 00),\n        BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF),\n        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),\n        BYTES_TO_WORDS_4(FF, FF, FF, FF) },\n    { BYTES_TO_WORDS_8(3D, 2A, 5C, 5C, 45, 29, DD, 13),\n        BYTES_TO_WORDS_8(3E, F0, B8, E0, A2, 16, FF, FF),\n        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),\n        BYTES_TO_WORDS_4(FF, FF, FF, FF) },\n    { BYTES_TO_WORDS_8(21, 1D, 5C, 11, D6, 80, 32, 34),\n        BYTES_TO_WORDS_8(22, 11, C2, 56, D3, C1, 03, 4A),\n        BYTES_TO_WORDS_8(B9, 90, 13, 32, 7F, BF, B4, 6B),\n        BYTES_TO_WORDS_4(BD, 0C, 0E, B7),\n\n        BYTES_TO_WORDS_8(34, 7E, 00, 85, 99, 81, D5, 44),\n        BYTES_TO_WORDS_8(64, 47, 07, 5A, A0, 75, 43, CD),\n        BYTES_TO_WORDS_8(E6, DF, 22, 4C, FB, 23, F7, B5),\n        BYTES_TO_WORDS_4(88, 63, 37, BD) },\n    { BYTES_TO_WORDS_8(B4, FF, 55, 23, 43, 39, 0B, 27),\n        BYTES_TO_WORDS_8(BA, D8, BF, D7, B7, B0, 44, 50),\n        BYTES_TO_WORDS_8(56, 32, 41, F5, AB, B3, 04, 0C),\n        BYTES_TO_WORDS_4(85, 0A, 05, B4) },\n    &double_jacobian_default,\n#if uECC_SUPPORT_COMPRESSED_POINT\n    &mod_sqrt_secp224r1,\n#endif\n    &x_side_default,\n#if (uECC_OPTIMIZATION_LEVEL > 0)\n    &vli_mmod_fast_secp224r1\n#endif\n};\n\nuECC_Curve uECC_secp224r1(void) { return &curve_secp224r1; }\n\n\n#if uECC_SUPPORT_COMPRESSED_POINT\n/* Routine 3.2.4 RS;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */\nstatic void mod_sqrt_secp224r1_rs(uECC_word_t *d1,\n                                  uECC_word_t *e1,\n                                  uECC_word_t *f1,\n                                  const uECC_word_t *d0,\n                                  const uECC_word_t *e0,\n                                  const uECC_word_t *f0) {\n    uECC_word_t t[num_words_secp224r1];\n\n    uECC_vli_modSquare_fast(t, d0, &curve_secp224r1);                    /* t <-- d0 ^ 2 */\n    uECC_vli_modMult_fast(e1, d0, e0, &curve_secp224r1);                 /* e1 <-- d0 * e0 */\n    uECC_vli_modAdd(d1, t, f0, curve_secp224r1.p, num_words_secp224r1);  /* d1 <-- t  + f0 */\n    uECC_vli_modAdd(e1, e1, e1, curve_secp224r1.p, num_words_secp224r1); /* e1 <-- e1 + e1 */\n    uECC_vli_modMult_fast(f1, t, f0, &curve_secp224r1);                  /* f1 <-- t  * f0 */\n    uECC_vli_modAdd(f1, f1, f1, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- f1 + f1 */\n    uECC_vli_modAdd(f1, f1, f1, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- f1 + f1 */\n}\n\n/* Routine 3.2.5 RSS;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */\nstatic void mod_sqrt_secp224r1_rss(uECC_word_t *d1,\n                                   uECC_word_t *e1,\n                                   uECC_word_t *f1,\n                                   const uECC_word_t *d0,\n                                   const uECC_word_t *e0,\n                                   const uECC_word_t *f0,\n                                   const bitcount_t j) {\n    bitcount_t i;\n\n    uECC_vli_set(d1, d0, num_words_secp224r1); /* d1 <-- d0 */\n    uECC_vli_set(e1, e0, num_words_secp224r1); /* e1 <-- e0 */\n    uECC_vli_set(f1, f0, num_words_secp224r1); /* f1 <-- f0 */\n    for (i = 1; i <= j; i++) {\n        mod_sqrt_secp224r1_rs(d1, e1, f1, d1, e1, f1); /* RS (d1,e1,f1,d1,e1,f1) */\n    }\n}\n\n/* Routine 3.2.6 RM;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */\nstatic void mod_sqrt_secp224r1_rm(uECC_word_t *d2,\n                                  uECC_word_t *e2,\n                                  uECC_word_t *f2,\n                                  const uECC_word_t *c,\n                                  const uECC_word_t *d0,\n                                  const uECC_word_t *e0,\n                                  const uECC_word_t *d1,\n                                  const uECC_word_t *e1) {\n    uECC_word_t t1[num_words_secp224r1];\n    uECC_word_t t2[num_words_secp224r1];\n\n    uECC_vli_modMult_fast(t1, e0, e1, &curve_secp224r1); /* t1 <-- e0 * e1 */\n    uECC_vli_modMult_fast(t1, t1, c, &curve_secp224r1);  /* t1 <-- t1 * c */\n    /* t1 <-- p  - t1 */\n    uECC_vli_modSub(t1, curve_secp224r1.p, t1, curve_secp224r1.p, num_words_secp224r1);\n    uECC_vli_modMult_fast(t2, d0, d1, &curve_secp224r1);                 /* t2 <-- d0 * d1 */\n    uECC_vli_modAdd(t2, t2, t1, curve_secp224r1.p, num_words_secp224r1); /* t2 <-- t2 + t1 */\n    uECC_vli_modMult_fast(t1, d0, e1, &curve_secp224r1);                 /* t1 <-- d0 * e1 */\n    uECC_vli_modMult_fast(e2, d1, e0, &curve_secp224r1);                 /* e2 <-- d1 * e0 */\n    uECC_vli_modAdd(e2, e2, t1, curve_secp224r1.p, num_words_secp224r1); /* e2 <-- e2 + t1 */\n    uECC_vli_modSquare_fast(f2, e2, &curve_secp224r1);                   /* f2 <-- e2^2 */\n    uECC_vli_modMult_fast(f2, f2, c, &curve_secp224r1);                  /* f2 <-- f2 * c */\n    /* f2 <-- p  - f2 */\n    uECC_vli_modSub(f2, curve_secp224r1.p, f2, curve_secp224r1.p, num_words_secp224r1);\n    uECC_vli_set(d2, t2, num_words_secp224r1); /* d2 <-- t2 */\n}\n\n/* Routine 3.2.7 RP;  from http://www.nsa.gov/ia/_files/nist-routines.pdf */\nstatic void mod_sqrt_secp224r1_rp(uECC_word_t *d1,\n                                  uECC_word_t *e1,\n                                  uECC_word_t *f1,\n                                  const uECC_word_t *c,\n                                  const uECC_word_t *r) {\n    wordcount_t i;\n    wordcount_t pow2i = 1;\n    uECC_word_t d0[num_words_secp224r1];\n    uECC_word_t e0[num_words_secp224r1] = {1}; /* e0 <-- 1 */\n    uECC_word_t f0[num_words_secp224r1];\n\n    uECC_vli_set(d0, r, num_words_secp224r1); /* d0 <-- r */\n    /* f0 <-- p  - c */\n    uECC_vli_modSub(f0, curve_secp224r1.p, c, curve_secp224r1.p, num_words_secp224r1);\n    for (i = 0; i <= 6; i++) {\n        mod_sqrt_secp224r1_rss(d1, e1, f1, d0, e0, f0, pow2i); /* RSS (d1,e1,f1,d0,e0,f0,2^i) */\n        mod_sqrt_secp224r1_rm(d1, e1, f1, c, d1, e1, d0, e0);  /* RM (d1,e1,f1,c,d1,e1,d0,e0) */\n        uECC_vli_set(d0, d1, num_words_secp224r1); /* d0 <-- d1 */\n        uECC_vli_set(e0, e1, num_words_secp224r1); /* e0 <-- e1 */\n        uECC_vli_set(f0, f1, num_words_secp224r1); /* f0 <-- f1 */\n        pow2i *= 2;\n    }\n}\n\n/* Compute a = sqrt(a) (mod curve_p). */\n/* Routine 3.2.8 mp_mod_sqrt_224; from http://www.nsa.gov/ia/_files/nist-routines.pdf */\nstatic void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve) {\n    bitcount_t i;\n    uECC_word_t e1[num_words_secp224r1];\n    uECC_word_t f1[num_words_secp224r1];\n    uECC_word_t d0[num_words_secp224r1];\n    uECC_word_t e0[num_words_secp224r1];\n    uECC_word_t f0[num_words_secp224r1];\n    uECC_word_t d1[num_words_secp224r1];\n\n    /* s = a; using constant instead of random value */\n    mod_sqrt_secp224r1_rp(d0, e0, f0, a, a);           /* RP (d0, e0, f0, c, s) */\n    mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0);     /* RS (d1, e1, f1, d0, e0, f0) */\n    for (i = 1; i <= 95; i++) {\n        uECC_vli_set(d0, d1, num_words_secp224r1);          /* d0 <-- d1 */\n        uECC_vli_set(e0, e1, num_words_secp224r1);          /* e0 <-- e1 */\n        uECC_vli_set(f0, f1, num_words_secp224r1);          /* f0 <-- f1 */\n        mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0); /* RS (d1, e1, f1, d0, e0, f0) */\n        if (uECC_vli_isZero(d1, num_words_secp224r1)) {     /* if d1 == 0 */\n                break;\n        }\n    }\n    uECC_vli_modInv(f1, e0, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- 1 / e0 */\n    uECC_vli_modMult_fast(a, d0, f1, &curve_secp224r1);              /* a  <-- d0 / e0 */\n}\n#endif /* uECC_SUPPORT_COMPRESSED_POINT */\n\n#if (uECC_OPTIMIZATION_LEVEL > 0)\n/* Computes result = product % curve_p\n   from http://www.nsa.gov/ia/_files/nist-routines.pdf */\n#if uECC_WORD_SIZE == 1\nstatic void vli_mmod_fast_secp224r1(uint8_t *result, uint8_t *product) {\n    uint8_t tmp[num_words_secp224r1];\n    int8_t carry;\n\n    /* t */\n    uECC_vli_set(result, product, num_words_secp224r1);\n\n    /* s1 */\n    tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;\n    tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;\n    tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0;\n    tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31];\n    tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35];\n    tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39];\n    tmp[24] = product[40]; tmp[25] = product[41]; tmp[26] = product[42]; tmp[27] = product[43];\n    carry = uECC_vli_add(result, result, tmp, num_words_secp224r1);\n\n    /* s2 */\n    tmp[12] = product[44]; tmp[13] = product[45]; tmp[14] = product[46]; tmp[15] = product[47];\n    tmp[16] = product[48]; tmp[17] = product[49]; tmp[18] = product[50]; tmp[19] = product[51];\n    tmp[20] = product[52]; tmp[21] = product[53]; tmp[22] = product[54]; tmp[23] = product[55];\n    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;\n    carry += uECC_vli_add(result, result, tmp, num_words_secp224r1);\n\n    /* d1 */\n    tmp[0]  = product[28]; tmp[1]  = product[29]; tmp[2]  = product[30]; tmp[3]  = product[31];\n    tmp[4]  = product[32]; tmp[5]  = product[33]; tmp[6]  = product[34]; tmp[7]  = product[35];\n    tmp[8]  = product[36]; tmp[9]  = product[37]; tmp[10] = product[38]; tmp[11] = product[39];\n    tmp[12] = product[40]; tmp[13] = product[41]; tmp[14] = product[42]; tmp[15] = product[43];\n    tmp[16] = product[44]; tmp[17] = product[45]; tmp[18] = product[46]; tmp[19] = product[47];\n    tmp[20] = product[48]; tmp[21] = product[49]; tmp[22] = product[50]; tmp[23] = product[51];\n    tmp[24] = product[52]; tmp[25] = product[53]; tmp[26] = product[54]; tmp[27] = product[55];\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1);\n\n    /* d2 */\n    tmp[0]  = product[44]; tmp[1]  = product[45]; tmp[2]  = product[46]; tmp[3]  = product[47];\n    tmp[4]  = product[48]; tmp[5]  = product[49]; tmp[6]  = product[50]; tmp[7]  = product[51];\n    tmp[8]  = product[52]; tmp[9]  = product[53]; tmp[10] = product[54]; tmp[11] = product[55];\n    tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0;\n    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;\n    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;\n    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1);\n\n    if (carry < 0) {\n        do {\n            carry += uECC_vli_add(result, result, curve_secp224r1.p, num_words_secp224r1);\n        } while (carry < 0);\n    } else {\n        while (carry || uECC_vli_cmp_unsafe(curve_secp224r1.p, result, num_words_secp224r1) != 1) {\n            carry -= uECC_vli_sub(result, result, curve_secp224r1.p, num_words_secp224r1);\n        }\n    }\n}\n#elif uECC_WORD_SIZE == 4\nstatic void vli_mmod_fast_secp224r1(uint32_t *result, uint32_t *product)\n{\n    uint32_t tmp[num_words_secp224r1];\n    int carry;\n\n    /* t */\n    uECC_vli_set(result, product, num_words_secp224r1);\n\n    /* s1 */\n    tmp[0] = tmp[1] = tmp[2] = 0;\n    tmp[3] = product[7];\n    tmp[4] = product[8];\n    tmp[5] = product[9];\n    tmp[6] = product[10];\n    carry = uECC_vli_add(result, result, tmp, num_words_secp224r1);\n\n    /* s2 */\n    tmp[3] = product[11];\n    tmp[4] = product[12];\n    tmp[5] = product[13];\n    tmp[6] = 0;\n    carry += uECC_vli_add(result, result, tmp, num_words_secp224r1);\n\n    /* d1 */\n    tmp[0] = product[7];\n    tmp[1] = product[8];\n    tmp[2] = product[9];\n    tmp[3] = product[10];\n    tmp[4] = product[11];\n    tmp[5] = product[12];\n    tmp[6] = product[13];\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1);\n\n    /* d2 */\n    tmp[0] = product[11];\n    tmp[1] = product[12];\n    tmp[2] = product[13];\n    tmp[3] = tmp[4] = tmp[5] = tmp[6] = 0;\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1);\n\n    if (carry < 0) {\n        do {\n            carry += uECC_vli_add(result, result, curve_secp224r1.p, num_words_secp224r1);\n        } while (carry < 0);\n    } else {\n        while (carry || uECC_vli_cmp_unsafe(curve_secp224r1.p, result, num_words_secp224r1) != 1) {\n            carry -= uECC_vli_sub(result, result, curve_secp224r1.p, num_words_secp224r1);\n        }\n    }\n}\n#else\nstatic void vli_mmod_fast_secp224r1(uint64_t *result, uint64_t *product)\n{\n    uint64_t tmp[num_words_secp224r1];\n    int carry = 0;\n\n    /* t */\n    uECC_vli_set(result, product, num_words_secp224r1);\n    result[num_words_secp224r1 - 1] &= 0xffffffff;\n\n    /* s1 */\n    tmp[0] = 0;\n    tmp[1] = product[3] & 0xffffffff00000000ull;\n    tmp[2] = product[4];\n    tmp[3] = product[5] & 0xffffffff;\n    uECC_vli_add(result, result, tmp, num_words_secp224r1);\n\n    /* s2 */\n    tmp[1] = product[5] & 0xffffffff00000000ull;\n    tmp[2] = product[6];\n    tmp[3] = 0;\n    uECC_vli_add(result, result, tmp, num_words_secp224r1);\n\n    /* d1 */\n    tmp[0] = (product[3] >> 32) | (product[4] << 32);\n    tmp[1] = (product[4] >> 32) | (product[5] << 32);\n    tmp[2] = (product[5] >> 32) | (product[6] << 32);\n    tmp[3] = product[6] >> 32;\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1);\n\n    /* d2 */\n    tmp[0] = (product[5] >> 32) | (product[6] << 32);\n    tmp[1] = product[6] >> 32;\n    tmp[2] = tmp[3] = 0;\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1);\n\n    if (carry < 0) {\n        do {\n            carry += uECC_vli_add(result, result, curve_secp224r1.p, num_words_secp224r1);\n        } while (carry < 0);\n    } else {\n        while (uECC_vli_cmp_unsafe(curve_secp224r1.p, result, num_words_secp224r1) != 1) {\n            uECC_vli_sub(result, result, curve_secp224r1.p, num_words_secp224r1);\n        }\n    }\n}\n#endif /* uECC_WORD_SIZE */\n#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */\n\n#endif /* uECC_SUPPORTS_secp224r1 */\n\n#if uECC_SUPPORTS_secp256r1\n\n#if (uECC_OPTIMIZATION_LEVEL > 0)\nstatic void vli_mmod_fast_secp256r1(uECC_word_t *result, uECC_word_t *product);\n#endif\n\nstatic const struct uECC_Curve_t curve_secp256r1 = {\n    num_words_secp256r1,\n    num_bytes_secp256r1,\n    256, /* num_n_bits */\n    { BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),\n        BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00),\n        BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),\n        BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF) },\n    { BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3),\n        BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC),\n        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),\n        BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF) },\n    { BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4),\n        BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77),\n        BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8),\n        BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B),\n\n        BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB),\n        BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B),\n        BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E),\n        BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F) },\n    { BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B),\n        BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65),\n        BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3),\n        BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A) },\n    &double_jacobian_default,\n#if uECC_SUPPORT_COMPRESSED_POINT\n    &mod_sqrt_default,\n#endif\n    &x_side_default,\n#if (uECC_OPTIMIZATION_LEVEL > 0)\n    &vli_mmod_fast_secp256r1\n#endif\n};\n\nuECC_Curve uECC_secp256r1(void) { return &curve_secp256r1; }\n\n\n#if (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256r1)\n/* Computes result = product % curve_p\n   from http://www.nsa.gov/ia/_files/nist-routines.pdf */\n#if uECC_WORD_SIZE == 1\nstatic void vli_mmod_fast_secp256r1(uint8_t *result, uint8_t *product) {\n    uint8_t tmp[num_words_secp256r1];\n    int8_t carry;\n    \n    /* t */\n    uECC_vli_set(result, product, num_words_secp256r1);\n    \n    /* s1 */\n    tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;\n    tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;\n    tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0;\n    tmp[12] = product[44]; tmp[13] = product[45]; tmp[14] = product[46]; tmp[15] = product[47];\n    tmp[16] = product[48]; tmp[17] = product[49]; tmp[18] = product[50]; tmp[19] = product[51];\n    tmp[20] = product[52]; tmp[21] = product[53]; tmp[22] = product[54]; tmp[23] = product[55];\n    tmp[24] = product[56]; tmp[25] = product[57]; tmp[26] = product[58]; tmp[27] = product[59];\n    tmp[28] = product[60]; tmp[29] = product[61]; tmp[30] = product[62]; tmp[31] = product[63];\n    carry = uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1);\n    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);\n    \n    /* s2 */\n    tmp[12] = product[48]; tmp[13] = product[49]; tmp[14] = product[50]; tmp[15] = product[51];\n    tmp[16] = product[52]; tmp[17] = product[53]; tmp[18] = product[54]; tmp[19] = product[55];\n    tmp[20] = product[56]; tmp[21] = product[57]; tmp[22] = product[58]; tmp[23] = product[59];\n    tmp[24] = product[60]; tmp[25] = product[61]; tmp[26] = product[62]; tmp[27] = product[63];\n    tmp[28] = tmp[29] = tmp[30] = tmp[31] = 0;\n    carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1);\n    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);\n    \n    /* s3 */\n    tmp[0] = product[32]; tmp[1] = product[33]; tmp[2] = product[34]; tmp[3] = product[35];\n    tmp[4] = product[36]; tmp[5] = product[37]; tmp[6] = product[38]; tmp[7] = product[39];\n    tmp[8] = product[40]; tmp[9] = product[41]; tmp[10] = product[42]; tmp[11] = product[43];\n    tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0;\n    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;\n    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;\n    tmp[24] = product[56]; tmp[25] = product[57]; tmp[26] = product[58]; tmp[27] = product[59];\n    tmp[28] = product[60]; tmp[29] = product[61]; tmp[30] = product[62]; tmp[31] = product[63];\n    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);\n    \n    /* s4 */\n    tmp[0] = product[36]; tmp[1] = product[37]; tmp[2] = product[38]; tmp[3] = product[39];\n    tmp[4] = product[40]; tmp[5] = product[41]; tmp[6] = product[42]; tmp[7] = product[43];\n    tmp[8] = product[44]; tmp[9] = product[45]; tmp[10] = product[46]; tmp[11] = product[47];\n    tmp[12] = product[52]; tmp[13] = product[53]; tmp[14] = product[54]; tmp[15] = product[55];\n    tmp[16] = product[56]; tmp[17] = product[57]; tmp[18] = product[58]; tmp[19] = product[59];\n    tmp[20] = product[60]; tmp[21] = product[61]; tmp[22] = product[62]; tmp[23] = product[63];\n    tmp[24] = product[52]; tmp[25] = product[53]; tmp[26] = product[54]; tmp[27] = product[55];\n    tmp[28] = product[32]; tmp[29] = product[33]; tmp[30] = product[34]; tmp[31] = product[35];\n    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);\n    \n    /* d1 */\n    tmp[0] = product[44]; tmp[1] = product[45]; tmp[2] = product[46]; tmp[3] = product[47];\n    tmp[4] = product[48]; tmp[5] = product[49]; tmp[6] = product[50]; tmp[7] = product[51];\n    tmp[8] = product[52]; tmp[9] = product[53]; tmp[10] = product[54]; tmp[11] = product[55];\n    tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0;\n    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;\n    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;\n    tmp[24] = product[32]; tmp[25] = product[33]; tmp[26] = product[34]; tmp[27] = product[35];\n    tmp[28] = product[40]; tmp[29] = product[41]; tmp[30] = product[42]; tmp[31] = product[43];\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);\n    \n    /* d2 */\n    tmp[0] = product[48]; tmp[1] = product[49]; tmp[2] = product[50]; tmp[3] = product[51];\n    tmp[4] = product[52]; tmp[5] = product[53]; tmp[6] = product[54]; tmp[7] = product[55];\n    tmp[8] = product[56]; tmp[9] = product[57]; tmp[10] = product[58]; tmp[11] = product[59];\n    tmp[12] = product[60]; tmp[13] = product[61]; tmp[14] = product[62]; tmp[15] = product[63];\n    tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0;\n    tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;\n    tmp[24] = product[36]; tmp[25] = product[37]; tmp[26] = product[38]; tmp[27] = product[39];\n    tmp[28] = product[44]; tmp[29] = product[45]; tmp[30] = product[46]; tmp[31] = product[47];\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);\n    \n    /* d3 */\n    tmp[0] = product[52]; tmp[1] = product[53]; tmp[2] = product[54]; tmp[3] = product[55];\n    tmp[4] = product[56]; tmp[5] = product[57]; tmp[6] = product[58]; tmp[7] = product[59];\n    tmp[8] = product[60]; tmp[9] = product[61]; tmp[10] = product[62]; tmp[11] = product[63];\n    tmp[12] = product[32]; tmp[13] = product[33]; tmp[14] = product[34]; tmp[15] = product[35];\n    tmp[16] = product[36]; tmp[17] = product[37]; tmp[18] = product[38]; tmp[19] = product[39];\n    tmp[20] = product[40]; tmp[21] = product[41]; tmp[22] = product[42]; tmp[23] = product[43];\n    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;\n    tmp[28] = product[48]; tmp[29] = product[49]; tmp[30] = product[50]; tmp[31] = product[51];\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);\n    \n    /* d4 */\n    tmp[0] = product[56]; tmp[1] = product[57]; tmp[2] = product[58]; tmp[3] = product[59];\n    tmp[4] = product[60]; tmp[5] = product[61]; tmp[6] = product[62]; tmp[7] = product[63];\n    tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0;\n    tmp[12] = product[36]; tmp[13] = product[37]; tmp[14] = product[38]; tmp[15] = product[39];\n    tmp[16] = product[40]; tmp[17] = product[41]; tmp[18] = product[42]; tmp[19] = product[43];\n    tmp[20] = product[44]; tmp[21] = product[45]; tmp[22] = product[46]; tmp[23] = product[47];\n    tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0;\n    tmp[28] = product[52]; tmp[29] = product[53]; tmp[30] = product[54]; tmp[31] = product[55];\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);\n    \n    if (carry < 0) {\n        do {\n            carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1);\n        } while (carry < 0);\n    } else {\n        while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) {\n            carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1);\n        }\n    }\n}\n#elif uECC_WORD_SIZE == 4\nstatic void vli_mmod_fast_secp256r1(uint32_t *result, uint32_t *product) {\n    uint32_t tmp[num_words_secp256r1];\n    int carry;\n    \n    /* t */\n    uECC_vli_set(result, product, num_words_secp256r1);\n    \n    /* s1 */\n    tmp[0] = tmp[1] = tmp[2] = 0;\n    tmp[3] = product[11];\n    tmp[4] = product[12];\n    tmp[5] = product[13];\n    tmp[6] = product[14];\n    tmp[7] = product[15];\n    carry = uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1);\n    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);\n    \n    /* s2 */\n    tmp[3] = product[12];\n    tmp[4] = product[13];\n    tmp[5] = product[14];\n    tmp[6] = product[15];\n    tmp[7] = 0;\n    carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1);\n    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);\n    \n    /* s3 */\n    tmp[0] = product[8];\n    tmp[1] = product[9];\n    tmp[2] = product[10];\n    tmp[3] = tmp[4] = tmp[5] = 0;\n    tmp[6] = product[14];\n    tmp[7] = product[15];\n    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);\n    \n    /* s4 */\n    tmp[0] = product[9];\n    tmp[1] = product[10];\n    tmp[2] = product[11];\n    tmp[3] = product[13];\n    tmp[4] = product[14];\n    tmp[5] = product[15];\n    tmp[6] = product[13];\n    tmp[7] = product[8];\n    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);\n    \n    /* d1 */\n    tmp[0] = product[11];\n    tmp[1] = product[12];\n    tmp[2] = product[13];\n    tmp[3] = tmp[4] = tmp[5] = 0;\n    tmp[6] = product[8];\n    tmp[7] = product[10];\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);\n    \n    /* d2 */\n    tmp[0] = product[12];\n    tmp[1] = product[13];\n    tmp[2] = product[14];\n    tmp[3] = product[15];\n    tmp[4] = tmp[5] = 0;\n    tmp[6] = product[9];\n    tmp[7] = product[11];\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);\n    \n    /* d3 */\n    tmp[0] = product[13];\n    tmp[1] = product[14];\n    tmp[2] = product[15];\n    tmp[3] = product[8];\n    tmp[4] = product[9];\n    tmp[5] = product[10];\n    tmp[6] = 0;\n    tmp[7] = product[12];\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);\n    \n    /* d4 */\n    tmp[0] = product[14];\n    tmp[1] = product[15];\n    tmp[2] = 0;\n    tmp[3] = product[9];\n    tmp[4] = product[10];\n    tmp[5] = product[11];\n    tmp[6] = 0;\n    tmp[7] = product[13];\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);\n    \n    if (carry < 0) {\n        do {\n            carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1);\n        } while (carry < 0);\n    } else {\n        while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) {\n            carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1);\n        }\n    }\n}\n#else\nstatic void vli_mmod_fast_secp256r1(uint64_t *result, uint64_t *product) {\n    uint64_t tmp[num_words_secp256r1];\n    int carry;\n    \n    /* t */\n    uECC_vli_set(result, product, num_words_secp256r1);\n    \n    /* s1 */\n    tmp[0] = 0;\n    tmp[1] = product[5] & 0xffffffff00000000ull;\n    tmp[2] = product[6];\n    tmp[3] = product[7];\n    carry = (int)uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1);\n    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);\n    \n    /* s2 */\n    tmp[1] = product[6] << 32;\n    tmp[2] = (product[6] >> 32) | (product[7] << 32);\n    tmp[3] = product[7] >> 32;\n    carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1);\n    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);\n    \n    /* s3 */\n    tmp[0] = product[4];\n    tmp[1] = product[5] & 0xffffffff;\n    tmp[2] = 0;\n    tmp[3] = product[7];\n    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);\n    \n    /* s4 */\n    tmp[0] = (product[4] >> 32) | (product[5] << 32);\n    tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull);\n    tmp[2] = product[7];\n    tmp[3] = (product[6] >> 32) | (product[4] << 32);\n    carry += uECC_vli_add(result, result, tmp, num_words_secp256r1);\n    \n    /* d1 */\n    tmp[0] = (product[5] >> 32) | (product[6] << 32);\n    tmp[1] = (product[6] >> 32);\n    tmp[2] = 0;\n    tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32);\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);\n    \n    /* d2 */\n    tmp[0] = product[6];\n    tmp[1] = product[7];\n    tmp[2] = 0;\n    tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull);\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);\n    \n    /* d3 */\n    tmp[0] = (product[6] >> 32) | (product[7] << 32);\n    tmp[1] = (product[7] >> 32) | (product[4] << 32);\n    tmp[2] = (product[4] >> 32) | (product[5] << 32);\n    tmp[3] = (product[6] << 32);\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);\n    \n    /* d4 */\n    tmp[0] = product[7];\n    tmp[1] = product[4] & 0xffffffff00000000ull;\n    tmp[2] = product[5];\n    tmp[3] = product[6] & 0xffffffff00000000ull;\n    carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1);\n    \n    if (carry < 0) {\n        do {\n            carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1);\n        } while (carry < 0);\n    } else {\n        while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) {\n            carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1);\n        }\n    }\n}\n#endif /* uECC_WORD_SIZE */\n#endif /* (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256r1) */\n\n#endif /* uECC_SUPPORTS_secp256r1 */\n\n#if uECC_SUPPORTS_secp256k1\n\nstatic void double_jacobian_secp256k1(uECC_word_t * X1,\n                                      uECC_word_t * Y1,\n                                      uECC_word_t * Z1,\n                                      uECC_Curve curve);\nstatic void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve);\n#if (uECC_OPTIMIZATION_LEVEL > 0)\nstatic void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product);\n#endif\n\nstatic const struct uECC_Curve_t curve_secp256k1 = {\n    num_words_secp256k1,\n    num_bytes_secp256k1,\n    256, /* num_n_bits */\n    { BYTES_TO_WORDS_8(2F, FC, FF, FF, FE, FF, FF, FF),\n        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),\n        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),\n        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) },\n    { BYTES_TO_WORDS_8(41, 41, 36, D0, 8C, 5E, D2, BF),\n        BYTES_TO_WORDS_8(3B, A0, 48, AF, E6, DC, AE, BA),\n        BYTES_TO_WORDS_8(FE, FF, FF, FF, FF, FF, FF, FF),\n        BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) },\n    { BYTES_TO_WORDS_8(98, 17, F8, 16, 5B, 81, F2, 59),\n        BYTES_TO_WORDS_8(D9, 28, CE, 2D, DB, FC, 9B, 02),\n        BYTES_TO_WORDS_8(07, 0B, 87, CE, 95, 62, A0, 55),\n        BYTES_TO_WORDS_8(AC, BB, DC, F9, 7E, 66, BE, 79),\n\n        BYTES_TO_WORDS_8(B8, D4, 10, FB, 8F, D0, 47, 9C),\n        BYTES_TO_WORDS_8(19, 54, 85, A6, 48, B4, 17, FD),\n        BYTES_TO_WORDS_8(A8, 08, 11, 0E, FC, FB, A4, 5D),\n        BYTES_TO_WORDS_8(65, C4, A3, 26, 77, DA, 3A, 48) },\n    { BYTES_TO_WORDS_8(07, 00, 00, 00, 00, 00, 00, 00),\n        BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),\n        BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),\n        BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00) },\n    &double_jacobian_secp256k1,\n#if uECC_SUPPORT_COMPRESSED_POINT\n    &mod_sqrt_default,\n#endif\n    &x_side_secp256k1,\n#if (uECC_OPTIMIZATION_LEVEL > 0)\n    &vli_mmod_fast_secp256k1\n#endif\n};\n\nuECC_Curve uECC_secp256k1(void) { return &curve_secp256k1; }\n\n\n/* Double in place */\nstatic void double_jacobian_secp256k1(uECC_word_t * X1,\n                                      uECC_word_t * Y1,\n                                      uECC_word_t * Z1,\n                                      uECC_Curve curve) {\n    /* t1 = X, t2 = Y, t3 = Z */\n    uECC_word_t t4[num_words_secp256k1];\n    uECC_word_t t5[num_words_secp256k1];\n    \n    if (uECC_vli_isZero(Z1, num_words_secp256k1)) {\n        return;\n    }\n    \n    uECC_vli_modSquare_fast(t5, Y1, curve);   /* t5 = y1^2 */\n    uECC_vli_modMult_fast(t4, X1, t5, curve); /* t4 = x1*y1^2 = A */\n    uECC_vli_modSquare_fast(X1, X1, curve);   /* t1 = x1^2 */\n    uECC_vli_modSquare_fast(t5, t5, curve);   /* t5 = y1^4 */\n    uECC_vli_modMult_fast(Z1, Y1, Z1, curve); /* t3 = y1*z1 = z3 */\n    \n    uECC_vli_modAdd(Y1, X1, X1, curve->p, num_words_secp256k1); /* t2 = 2*x1^2 */\n    uECC_vli_modAdd(Y1, Y1, X1, curve->p, num_words_secp256k1); /* t2 = 3*x1^2 */\n    if (uECC_vli_testBit(Y1, 0)) {\n        uECC_word_t carry = uECC_vli_add(Y1, Y1, curve->p, num_words_secp256k1);\n        uECC_vli_rshift1(Y1, num_words_secp256k1);\n        Y1[num_words_secp256k1 - 1] |= carry << (uECC_WORD_BITS - 1);\n    } else {\n        uECC_vli_rshift1(Y1, num_words_secp256k1);\n    }\n    /* t2 = 3/2*(x1^2) = B */\n    \n    uECC_vli_modSquare_fast(X1, Y1, curve);                     /* t1 = B^2 */\n    uECC_vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - A */\n    uECC_vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - 2A = x3 */\n    \n    uECC_vli_modSub(t4, t4, X1, curve->p, num_words_secp256k1); /* t4 = A - x3 */\n    uECC_vli_modMult_fast(Y1, Y1, t4, curve);                   /* t2 = B * (A - x3) */\n    uECC_vli_modSub(Y1, Y1, t5, curve->p, num_words_secp256k1); /* t2 = B * (A - x3) - y1^4 = y3 */\n}\n\n/* Computes result = x^3 + b. result must not overlap x. */\nstatic void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) {\n    uECC_vli_modSquare_fast(result, x, curve);                                /* r = x^2 */\n    uECC_vli_modMult_fast(result, result, x, curve);                          /* r = x^3 */\n    uECC_vli_modAdd(result, result, curve->b, curve->p, num_words_secp256k1); /* r = x^3 + b */\n}\n\n#if (uECC_OPTIMIZATION_LEVEL > 0)\nstatic void omega_mult_secp256k1(uECC_word_t *result, const uECC_word_t *right);\nstatic void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product) {\n    uECC_word_t tmp[2 * num_words_secp256k1];\n    uECC_word_t carry;\n    \n    uECC_vli_clear(tmp, num_words_secp256k1);\n    uECC_vli_clear(tmp + num_words_secp256k1, num_words_secp256k1);\n    \n    omega_mult_secp256k1(tmp, product + num_words_secp256k1); /* (Rq, q) = q * c */\n    \n    carry = uECC_vli_add(result, product, tmp, num_words_secp256k1); /* (C, r) = r + q       */\n    uECC_vli_clear(product, num_words_secp256k1);\n    omega_mult_secp256k1(product, tmp + num_words_secp256k1); /* Rq*c */\n    carry += uECC_vli_add(result, result, product, num_words_secp256k1); /* (C1, r) = r + Rq*c */\n    \n    while (carry > 0) {\n        --carry;\n        uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1);\n    }\n    if (uECC_vli_cmp_unsafe(result, curve_secp256k1.p, num_words_secp256k1) > 0) {\n        uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1);\n    }\n}\n\n#if uECC_WORD_SIZE == 1\nstatic void omega_mult_secp256k1(uint8_t * result, const uint8_t * right) {\n    /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */\n    uECC_word_t r0 = 0;\n    uECC_word_t r1 = 0;\n    uECC_word_t r2 = 0;\n    wordcount_t k;\n    \n    /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */\n    muladd(0xD1, right[0], &r0, &r1, &r2);\n    result[0] = r0;\n    r0 = r1;\n    r1 = r2;\n    /* r2 is still 0 */\n    \n    for (k = 1; k < num_words_secp256k1; ++k) {\n        muladd(0x03, right[k - 1], &r0, &r1, &r2);\n        muladd(0xD1, right[k], &r0, &r1, &r2);\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n    muladd(0x03, right[num_words_secp256k1 - 1], &r0, &r1, &r2);\n    result[num_words_secp256k1] = r0;\n    result[num_words_secp256k1 + 1] = r1;\n    /* add the 2^32 multiple */\n    result[4 + num_words_secp256k1] =\n        uECC_vli_add(result + 4, result + 4, right, num_words_secp256k1); \n}\n#elif uECC_WORD_SIZE == 4\nstatic void omega_mult_secp256k1(uint32_t * result, const uint32_t * right) {\n    /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */\n    uint32_t carry = 0;\n    wordcount_t k;\n    \n    for (k = 0; k < num_words_secp256k1; ++k) {\n        uint64_t p = (uint64_t)0x3D1 * right[k] + carry;\n        result[k] = p;\n        carry = p >> 32;\n    }\n    result[num_words_secp256k1] = carry;\n    /* add the 2^32 multiple */\n    result[1 + num_words_secp256k1] =\n        uECC_vli_add(result + 1, result + 1, right, num_words_secp256k1); \n}\n#else\nstatic void omega_mult_secp256k1(uint64_t * result, const uint64_t * right) {\n    uECC_word_t r0 = 0;\n    uECC_word_t r1 = 0;\n    uECC_word_t r2 = 0;\n    wordcount_t k;\n    \n    /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */\n    for (k = 0; k < num_words_secp256k1; ++k) {\n        muladd(0x1000003D1ull, right[k], &r0, &r1, &r2);\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n    result[num_words_secp256k1] = r0;\n}\n#endif /* uECC_WORD_SIZE */\n#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */\n\n#endif /* uECC_SUPPORTS_secp256k1 */\n\n#endif /* _UECC_CURVE_SPECIFIC_H_ */\n"
  },
  {
    "path": "u2f/desktop_test.cpp",
    "content": "//to prevent arduino IDE from compiling this\n#ifdef IS_DESKTOP_TEST\n\n//test in desktop\n#define _POSIX_C_SOURCE 200809L\n\n#include <sys/time.h>\n#include <inttypes.h>\n#include <math.h>\n#include <stdio.h>\n#include <time.h>\n#include <stdlib.h>\n\n//for storing fake eprom\n#include <map>\n//for fake input\n#include <vector>\n#include <string>\n#include <iostream>\n#include <fstream>\n#include <cctype>\n\n#define DESKTOP_TEST\n\n//fake eprom\n#define F(X) X\n\ntypedef unsigned char byte;\n\n//this is used for random\n\nenum OUTPUT_FORMAT_ENUM\n{\n    HEX = 1\n};\n\nstd::vector<std::string> fake_input;\nint current_fake_input;\n\nint hexchar2int(int c)\n{\n    if (c<='9')\n\treturn c-'0';\n    return 10 + (c-'A');\n}\n\nvoid hex2bytes(const std::string & inp, unsigned char **res, int *len)\n{\n    std::string tmp;\n    //ignore non hex characters (e.g: space, tab)\n    for (size_t i = 0; i < inp.size(); i++) {\n\tint c = toupper(inp[i]);\n\tif ((c>='0' && c<='9') || (c>='A' && c<='F')) {\n\t    tmp += (char)c;\n\t}\n    }\n    *len = tmp.size()/2;    \n    unsigned char *tmpres = (unsigned char *)malloc(*len);\n    size_t j =0;\n    for (size_t i = 0; i < tmp.size(); i+=2, j++) {\n\tunsigned int c1 = hexchar2int(tmp[i]);\n\tunsigned int c2 = hexchar2int(tmp[i+1]);\n\tunsigned int c = (c1 << 4) + c2;\n\ttmpres[j] = c;\n    }\n    *res = tmpres;\n\n}\n\nint get_next_fake_input(unsigned char **res)\n{\n    if (current_fake_input >= fake_input.size())\n\treturn -1;\n\t    \n    int len;\n    printf(\"CURRENT FAKE INPUT: %s\\n\", fake_input[current_fake_input].c_str());\n    hex2bytes(fake_input[current_fake_input++], res, &len);\n    return len;   \n}\n\nvoid read_file(const std::string & filename)\n{\n    std::ifstream file(filename);\n    std::string temp;\n    while(std::getline(file, temp)) {\n\tfake_input.push_back(temp);\n    }\n    current_fake_input = 0;\n}\n\n\nint RNG(uint8_t *dest, unsigned size)\n{\n    for (int i =0; i < size; i++) {\n\tdest[i] = rand() % 255;\n    }\n    return 1;\n}\n\nlong system_millis()\n{\n#if 0    \n    long            ms; // Milliseconds\n    time_t          s;  // Seconds\n    struct timespec spec;\n    \n    clock_gettime(CLOCK_REALTIME, &spec);\n\n    s  = spec.tv_sec;\n    ms = round(spec.tv_nsec / 1.0e6); // Convert nanoseconds to milliseconds\n\n    return s*1000 + ms;\n#endif\n    struct timeval  tv;\n    gettimeofday(&tv, NULL);\n    \n    long time_in_mill = \n\t(tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; // convert tv_sec & tv_usec to millisecond\n    return time_in_mill;\n}\n\n\nint millis()\n{\n    \n    return 0;\n}\n\nvoid delayMicroseconds(int micro)\n{\n\n}\n\nclass EEPROMClass {\n    std::map<int, unsigned int> values;\npublic:\n    void get(int address, unsigned int &value)\n\t{\n\t    value =  values[address];\n\t}\n    void put(int address, int value)\n\t{\n\t    values[address] = value;\n\t}\n};\n\nclass SerialClass {\n\npublic:\n\tvoid begin(int speed) {\n} \nvoid print(const char *msg)\n{\n    printf(\"%s\", msg);\n}\n    void println() {\n\tprintf(\"\\n\");\n    }\nvoid println(const char *msg)\n\t{\n\t    printf(\"%s\\n\", msg);\n\t}\nvoid println(int number)\n\t{\n\t    printf(\"%d\\n\", number);\n\t}\nvoid print(int number, OUTPUT_FORMAT_ENUM e)\n\t{\n\t    printf(\"%02x\", number);\n\t}\nvoid println(int number, OUTPUT_FORMAT_ENUM e)\n\t{\n\t    printf(\"%02x\", number);\n\t}\n};\n\nclass RawHIDClass {\npublic:\nvoid send(byte *buffer, int to)\n\t{\n\t    printf(\"HID SEND: \");\n\t    for (int i =0; i < 64; i++) {\n\t\tprintf(\"%02x \", buffer[i]);\n\t    }\n\t    printf(\"\\n\");\n\t}\nint recv(byte *buffer, int timeout)\n\t{\n\t    unsigned char *inp;\n\t    int len = get_next_fake_input(&inp);\n\t    if (len==-1) {\n\t\tprintf(\"END OF INPUT\\n\");\n\t\texit(0);\n\t    }\n\t    printf(\"HID READ: \");\n\t    for (int i =0; i < len; i++) {\n\t\tprintf(\"%02x \", inp[i]);\n\t    }\n\t    printf(\"\\n\");\n\t    memcpy(buffer, inp, len);\n\t    free(inp);\t    \n\t    return len;\n\t}\n};\n\nSerialClass Serial;\nRawHIDClass RawHID;\nEEPROMClass EEPROM;\n\n\n#include \"u2f.ino\"\n\nint main(int argc, char *argv[])\n{\n    if (argc<2) {\n\tprintf(\"usage desktop_test <INPUT>\\n\");\n\treturn 0;\n    }\n    read_file(argv[1]);\n    setup();\n    while (1) {\n\tloop();\n    }\n}\n\n#endif\n"
  },
  {
    "path": "u2f/platform-specific.h",
    "content": "/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */\n\n#ifndef _UECC_PLATFORM_SPECIFIC_H_\n#define _UECC_PLATFORM_SPECIFIC_H_\n\n#include \"types.h\"\n\n#if (defined(_WIN32) || defined(_WIN64))\n/* Windows */\n\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#include <wincrypt.h>\n\nstatic int default_RNG(uint8_t *dest, unsigned size) {\n    HCRYPTPROV prov;\n    if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {\n        return 0;\n    }\n\n    CryptGenRandom(prov, size, (BYTE *)dest);\n    CryptReleaseContext(prov, 0);\n    return 1;\n}\n#define default_RNG_defined 1\n\n#elif defined(unix) || defined(__linux__) || defined(__unix__) || defined(__unix) || \\\n    (defined(__APPLE__) && defined(__MACH__)) || defined(uECC_POSIX)\n\n/* Some POSIX-like system with /dev/urandom or /dev/random. */\n#include <sys/types.h>\n#include <fcntl.h>\n#include <unistd.h>\n\n#ifndef O_CLOEXEC\n    #define O_CLOEXEC 0\n#endif\n\nstatic int default_RNG(uint8_t *dest, unsigned size) {\n    int fd = open(\"/dev/urandom\", O_RDONLY | O_CLOEXEC);\n    if (fd == -1) {\n        fd = open(\"/dev/random\", O_RDONLY | O_CLOEXEC);\n        if (fd == -1) {\n            return 0;\n        }\n    }\n    \n    char *ptr = (char *)dest;\n    size_t left = size;\n    while (left > 0) {\n        ssize_t bytes_read = read(fd, ptr, left);\n        if (bytes_read <= 0) { // read failed\n            close(fd);\n            return 0;\n        }\n        left -= bytes_read;\n        ptr += bytes_read;\n    }\n    \n    close(fd);\n    return 1;\n}\n#define default_RNG_defined 1\n\n#endif /* platform */\n\n#endif /* _UECC_PLATFORM_SPECIFIC_H_ */\n"
  },
  {
    "path": "u2f/sha256.c",
    "content": "/*********************************************************************\n* Filename:   sha256.c\n* Author:     Brad Conte (brad AT bradconte.com)\n* Copyright:\n* Disclaimer: This code is presented \"as is\" without any guarantees.\n* Details:    Implementation of the SHA-256 hashing algorithm.\n              SHA-256 is one of the three algorithms in the SHA2\n              specification. The others, SHA-384 and SHA-512, are not\n              offered in this implementation.\n              Algorithm specification can be found here:\n               * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf\n              This implementation uses little endian byte order.\n*********************************************************************/\n\n/*************************** HEADER FILES ***************************/\n#include <stdlib.h>\n#include <string.h>\n//#include <memory.h>\n#include \"sha256.h\"\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n\n/****************************** MACROS ******************************/\n#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))\n#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))\n\n#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))\n#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))\n#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))\n#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))\n#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))\n#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))\n\n/**************************** VARIABLES *****************************/\nstatic const WORD k[64] = {\n\t0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,\n\t0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,\n\t0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,\n\t0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,\n\t0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,\n\t0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,\n\t0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,\n\t0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2\n};\n\n/*********************** FUNCTION DEFINITIONS ***********************/\nvoid sha256_transform(SHA256_CTX *ctx, const BYTE data[])\n{\n\tWORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];\n\n\tfor (i = 0, j = 0; i < 16; ++i, j += 4)\n\t\tm[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);\n\tfor ( ; i < 64; ++i)\n\t\tm[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];\n\n\ta = ctx->state[0];\n\tb = ctx->state[1];\n\tc = ctx->state[2];\n\td = ctx->state[3];\n\te = ctx->state[4];\n\tf = ctx->state[5];\n\tg = ctx->state[6];\n\th = ctx->state[7];\n\n\tfor (i = 0; i < 64; ++i) {\n\t\tt1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];\n\t\tt2 = EP0(a) + MAJ(a,b,c);\n\t\th = g;\n\t\tg = f;\n\t\tf = e;\n\t\te = d + t1;\n\t\td = c;\n\t\tc = b;\n\t\tb = a;\n\t\ta = t1 + t2;\n\t}\n\n\tctx->state[0] += a;\n\tctx->state[1] += b;\n\tctx->state[2] += c;\n\tctx->state[3] += d;\n\tctx->state[4] += e;\n\tctx->state[5] += f;\n\tctx->state[6] += g;\n\tctx->state[7] += h;\n}\n\nvoid sha256_init(SHA256_CTX *ctx)\n{\n\tctx->datalen = 0;\n\tctx->bitlen = 0;\n\tctx->state[0] = 0x6a09e667;\n\tctx->state[1] = 0xbb67ae85;\n\tctx->state[2] = 0x3c6ef372;\n\tctx->state[3] = 0xa54ff53a;\n\tctx->state[4] = 0x510e527f;\n\tctx->state[5] = 0x9b05688c;\n\tctx->state[6] = 0x1f83d9ab;\n\tctx->state[7] = 0x5be0cd19;\n}\n\nvoid sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)\n{\n\tWORD i;\n\n\tfor (i = 0; i < len; ++i) {\n\t\tctx->data[ctx->datalen] = data[i];\n\t\tctx->datalen++;\n\t\tif (ctx->datalen == 64) {\n\t\t\tsha256_transform(ctx, ctx->data);\n\t\t\tctx->bitlen += 512;\n\t\t\tctx->datalen = 0;\n\t\t}\n\t}\n}\n\nvoid sha256_final(SHA256_CTX *ctx, BYTE hash[])\n{\n\tWORD i;\n\n\ti = ctx->datalen;\n\n\t// Pad whatever data is left in the buffer.\n\tif (ctx->datalen < 56) {\n\t\tctx->data[i++] = 0x80;\n\t\twhile (i < 56)\n\t\t\tctx->data[i++] = 0x00;\n\t}\n\telse {\n\t\tctx->data[i++] = 0x80;\n\t\twhile (i < 64)\n\t\t\tctx->data[i++] = 0x00;\n\t\tsha256_transform(ctx, ctx->data);\n\t\tmemset(ctx->data, 0, 56);\n\t}\n\n\t// Append to the padding the total message's length in bits and transform.\n\tctx->bitlen += ctx->datalen * 8;\n\tctx->data[63] = ctx->bitlen;\n\tctx->data[62] = ctx->bitlen >> 8;\n\tctx->data[61] = ctx->bitlen >> 16;\n\tctx->data[60] = ctx->bitlen >> 24;\n\tctx->data[59] = ctx->bitlen >> 32;\n\tctx->data[58] = ctx->bitlen >> 40;\n\tctx->data[57] = ctx->bitlen >> 48;\n\tctx->data[56] = ctx->bitlen >> 56;\n\tsha256_transform(ctx, ctx->data);\n\n\t// Since this implementation uses little endian byte ordering and SHA uses big endian,\n\t// reverse all the bytes when copying the final state to the output hash.\n\tfor (i = 0; i < 4; ++i) {\n\t\thash[i]      = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;\n\t\thash[i + 4]  = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;\n\t\thash[i + 8]  = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;\n\t\thash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;\n\t\thash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;\n\t\thash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;\n\t\thash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;\n\t\thash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;\n\t}\n}\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "u2f/sha256.h",
    "content": "/*********************************************************************\n* Filename:   sha256.h\n* Author:     Brad Conte (brad AT bradconte.com)\n* Copyright:\n* Disclaimer: This code is presented \"as is\" without any guarantees.\n* Details:    Defines the API for the corresponding SHA1 implementation.\n*********************************************************************/\n\n#ifndef SHA256_H\n#define SHA256_H\n\n/*************************** HEADER FILES ***************************/\n#include <stddef.h>\n\n/****************************** MACROS ******************************/\n#define SHA256_BLOCK_SIZE 32            // SHA256 outputs a 32 byte digest\n\n\n/**************************** DATA TYPES ****************************/\ntypedef unsigned char BYTE;             // 8-bit byte\ntypedef unsigned int  WORD;             // 32-bit word, change to \"long\" for 16-bit machines\n\ntypedef struct {\n\tBYTE data[64];\n\tWORD datalen;\n\tunsigned long long bitlen;\n\tWORD state[8];\n} SHA256_CTX;\n\n/*********************** FUNCTION DECLARATIONS **********************/\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n\t\nvoid sha256_init(SHA256_CTX *ctx);\nvoid sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);\nvoid sha256_final(SHA256_CTX *ctx, BYTE hash[]);\n\n#ifdef __cplusplus\n}\n#endif\n\n\n#endif   // SHA256_H\n"
  },
  {
    "path": "u2f/types.h",
    "content": "/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */\n\n#ifndef _UECC_TYPES_H_\n#define _UECC_TYPES_H_\n\n#ifndef uECC_PLATFORM\n    #if __AVR__\n        #define uECC_PLATFORM uECC_avr\n    #elif defined(__thumb2__) || defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */\n        #define uECC_PLATFORM uECC_arm_thumb2\n    #elif defined(__thumb__)\n        #define uECC_PLATFORM uECC_arm_thumb\n    #elif defined(__arm__) || defined(_M_ARM)\n        #define uECC_PLATFORM uECC_arm\n    #elif defined(__aarch64__)\n        #define uECC_PLATFORM uECC_arm64\n    #elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__)\n        #define uECC_PLATFORM uECC_x86\n    #elif defined(__amd64__) || defined(_M_X64)\n        #define uECC_PLATFORM uECC_x86_64\n    #else\n        #define uECC_PLATFORM uECC_arch_other\n    #endif\n#endif\n\n#ifndef uECC_WORD_SIZE\n    #if uECC_PLATFORM == uECC_avr\n        #define uECC_WORD_SIZE 1\n    #elif (uECC_PLATFORM == uECC_x86_64 || uECC_PLATFORM == uECC_arm64)\n        #define uECC_WORD_SIZE 8\n    #else\n        #define uECC_WORD_SIZE 4\n    #endif\n#endif\n\n#if (uECC_WORD_SIZE != 1) && (uECC_WORD_SIZE != 4) && (uECC_WORD_SIZE != 8)\n    #error \"Unsupported value for uECC_WORD_SIZE\"\n#endif\n\n#if ((uECC_PLATFORM == uECC_avr) && (uECC_WORD_SIZE != 1))\n    #pragma message (\"uECC_WORD_SIZE must be 1 for AVR\")\n    #undef uECC_WORD_SIZE\n    #define uECC_WORD_SIZE 1\n#endif\n\n#if ((uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \\\n        uECC_PLATFORM ==  uECC_arm_thumb2) && \\\n     (uECC_WORD_SIZE != 4))\n    #pragma message (\"uECC_WORD_SIZE must be 4 for ARM\")\n    #undef uECC_WORD_SIZE\n    #define uECC_WORD_SIZE 4\n#endif\n\n#if defined(__SIZEOF_INT128__) || ((__clang_major__ * 100 + __clang_minor__) >= 302)\n    #define SUPPORTS_INT128 1\n#else\n    #define SUPPORTS_INT128 0\n#endif\n\ntypedef int8_t wordcount_t;\ntypedef int16_t bitcount_t;\ntypedef int8_t cmpresult_t;\n\n#if (uECC_WORD_SIZE == 1)\n\ntypedef uint8_t uECC_word_t;\ntypedef uint16_t uECC_dword_t;\n\n#define HIGH_BIT_SET 0x80\n#define uECC_WORD_BITS 8\n#define uECC_WORD_BITS_SHIFT 3\n#define uECC_WORD_BITS_MASK 0x07\n\n#elif (uECC_WORD_SIZE == 4)\n\ntypedef uint32_t uECC_word_t;\ntypedef uint64_t uECC_dword_t;\n\n#define HIGH_BIT_SET 0x80000000\n#define uECC_WORD_BITS 32\n#define uECC_WORD_BITS_SHIFT 5\n#define uECC_WORD_BITS_MASK 0x01F\n\n#elif (uECC_WORD_SIZE == 8)\n\ntypedef uint64_t uECC_word_t;\n#if SUPPORTS_INT128\ntypedef unsigned __int128 uECC_dword_t;\n#endif\n\n#define HIGH_BIT_SET 0x8000000000000000ull\n#define uECC_WORD_BITS 64\n#define uECC_WORD_BITS_SHIFT 6\n#define uECC_WORD_BITS_MASK 0x03F\n\n#endif /* uECC_WORD_SIZE */\n\n#endif /* _UECC_TYPES_H_ */\n"
  },
  {
    "path": "u2f/u2f.ino",
    "content": "#ifndef DESKTOP_TEST\n#include <EEPROM.h>\n#endif\n#include <string.h>\n\n#include \"sha256.h\"\n#include \"uECC.h\"\n\n#undef DEBUG\n#define DEBUG\n\n#define CID_BROADCAST           0xffffffff  // Broadcast channel id\n\n#define TYPE_MASK               0x80  // Frame type mask\n#define TYPE_INIT               0x80  // Initial frame identifier\n#define TYPE_CONT               0x00  // Continuation frame identifier\n\n\n#define U2FHID_PING         (TYPE_INIT | 0x01)  // Echo data through local processor only\n#define U2FHID_MSG          (TYPE_INIT | 0x03)  // Send U2F message frame\n#define U2FHID_LOCK         (TYPE_INIT | 0x04)  // Send lock channel command\n#define U2FHID_INIT         (TYPE_INIT | 0x06)  // Channel initialization\n#define U2FHID_WINK         (TYPE_INIT | 0x08)  // Send device identification wink\n#define U2FHID_ERROR        (TYPE_INIT | 0x3f)  // Error response\n\n// Errors\n#define ERR_NONE  0\n#define ERR_INVALID_CMD  1\n#define ERR_INVALID_PAR  2\n#define ERR_INVALID_LEN  3\n#define ERR_INVALID_SEQ  4\n#define ERR_MSG_TIMEOUT  5\n#define ERR_CHANNEL_BUSY  6\n#define ERR_LOCK_REQUIRED  10\n#define ERR_INVALID_CID  11\n#define ERR_OTHER  127\n\n#define U2F_INS_REGISTER  0x01\n#define U2F_INS_AUTHENTICATE  0x02\n#define U2F_INS_VERSION  0x03\n\n\n#define STATE_CHANNEL_AVAILABLE 0\n#define STATE_CHANNEL_WAIT_PACKET 1\n#define STATE_CHANNEL_WAIT_CONT 2\n#define STATE_CHANNEL_TIMEOUT 3\n#define STATE_LARGE_PACKET 4\n\n#define MAX_TOTAL_PACKET 7609\n\n#define MAX_INITIAL_PACKET 57\n#define MAX_CONTINUATION_PACKET 59\n#define SET_MSG_LEN(b, v) do { (b)[5] = ((v) >> 8) & 0xff;  (b)[6] = (v) & 0xff; } while(0)\n\n\n#define U2FHID_IF_VERSION       2  // Current interface implementation version\n\nbyte expected_next_packet;\nint large_data_len;\nint large_data_offset;\nbyte large_buffer[1024];\nbyte large_resp_buffer[1024];\nbyte recv_buffer[64];\nbyte resp_buffer[64];\nbyte handle[64];\nbyte sha256_hash[32];\n#define MAX_CHANNEL 4\n\nconst char attestation_key[] = \"\\xf3\\xfc\\xcc\\x0d\\x00\\xd8\\x03\\x19\\x54\\xf9\"\n\t\"\\x08\\x64\\xd4\\x3c\\x24\\x7f\\x4b\\xf5\\xf0\\x66\\x5c\\x6b\\x50\\xcc\"\n\t\"\\x17\\x74\\x9a\\x27\\xd1\\xcf\\x76\\x64\";\n\nconst char attestation_der[] = \"\\x30\\x82\\x01\\x3c\\x30\\x81\\xe4\\xa0\\x03\\x02\"\n\t\"\\x01\\x02\\x02\\x0a\\x47\\x90\\x12\\x80\\x00\\x11\\x55\\x95\\x73\\x52\"\n\t\"\\x30\\x0a\\x06\\x08\\x2a\\x86\\x48\\xce\\x3d\\x04\\x03\\x02\\x30\\x17\"\n\t\"\\x31\\x15\\x30\\x13\\x06\\x03\\x55\\x04\\x03\\x13\\x0c\\x47\\x6e\\x75\"\n\t\"\\x62\\x62\\x79\\x20\\x50\\x69\\x6c\\x6f\\x74\\x30\\x1e\\x17\\x0d\\x31\"\n\t\"\\x32\\x30\\x38\\x31\\x34\\x31\\x38\\x32\\x39\\x33\\x32\\x5a\\x17\\x0d\"\n\t\"\\x31\\x33\\x30\\x38\\x31\\x34\\x31\\x38\\x32\\x39\\x33\\x32\\x5a\\x30\"\n\t\"\\x31\\x31\\x2f\\x30\\x2d\\x06\\x03\\x55\\x04\\x03\\x13\\x26\\x50\\x69\"\n\t\"\\x6c\\x6f\\x74\\x47\\x6e\\x75\\x62\\x62\\x79\\x2d\\x30\\x2e\\x34\\x2e\"\n\t\"\\x31\\x2d\\x34\\x37\\x39\\x30\\x31\\x32\\x38\\x30\\x30\\x30\\x31\\x31\"\n\t\"\\x35\\x35\\x39\\x35\\x37\\x33\\x35\\x32\\x30\\x59\\x30\\x13\\x06\\x07\"\n\t\"\\x2a\\x86\\x48\\xce\\x3d\\x02\\x01\\x06\\x08\\x2a\\x86\\x48\\xce\\x3d\"\n\t\"\\x03\\x01\\x07\\x03\\x42\\x00\\x04\\x8d\\x61\\x7e\\x65\\xc9\\x50\\x8e\"\n\t\"\\x64\\xbc\\xc5\\x67\\x3a\\xc8\\x2a\\x67\\x99\\xda\\x3c\\x14\\x46\\x68\"\n\t\"\\x2c\\x25\\x8c\\x46\\x3f\\xff\\xdf\\x58\\xdf\\xd2\\xfa\\x3e\\x6c\\x37\"\n\t\"\\x8b\\x53\\xd7\\x95\\xc4\\xa4\\xdf\\xfb\\x41\\x99\\xed\\xd7\\x86\\x2f\"\n\t\"\\x23\\xab\\xaf\\x02\\x03\\xb4\\xb8\\x91\\x1b\\xa0\\x56\\x99\\x94\\xe1\"\n\t\"\\x01\\x30\\x0a\\x06\\x08\\x2a\\x86\\x48\\xce\\x3d\\x04\\x03\\x02\\x03\"\n\t\"\\x47\\x00\\x30\\x44\\x02\\x20\\x60\\xcd\\xb6\\x06\\x1e\\x9c\\x22\\x26\"\n\t\"\\x2d\\x1a\\xac\\x1d\\x96\\xd8\\xc7\\x08\\x29\\xb2\\x36\\x65\\x31\\xdd\"\n\t\"\\xa2\\x68\\x83\\x2c\\xb8\\x36\\xbc\\xd3\\x0d\\xfa\\x02\\x20\\x63\\x1b\"\n\t\"\\x14\\x59\\xf0\\x9e\\x63\\x30\\x05\\x57\\x22\\xc8\\xd8\\x9b\\x7f\\x48\"\n\t\"\\x88\\x3b\\x90\\x89\\xb8\\x8d\\x60\\xd1\\xd9\\x79\\x59\\x02\\xb3\\x04\"\n\t\"\\x10\\xdf\";\n\n//key handle: (private key + app parameter) ^ this array\nconst char handlekey[] = \"-YOHANES-NUGROHO-YOHANES-NUGROHO-\";\n\nconst struct uECC_Curve_t * curve = uECC_secp256r1(); //P-256\nuint8_t private_k[36]; //32\nuint8_t public_k[68]; //64\n\nstruct ch_state {\n\tint cid;\n\tbyte state;\n\tint last_millis;\n};\n\nch_state channel_states[MAX_CHANNEL];\n\n#ifdef DESKTOP_TEST\nextern int RNG(uint8_t *dest, unsigned size);\n#else\nextern \"C\" {\n\n\tstatic int RNG(uint8_t *dest, unsigned size) {\n\t\t// Use the least-significant bits from the ADC for an unconnected pin (or connected to a source of\n\t\t// random noise). This can take a long time to generate random data if the result of analogRead(0)\n\t\t// doesn't change very frequently.\n\t\twhile (size) {\n\t\t\tuint8_t val = 0;\n\t\t\tfor (unsigned i = 0; i < 8; ++i) {\n\t\t\t\tint init = analogRead(0);\n\t\t\t\tint count = 0;\n\t\t\t\twhile (analogRead(0) == init) {\n\t\t\t\t\t++count;\n\t\t\t\t}\n\n\t\t\t\tif (count == 0) {\n\t\t\t\t\tval = (val << 1) | (init & 0x01);\n\t\t\t\t} else {\n\t\t\t\t\tval = (val << 1) | (count & 0x01);\n\t\t\t\t}\n\t\t\t}\n\t\t\t*dest = val;\n\t\t\t++dest;\n\t\t\t--size;\n\t\t}\n\t\t// NOTE: it would be a good idea to hash the resulting random data using SHA-256 or similar.\n\t\treturn 1;\n\t}\n\n}  // extern \"C\"\n#endif\n\n#define TIMEOUT_VALUE 1000\n\ntypedef struct SHA256_HashContext {\n    uECC_HashContext uECC;\n    SHA256_CTX ctx;\n} SHA256_HashContext;\n\nvoid init_SHA256(uECC_HashContext *base) {\n    SHA256_HashContext *context = (SHA256_HashContext *)base;\n    sha256_init(&context->ctx);\n}\nvoid update_SHA256(uECC_HashContext *base,\n                   const uint8_t *message,\n                   unsigned message_size) {\n    SHA256_HashContext *context = (SHA256_HashContext *)base;\n    sha256_update(&context->ctx, message, message_size);\n}\nvoid finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) {\n    SHA256_HashContext *context = (SHA256_HashContext *)base;\n    sha256_final(&context->ctx, hash_result);\n}\n\nvoid setup() {\n\tSerial.begin(9600);\n\tSerial.println(F(\"U2F\"));\n\tuECC_set_rng(&RNG);\n}\n\nvoid cleanup_timeout()\n{\n\tint i;\n\tfor (i = 0;  i < MAX_CHANNEL; i++) {\n\t\t//free channel that is inactive\n\t\tch_state &c = channel_states[i];\n\t\tint m = millis();\n\t\tif (c.state != STATE_CHANNEL_AVAILABLE) {\n\t\t\tif ((m - c.last_millis) > TIMEOUT_VALUE) {\n\t\t\t\tc.state = STATE_CHANNEL_AVAILABLE;\n\t\t\t}\n\t\t}\n\t}\n}\n\nint allocate_new_channel()\n{\n\tint i;\n\t//alloace new channel_id\n\tint channel_id = 1;\n\n\tdo {\n\t\tbool found = false;\n\t\tfor (i = 0;  i < MAX_CHANNEL; i++) {\n\t\t\tif (channel_states[i].state != STATE_CHANNEL_AVAILABLE) {\n\t\t\t\tif (channel_states[i].cid == channel_id) {\n\t\t\t\t\tfound = true;\n\t\t\t\t\tchannel_id++;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (!found)\n\t\t\tbreak;\n\t} while (true);\n\treturn channel_id;\n}\n\nint allocate_channel(int channel_id)\n{\n\tint i;\n\tif (channel_id==0) {\n\t\tchannel_id =  allocate_new_channel();\n\t}\n\n\tbool has_free_slots = false;\n\tfor (i = 0;  i < MAX_CHANNEL; i++) {\n\t\tif (channel_states[i].state == STATE_CHANNEL_AVAILABLE) {\n\t\t\thas_free_slots = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (!has_free_slots)\n\t\tcleanup_timeout();\n\n\tfor (i = 0;  i < MAX_CHANNEL; i++) {\n\t\tch_state &c = channel_states[i];\n\t\tif (c.state == STATE_CHANNEL_AVAILABLE) {\n\t\t\tc.cid = channel_id;\n\t\t\tc.state = STATE_CHANNEL_WAIT_PACKET;\n\t\t\tc.last_millis = millis();\n\t\t\treturn channel_id;\n\t\t}\n\t}\n\treturn 0;\n}\n\nint initResponse(byte *buffer)\n{\n#ifdef DEBUG\n\tSerial.print(\"INIT RESPONSE\");\n#endif\n\tint cid = *(int*)buffer;\n#ifdef DEBUG\n\tSerial.println(cid, HEX);\n#endif\n\tint len = buffer[5] << 8 | buffer[6];\n\tint i;\n\tmemcpy(resp_buffer, buffer, 5);\n\tSET_MSG_LEN(resp_buffer, 17);\n\tmemcpy(resp_buffer + 7, buffer + 7, len); //nonce\n\ti = 7 + len;\n\tif (cid==-1) {\n\t\tcid = allocate_channel(0);\n\t} else {\n#ifdef DEBUG\n\t\tSerial.println(\"using existing CID\");\n#endif\n\t\tallocate_channel(cid);\n\t}\n\tmemcpy(resp_buffer + i, &cid, 4);\n\ti += 4;\n\tresp_buffer[i++] = U2FHID_IF_VERSION;\n\tresp_buffer[i++] = 1; //major\n\tresp_buffer[i++] = 0;\n\tresp_buffer[i++] = 1; //build\n\t//resp_buffer[i++] = CAPABILITY_WINK; //capabilities\n\tresp_buffer[i++] = 0; //capabilities\n#ifdef DEBUG\n\tSerial.println(\"SENT RESPONSE 1\");\n#endif\t\n\tRawHID.send(resp_buffer, 100);\n#ifdef DEBUG\n\tSerial.println(cid, HEX);\n#endif\t\n\treturn cid;\n}\n\n\nvoid errorResponse(byte *buffer, int code)\n{\n        memcpy(resp_buffer, buffer, 4);\n        resp_buffer[4] = U2FHID_ERROR;\n        SET_MSG_LEN(resp_buffer, 1);\n        resp_buffer[7] = code & 0xff;\n#ifdef DEBUG\n\tSerial.print(\"SENT RESPONSE error:\");\n\tSerial.println(code);\n#endif\n\tRawHID.send(resp_buffer, 100);\n}\n\n\n//find channel index and update last access\nint find_channel_index(int channel_id)\n{\n\tint i;\n\n\tfor (i = 0;  i < MAX_CHANNEL; i++) {\n\t\tif (channel_states[i].cid==channel_id) {\n\t\t\tchannel_states[i].last_millis = millis();\n\t\t\treturn i;\n\t\t}\n\t}\n\n\treturn -1;\n}\n\n#define IS_CONTINUATION_PACKET(x) ( (x) < 0x80)\n#define IS_NOT_CONTINUATION_PACKET(x) ( (x) >= 0x80)\n\n#define SW_NO_ERROR                       0x9000\n#define SW_CONDITIONS_NOT_SATISFIED       0x6985\n#define SW_WRONG_DATA                     0x6A80\n#define SW_WRONG_LENGTH                     0x6700\n#define SW_INS_NOT_SUPPORTED 0x6D00\n#define SW_CLA_NOT_SUPPORTED 0x6E00\n\n\n#define APPEND_SW(x, v1, v2) do { (*x++)=v1; (*x++)=v2;} while (0)\n#define APPEND_SW_NO_ERROR(x) do { (*x++)=0x90; (*x++)=0x00;} while (0)\n\n\n\nvoid respondErrorPDU(byte *buffer, int err)\n{\n\tSET_MSG_LEN(buffer, 2); //len(\"\") + 2 byte SW\n\tbyte *datapart = buffer + 7;\n\tAPPEND_SW(datapart, (err >> 8) & 0xff, err & 0xff);\n\tRawHID.send(buffer, 100);\n}\n\nvoid sendLargeResponse(byte *request, int len)\n{\n#ifdef DEBUG\t\n\tSerial.print(\"Sending large response \");\n\tSerial.println(len);\n\tfor (int i = 0; i < len; i++) {\n\t\tSerial.print(large_resp_buffer[i], HEX);\n\t\tSerial.print(\" \");\n\t}\n\tSerial.println(\"\\n--\\n\");\n#endif\t\n\tmemcpy(resp_buffer, request, 4); //copy cid\n\tresp_buffer[4] = U2FHID_MSG;\n\tint r = len;\n\tif (r>MAX_INITIAL_PACKET) {\n\t\tr = MAX_INITIAL_PACKET;\n\t}\n\n\tSET_MSG_LEN(resp_buffer, len);\n\tmemcpy(resp_buffer + 7, large_resp_buffer, r);\n\n\tRawHID.send(resp_buffer, 100);\n\tlen -= r;\n\tbyte p = 0;\n\tint offset = MAX_INITIAL_PACKET;\n\twhile (len > 0) {\n\t\t//memcpy(resp_buffer, request, 4); //copy cid, doesn't need to recopy\n\t\tresp_buffer[4] = p++;\n\t\tmemcpy(resp_buffer + 5, large_resp_buffer + offset, MAX_CONTINUATION_PACKET);\n\t\tRawHID.send(resp_buffer, 100);\n\t\tlen-= MAX_CONTINUATION_PACKET;\n\t\toffset += MAX_CONTINUATION_PACKET;\n\t\tdelayMicroseconds(2500);\n\t}\n}\n\n\n\nint getCounter() {\n\tunsigned int eeAddress = 0; //EEPROM address to start reading from\n\tunsigned int counter;\n\tEEPROM.get( eeAddress, counter );\n\treturn counter;\n}\n\nvoid setCounter(int counter)\n{\n\tunsigned int eeAddress = 0; //EEPROM address to start reading from\n\tEEPROM.put( eeAddress, counter );\n}\n\n#ifdef SIMULATE_BUTTON\n//for now just simulate this\nint button_pressed = 0;\n#endif\n\nvoid processMessage(byte *buffer)\n{\n\tint len = buffer[5] << 8 | buffer[6];\n#ifdef DEBUG\t\n\tSerial.println(F(\"Got message\"));\n\tSerial.println(len);\n\tSerial.println(F(\"Data:\"));\n#endif\t\n\tbyte *message = buffer + 7;\n#ifdef DEBUG\n\tfor (int i = 7; i < 7+len; i++) {\n\t\tSerial.print(buffer[i], HEX);\n\t}\n\tSerial.println(F(\"\"));\n#endif\t\n\t//todo: check CLA = 0\n\tbyte CLA = message[0];\n\n\tif (CLA!=0) {\n\t\trespondErrorPDU(buffer, SW_CLA_NOT_SUPPORTED);\n\t\treturn;\n\t}\n\n\tbyte INS = message[1];\n\tbyte P1 = message[2];\n\t//byte P2 = message[3];\n\tint reqlength = (message[4] << 16) | (message[5] << 8) | message[6];\n\n\tswitch (INS) {\n\tcase U2F_INS_REGISTER:\n\t\t{\n\t\t\tif (reqlength!=64) {\n\t\t\t\trespondErrorPDU(buffer, SW_WRONG_LENGTH);\n\t\t\t\treturn;\n\t\t\t}\n\n#ifdef SIMULATE_BUTTON\t\t\t\n\t\t\tif (!button_pressed) {\n\t\t\t\trespondErrorPDU(buffer, SW_CONDITIONS_NOT_SATISFIED);\n\t\t\t\tbutton_pressed = 1;\n\t\t\t\treturn;\n\t\t\t}\n#endif\t\t\t\n\n\t\t\tbyte *datapart = message + 7;\n\t\t\tbyte *challenge_parameter = datapart;\n\t\t\tbyte *application_parameter = datapart+32;\n\n\t\t\tmemset(public_k, 0, sizeof(public_k));\n\t\t\tmemset(private_k, 0, sizeof(private_k));\n\t\t\tuECC_make_key(public_k + 1, private_k, curve); //so we ca insert 0x04\n\t\t\tpublic_k[0] = 0x04;\n#ifdef DEBUG\n\t\t\tSerial.println(F(\"Public K\"));\n\t\t\tfor (size_t i =0; i < sizeof(public_k); i++) {\n\t\t\t\tSerial.print(public_k[i], HEX);\n\t\t\t\tSerial.print(\" \");\n\t\t\t}\n\t\t\tSerial.println(\"\");\n\t\t\tSerial.println(F(\"Private K\"));\n\t\t\tfor (size_t i =0; i < sizeof(private_k); i++) {\n\t\t\t\tSerial.print(private_k[i], HEX);\n\t\t\t\tSerial.print(\" \");\n\t\t\t}\n\t\t\tSerial.println(\"\");\n#endif\t\t\t\n\t\t\t//construct hash\n\n\t\t\tmemcpy(handle, application_parameter, 32);\n\t\t\tmemcpy(handle+32, private_k, 32);\n\t\t\tfor (int i =0; i < 64; i++) {\n\t\t\t\thandle[i] ^= handlekey[i%(sizeof(handlekey)-1)];\n\t\t\t}\n\n\t\t\tSHA256_CTX ctx;\n\t\t\tsha256_init(&ctx);\n\t\t\tlarge_resp_buffer[0] = 0x00;\n\t\t\tsha256_update(&ctx, large_resp_buffer, 1);\n#ifdef DEBUG\t\t\t\n\t\t\tSerial.println(F(\"App Parameter:\"));\n\t\t\tfor (int i =0; i < 32; i++) {\n\t\t\t\tSerial.print(application_parameter[i], HEX);\n\t\t\t\tSerial.print(\" \");\n\t\t\t}\n\t\t\tSerial.println(\"\");\n#endif\n\t\t\tsha256_update(&ctx, application_parameter, 32);\n#ifdef DEBUG\n\t\t\tSerial.println(F(\"Chal Parameter:\"));\n\t\t\tfor (int i =0; i < 32; i++) {\n\t\t\t\tSerial.print(challenge_parameter[i], HEX);\n\t\t\t\tSerial.print(\" \");\n\t\t\t}\n\t\t\tSerial.println(\"\");\n#endif\n\t\t\tsha256_update(&ctx, challenge_parameter, 32);\n#ifdef DEBUG\n\t\t\tSerial.println(F(\"Handle Parameter:\"));\n\t\t\tfor (int i =0; i < 64; i++) {\n\t\t\t\tSerial.print(handle[i], HEX);\n\t\t\t\tSerial.print(\" \");\n\t\t\t}\n\t\t\tSerial.println(\"\");\n#endif\n\t\t\tsha256_update(&ctx, handle, 64);\n\t\t\tsha256_update(&ctx, public_k, 65);\n#ifdef DEBUG\t\t\t\n\t\t\tSerial.println(F(\"Public key:\"));\n\t\t\tfor (int i =0; i < 65; i++) {\n\t\t\t\tSerial.print(public_k[i], HEX);\n\t\t\t\tSerial.print(\" \");\n\t\t\t}\n\t\t\tSerial.println(\"\");\n#endif\n\t\t\tsha256_final(&ctx, sha256_hash);\n#ifdef DEBUG\n\t\t\tSerial.println(F(\"Hash:\"));\n\t\t\tfor (int i =0; i < 32; i++) {\n\t\t\t\tSerial.print(sha256_hash[i], HEX);\n\t\t\t\tSerial.print(\" \");\n\t\t\t}\n\t\t\tSerial.println(\"\");\n#endif\n\n\t\t\tuint8_t *signature = resp_buffer; //temporary\n\n\t\t\tuint8_t tmp[32 + 32 + 64];\n\t\t\tSHA256_HashContext ectx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}};\n\n\n\t\t\tuECC_sign_deterministic((uint8_t *)attestation_key,\n\t\t\t\t\t\tsha256_hash,\n\t\t\t\t\t\t32,\n\t\t\t\t\t\t&ectx.uECC,\n\t\t\t\t\t\tsignature,\n\t\t\t\t\t\tcurve);\n\n\t\t\tint len = 0;\n\t\t\tlarge_resp_buffer[len++] = 0x05;\n\t\t\tmemcpy(large_resp_buffer + len, public_k, 65);\n\t\t\tlen+=65;\n\t\t\tlarge_resp_buffer[len++] = 64; //length of handle\n\t\t\tmemcpy(large_resp_buffer+len, handle, 64);\n\t\t\tlen += 64;\n\t\t\tmemcpy(large_resp_buffer+len, attestation_der, sizeof(attestation_der));\n\t\t\tlen += sizeof(attestation_der)-1;\n\t\t\t//convert signature format\n\t\t\t//http://bitcoin.stackexchange.com/questions/12554/why-the-signature-is-always-65-13232-bytes-long\n\t\t\tlarge_resp_buffer[len++] = 0x30; //header: compound structure\n\t\t\tuint8_t *total_len = &large_resp_buffer[len];\t\t\t\n\t\t\tlarge_resp_buffer[len++] = 0x44; //total length (32 + 32 + 2 + 2)\n\t\t\tlarge_resp_buffer[len++] = 0x02;  //header: integer\n\n\t\t\tif (signature[0]>0x7f) {\n\t\t\t   \tlarge_resp_buffer[len++] = 33;  //33 byte\n\t\t\t\tlarge_resp_buffer[len++] = 0;\n\t\t\t\t(*total_len)++; //update total length\n\t\t\t}  else {\n\t\t\t\tlarge_resp_buffer[len++] = 32;  //32 byte\n\t\t\t}\n\t\t\t\n\t\t\tmemcpy(large_resp_buffer+len, signature, 32); //R value\n\t\t\tlen +=32;\n\t\t\tlarge_resp_buffer[len++] = 0x02;  //header: integer\n\n\t\t\tif (signature[32]>0x7f) {\n\t\t\t\tlarge_resp_buffer[len++] = 33;  //32 byte\n\t\t\t\tlarge_resp_buffer[len++] = 0;\n\t\t\t\t(*total_len)++;\t//update total length\n\t\t\t} else {\n\t\t\t\tlarge_resp_buffer[len++] = 32;  //32 byte\n\t\t\t}\n\t\t\t\n\t\t\tmemcpy(large_resp_buffer+len, signature+32, 32); //R value\n\t\t\tlen +=32;\n\n\t\t\tbyte *last = large_resp_buffer+len;\n\t\t\tAPPEND_SW_NO_ERROR(last);\n\t\t\tlen += 2;\n#ifdef SIMULATE_BUTTON\t\t\t\n\t\t\tbutton_pressed = 0;\n#endif\t\t\t\n\t\t\tsendLargeResponse(buffer, len);\n\t\t}\n\n\t\tbreak;\n\tcase U2F_INS_AUTHENTICATE:\n\t\t{\n\n\t\t\t//minimum is 64 + 1 + 64\n\t\t\tif (reqlength!=(64+1+64)) {\n\t\t\t\trespondErrorPDU(buffer, SW_WRONG_LENGTH);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tbyte *datapart = message + 7;\n\t\t\tbyte *challenge_parameter = datapart;\n\t\t\tbyte *application_parameter = datapart+32;\n\t\t\tbyte handle_len = datapart[64];\n\t\t\tbyte *client_handle = datapart+65;\n\n\t\t\tif (handle_len!=64) {\n\t\t\t\t//not from this device\n\t\t\t\trespondErrorPDU(buffer, SW_WRONG_DATA);\n\t\t\t\treturn;\n\t\t\t}\n#ifdef SIMULATE_BUTTON\t\t\t\n\t\t\tif (!button_pressed) {\n\t\t\t\trespondErrorPDU(buffer, SW_CONDITIONS_NOT_SATISFIED);\n\t\t\t\tbutton_pressed = 1;\n\t\t\t\treturn;\n\t\t\t}\n#endif\n\n\t\t\tmemcpy(handle, client_handle, 64);\n\t\t\tfor (int i =0; i < 64; i++) {\n\t\t\t\thandle[i] ^= handlekey[i%(sizeof(handlekey)-1)];\n\t\t\t}\n\t\t\tuint8_t *key = handle + 32;\n\n\t\t\tif (memcmp(handle, application_parameter, 32)!=0) {\n\t\t\t\t//this handle is not from us\n\t\t\t\trespondErrorPDU(buffer, SW_WRONG_DATA);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (P1==0x07) { //check-only\n\t\t\t\trespondErrorPDU(buffer, SW_CONDITIONS_NOT_SATISFIED);\n\t\t\t} else if (P1==0x03) { //enforce-user-presence-and-sign\n\t\t\t\tint counter = getCounter();\n\t\t\t\tSHA256_CTX ctx;\n\t\t\t\tsha256_init(&ctx);\n\t\t\t\tsha256_update(&ctx, application_parameter, 32);\n\t\t\t\tlarge_resp_buffer[0] = 0x01; // user_presence\n\n\t\t\t\tint ctr = ((counter>>24)&0xff) | // move byte 3 to byte 0\n\t\t\t\t\t((counter<<8)&0xff0000) | // move byte 1 to byte 2\n\t\t\t\t\t((counter>>8)&0xff00) | // move byte 2 to byte 1\n\t\t\t\t\t((counter<<24)&0xff000000); // byte 0 to byte 3\n\n\t\t\t\tmemcpy(large_resp_buffer + 1, &ctr, 4);\n\n\t\t\t\tsha256_update(&ctx, large_resp_buffer, 5); //user presence + ctr\n\n\t\t\t\tsha256_update(&ctx, challenge_parameter, 32);\n\t\t\t\tsha256_final(&ctx, sha256_hash);\n\n\t\t\t\tuint8_t *signature = resp_buffer; //temporary\n\n\t\t\t\tuint8_t tmp[32 + 32 + 64];\n\t\t\t\tSHA256_HashContext ectx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}};\n\n\t\t\t\tuECC_sign_deterministic((uint8_t *)key,\n\t\t\t\t\t\t\tsha256_hash,\n\t\t\t\t\t\t\t32,\n\t\t\t\t\t\t\t&ectx.uECC,\n\t\t\t\t\t\t\tsignature,\n\t\t\t\t\t\t\tcurve);\n\n\t\t\t\tint len = 5;\n\n\t\t\t\t//convert signature format\n\t\t\t\t//http://bitcoin.stackexchange.com/questions/12554/why-the-signature-is-always-65-13232-bytes-long\n\t\t\t\tlarge_resp_buffer[len++] = 0x30; //header: compound structure\n\t\t\t\tuint8_t *total_len = &large_resp_buffer[len];\t\t\t\t\n\t\t\t\tlarge_resp_buffer[len++] = 0x44; //total length (32 + 32 + 2 + 2)\n\t\t\t\tlarge_resp_buffer[len++] = 0x02;  //header: integer\n\n\t\t\t\tif (signature[0]>0x7f) {\n\t\t\t   \t   large_resp_buffer[len++] = 33;  //33 byte\n\t\t\t\t   large_resp_buffer[len++] = 0;\n\t\t\t\t   (*total_len)++; //update total length\n\t\t\t\t} else {\n\t\t\t\t   large_resp_buffer[len++] = 32;  //32 byte\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tmemcpy(large_resp_buffer+len, signature, 32); //R value\n\t\t\t\tlen +=32;\n\t\t\t\tlarge_resp_buffer[len++] = 0x02;  //header: integer\n\n\t\t\t\tif (signature[32]>0x7f) {\n\t\t\t\t    large_resp_buffer[len++] = 33;  //32 byte\n\t\t\t\t    large_resp_buffer[len++] = 0;\n\t\t\t\t    (*total_len)++;\t//update total length\n\t\t\t\t} else {\n\t\t\t\t    large_resp_buffer[len++] = 32;  //32 byte\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tmemcpy(large_resp_buffer+len, signature+32, 32); //R value\n\t\t\t\tlen +=32;\n\t\t\t\tbyte *last = large_resp_buffer+len;\n\t\t\t\tAPPEND_SW_NO_ERROR(last);\n\t\t\t\tlen += 2;\n#ifdef DEBUG\n\t\t\t\tSerial.print(\"Len to send \");\n\t\t\t\tSerial.println(len);\n#endif\n#ifdef SIMULATE_BUTTON\t\t\t\t\t\t\t\n\t\t\t\tbutton_pressed = 0;\n#endif\t\t\t\t\n\t\t\t\tsendLargeResponse(buffer, len);\n\n\t\t\t\tsetCounter(counter+1);\n\t\t\t} else {\n\t\t\t\t//return error\n\t\t\t}\n\t\t}\n\t\tbreak;\n\tcase U2F_INS_VERSION:\n\t\t{\n\t\t\tif (reqlength!=0) {\n\t\t\t\trespondErrorPDU(buffer, SW_WRONG_LENGTH);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t//reuse input buffer for sending\n\t\t\tSET_MSG_LEN(buffer, 8); //len(\"U2F_V2\") + 2 byte SW\n\t\t\tbyte *datapart = buffer + 7;\n\t\t\tmemcpy(datapart, \"U2F_V2\", 6);\n\t\t\tdatapart += 6;\n\t\t\tAPPEND_SW_NO_ERROR(datapart);\n\t\t\tRawHID.send(buffer, 100);\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\t{\n\t\t\trespondErrorPDU(buffer, SW_INS_NOT_SUPPORTED);\n\t\t}\n\t\t;\n\t}\n\n}\n\nvoid processPacket(byte *buffer)\n{\n#ifdef DEBUG\t\n\tSerial.print(\"Process CMD \");\n#endif\n\tunsigned char cmd = buffer[4]; //cmd or continuation\n#ifdef DEBUG\n\tSerial.println((int)cmd, HEX);\n#endif\n\n\tint len = buffer[5] << 8 | buffer[6];\n\tif (cmd > U2FHID_INIT || cmd==U2FHID_LOCK) {\n\t\terrorResponse(recv_buffer, ERR_INVALID_CMD);\n\t\treturn;\n\t}\n\tif (cmd==U2FHID_PING) {\n\t\tif (len <= MAX_INITIAL_PACKET) {\n#ifdef DEBUG\t\t\t\n\t\t\tSerial.println(\"Sending ping response\");\n#endif\t\t\t\n\t\t\tRawHID.send(buffer, 100);\n\t\t} else {\n\t\t\t//large packet\n\t\t\t//send first one\n#ifdef DEBUG\t\t\t\n\t\t\tSerial.println(\"SENT RESPONSE 3\");\n#endif\t\t\t\n\t\t\tRawHID.send(buffer, 100);\n\t\t\tlen -= MAX_INITIAL_PACKET;\n\t\t\tbyte p = 0;\n\t\t\tint offset = 7 + MAX_INITIAL_PACKET;\n\t\t\twhile (len > 0) {\n\t\t\t\tmemcpy(resp_buffer, buffer, 4); //copy cid\n\t\t\t\tresp_buffer[4] = p++;\n\t\t\t\tmemcpy(resp_buffer + 5, buffer + offset, MAX_CONTINUATION_PACKET);\n\t\t\t\tRawHID.send(resp_buffer, 100);\n\t\t\t\tlen-= MAX_CONTINUATION_PACKET;\n\t\t\t\toffset += MAX_CONTINUATION_PACKET;\n\t\t\t\tdelayMicroseconds(2500);\n\t\t\t}\n#ifdef DEBUG\t\t\t\n\t\t\tSerial.println(\"Sending large ping response\");\n#endif\t\t\t\n\t\t}\n\t}\n\tif (cmd==U2FHID_MSG) {\n\t\tprocessMessage(buffer);\n\t}\n\n}\n\nvoid setOtherTimeout()\n{\n\t//we can process the data\n\t//but if we find another channel is waiting for continuation, we set it as timeout\n\tfor (int i = 0; i < MAX_CHANNEL; i++) {\n\t\tif (channel_states[i].state==STATE_CHANNEL_WAIT_CONT) {\n#ifdef DEBUG\t\t\t\n\t\t\tSerial.println(\"Set other timeout\");\n#endif\t\t\t\n\t\t\tchannel_states[i].state= STATE_CHANNEL_TIMEOUT;\n\t\t}\n\t}\n\n}\n\nint cont_start = 0;\n\n#ifndef DESKTOP_TEST\n#ifdef DEBUG\n\nvoid dump_hex(byte *buffer, int len)\n{\n\tfor (int i = 0 ; i < len; i++) {\n\t    if (buffer[i] <= 0xf) {\n\t       Serial.print(0);\n\t    }\n\t    Serial.print(buffer[i], HEX);\n\t    Serial.print(\" \");\n\t}\n\tSerial.println();\n}\n\n#endif\n#endif\n\nvoid loop() {\n\tint n;\n\n\tn = RawHID.recv(recv_buffer, 0); // 0 timeout = do not wait\n\n\tif (n > 0) {\n#ifdef DEBUG\n#ifndef DESKTOP_TEST\n       Serial.print(\"RAW_RECV: \");\t    \n       dump_hex(recv_buffer, n);\n#endif\t    \n\t\tSerial.print(F(\"\\n\\nReceived packet, CID: \"));\t\t\n#endif\t\t\n\t\t//int cid = *(int*)recv_buffer;\n\t\tint cid; //handle strict-aliasing warning\n\t\tmemcpy(&cid, recv_buffer, sizeof(cid));\t\t\n#ifdef DEBUG\t\t\n\t\tSerial.println(cid, HEX);\n#endif\t\t\n\t\tif (cid==0) {\n\t\t\terrorResponse(recv_buffer, ERR_INVALID_CID);\n\t\t\treturn;\n\t\t}\n\n\t\tunsigned char cmd_or_cont = recv_buffer[4]; //cmd or continuation\n\n\n\t\tint len = (recv_buffer[5]) << 8 | recv_buffer[6];\n\n#ifdef DEBUG\n\t\tif (IS_NOT_CONTINUATION_PACKET(cmd_or_cont)) {\n\t\t\tSerial.print(F(\"LEN \"));\n\t\t\tSerial.println((int)len);\n\t\t}\n#endif\n\n\n\t\t//don't care about cid\n\t\tif (cmd_or_cont==U2FHID_INIT) {\n\t\t\tsetOtherTimeout();\n\t\t\tcid = initResponse(recv_buffer);\n\t\t\tint cidx = find_channel_index(cid);\n\t\t\tchannel_states[cidx].state= STATE_CHANNEL_WAIT_PACKET;\n\t\t\treturn;\n\t\t}\n\n\t\tif (cid==-1) {\n\t\t\terrorResponse(recv_buffer, ERR_INVALID_CID);\n\t\t\treturn;\n\t\t}\n\n\t\tint cidx = find_channel_index(cid);\n\n\t\tif (cidx==-1) {\n#ifdef DEBUG\t\t\t\n\t\t\tSerial.println(\"allocating new CID\");\n#endif\t\t\t\n\t\t\tallocate_channel(cid);\n\t\t\tcidx = find_channel_index(cid);\n\t\t\tif (cidx==-1) {\n\t\t\t\terrorResponse(recv_buffer, ERR_INVALID_CID);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t}\n\n\t\tif (IS_NOT_CONTINUATION_PACKET(cmd_or_cont)) {\n\n\t\t\tif (len > MAX_TOTAL_PACKET) {\n\t\t\t\terrorResponse(recv_buffer, ERR_INVALID_LEN); //invalid length\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (len > MAX_INITIAL_PACKET) {\n\t\t\t\t//if another channel is waiting for continuation, we respond with busy\n\t\t\t\tfor (int i = 0; i < MAX_CHANNEL; i++) {\n\t\t\t\t\tif (channel_states[i].state==STATE_CHANNEL_WAIT_CONT) {\n\t\t\t\t\t\tif (i==cidx) {\n\t\t\t\t\t\t\terrorResponse(recv_buffer, ERR_INVALID_SEQ); //invalid sequence\n\t\t\t\t\t\t\tchannel_states[i].state= STATE_CHANNEL_WAIT_PACKET;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\terrorResponse(recv_buffer, ERR_CHANNEL_BUSY);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t//no other channel is waiting\n\t\t\t\tchannel_states[cidx].state=STATE_CHANNEL_WAIT_CONT;\n\t\t\t\tcont_start = millis();\n\t\t\t\tmemcpy(large_buffer, recv_buffer, 64);\n\t\t\t\tlarge_data_len = len;\n\t\t\t\tlarge_data_offset = MAX_INITIAL_PACKET;\n\t\t\t\texpected_next_packet = 0;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsetOtherTimeout();\n\t\t\tprocessPacket(recv_buffer);\n\t\t\tchannel_states[cidx].state= STATE_CHANNEL_WAIT_PACKET;\n\t\t} else {\n\n\t\t\tif (channel_states[cidx].state!=STATE_CHANNEL_WAIT_CONT) {\n#ifdef DEBUG\t\t\t\t\n\t\t\t\tSerial.println(\"ignoring stray packet\");\n\t\t\t\tSerial.println(cid, HEX);\n#endif\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t//this is a continuation\n\t\t\tif (cmd_or_cont != expected_next_packet) {\n\t\t\t\terrorResponse(recv_buffer, ERR_INVALID_SEQ); //invalid sequence\n\t\t\t\tchannel_states[cidx].state= STATE_CHANNEL_WAIT_PACKET;\n\t\t\t\treturn;\n\t\t\t} else {\n\n\t\t\t\tmemcpy(large_buffer + large_data_offset + 7, recv_buffer + 5, MAX_CONTINUATION_PACKET);\n\t\t\t\tlarge_data_offset += MAX_CONTINUATION_PACKET;\n\n\t\t\t\tif (large_data_offset < large_data_len) {\n\t\t\t\t\texpected_next_packet++;\n#ifdef DEBUG\t\t\t\t\t\n\t\t\t\t\tSerial.println(\"Expecting next cont\");\n#endif\t\t\t\t\t\n\t\t\t\t\treturn;\n\t\t\t\t}\n#ifdef DEBUG\t\t\t\t\n\t\t\t\tSerial.println(\"Completed\");\n#endif\t\t\t\t\n\t\t\t\tchannel_states[cidx].state= STATE_CHANNEL_WAIT_PACKET;\n\t\t\t\tprocessPacket(large_buffer);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t} else {\n\n\t\tfor (int i = 0; i < MAX_CHANNEL; i++) {\n\t\t\tif (channel_states[i].state==STATE_CHANNEL_TIMEOUT) {\n#ifdef DEBUG\t\t\t\t\n\t\t\t\tSerial.println(\"send timeout\");\n\t\t\t\tSerial.println(channel_states[i].cid, HEX);\n#endif\t\t\t\t\n\t\t\t\tmemcpy(recv_buffer, &channel_states[i].cid, 4);\n\t\t\t\terrorResponse(recv_buffer, ERR_MSG_TIMEOUT);\n\t\t\t\tchannel_states[i].state= STATE_CHANNEL_WAIT_PACKET;\n\n\t\t\t}\n\t\t\tif (channel_states[i].state==STATE_CHANNEL_WAIT_CONT) {\n\n\t\t\t\tint now = millis();\n\t\t\t\tif ((now - channel_states[i].last_millis)>500) {\n#ifdef DEBUG\t\t\t\t\t\n\t\t\t\t\tSerial.println(\"SET timeout\");\n#endif\t\t\t\t\t\n\t\t\t\t\tchannel_states[i].state=STATE_CHANNEL_TIMEOUT;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "u2f/uECC.c",
    "content": "/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */\n\n#include \"uECC.h\"\n#include \"uECC_vli.h\"\n\n#ifndef uECC_RNG_MAX_TRIES\n    #define uECC_RNG_MAX_TRIES 64\n#endif\n\n#if uECC_ENABLE_VLI_API\n    #define uECC_VLI_API\n#else\n    #define uECC_VLI_API static\n#endif\n\n#define CONCATX(a, ...) a ## __VA_ARGS__\n#define CONCAT(a, ...) CONCATX(a, __VA_ARGS__)\n\n#define STRX(a) #a\n#define STR(a) STRX(a)\n\n#define EVAL(...)  EVAL1(EVAL1(EVAL1(EVAL1(__VA_ARGS__))))\n#define EVAL1(...) EVAL2(EVAL2(EVAL2(EVAL2(__VA_ARGS__))))\n#define EVAL2(...) EVAL3(EVAL3(EVAL3(EVAL3(__VA_ARGS__))))\n#define EVAL3(...) EVAL4(EVAL4(EVAL4(EVAL4(__VA_ARGS__))))\n#define EVAL4(...) __VA_ARGS__\n\n#define DEC_1  0\n#define DEC_2  1\n#define DEC_3  2\n#define DEC_4  3\n#define DEC_5  4\n#define DEC_6  5\n#define DEC_7  6\n#define DEC_8  7\n#define DEC_9  8\n#define DEC_10 9\n#define DEC_11 10\n#define DEC_12 11\n#define DEC_13 12\n#define DEC_14 13\n#define DEC_15 14\n#define DEC_16 15\n#define DEC_17 16\n#define DEC_18 17\n#define DEC_19 18\n#define DEC_20 19\n#define DEC_21 20\n#define DEC_22 21\n#define DEC_23 22\n#define DEC_24 23\n#define DEC_25 24\n#define DEC_26 25\n#define DEC_27 26\n#define DEC_28 27\n#define DEC_29 28\n#define DEC_30 29\n#define DEC_31 30\n#define DEC_32 31\n\n#define DEC(N) CONCAT(DEC_, N)\n\n#define SECOND_ARG(_, val, ...) val\n#define SOME_CHECK_0 ~, 0\n#define GET_SECOND_ARG(...) SECOND_ARG(__VA_ARGS__, SOME,)\n#define SOME_OR_0(N) GET_SECOND_ARG(CONCAT(SOME_CHECK_, N))\n\n#define EMPTY(...)\n#define DEFER(...) __VA_ARGS__ EMPTY()\n\n#define REPEAT_NAME_0() REPEAT_0\n#define REPEAT_NAME_SOME() REPEAT_SOME\n#define REPEAT_0(...)\n#define REPEAT_SOME(N, stuff) DEFER(CONCAT(REPEAT_NAME_, SOME_OR_0(DEC(N))))()(DEC(N), stuff) stuff\n#define REPEAT(N, stuff) EVAL(REPEAT_SOME(N, stuff))\n\n#define REPEATM_NAME_0() REPEATM_0\n#define REPEATM_NAME_SOME() REPEATM_SOME\n#define REPEATM_0(...)\n#define REPEATM_SOME(N, macro) macro(N) \\\n    DEFER(CONCAT(REPEATM_NAME_, SOME_OR_0(DEC(N))))()(DEC(N), macro)\n#define REPEATM(N, macro) EVAL(REPEATM_SOME(N, macro))\n\n#include \"platform-specific.h\"\n\n#if (uECC_WORD_SIZE == 1)\n    #if uECC_SUPPORTS_secp160r1\n        #define uECC_MAX_WORDS 21 /* Due to the size of curve_n. */\n    #endif\n    #if uECC_SUPPORTS_secp192r1\n        #undef uECC_MAX_WORDS\n        #define uECC_MAX_WORDS 24\n    #endif\n    #if uECC_SUPPORTS_secp224r1\n        #undef uECC_MAX_WORDS\n        #define uECC_MAX_WORDS 28\n    #endif\n    #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)\n        #undef uECC_MAX_WORDS\n        #define uECC_MAX_WORDS 32\n    #endif\n#elif (uECC_WORD_SIZE == 4)\n    #if uECC_SUPPORTS_secp160r1\n        #define uECC_MAX_WORDS 6 /* Due to the size of curve_n. */\n    #endif\n    #if uECC_SUPPORTS_secp192r1\n        #undef uECC_MAX_WORDS\n        #define uECC_MAX_WORDS 6\n    #endif\n    #if uECC_SUPPORTS_secp224r1\n        #undef uECC_MAX_WORDS\n        #define uECC_MAX_WORDS 7\n    #endif\n    #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)\n        #undef uECC_MAX_WORDS\n        #define uECC_MAX_WORDS 8\n    #endif\n#elif (uECC_WORD_SIZE == 8)\n    #if uECC_SUPPORTS_secp160r1\n        #define uECC_MAX_WORDS 3\n    #endif\n    #if uECC_SUPPORTS_secp192r1\n        #undef uECC_MAX_WORDS\n        #define uECC_MAX_WORDS 3\n    #endif\n    #if uECC_SUPPORTS_secp224r1\n        #undef uECC_MAX_WORDS\n        #define uECC_MAX_WORDS 4\n    #endif\n    #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)\n        #undef uECC_MAX_WORDS\n        #define uECC_MAX_WORDS 4\n    #endif\n#endif /* uECC_WORD_SIZE */\n\n#define BITS_TO_WORDS(num_bits) ((num_bits + ((uECC_WORD_SIZE * 8) - 1)) / (uECC_WORD_SIZE * 8))\n#define BITS_TO_BYTES(num_bits) ((num_bits + 7) / 8)\n\nstruct uECC_Curve_t {\n    wordcount_t num_words;\n    wordcount_t num_bytes;\n    bitcount_t num_n_bits;\n    uECC_word_t p[uECC_MAX_WORDS];\n    uECC_word_t n[uECC_MAX_WORDS];\n    uECC_word_t G[uECC_MAX_WORDS * 2];\n    uECC_word_t b[uECC_MAX_WORDS];\n    void (*double_jacobian)(uECC_word_t * X1,\n                            uECC_word_t * Y1,\n                            uECC_word_t * Z1,\n                            uECC_Curve curve);\n#if uECC_SUPPORT_COMPRESSED_POINT\n    void (*mod_sqrt)(uECC_word_t *a, uECC_Curve curve);\n#endif\n    void (*x_side)(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve);\n#if (uECC_OPTIMIZATION_LEVEL > 0)\n    void (*mmod_fast)(uECC_word_t *result, uECC_word_t *product);\n#endif\n};\n\nstatic cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,\n                                       const uECC_word_t *right,\n                                       wordcount_t num_words);\n\n#if (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \\\n        uECC_PLATFORM == uECC_arm_thumb2)\n    #include \"asm_arm.h\"\n#endif\n\n#if (uECC_PLATFORM == uECC_avr)\n    #include \"asm_avr.inc\"\n#endif\n\n#if default_RNG_defined\nstatic uECC_RNG_Function g_rng_function = &default_RNG;\n#else \nstatic uECC_RNG_Function g_rng_function = 0;\n#endif\n\nvoid uECC_set_rng(uECC_RNG_Function rng_function) {\n    g_rng_function = rng_function;\n}\n\n#if !asm_clear\nuECC_VLI_API void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words) {\n    wordcount_t i;\n    for (i = 0; i < num_words; ++i) {\n        vli[i] = 0;\n    }\n}\n#endif /* !asm_clear */\n\n/* Constant-time comparison to zero - secure way to compare long integers */\n/* Returns 1 if vli == 0, 0 otherwise. */\nuECC_VLI_API uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words) {\n    uECC_word_t bits = 0;\n    wordcount_t i;\n    for (i = 0; i < num_words; ++i) {\n        bits |= vli[i];\n    }\n    return (bits == 0);\n}\n\n/* Returns nonzero if bit 'bit' of vli is set. */\nuECC_VLI_API uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit) {\n    return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK)));\n}\n\n/* Counts the number of words in vli. */\nstatic wordcount_t vli_numDigits(const uECC_word_t *vli, const wordcount_t max_words) {\n    wordcount_t i;\n    /* Search from the end until we find a non-zero digit.\n       We do it in reverse because we expect that most digits will be nonzero. */\n    for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) {\n    }\n\n    return (i + 1);\n}\n\n/* Counts the number of bits required to represent vli. */\nuECC_VLI_API bitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words) {\n    uECC_word_t i;\n    uECC_word_t digit;\n\n    wordcount_t num_digits = vli_numDigits(vli, max_words);\n    if (num_digits == 0) {\n        return 0;\n    }\n\n    digit = vli[num_digits - 1];\n    for (i = 0; digit; ++i) {\n        digit >>= 1;\n    }\n\n    return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i);\n}\n\n/* Sets dest = src. */\n#if !asm_set\nuECC_VLI_API void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words) {\n    wordcount_t i;\n    for (i = 0; i < num_words; ++i) {\n        dest[i] = src[i];\n    }\n}\n#endif /* !asm_set */\n\n/* Returns sign of left - right. */\nstatic cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,\n                                       const uECC_word_t *right,\n                                       wordcount_t num_words) {\n    wordcount_t i;\n    for (i = num_words - 1; i >= 0; --i) {\n        if (left[i] > right[i]) {\n            return 1;\n        } else if (left[i] < right[i]) {\n            return -1;\n        }\n    }\n    return 0;\n}\n\n/* Constant-time comparison function - secure way to compare long integers */\n/* Returns one if left == right, zero otherwise. */\nuECC_VLI_API uECC_word_t uECC_vli_equal(const uECC_word_t *left,\n                                        const uECC_word_t *right,\n                                        wordcount_t num_words) {\n    uECC_word_t diff = 0;\n    wordcount_t i;\n    for (i = num_words - 1; i >= 0; --i) {\n        diff |= (left[i] ^ right[i]);\n    }\n    return (diff == 0);\n}\n\nuECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result,\n                                      const uECC_word_t *left,\n                                      const uECC_word_t *right,\n                                      wordcount_t num_words);\n\n/* Returns sign of left - right, in constant time. */\nuECC_VLI_API cmpresult_t uECC_vli_cmp(const uECC_word_t *left,\n                                      const uECC_word_t *right,\n                                      wordcount_t num_words) {\n    uECC_word_t tmp[uECC_MAX_WORDS];\n    uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words);\n    uECC_word_t equal = uECC_vli_isZero(tmp, num_words);\n    return (!equal - 2 * neg);\n}\n\n/* Computes vli = vli >> 1. */\n#if !asm_rshift1\nuECC_VLI_API void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words) {\n    uECC_word_t *end = vli;\n    uECC_word_t carry = 0;\n    \n    vli += num_words;\n    while (vli-- > end) {\n        uECC_word_t temp = *vli;\n        *vli = (temp >> 1) | carry;\n        carry = temp << (uECC_WORD_BITS - 1);\n    }\n}\n#endif /* !asm_rshift1 */\n\n/* Computes result = left + right, returning carry. Can modify in place. */\n#if !asm_add\nuECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result,\n                                      const uECC_word_t *left,\n                                      const uECC_word_t *right,\n                                      wordcount_t num_words) {\n    uECC_word_t carry = 0;\n    wordcount_t i;\n    for (i = 0; i < num_words; ++i) {\n        uECC_word_t sum = left[i] + right[i] + carry;\n        if (sum != left[i]) {\n            carry = (sum < left[i]);\n        }\n        result[i] = sum;\n    }\n    return carry;\n}\n#endif /* !asm_add */\n\n/* Computes result = left - right, returning borrow. Can modify in place. */\n#if !asm_sub\nuECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result,\n                                      const uECC_word_t *left,\n                                      const uECC_word_t *right,\n                                      wordcount_t num_words) {\n    uECC_word_t borrow = 0;\n    wordcount_t i;\n    for (i = 0; i < num_words; ++i) {\n        uECC_word_t diff = left[i] - right[i] - borrow;\n        if (diff != left[i]) {\n            borrow = (diff > left[i]);\n        }\n        result[i] = diff;\n    }\n    return borrow;\n}\n#endif /* !asm_sub */\n\n#if !asm_mult || (uECC_SQUARE_FUNC && !asm_square) || \\\n    (uECC_SUPPORTS_secp256k1 && (uECC_OPTIMIZATION_LEVEL > 0) && \\\n        ((uECC_WORD_SIZE == 1) || (uECC_WORD_SIZE == 8)))\nstatic void muladd(uECC_word_t a,\n                   uECC_word_t b,\n                   uECC_word_t *r0,\n                   uECC_word_t *r1,\n                   uECC_word_t *r2) {\n#if uECC_WORD_SIZE == 8 && !SUPPORTS_INT128\n    uint64_t a0 = a & 0xffffffffull;\n    uint64_t a1 = a >> 32;\n    uint64_t b0 = b & 0xffffffffull;\n    uint64_t b1 = b >> 32;\n\n    uint64_t i0 = a0 * b0;\n    uint64_t i1 = a0 * b1;\n    uint64_t i2 = a1 * b0;\n    uint64_t i3 = a1 * b1;\n\n    uint64_t p0, p1;\n\n    i2 += (i0 >> 32);\n    i2 += i1;\n    if (i2 < i1) { /* overflow */\n        i3 += 0x100000000ull;\n    }\n\n    p0 = (i0 & 0xffffffffull) | (i2 << 32);\n    p1 = i3 + (i2 >> 32);\n\n    *r0 += p0;\n    *r1 += (p1 + (*r0 < p0));\n    *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0));\n#else\n    uECC_dword_t p = (uECC_dword_t)a * b;\n    uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;\n    r01 += p;\n    *r2 += (r01 < p);\n    *r1 = r01 >> uECC_WORD_BITS;\n    *r0 = (uECC_word_t)r01;\n#endif\n}\n#endif /* muladd needed */\n\n#if !asm_mult\nuECC_VLI_API void uECC_vli_mult(uECC_word_t *result,\n                                const uECC_word_t *left,\n                                const uECC_word_t *right,\n                                wordcount_t num_words) {\n    uECC_word_t r0 = 0;\n    uECC_word_t r1 = 0;\n    uECC_word_t r2 = 0;\n    wordcount_t i, k;\n\n    /* Compute each digit of result in sequence, maintaining the carries. */\n    for (k = 0; k < num_words; ++k) {\n        for (i = 0; i <= k; ++i) {\n            muladd(left[i], right[k - i], &r0, &r1, &r2);\n        }\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n    for (k = num_words; k < num_words * 2 - 1; ++k) {\n        for (i = (k + 1) - num_words; i < num_words; ++i) {\n            muladd(left[i], right[k - i], &r0, &r1, &r2);\n        }\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n    result[num_words * 2 - 1] = r0;\n}\n#endif /* !asm_mult */\n\n#if uECC_SQUARE_FUNC\n\n#if !asm_square\nstatic void mul2add(uECC_word_t a,\n                    uECC_word_t b,\n                    uECC_word_t *r0,\n                    uECC_word_t *r1,\n                    uECC_word_t *r2) {\n#if uECC_WORD_SIZE == 8 && !SUPPORTS_INT128\n    uint64_t a0 = a & 0xffffffffull;\n    uint64_t a1 = a >> 32;\n    uint64_t b0 = b & 0xffffffffull;\n    uint64_t b1 = b >> 32;\n\n    uint64_t i0 = a0 * b0;\n    uint64_t i1 = a0 * b1;\n    uint64_t i2 = a1 * b0;\n    uint64_t i3 = a1 * b1;\n\n    uint64_t p0, p1;\n\n    i2 += (i0 >> 32);\n    i2 += i1;\n    if (i2 < i1)\n    { /* overflow */\n        i3 += 0x100000000ull;\n    }\n\n    p0 = (i0 & 0xffffffffull) | (i2 << 32);\n    p1 = i3 + (i2 >> 32);\n\n    *r2 += (p1 >> 63);\n    p1 = (p1 << 1) | (p0 >> 63);\n    p0 <<= 1;\n\n    *r0 += p0;\n    *r1 += (p1 + (*r0 < p0));\n    *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0));\n#else\n    uECC_dword_t p = (uECC_dword_t)a * b;\n    uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0;\n    *r2 += (p >> (uECC_WORD_BITS * 2 - 1));\n    p *= 2;\n    r01 += p;\n    *r2 += (r01 < p);\n    *r1 = r01 >> uECC_WORD_BITS;\n    *r0 = (uECC_word_t)r01;\n#endif\n}\n\nuECC_VLI_API void uECC_vli_square(uECC_word_t *result,\n                                  const uECC_word_t *left,\n                                  wordcount_t num_words) {\n    uECC_word_t r0 = 0;\n    uECC_word_t r1 = 0;\n    uECC_word_t r2 = 0;\n\n    wordcount_t i, k;\n    \n    for (k = 0; k < num_words * 2 - 1; ++k) {\n        uECC_word_t min = (k < num_words ? 0 : (k + 1) - num_words);\n        for (i = min; i <= k && i <= k - i; ++i) {\n            if (i < k-i) {\n                mul2add(left[i], left[k - i], &r0, &r1, &r2);\n            } else {\n                muladd(left[i], left[k - i], &r0, &r1, &r2);\n            }\n        }\n        result[k] = r0;\n        r0 = r1;\n        r1 = r2;\n        r2 = 0;\n    }\n    \n    result[num_words * 2 - 1] = r0;\n}\n#endif /* !asm_square */\n\n#else /* uECC_SQUARE_FUNC */\n\n#if uECC_ENABLE_VLI_API\nuECC_VLI_API void uECC_vli_square(uECC_word_t *result,\n                                  const uECC_word_t *left,\n                                  wordcount_t num_words) {\n    uECC_vli_mult(result, left, left, num_words);\n}\n#endif /* uECC_ENABLE_VLI_API */\n    \n#endif /* uECC_SQUARE_FUNC */\n\n/* Computes result = (left + right) % mod.\n   Assumes that left < mod and right < mod, and that result does not overlap mod. */\nuECC_VLI_API void uECC_vli_modAdd(uECC_word_t *result,\n                                  const uECC_word_t *left,\n                                  const uECC_word_t *right,\n                                  const uECC_word_t *mod,\n                                  wordcount_t num_words) {\n    uECC_word_t carry = uECC_vli_add(result, left, right, num_words);\n    if (carry || uECC_vli_cmp_unsafe(mod, result, num_words) != 1) {\n        /* result > mod (result = mod + remainder), so subtract mod to get remainder. */\n        uECC_vli_sub(result, result, mod, num_words);\n    }\n}\n\n/* Computes result = (left - right) % mod.\n   Assumes that left < mod and right < mod, and that result does not overlap mod. */\nuECC_VLI_API void uECC_vli_modSub(uECC_word_t *result,\n                                  const uECC_word_t *left,\n                                  const uECC_word_t *right,\n                                  const uECC_word_t *mod,\n                                  wordcount_t num_words) {\n    uECC_word_t l_borrow = uECC_vli_sub(result, left, right, num_words);\n    if (l_borrow) {\n        /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,\n           we can get the correct result from result + mod (with overflow). */\n        uECC_vli_add(result, result, mod, num_words);\n    }\n}\n\n/* Computes result = product % mod, where product is 2N words long. */\n/* Currently only designed to work for curve_p or curve_n. */\nuECC_VLI_API void uECC_vli_mmod(uECC_word_t *result,\n                                uECC_word_t *product,\n                                const uECC_word_t *mod,\n                                wordcount_t num_words) {\n    uECC_word_t mod_multiple[2 * uECC_MAX_WORDS];\n    uECC_word_t tmp[2 * uECC_MAX_WORDS];\n    uECC_word_t *v[2] = {tmp, product};\n    uECC_word_t index;\n    \n    /* Shift mod so its highest set bit is at the maximum position. */\n    bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) - uECC_vli_numBits(mod, num_words);\n    wordcount_t word_shift = shift / uECC_WORD_BITS;\n    wordcount_t bit_shift = shift % uECC_WORD_BITS;\n    uECC_word_t carry = 0;\n    uECC_vli_clear(mod_multiple, word_shift);\n    if (bit_shift > 0) {\n        for(index = 0; index < (uECC_word_t)num_words; ++index) {\n            mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry;\n            carry = mod[index] >> (uECC_WORD_BITS - bit_shift);\n        }\n    } else {\n        uECC_vli_set(mod_multiple + word_shift, mod, num_words);\n    }\n\n    for (index = 1; shift >= 0; --shift) {\n        uECC_word_t borrow = 0;\n        wordcount_t i;\n        for (i = 0; i < num_words * 2; ++i) {\n            uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow;\n            if (diff != v[index][i]) {\n                borrow = (diff > v[index][i]);\n            }\n            v[1 - index][i] = diff;\n        }\n        index = !(index ^ borrow); /* Swap the index if there was no borrow */\n        uECC_vli_rshift1(mod_multiple, num_words);\n        mod_multiple[num_words - 1] |= mod_multiple[num_words] << (uECC_WORD_BITS - 1);\n        uECC_vli_rshift1(mod_multiple + num_words, num_words);\n    }\n    uECC_vli_set(result, v[index], num_words);\n}\n\n/* Computes result = (left * right) % mod. */\nuECC_VLI_API void uECC_vli_modMult(uECC_word_t *result,\n                                   const uECC_word_t *left,\n                                   const uECC_word_t *right,\n                                   const uECC_word_t *mod,\n                                   wordcount_t num_words) {\n    uECC_word_t product[2 * uECC_MAX_WORDS];\n    uECC_vli_mult(product, left, right, num_words);\n    uECC_vli_mmod(result, product, mod, num_words);\n}\n\nuECC_VLI_API void uECC_vli_modMult_fast(uECC_word_t *result,\n                                        const uECC_word_t *left,\n                                        const uECC_word_t *right,\n                                        uECC_Curve curve) {\n    uECC_word_t product[2 * uECC_MAX_WORDS];\n    uECC_vli_mult(product, left, right, curve->num_words);\n#if (uECC_OPTIMIZATION_LEVEL > 0)\n    curve->mmod_fast(result, product);\n#else\n    uECC_vli_mmod(result, product, curve->p, curve->num_words);\n#endif\n}\n\n#if uECC_SQUARE_FUNC\n\n#if uECC_ENABLE_VLI_API\n/* Computes result = left^2 % mod. */\nuECC_VLI_API void uECC_vli_modSquare(uECC_word_t *result,\n                                     const uECC_word_t *left,\n                                     const uECC_word_t *mod,\n                                     wordcount_t num_words) {\n    uECC_word_t product[2 * uECC_MAX_WORDS];\n    uECC_vli_square(product, left, num_words);\n    uECC_vli_mmod(result, product, mod, num_words);\n}\n#endif /* uECC_ENABLE_VLI_API */\n\nuECC_VLI_API void uECC_vli_modSquare_fast(uECC_word_t *result,\n                                          const uECC_word_t *left,\n                                          uECC_Curve curve) {\n    uECC_word_t product[2 * uECC_MAX_WORDS];\n    uECC_vli_square(product, left, curve->num_words);\n#if (uECC_OPTIMIZATION_LEVEL > 0)\n    curve->mmod_fast(result, product);\n#else\n    uECC_vli_mmod(result, product, curve->p, curve->num_words);\n#endif\n}\n\n#else /* uECC_SQUARE_FUNC */\n\n#if uECC_ENABLE_VLI_API\nuECC_VLI_API void uECC_vli_modSquare(uECC_word_t *result,\n                                     const uECC_word_t *left,\n                                     const uECC_word_t *mod,\n                                     wordcount_t num_words) {\n    uECC_vli_modMult(result, left, left, mod, num_words);\n}\n#endif /* uECC_ENABLE_VLI_API */\n\nuECC_VLI_API void uECC_vli_modSquare_fast(uECC_word_t *result,\n                                          const uECC_word_t *left,\n                                          uECC_Curve curve) {\n    uECC_vli_modMult_fast(result, left, left, curve);\n}\n    \n#endif /* uECC_SQUARE_FUNC */\n\n#define EVEN(vli) (!(vli[0] & 1))\nstatic void vli_modInv_update(uECC_word_t *uv,\n                              const uECC_word_t *mod,\n                              wordcount_t num_words) {\n    uECC_word_t carry = 0;\n    if (!EVEN(uv)) {\n        carry = uECC_vli_add(uv, uv, mod, num_words);\n    }\n    uECC_vli_rshift1(uv, num_words);\n    if (carry) {\n        uv[num_words - 1] |= HIGH_BIT_SET;\n    }\n}\n\n/* Computes result = (1 / input) % mod. All VLIs are the same size.\n   See \"From Euclid's GCD to Montgomery Multiplication to the Great Divide\" */\nuECC_VLI_API void uECC_vli_modInv(uECC_word_t *result,\n                                  const uECC_word_t *input,\n                                  const uECC_word_t *mod,\n                                  wordcount_t num_words) {\n    uECC_word_t a[uECC_MAX_WORDS], b[uECC_MAX_WORDS], u[uECC_MAX_WORDS], v[uECC_MAX_WORDS];\n    cmpresult_t cmpResult;\n    \n    if (uECC_vli_isZero(input, num_words)) {\n        uECC_vli_clear(result, num_words);\n        return;\n    }\n\n    uECC_vli_set(a, input, num_words);\n    uECC_vli_set(b, mod, num_words);\n    uECC_vli_clear(u, num_words);\n    u[0] = 1;\n    uECC_vli_clear(v, num_words);\n    while ((cmpResult = uECC_vli_cmp_unsafe(a, b, num_words)) != 0) {\n        if (EVEN(a)) {\n            uECC_vli_rshift1(a, num_words);\n            vli_modInv_update(u, mod, num_words);\n        } else if (EVEN(b)) {\n            uECC_vli_rshift1(b, num_words);\n            vli_modInv_update(v, mod, num_words);\n        } else if (cmpResult > 0) {\n            uECC_vli_sub(a, a, b, num_words);\n            uECC_vli_rshift1(a, num_words);\n            if (uECC_vli_cmp_unsafe(u, v, num_words) < 0) {\n                uECC_vli_add(u, u, mod, num_words);\n            }\n            uECC_vli_sub(u, u, v, num_words);\n            vli_modInv_update(u, mod, num_words);\n        } else {\n            uECC_vli_sub(b, b, a, num_words);\n            uECC_vli_rshift1(b, num_words);\n            if (uECC_vli_cmp_unsafe(v, u, num_words) < 0) {\n                uECC_vli_add(v, v, mod, num_words);\n            }\n            uECC_vli_sub(v, v, u, num_words);\n            vli_modInv_update(v, mod, num_words);\n        }\n    }\n    uECC_vli_set(result, u, num_words);\n}\n\n/* ------ Point operations ------ */\n\n#include \"curve-specific.h\"\n\n/* Returns 1 if 'point' is the point at infinity, 0 otherwise. */\n#define EccPoint_isZero(point, curve) uECC_vli_isZero((point), (curve)->num_words * 2)\n\n/* Point multiplication algorithm using Montgomery's ladder with co-Z coordinates.\nFrom http://eprint.iacr.org/2011/338.pdf\n*/\n\n/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */\nstatic void apply_z(uECC_word_t * X1,\n                    uECC_word_t * Y1,\n                    const uECC_word_t * const Z,\n                    uECC_Curve curve) {\n    uECC_word_t t1[uECC_MAX_WORDS];\n\n    uECC_vli_modSquare_fast(t1, Z, curve);    /* z^2 */\n    uECC_vli_modMult_fast(X1, X1, t1, curve); /* x1 * z^2 */\n    uECC_vli_modMult_fast(t1, t1, Z, curve);  /* z^3 */\n    uECC_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */\n}\n\n/* P = (x1, y1) => 2P, (x2, y2) => P' */\nstatic void XYcZ_initial_double(uECC_word_t * X1,\n                                uECC_word_t * Y1,\n                                uECC_word_t * X2,\n                                uECC_word_t * Y2,\n                                const uECC_word_t * const initial_Z,\n                                uECC_Curve curve) {\n    uECC_word_t z[uECC_MAX_WORDS];\n    wordcount_t num_words = curve->num_words;\n    if (initial_Z) {\n        uECC_vli_set(z, initial_Z, num_words);\n    } else {\n        uECC_vli_clear(z, num_words);\n        z[0] = 1;\n    }\n\n    uECC_vli_set(X2, X1, num_words);\n    uECC_vli_set(Y2, Y1, num_words);\n\n    apply_z(X1, Y1, z, curve);\n    curve->double_jacobian(X1, Y1, z, curve);\n    apply_z(X2, Y2, z, curve);\n}\n\n/* Input P = (x1, y1, Z), Q = (x2, y2, Z)\n   Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3)\n   or P => P', Q => P + Q\n*/\nstatic void XYcZ_add(uECC_word_t * X1,\n                     uECC_word_t * Y1,\n                     uECC_word_t * X2,\n                     uECC_word_t * Y2,\n                     uECC_Curve curve) {\n    /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */\n    uECC_word_t t5[uECC_MAX_WORDS];\n    wordcount_t num_words = curve->num_words;\n    \n    uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */\n    uECC_vli_modSquare_fast(t5, t5, curve);                  /* t5 = (x2 - x1)^2 = A */\n    uECC_vli_modMult_fast(X1, X1, t5, curve);                /* t1 = x1*A = B */\n    uECC_vli_modMult_fast(X2, X2, t5, curve);                /* t3 = x2*A = C */\n    uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */\n    uECC_vli_modSquare_fast(t5, Y2, curve);                  /* t5 = (y2 - y1)^2 = D */\n                                                        \n    uECC_vli_modSub(t5, t5, X1, curve->p, num_words); /* t5 = D - B */\n    uECC_vli_modSub(t5, t5, X2, curve->p, num_words); /* t5 = D - B - C = x3 */\n    uECC_vli_modSub(X2, X2, X1, curve->p, num_words); /* t3 = C - B */\n    uECC_vli_modMult_fast(Y1, Y1, X2, curve);                /* t2 = y1*(C - B) */\n    uECC_vli_modSub(X2, X1, t5, curve->p, num_words); /* t3 = B - x3 */\n    uECC_vli_modMult_fast(Y2, Y2, X2, curve);                /* t4 = (y2 - y1)*(B - x3) */\n    uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y3 */\n    \n    uECC_vli_set(X2, t5, num_words);\n}\n\n/* Input P = (x1, y1, Z), Q = (x2, y2, Z)\n   Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)\n   or P => P - Q, Q => P + Q\n*/\nstatic void XYcZ_addC(uECC_word_t * X1,\n                      uECC_word_t * Y1,\n                      uECC_word_t * X2,\n                      uECC_word_t * Y2,\n                      uECC_Curve curve) {\n    /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */\n    uECC_word_t t5[uECC_MAX_WORDS];\n    uECC_word_t t6[uECC_MAX_WORDS];\n    uECC_word_t t7[uECC_MAX_WORDS];\n    wordcount_t num_words = curve->num_words;\n    \n    uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */\n    uECC_vli_modSquare_fast(t5, t5, curve);                  /* t5 = (x2 - x1)^2 = A */\n    uECC_vli_modMult_fast(X1, X1, t5, curve);                /* t1 = x1*A = B */\n    uECC_vli_modMult_fast(X2, X2, t5, curve);                /* t3 = x2*A = C */\n    uECC_vli_modAdd(t5, Y2, Y1, curve->p, num_words); /* t5 = y2 + y1 */\n    uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */\n                                                        \n    uECC_vli_modSub(t6, X2, X1, curve->p, num_words); /* t6 = C - B */\n    uECC_vli_modMult_fast(Y1, Y1, t6, curve);                /* t2 = y1 * (C - B) = E */\n    uECC_vli_modAdd(t6, X1, X2, curve->p, num_words); /* t6 = B + C */\n    uECC_vli_modSquare_fast(X2, Y2, curve);                  /* t3 = (y2 - y1)^2 = D */\n    uECC_vli_modSub(X2, X2, t6, curve->p, num_words); /* t3 = D - (B + C) = x3 */\n                                                        \n    uECC_vli_modSub(t7, X1, X2, curve->p, num_words); /* t7 = B - x3 */\n    uECC_vli_modMult_fast(Y2, Y2, t7, curve);                /* t4 = (y2 - y1)*(B - x3) */\n    uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = (y2 - y1)*(B - x3) - E = y3 */\n                                                        \n    uECC_vli_modSquare_fast(t7, t5, curve);                  /* t7 = (y2 + y1)^2 = F */\n    uECC_vli_modSub(t7, t7, t6, curve->p, num_words); /* t7 = F - (B + C) = x3' */\n    uECC_vli_modSub(t6, t7, X1, curve->p, num_words); /* t6 = x3' - B */\n    uECC_vli_modMult_fast(t6, t6, t5, curve);                /* t6 = (y2+y1)*(x3' - B) */\n    uECC_vli_modSub(Y1, t6, Y1, curve->p, num_words); /* t2 = (y2+y1)*(x3' - B) - E = y3' */\n    \n    uECC_vli_set(X1, t7, num_words);\n}\n\n/* result may overlap point. */\nstatic void EccPoint_mult(uECC_word_t * result,\n                          const uECC_word_t * point,\n                          const uECC_word_t * scalar,\n                          const uECC_word_t * initial_Z,\n                          bitcount_t num_bits,\n                          uECC_Curve curve) {\n    /* R0 and R1 */\n    uECC_word_t Rx[2][uECC_MAX_WORDS];\n    uECC_word_t Ry[2][uECC_MAX_WORDS];\n    uECC_word_t z[uECC_MAX_WORDS];\n    bitcount_t i;\n    uECC_word_t nb;\n    wordcount_t num_words = curve->num_words;\n    \n    uECC_vli_set(Rx[1], point, num_words);\n    uECC_vli_set(Ry[1], point + num_words, num_words);\n\n    XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z, curve);\n\n    for (i = num_bits - 2; i > 0; --i) {\n        nb = !uECC_vli_testBit(scalar, i);\n        XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve);\n        XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve);\n    }\n\n    nb = !uECC_vli_testBit(scalar, 0);\n    XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve);\n    \n    /* Find final 1/Z value. */\n    uECC_vli_modSub(z, Rx[1], Rx[0], curve->p, num_words); /* X1 - X0 */\n    uECC_vli_modMult_fast(z, z, Ry[1 - nb], curve);               /* Yb * (X1 - X0) */\n    uECC_vli_modMult_fast(z, z, point, curve);                    /* xP * Yb * (X1 - X0) */\n    uECC_vli_modInv(z, z, curve->p, num_words);            /* 1 / (xP * Yb * (X1 - X0)) */\n    /* yP / (xP * Yb * (X1 - X0)) */\n    uECC_vli_modMult_fast(z, z, point + num_words, curve); \n    uECC_vli_modMult_fast(z, z, Rx[1 - nb], curve); /* Xb * yP / (xP * Yb * (X1 - X0)) */\n    /* End 1/Z calculation */\n\n    XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve);\n    apply_z(Rx[0], Ry[0], z, curve);\n    \n    uECC_vli_set(result, Rx[0], num_words);\n    uECC_vli_set(result + num_words, Ry[0], num_words);\n}\n\nstatic uECC_word_t regularize_k(const uECC_word_t * const k,\n                                uECC_word_t *k0,\n                                uECC_word_t *k1,\n                                uECC_Curve curve) {\n    wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);\n    bitcount_t num_n_bits = curve->num_n_bits;\n    uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) ||\n        (num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) &&\n         uECC_vli_testBit(k0, num_n_bits));\n    uECC_vli_add(k1, k0, curve->n, num_n_words);\n    return carry;\n}\n\nstatic uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,\n                                               uECC_word_t *private,\n                                               uECC_Curve curve) {\n    uECC_word_t tmp1[uECC_MAX_WORDS];\n    uECC_word_t tmp2[uECC_MAX_WORDS];\n    uECC_word_t *p2[2] = {tmp1, tmp2};\n    uECC_word_t carry;\n\n    /* Regularize the bitcount for the private key so that attackers cannot use a side channel\n       attack to learn the number of leading zeros. */\n    carry = regularize_k(private, tmp1, tmp2, curve);\n\n    EccPoint_mult(result, curve->G, p2[!carry], 0, curve->num_n_bits + 1, curve);\n\n    if (EccPoint_isZero(result, curve)) {\n        return 0;\n    }\n    return 1;\n}\n\n#if uECC_WORD_SIZE == 1\n\nuECC_VLI_API void uECC_vli_nativeToBytes(uint8_t *bytes,\n                                         int num_bytes,\n                                         const uint8_t *native) {\n    wordcount_t i;\n    for (i = 0; i < num_bytes; ++i) {\n        bytes[i] = native[(num_bytes - 1) - i];\n    }\n}\n\nuECC_VLI_API void uECC_vli_bytesToNative(uint8_t *native,\n                                         const uint8_t *bytes,\n                                         int num_bytes) {\n    uECC_vli_nativeToBytes(native, num_bytes, bytes);\n}\n\n#else\n\nuECC_VLI_API void uECC_vli_nativeToBytes(uint8_t *bytes,\n                                         int num_bytes,\n                                         const uECC_word_t *native) {\n    wordcount_t i;\n    for (i = 0; i < num_bytes; ++i) {\n        unsigned b = num_bytes - 1 - i;\n        bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE));\n    }\n}\n\nuECC_VLI_API void uECC_vli_bytesToNative(uECC_word_t *native,\n                                         const uint8_t *bytes,\n                                         int num_bytes) {\n    wordcount_t i;\n    uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE);\n    for (i = 0; i < num_bytes; ++i) {\n        unsigned b = num_bytes - 1 - i;\n        native[b / uECC_WORD_SIZE] |= \n            (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE));\n    }\n}\n\n#endif /* uECC_WORD_SIZE */\n\n/* Generates a random integer in the range 0 < random < top.\n   Both random and top have num_words words. */\nuECC_VLI_API int uECC_generate_random_int(uECC_word_t *random,\n                                          const uECC_word_t *top,\n                                          wordcount_t num_words) {\n    uECC_word_t mask = (uECC_word_t)-1;\n    uECC_word_t tries;\n    bitcount_t num_bits = uECC_vli_numBits(top, num_words);\n\n    if (!g_rng_function) {\n        return 0;\n    }\n\n    for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {\n        if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) {\n            return 0;\n\t    }\n        random[num_words - 1] &= mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits));\n        if (!uECC_vli_isZero(random, num_words) &&\n\t\t        uECC_vli_cmp(top, random, num_words) == 1) {\n            return 1;\n        }\n    }\n    return 0;\n}\n\nint uECC_make_key(uint8_t *public_key,\n                  uint8_t *private_key,\n                  uECC_Curve curve) {\n    uECC_word_t private[uECC_MAX_WORDS];\n    uECC_word_t public[uECC_MAX_WORDS * 2];\n    uECC_word_t tries;\n\n    for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {\n        if (!uECC_generate_random_int(private, curve->n, BITS_TO_WORDS(curve->num_n_bits))) {\n            return 0;\n        }\n\n        if (EccPoint_compute_public_key(public, private, curve)) {\n            uECC_vli_nativeToBytes(private_key, BITS_TO_BYTES(curve->num_n_bits), private);\n            uECC_vli_nativeToBytes(public_key, curve->num_bytes, public);\n            uECC_vli_nativeToBytes(\n                public_key + curve->num_bytes, curve->num_bytes, public + curve->num_words);\n            return 1;\n        }\n    }\n    return 0;\n}\n\nint uECC_shared_secret(const uint8_t *public_key,\n                       const uint8_t *private_key,\n                       uint8_t *secret,\n                       uECC_Curve curve) {\n    uECC_word_t public[uECC_MAX_WORDS * 2];\n    uECC_word_t private[uECC_MAX_WORDS];\n    uECC_word_t tmp[uECC_MAX_WORDS];\n    uECC_word_t *p2[2] = {private, tmp};\n    uECC_word_t *initial_Z = 0;\n    uECC_word_t carry;\n    wordcount_t num_words = curve->num_words;\n    wordcount_t num_bytes = curve->num_bytes;\n    \n    uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits));\n    uECC_vli_bytesToNative(public, public_key, num_bytes);\n    uECC_vli_bytesToNative(public + num_words, public_key + num_bytes, num_bytes);\n    \n    /* Regularize the bitcount for the private key so that attackers cannot use a side channel\n       attack to learn the number of leading zeros. */\n    carry = regularize_k(private, private, tmp, curve);\n    \n    /* If an RNG function was specified, try to get a random initial Z value to improve\n       protection against side-channel attacks. */\n    if (g_rng_function) {\n        if (!uECC_generate_random_int(p2[carry], curve->p, num_words)) {\n            return 0;\n        }\n        initial_Z = p2[carry];\n    }\n    \n    EccPoint_mult(public, public, p2[!carry], initial_Z, curve->num_n_bits + 1, curve);\n    uECC_vli_nativeToBytes(secret, num_bytes, public);\n    return !EccPoint_isZero(public, curve);\n}\n\n#if uECC_SUPPORT_COMPRESSED_POINT\nvoid uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve) {\n    wordcount_t i;\n    for (i = 0; i < curve->num_bytes; ++i) {\n        compressed[i+1] = public_key[i];\n    }\n    compressed[0] = 2 + (public_key[curve->num_bytes * 2 - 1] & 0x01);\n}\n\nvoid uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve) {\n    uECC_word_t point[uECC_MAX_WORDS * 2];\n    uECC_word_t *y = point + curve->num_words;\n    uECC_vli_bytesToNative(point, compressed + 1, curve->num_bytes);\n    curve->x_side(y, point, curve);\n    curve->mod_sqrt(y, curve);\n    \n    if ((y[0] & 0x01) != (compressed[0] & 0x01)) {\n        uECC_vli_sub(y, curve->p, y, curve->num_words);\n    }\n    \n    uECC_vli_nativeToBytes(public_key, curve->num_bytes, point);\n    uECC_vli_nativeToBytes(public_key + curve->num_bytes, curve->num_bytes, y);\n}\n#endif /* uECC_SUPPORT_COMPRESSED_POINT */\n\nint uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) {\n    uECC_word_t tmp1[uECC_MAX_WORDS];\n    uECC_word_t tmp2[uECC_MAX_WORDS];\n    wordcount_t num_words = curve->num_words;\n\n    /* The point at infinity is invalid. */\n    if (EccPoint_isZero(point, curve)) {\n        return 0;\n    }\n    \n    /* x and y must be smaller than p. */\n    if (uECC_vli_cmp_unsafe(curve->p, point, num_words) != 1 ||\n            uECC_vli_cmp_unsafe(curve->p, point + num_words, num_words) != 1) {\n        return 0;\n    }\n    \n    uECC_vli_modSquare_fast(tmp1, point + num_words, curve);\n    curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */\n    \n    /* Make sure that y^2 == x^3 + ax + b */\n    return (int)(uECC_vli_equal(tmp1, tmp2, num_words));\n}\n\nint uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve) {\n    uECC_word_t public[uECC_MAX_WORDS * 2];\n\n    uECC_vli_bytesToNative(public, public_key, curve->num_bytes);\n    uECC_vli_bytesToNative(\n        public + curve->num_words, public_key + curve->num_bytes, curve->num_bytes);\n    return uECC_valid_point(public, curve);\n}\n\nint uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve) {\n    uECC_word_t private[uECC_MAX_WORDS];\n    uECC_word_t public[uECC_MAX_WORDS * 2];\n\n    uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits));\n\n    /* Make sure the private key is in the range [1, n-1]. */\n    if (uECC_vli_isZero(private, BITS_TO_WORDS(curve->num_n_bits))) {\n        return 0;\n    }\n\n    if (uECC_vli_cmp(curve->n, private, BITS_TO_WORDS(curve->num_n_bits)) != 1) {\n        return 0;\n    }\n\n    /* Compute public key. */\n    if (!EccPoint_compute_public_key(public, private, curve)) {\n        return 0;\n    }\n\n    uECC_vli_nativeToBytes(public_key, curve->num_bytes, public);\n    uECC_vli_nativeToBytes(\n        public_key + curve->num_bytes, curve->num_bytes, public + curve->num_words);\n    return 1;\n}\n\n\n/* -------- ECDSA code -------- */\n\nstatic void bits2int(uECC_word_t *native,\n                     const uint8_t *bits,\n                     unsigned bits_size,\n                     uECC_Curve curve) {\n    unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits);\n    unsigned num_n_words = BITS_TO_WORDS(curve->num_n_bits);\n    if (bits_size > num_n_bytes) {\n        bits_size = num_n_bytes;\n    }\n    uECC_vli_clear(native, num_n_words);\n    uECC_vli_bytesToNative(native, bits, bits_size);\n    if (bits_size * 8 <= (unsigned)curve->num_n_bits) {\n        return;\n    }\n    int shift = bits_size * 8 - curve->num_n_bits;\n    uECC_word_t carry = 0;\n    uECC_word_t *ptr = native + num_n_words;\n    while (ptr-- > native) {\n        uECC_word_t temp = *ptr;\n        *ptr = (temp >> shift) | carry;\n        carry = temp << (uECC_WORD_BITS - shift);\n    }\n\n    /* Reduce mod curve_n */\n    if (uECC_vli_cmp_unsafe(curve->n, native, num_n_words) != 1) {\n        uECC_vli_sub(native, native, curve->n, num_n_words);\n    }\n}\n\nstatic int uECC_sign_with_k(const uint8_t *private_key,\n                            const uint8_t *message_hash,\n                            unsigned hash_size,\n                            uECC_word_t *k,\n                            uint8_t *signature,\n                            uECC_Curve curve) {\n    uECC_word_t tmp[uECC_MAX_WORDS];\n    uECC_word_t s[uECC_MAX_WORDS];\n    uECC_word_t *k2[2] = {tmp, s};\n    uECC_word_t p[uECC_MAX_WORDS * 2];\n    uECC_word_t carry;\n    wordcount_t num_words = curve->num_words;\n    wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);\n    bitcount_t num_n_bits = curve->num_n_bits;\n    \n    /* Make sure 0 < k < curve_n */\n    if (uECC_vli_isZero(k, num_words) || uECC_vli_cmp(curve->n, k, num_n_words) != 1) {\n        return 0;\n    }\n    \n    carry = regularize_k(k, tmp, s, curve);\n    EccPoint_mult(p, curve->G, k2[!carry], 0, num_n_bits + 1, curve);\n    if (uECC_vli_isZero(p, num_words)) {\n        return 0;\n    }\n    \n    /* If an RNG function was specified, get a random number\n       to prevent side channel analysis of k. */\n    if (!g_rng_function) {\n        uECC_vli_clear(tmp, num_n_words);\n        tmp[0] = 1;\n    } else if (!uECC_generate_random_int(tmp, curve->n, num_n_words)) {\n        return 0;\n    }\n\n    /* Prevent side channel analysis of uECC_vli_modInv() to determine\n       bits of k / the private key by premultiplying by a random number */\n    uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */\n    uECC_vli_modInv(k, k, curve->n, num_n_words);       /* k = 1 / k' */\n    uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k = 1 / k */\n    \n    uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r */\n    \n    uECC_vli_bytesToNative(tmp, private_key, BITS_TO_BYTES(curve->num_n_bits)); /* tmp = d */\n    s[num_n_words - 1] = 0;\n    uECC_vli_set(s, p, num_words);\n    uECC_vli_modMult(s, tmp, s, curve->n, num_n_words); /* s = r*d */\n\n    bits2int(tmp, message_hash, hash_size, curve);\n    uECC_vli_modAdd(s, tmp, s, curve->n, num_n_words); /* s = e + r*d */\n    uECC_vli_modMult(s, s, k, curve->n, num_n_words);  /* s = (e + r*d) / k */\n    if (uECC_vli_numBits(s, num_n_words) > (bitcount_t)curve->num_bytes * 8) {\n        return 0;\n    }\n    uECC_vli_nativeToBytes(signature + curve->num_bytes, curve->num_bytes, s);\n    return 1;\n}\n\nint uECC_sign(const uint8_t *private_key,\n              const uint8_t *message_hash,\n              unsigned hash_size,\n              uint8_t *signature,\n              uECC_Curve curve) {\n    uECC_word_t k[uECC_MAX_WORDS];\n    uECC_word_t tries;\n\n    for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {\n        if (!uECC_generate_random_int(k, curve->n, BITS_TO_WORDS(curve->num_n_bits))) {\n            return 0;\n        }\n\n        if (uECC_sign_with_k(private_key, message_hash, hash_size, k, signature, curve)) {\n            return 1;\n        }\n    }\n    return 0;\n}\n\n/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always\n   the same size as the hash result size. */\nstatic void HMAC_init(uECC_HashContext *hash_context, const uint8_t *K) {\n    uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size;\n    unsigned i;\n    for (i = 0; i < hash_context->result_size; ++i)\n        pad[i] = K[i] ^ 0x36;\n    for (; i < hash_context->block_size; ++i)\n        pad[i] = 0x36;\n\n    hash_context->init_hash(hash_context);\n    hash_context->update_hash(hash_context, pad, hash_context->block_size);\n}\n\nstatic void HMAC_update(uECC_HashContext *hash_context,\n                        const uint8_t *message,\n                        unsigned message_size) {\n    hash_context->update_hash(hash_context, message, message_size);\n}\n\nstatic void HMAC_finish(uECC_HashContext *hash_context, const uint8_t *K, uint8_t *result) {\n    uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size;\n    unsigned i;\n    for (i = 0; i < hash_context->result_size; ++i)\n        pad[i] = K[i] ^ 0x5c;\n    for (; i < hash_context->block_size; ++i)\n        pad[i] = 0x5c;\n\n    hash_context->finish_hash(hash_context, result);\n\n    hash_context->init_hash(hash_context);\n    hash_context->update_hash(hash_context, pad, hash_context->block_size);\n    hash_context->update_hash(hash_context, result, hash_context->result_size);\n    hash_context->finish_hash(hash_context, result);\n}\n\n/* V = HMAC_K(V) */\nstatic void update_V(uECC_HashContext *hash_context, uint8_t *K, uint8_t *V) {\n    HMAC_init(hash_context, K);\n    HMAC_update(hash_context, V, hash_context->result_size);\n    HMAC_finish(hash_context, K, V);\n}\n\n/* Deterministic signing, similar to RFC 6979. Differences are:\n    * We just use H(m) directly rather than bits2octets(H(m))\n      (it is not reduced modulo curve_n).\n    * We generate a value for k (aka T) directly rather than converting endianness.\n\n   Layout of hash_context->tmp: <K> | <V> | (1 byte overlapped 0x00 or 0x01) / <HMAC pad> */\nint uECC_sign_deterministic(const uint8_t *private_key,\n                            const uint8_t *message_hash,\n                            unsigned hash_size,\n                            uECC_HashContext *hash_context,\n                            uint8_t *signature,\n                            uECC_Curve curve) {\n    uint8_t *K = hash_context->tmp;\n    uint8_t *V = K + hash_context->result_size;\n    wordcount_t num_bytes = curve->num_bytes;\n    wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);\n    bitcount_t num_n_bits = curve->num_n_bits;\n    uECC_word_t tries;\n    unsigned i;\n    for (i = 0; i < hash_context->result_size; ++i) {\n        V[i] = 0x01;\n        K[i] = 0;\n    }\n    \n    /* K = HMAC_K(V || 0x00 || int2octets(x) || h(m)) */\n    HMAC_init(hash_context, K);\n    V[hash_context->result_size] = 0x00;\n    HMAC_update(hash_context, V, hash_context->result_size + 1);\n    HMAC_update(hash_context, private_key, num_bytes);\n    HMAC_update(hash_context, message_hash, hash_size);\n    HMAC_finish(hash_context, K, K);\n\n    update_V(hash_context, K, V);\n    \n    /* K = HMAC_K(V || 0x01 || int2octets(x) || h(m)) */\n    HMAC_init(hash_context, K);\n    V[hash_context->result_size] = 0x01;\n    HMAC_update(hash_context, V, hash_context->result_size + 1);\n    HMAC_update(hash_context, private_key, num_bytes);\n    HMAC_update(hash_context, message_hash, hash_size);\n    HMAC_finish(hash_context, K, K);\n\n    update_V(hash_context, K, V);\n\n    for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {\n        uECC_word_t T[uECC_MAX_WORDS];\n        uint8_t *T_ptr = (uint8_t *)T;\n        wordcount_t T_bytes = 0;\n        for (;;) {\n            update_V(hash_context, K, V);\n            for (i = 0; i < hash_context->result_size; ++i) {\n                T_ptr[T_bytes++] = V[i];\n                if (T_bytes >= num_n_words * uECC_WORD_SIZE) {\n                    goto filled;\n                }\n            }\n        }\n    filled:\n        if ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8 > num_n_bits) {\n            uECC_word_t mask = (uECC_word_t)-1;\n            T[num_n_words - 1] &=\n                mask >> ((bitcount_t)(num_n_words * uECC_WORD_SIZE * 8 - num_n_bits));\n        }\n    \n        if (uECC_sign_with_k(private_key, message_hash, hash_size, T, signature, curve)) {\n            return 1;\n        }\n\n        /* K = HMAC_K(V || 0x00) */\n        HMAC_init(hash_context, K);\n        V[hash_context->result_size] = 0x00;\n        HMAC_update(hash_context, V, hash_context->result_size + 1);\n        HMAC_finish(hash_context, K, K);\n\n        update_V(hash_context, K, V);\n    }\n    return 0;\n}\n\nstatic bitcount_t smax(bitcount_t a, bitcount_t b) {\n    return (a > b ? a : b);\n}\n\nint uECC_verify(const uint8_t *public_key,\n                const uint8_t *message_hash,\n                unsigned hash_size,\n                const uint8_t *signature,\n                uECC_Curve curve) {\n    uECC_word_t u1[uECC_MAX_WORDS], u2[uECC_MAX_WORDS];\n    uECC_word_t z[uECC_MAX_WORDS];\n    uECC_word_t public[uECC_MAX_WORDS * 2];\n    uECC_word_t sum[uECC_MAX_WORDS * 2];\n    uECC_word_t rx[uECC_MAX_WORDS];\n    uECC_word_t ry[uECC_MAX_WORDS];\n    uECC_word_t tx[uECC_MAX_WORDS];\n    uECC_word_t ty[uECC_MAX_WORDS];\n    uECC_word_t tz[uECC_MAX_WORDS];\n    const uECC_word_t *points[4];\n    const uECC_word_t *point;\n    bitcount_t num_bits;\n    bitcount_t i;\n    uECC_word_t r[uECC_MAX_WORDS], s[uECC_MAX_WORDS];\n    wordcount_t num_words = curve->num_words;\n    wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);\n    \n    rx[num_n_words - 1] = 0;\n    r[num_n_words - 1] = 0;\n    s[num_n_words - 1] = 0;\n\n    uECC_vli_bytesToNative(public, public_key, curve->num_bytes);\n    uECC_vli_bytesToNative(\n        public + num_words, public_key + curve->num_bytes, curve->num_bytes);\n    uECC_vli_bytesToNative(r, signature, curve->num_bytes);\n    uECC_vli_bytesToNative(s, signature + curve->num_bytes, curve->num_bytes);\n    \n    /* r, s must not be 0. */\n    if (uECC_vli_isZero(r, num_words) || uECC_vli_isZero(s, num_words)) {\n        return 0;\n    }\n\n    /* r, s must be < n. */\n    if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 ||\n            uECC_vli_cmp_unsafe(curve->n, s, num_n_words) != 1) {\n        return 0;\n    }\n\n    /* Calculate u1 and u2. */\n    uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */\n    u1[num_n_words - 1] = 0;\n    bits2int(u1, message_hash, hash_size, curve);\n    uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */\n    uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */\n    \n    /* Calculate sum = G + Q. */\n    uECC_vli_set(sum, public, num_words);\n    uECC_vli_set(sum + num_words, public + num_words, num_words);\n    uECC_vli_set(tx, curve->G, num_words);\n    uECC_vli_set(ty, curve->G + num_words, num_words);\n    uECC_vli_modSub(z, sum, tx, curve->p, num_words); /* z = x2 - x1 */\n    XYcZ_add(tx, ty, sum, sum + num_words, curve);\n    uECC_vli_modInv(z, z, curve->p, num_words); /* z = 1/z */\n    apply_z(sum, sum + num_words, z, curve);\n    \n    /* Use Shamir's trick to calculate u1*G + u2*Q */\n    points[0] = 0;\n    points[1] = curve->G;\n    points[2] = public;\n    points[3] = sum;\n    num_bits = smax(uECC_vli_numBits(u1, num_n_words),\n                    uECC_vli_numBits(u2, num_n_words));\n    \n    point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) |\n                   ((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)];\n    uECC_vli_set(rx, point, num_words);\n    uECC_vli_set(ry, point + num_words, num_words);\n    uECC_vli_clear(z, num_words);\n    z[0] = 1;\n\n    for (i = num_bits - 2; i >= 0; --i) {\n        uECC_word_t index;\n        curve->double_jacobian(rx, ry, z, curve);\n        \n        index = (!!uECC_vli_testBit(u1, i)) | ((!!uECC_vli_testBit(u2, i)) << 1);\n        point = points[index];\n        if (point) {\n            uECC_vli_set(tx, point, num_words);\n            uECC_vli_set(ty, point + num_words, num_words);\n            apply_z(tx, ty, z, curve);\n            uECC_vli_modSub(tz, rx, tx, curve->p, num_words); /* Z = x2 - x1 */\n            XYcZ_add(tx, ty, rx, ry, curve);\n            uECC_vli_modMult_fast(z, z, tz, curve);\n        }\n    }\n\n    uECC_vli_modInv(z, z, curve->p, num_words); /* Z = 1/Z */\n    apply_z(rx, ry, z, curve);\n    \n    /* v = x1 (mod n) */\n    if (uECC_vli_cmp_unsafe(curve->n, rx, num_n_words) != 1) {\n        uECC_vli_sub(rx, rx, curve->n, num_n_words);\n    }\n\n    /* Accept only if v == r. */\n    return (int)(uECC_vli_equal(rx, r, num_words));\n}\n\n#if uECC_ENABLE_VLI_API\n\nunsigned uECC_curve_num_words(uECC_Curve curve) {\n    return curve->num_words;\n}\n\nunsigned uECC_curve_num_bytes(uECC_Curve curve) {\n    return curve->num_bytes;\n}\n\nunsigned uECC_curve_num_bits(uECC_Curve curve) {\n    return curve->num_bytes * 8;\n}\n\nunsigned uECC_curve_num_n_words(uECC_Curve curve) {\n    return BITS_TO_WORDS(curve->num_n_bits);\n}\n\nunsigned uECC_curve_num_n_bytes(uECC_Curve curve) {\n    return BITS_TO_BYTES(curve->num_n_bits);\n}\n\nunsigned uECC_curve_num_n_bits(uECC_Curve curve) {\n    return curve->num_n_bits;\n}\n\nconst uECC_word_t *uECC_curve_p(uECC_Curve curve) {\n    return curve->p;\n}\n\nconst uECC_word_t *uECC_curve_n(uECC_Curve curve) {\n    return curve->n;\n}\n\nconst uECC_word_t *uECC_curve_G(uECC_Curve curve) {\n    return curve->G;\n}\n\nconst uECC_word_t *uECC_curve_b(uECC_Curve curve) {\n    return curve->b;\n}\n\n#if uECC_SUPPORT_COMPRESSED_POINT\nvoid uECC_vli_mod_sqrt(uECC_word_t *a, uECC_Curve curve) {\n    curve->mod_sqrt(a, curve);\n}\n#endif\n\nvoid uECC_vli_mmod_fast(uECC_word_t *result, uECC_word_t *product, uECC_Curve curve) {\n#if (uECC_OPTIMIZATION_LEVEL > 0)\n    curve->mmod_fast(result, product);\n#else\n    uECC_vli_mmod(result, product, curve->p, curve->num_words);\n#endif\n}\n\nvoid uECC_point_mult(uECC_word_t *result,\n                     const uECC_word_t *point,\n                     const uECC_word_t *scalar,\n                     uECC_Curve curve) {\n    uECC_word_t tmp1[uECC_MAX_WORDS];\n    uECC_word_t tmp2[uECC_MAX_WORDS];\n    uECC_word_t *p2[2] = {tmp1, tmp2};\n    uECC_word_t carry = regularize_k(scalar, tmp1, tmp2, curve);\n\n    EccPoint_mult(result, point, p2[!carry], 0, curve->num_n_bits + 1, curve);\n}\n\n#endif /* uECC_ENABLE_VLI_API */\n"
  },
  {
    "path": "u2f/uECC.h",
    "content": "/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */\n\n#ifndef _UECC_H_\n#define _UECC_H_\n\n#include <stdint.h>\n\n/* Platform selection options.\nIf uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros.\nPossible values for uECC_PLATFORM are defined below: */\n#define uECC_arch_other 0\n#define uECC_x86        1\n#define uECC_x86_64     2\n#define uECC_arm        3\n#define uECC_arm_thumb  4\n#define uECC_arm_thumb2 5\n#define uECC_arm64      6\n#define uECC_avr        7\n\n/* If desired, you can define uECC_WORD_SIZE as appropriate for your platform (1, 4, or 8 bytes).\nIf uECC_WORD_SIZE is not explicitly defined then it will be automatically set based on your\nplatform. */\n\n/* Optimization level; trade speed for code size.\n   Larger values produce code that is faster but larger.\n   Currently supported values are 0 - 3; 0 is unusably slow for most applications. */\n#ifndef uECC_OPTIMIZATION_LEVEL\n    #define uECC_OPTIMIZATION_LEVEL 2\n#endif\n\n/* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be\nused for (scalar) squaring instead of the generic multiplication function. This can make things\nfaster somewhat faster, but increases the code size. */\n#ifndef uECC_SQUARE_FUNC\n    #define uECC_SQUARE_FUNC 0\n#endif\n\n/* Curve support selection. Set to 0 to remove that curve. */\n#ifndef uECC_SUPPORTS_secp160r1\n    #define uECC_SUPPORTS_secp160r1 1\n#endif\n#ifndef uECC_SUPPORTS_secp192r1\n    #define uECC_SUPPORTS_secp192r1 1\n#endif\n#ifndef uECC_SUPPORTS_secp224r1\n    #define uECC_SUPPORTS_secp224r1 1\n#endif\n#ifndef uECC_SUPPORTS_secp256r1\n    #define uECC_SUPPORTS_secp256r1 1\n#endif\n#ifndef uECC_SUPPORTS_secp256k1\n    #define uECC_SUPPORTS_secp256k1 1\n#endif\n\n/* Specifies whether compressed point format is supported.\n   Set to 0 to disable point compression/decompression functions. */\n#ifndef uECC_SUPPORT_COMPRESSED_POINT\n    #define uECC_SUPPORT_COMPRESSED_POINT 0\n#endif\n\nstruct uECC_Curve_t;\ntypedef const struct uECC_Curve_t * uECC_Curve;\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n#if uECC_SUPPORTS_secp160r1\nuECC_Curve uECC_secp160r1(void);\n#endif\n#if uECC_SUPPORTS_secp192r1\nuECC_Curve uECC_secp192r1(void);\n#endif\n#if uECC_SUPPORTS_secp224r1\nuECC_Curve uECC_secp224r1(void);\n#endif\n#if uECC_SUPPORTS_secp256r1\nuECC_Curve uECC_secp256r1(void);\n#endif\n#if uECC_SUPPORTS_secp256k1\nuECC_Curve uECC_secp256k1(void);\n#endif\n\n/* uECC_RNG_Function type\nThe RNG function should fill 'size' random bytes into 'dest'. It should return 1 if\n'dest' was filled with random data, or 0 if the random data could not be generated.\nThe filled-in values should be either truly random, or from a cryptographically-secure PRNG.\n\nA correctly functioning RNG function must be set (using uECC_set_rng()) before calling\nuECC_make_key() or uECC_sign().\n\nSetting a correctly functioning RNG function improves the resistance to side-channel attacks\nfor uECC_shared_secret() and uECC_sign_deterministic().\n\nA correct RNG function is set by default when building for Windows, Linux, or OS X.\nIf you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom,\nyou can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined\nRNG function; you must provide your own.\n*/\ntypedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size);\n\n/* uECC_set_rng() function.\nSet the function that will be used to generate random bytes. The RNG function should\nreturn 1 if the random data was generated, or 0 if the random data could not be generated.\n\nOn platforms where there is no predefined RNG function (eg embedded platforms), this must\nbe called before uECC_make_key() or uECC_sign() are used.\n\nInputs:\n    rng_function - The function that will be used to generate random bytes.\n*/\nvoid uECC_set_rng(uECC_RNG_Function rng_function);\n\n/* uECC_make_key() function.\nCreate a public/private key pair.\n\nOutputs:\n    public_key  - Will be filled in with the public key. Must be at least 2 * the curve size\n                  (in bytes) long. For example, if the curve is secp256r1, public_key must be 64\n                  bytes long.\n    private_key - Will be filled in with the private key. Must be as long as the curve order; this\n                  is typically the same as the curve size, except for secp160r1. For example, if the\n                  curve is secp256r1, private_key must be 32 bytes long.\n                  \n                  For secp160r1, private_key must be 21 bytes long! Note that the first byte will \n                  almost always be 0 (there is about a 1 in 2^80 chance of it being non-zero).\n\nReturns 1 if the key pair was generated successfully, 0 if an error occurred.\n*/\nint uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve);\n\n/* uECC_shared_secret() function.\nCompute a shared secret given your secret key and someone else's public key.\nNote: It is recommended that you hash the result of uECC_shared_secret() before using it for\nsymmetric encryption or HMAC.\n\nInputs:\n    public_key  - The public key of the remote party.\n    private_key - Your private key.\n\nOutputs:\n    secret - Will be filled in with the shared secret value. Must be the same size as the\n             curve size; for example, if the curve is secp256r1, secret must be 32 bytes long.\n\nReturns 1 if the shared secret was generated successfully, 0 if an error occurred.\n*/\nint uECC_shared_secret(const uint8_t *public_key,\n                       const uint8_t *private_key,\n                       uint8_t *secret,\n                       uECC_Curve curve);\n\n#if uECC_SUPPORT_COMPRESSED_POINT\n/* uECC_compress() function.\nCompress a public key.\n\nInputs:\n    public_key - The public key to compress.\n\nOutputs:\n    compressed - Will be filled in with the compressed public key. Must be at least\n                 (curve size + 1) bytes long; for example, if the curve is secp256r1,\n                 compressed must be 33 bytes long.\n*/\nvoid uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve);\n\n/* uECC_decompress() function.\nDecompress a compressed public key.\n\nInputs:\n    compressed - The compressed public key.\n\nOutputs:\n    public_key - Will be filled in with the decompressed public key.\n*/\nvoid uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve);\n#endif /* uECC_SUPPORT_COMPRESSED_POINT */\n\n/* uECC_valid_public_key() function.\nCheck to see if a public key is valid.\n\nNote that you are not required to check for a valid public key before using any other uECC\nfunctions. However, you may wish to avoid spending CPU time computing a shared secret or\nverifying a signature using an invalid public key.\n\nInputs:\n    public_key - The public key to check.\n\nReturns 1 if the public key is valid, 0 if it is invalid.\n*/\nint uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve);\n\n/* uECC_compute_public_key() function.\nCompute the corresponding public key for a private key.\n\nInputs:\n    private_key - The private key to compute the public key for\n\nOutputs:\n    public_key - Will be filled in with the corresponding public key\n\nReturns 1 if the key was computed successfully, 0 if an error occurred.\n*/\nint uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve);\n\n/* uECC_sign() function.\nGenerate an ECDSA signature for a given hash value.\n\nUsage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to\nthis function along with your private key.\n\nInputs:\n    private_key  - Your private key.\n    message_hash - The hash of the message to sign.\n    hash_size    - The size of message_hash in bytes.\n\nOutputs:\n    signature - Will be filled in with the signature value. Must be at least 2 * curve size long.\n                For example, if the curve is secp256r1, signature must be 64 bytes long.\n\nReturns 1 if the signature generated successfully, 0 if an error occurred.\n*/\nint uECC_sign(const uint8_t *private_key,\n              const uint8_t *message_hash,\n              unsigned hash_size,\n              uint8_t *signature,\n              uECC_Curve curve);\n\n/* uECC_HashContext structure.\nThis is used to pass in an arbitrary hash function to uECC_sign_deterministic().\nThe structure will be used for multiple hash computations; each time a new hash\nis computed, init_hash() will be called, followed by one or more calls to\nupdate_hash(), and finally a call to finish_hash() to prudoce the resulting hash.\n\nThe intention is that you will create a structure that includes uECC_HashContext\nfollowed by any hash-specific data. For example:\n\ntypedef struct SHA256_HashContext {\n    uECC_HashContext uECC;\n    SHA256_CTX ctx;\n} SHA256_HashContext;\n\nvoid init_SHA256(uECC_HashContext *base) {\n    SHA256_HashContext *context = (SHA256_HashContext *)base;\n    SHA256_Init(&context->ctx);\n}\n\nvoid update_SHA256(uECC_HashContext *base,\n                   const uint8_t *message,\n                   unsigned message_size) {\n    SHA256_HashContext *context = (SHA256_HashContext *)base;\n    SHA256_Update(&context->ctx, message, message_size);\n}\n\nvoid finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) {\n    SHA256_HashContext *context = (SHA256_HashContext *)base;\n    SHA256_Final(hash_result, &context->ctx);\n}\n\n... when signing ...\n{\n    uint8_t tmp[32 + 32 + 64];\n    SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}};\n    uECC_sign_deterministic(key, message_hash, &ctx.uECC, signature);\n}\n*/\ntypedef struct uECC_HashContext {\n    void (*init_hash)(struct uECC_HashContext *context);\n    void (*update_hash)(struct uECC_HashContext *context,\n                        const uint8_t *message,\n                        unsigned message_size);\n    void (*finish_hash)(struct uECC_HashContext *context, uint8_t *hash_result);\n    unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */\n    unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */\n    uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */\n} uECC_HashContext;\n\n/* uECC_sign_deterministic() function.\nGenerate an ECDSA signature for a given hash value, using a deterministic algorithm\n(see RFC 6979). You do not need to set the RNG using uECC_set_rng() before calling\nthis function; however, if the RNG is defined it will improve resistance to side-channel\nattacks.\n\nUsage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to\nthis function along with your private key and a hash context. Note that the message_hash\ndoes not need to be computed with the same hash function used by hash_context.\n\nInputs:\n    private_key  - Your private key.\n    message_hash - The hash of the message to sign.\n    hash_size    - The size of message_hash in bytes.\n    hash_context - A hash context to use.\n\nOutputs:\n    signature - Will be filled in with the signature value.\n\nReturns 1 if the signature generated successfully, 0 if an error occurred.\n*/\nint uECC_sign_deterministic(const uint8_t *private_key,\n                            const uint8_t *message_hash,\n                            unsigned hash_size,\n                            uECC_HashContext *hash_context,\n                            uint8_t *signature,\n                            uECC_Curve curve);\n\n/* uECC_verify() function.\nVerify an ECDSA signature.\n\nUsage: Compute the hash of the signed data using the same hash as the signer and\npass it to this function along with the signer's public key and the signature values (r and s).\n\nInputs:\n    public_key   - The signer's public key.\n    message_hash - The hash of the signed data.\n    hash_size    - The size of message_hash in bytes.\n    signature    - The signature value.\n\nReturns 1 if the signature is valid, 0 if it is invalid.\n*/\nint uECC_verify(const uint8_t *private_key,\n                const uint8_t *message_hash,\n                unsigned hash_size,\n                const uint8_t *signature,\n                uECC_Curve curve);\n\n#ifdef __cplusplus\n} /* end of extern \"C\" */\n#endif\n\n#endif /* _UECC_H_ */\n"
  },
  {
    "path": "u2f/uECC_vli.h",
    "content": "/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */\n\n#ifndef _UECC_VLI_H_\n#define _UECC_VLI_H_\n\n#include \"uECC.h\"\n#include \"types.h\"\n\n/* Functions for raw large-integer manipulation. These are only available\n   if uECC.c is compiled with uECC_ENABLE_VLI_API defined to 1. */\n#ifndef uECC_ENABLE_VLI_API\n    #define uECC_ENABLE_VLI_API 0\n#endif\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n#if uECC_ENABLE_VLI_API\n\nvoid uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words);\n\n/* Constant-time comparison to zero - secure way to compare long integers */\n/* Returns 1 if vli == 0, 0 otherwise. */\nuECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words);\n\n/* Returns nonzero if bit 'bit' of vli is set. */\nuECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit);\n\n/* Counts the number of bits required to represent vli. */\nbitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words);\n\n/* Sets dest = src. */\nvoid uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words);\n\n/* Constant-time comparison function - secure way to compare long integers */\n/* Returns one if left == right, zero otherwise */\nuECC_word_t uECC_vli_equal(const uECC_word_t *left,\n                           const uECC_word_t *right,\n                           wordcount_t num_words);\n\n/* Constant-time comparison function - secure way to compare long integers */\n/* Returns sign of left - right, in constant time. */\ncmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right, wordcount_t num_words);\n\n/* Computes vli = vli >> 1. */\nvoid uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words);\n\n/* Computes result = left + right, returning carry. Can modify in place. */\nuECC_word_t uECC_vli_add(uECC_word_t *result,\n                         const uECC_word_t *left,\n                         const uECC_word_t *right,\n                         wordcount_t num_words);\n\n/* Computes result = left - right, returning borrow. Can modify in place. */\nuECC_word_t uECC_vli_sub(uECC_word_t *result,\n                         const uECC_word_t *left,\n                         const uECC_word_t *right,\n                         wordcount_t num_words);\n\n/* Computes result = left * right. Result must be 2 * num_words long. */\nvoid uECC_vli_mult(uECC_word_t *result,\n                   const uECC_word_t *left,\n                   const uECC_word_t *right,\n                   wordcount_t num_words);\n\n/* Computes result = left^2. Result must be 2 * num_words long. */\nvoid uECC_vli_square(uECC_word_t *result, const uECC_word_t *left, wordcount_t num_words);\n\n/* Computes result = (left + right) % mod.\n   Assumes that left < mod and right < mod, and that result does not overlap mod. */\nvoid uECC_vli_modAdd(uECC_word_t *result,\n                     const uECC_word_t *left,\n                     const uECC_word_t *right,\n                     const uECC_word_t *mod,\n                     wordcount_t num_words);\n\n/* Computes result = (left - right) % mod.\n   Assumes that left < mod and right < mod, and that result does not overlap mod. */\nvoid uECC_vli_modSub(uECC_word_t *result,\n                     const uECC_word_t *left,\n                     const uECC_word_t *right,\n                     const uECC_word_t *mod,\n                     wordcount_t num_words);\n\n/* Computes result = product % mod, where product is 2N words long.\n   Currently only designed to work for mod == curve->p or curve_n. */\nvoid uECC_vli_mmod(uECC_word_t *result,\n                   uECC_word_t *product,\n                   const uECC_word_t *mod,\n                   wordcount_t num_words);\n\n/* Calculates result = product (mod curve->p), where product is up to\n   2 * curve->num_words long. */\nvoid uECC_vli_mmod_fast(uECC_word_t *result, uECC_word_t *product, uECC_Curve curve);\n\n/* Computes result = (left * right) % mod.\n   Currently only designed to work for mod == curve->p or curve_n. */\nvoid uECC_vli_modMult(uECC_word_t *result,\n                      const uECC_word_t *left,\n                      const uECC_word_t *right,\n                      const uECC_word_t *mod,\n                      wordcount_t num_words);\n\n/* Computes result = (left * right) % curve->p. */\nvoid uECC_vli_modMult_fast(uECC_word_t *result,\n                           const uECC_word_t *left,\n                           const uECC_word_t *right,\n                           uECC_Curve curve);\n\n/* Computes result = left^2 % mod.\n   Currently only designed to work for mod == curve->p or curve_n. */\nvoid uECC_vli_modSquare(uECC_word_t *result,\n                        const uECC_word_t *left,\n                        const uECC_word_t *mod,\n                        wordcount_t num_words);\n\n/* Computes result = left^2 % curve->p. */\nvoid uECC_vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left, uECC_Curve curve);\n\n/* Computes result = (1 / input) % mod.*/\nvoid uECC_vli_modInv(uECC_word_t *result,\n                     const uECC_word_t *input,\n                     const uECC_word_t *mod,\n                     wordcount_t num_words);\n\n#if uECC_SUPPORT_COMPRESSED_POINT\n/* Calculates a = sqrt(a) (mod curve->p) */\nvoid uECC_vli_mod_sqrt(uECC_word_t *a, uECC_Curve curve);\n#endif\n\n/* Converts an integer in uECC native format to big-endian bytes. */\nvoid uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes, const uECC_word_t *native);\n/* Converts big-endian bytes to an integer in uECC native format. */\nvoid uECC_vli_bytesToNative(uECC_word_t *native, const uint8_t *bytes, int num_bytes);\n\nunsigned uECC_curve_num_words(uECC_Curve curve);\nunsigned uECC_curve_num_bytes(uECC_Curve curve);\nunsigned uECC_curve_num_bits(uECC_Curve curve);\nunsigned uECC_curve_num_n_words(uECC_Curve curve);\nunsigned uECC_curve_num_n_bytes(uECC_Curve curve);\nunsigned uECC_curve_num_n_bits(uECC_Curve curve);\n\nconst uECC_word_t *uECC_curve_p(uECC_Curve curve);\nconst uECC_word_t *uECC_curve_n(uECC_Curve curve);\nconst uECC_word_t *uECC_curve_G(uECC_Curve curve);\nconst uECC_word_t *uECC_curve_b(uECC_Curve curve);\n\nint uECC_valid_point(const uECC_word_t *point, uECC_Curve curve);\n\n/* Multiplies a point by a scalar. Points are represented by the X coordinate followed by\n   the Y coordinate in the same array, both coordinates are curve->num_words long. Note\n   that scalar must be curve->num_n_words long (NOT curve->num_words). */\nvoid uECC_point_mult(uECC_word_t *result,\n                     const uECC_word_t *point,\n                     const uECC_word_t *scalar,\n                     uECC_Curve curve);\n\n/* Generates a random integer in the range 0 < random < top.\n   Both random and top have num_words words. */\nint uECC_generate_random_int(uECC_word_t *random,\n                             const uECC_word_t *top,\n                             wordcount_t num_words);\n\n#endif /* uECC_ENABLE_VLI_API */\n\n#ifdef __cplusplus\n} /* end of extern \"C\" */\n#endif\n\n#endif /* _UECC_VLI_H_ */\n"
  },
  {
    "path": "usb_desc.h",
    "content": "/* Teensyduino Core Library\n * http://www.pjrc.com/teensy/\n * Copyright (c) 2013 PJRC.COM, LLC.\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * 1. The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * 2. If the Software is incorporated into a build system that allows\n * selection among a list of target devices, then similar target\n * devices manufactured by PJRC.COM must be included in the list of\n * target devices and selectable in the same manner.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#ifndef _usb_desc_h_\n#define _usb_desc_h_\n\n// This header is NOT meant to be included when compiling\n// user sketches in Arduino.  The low-level functions\n// provided by usb_dev.c are meant to be called only by\n// code which provides higher-level interfaces to the user.\n\n#include <stdint.h>\n#include <stddef.h>\n\n#define ENDPOINT_UNUSED\t\t\t0x00\n#define ENDPOINT_TRANSIMIT_ONLY\t\t0x15\n#define ENDPOINT_RECEIVE_ONLY\t\t0x19\n#define ENDPOINT_TRANSMIT_AND_RECEIVE\t0x1D\n\n/*\nEach group of #define lines below corresponds to one of the\nsettings in the Tools > USB Type menu.  This file defines what\ntype of USB device is actually created for each of those menu\noptions.\n\nEach \"interface\" is a set of functionality your PC or Mac will\nuse and treat as if it is a unique device.  Within each interface,\nthe \"endpoints\" are the actual communication channels.  Most\ninterfaces use 1, 2 or 3 endpoints.  By editing only this file,\nyou can customize the USB Types to be any collection of interfaces.\n\nTo modify a USB Type, delete the XYZ_INTERFACE lines for any\ninterfaces you wish to remove, and copy them from another USB Type\nfor any you want to add.\n\nGive each interface a unique number, and edit NUM_INTERFACE to\nreflect the total number of interfaces.\n\nNext, assign unique endpoint numbers to all the endpoints across\nall the interfaces your device has.  You can reuse an endpoint\nnumber for transmit and receive, but the same endpoint number must\nnot be used twice to transmit, or twice to receive.\n\nMost endpoints also require their maximum size, and some also\nneed an interval specification (the number of milliseconds the\nPC will check for data from that endpoint).  For existing\ninterfaces, usually these other settings should not be changed.\n\nEdit NUM_ENDPOINTS to be at least the largest endpoint number used.\n\nEdit NUM_USB_BUFFERS to control how much memory the USB stack will\nallocate.  At least 2 should be used for each endpoint.  More\nmemory will allow higher throughput for user programs that have\nhigh latency (eg, spending time doing things other than interacting\nwith the USB).\n\nEdit the ENDPOINT*_CONFIG lines so each endpoint is configured\nthe proper way (transmit, receive, or both).\n\nIf you are using existing interfaces (making your own device with\na different set of interfaces) the code in all other files should\nautomatically adapt to the new endpoints you specify here.\n\nIf you need to create a new type of interface, you'll need to write\nthe code which sends and receives packets, and presents an API to\nthe user.  Usually, a pair of files are added for the actual code,\nand code is also added in usb_dev.c for any control transfers,\ninterrupt-level code, or other very low-level stuff not possible\nfrom the packet send/receive functons.  Code also is added in\nusb_inst.c to create an instance of your C++ object.\n\nYou may edit the Vendor and Product ID numbers, and strings.  If\nthe numbers are changed, Teensyduino may not be able to automatically\nfind and reboot your board when you click the Upload button in\nthe Arduino IDE.  You will need to press the Program button on\nTeensy to initiate programming.\n\nSome operating systems, especially Windows, may cache USB device\ninfo.  Changes to the device name may not update on the same\ncomputer unless the vendor or product ID numbers change, or the\n\"bcdDevice\" revision code is increased.\n\nIf these instructions are missing steps or could be improved, please\nlet me know?  http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports\n*/\n\n\n#if defined(USB_SERIAL)\n  #define VENDOR_ID\t\t0x16C0\n  #define PRODUCT_ID\t\t0x0483\n  #define DEVICE_CLASS\t\t2\t// 2 = Communication Class\n  #define MANUFACTURER_NAME\t{'T','e','e','n','s','y','d','u','i','n','o'}\n  #define MANUFACTURER_NAME_LEN\t11\n  #define PRODUCT_NAME\t\t{'U','S','B',' ','S','e','r','i','a','l'}\n  #define PRODUCT_NAME_LEN\t10\n  #define EP0_SIZE\t\t64\n  #define NUM_ENDPOINTS\t\t4\n  #define NUM_USB_BUFFERS\t12\n  #define NUM_INTERFACE\t\t2\n  #define CDC_STATUS_INTERFACE\t0\n  #define CDC_DATA_INTERFACE\t1\n  #define CDC_ACM_ENDPOINT\t2\n  #define CDC_RX_ENDPOINT       3\n  #define CDC_TX_ENDPOINT       4\n  #define CDC_ACM_SIZE          16\n  #define CDC_RX_SIZE           64\n  #define CDC_TX_SIZE           64\n  #define ENDPOINT2_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n  #define ENDPOINT3_CONFIG\tENDPOINT_RECEIVE_ONLY\n  #define ENDPOINT4_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n\n#elif defined(USB_HID)\n  #define VENDOR_ID\t\t0x16C0\n  #define PRODUCT_ID\t\t0x0482\n  #define MANUFACTURER_NAME\t{'T','e','e','n','s','y','d','u','i','n','o'}\n  #define MANUFACTURER_NAME_LEN\t11\n  #define PRODUCT_NAME\t\t{'K','e','y','b','o','a','r','d','/','M','o','u','s','e','/','J','o','y','s','t','i','c','k'}\n  #define PRODUCT_NAME_LEN\t23\n  #define EP0_SIZE\t\t64\n  #define NUM_ENDPOINTS         5\n  #define NUM_USB_BUFFERS\t24\n  #define NUM_INTERFACE\t\t4\n  #define SEREMU_INTERFACE      2\t// Serial emulation\n  #define SEREMU_TX_ENDPOINT    1\n  #define SEREMU_TX_SIZE        64\n  #define SEREMU_TX_INTERVAL    1\n  #define SEREMU_RX_ENDPOINT    2\n  #define SEREMU_RX_SIZE        32\n  #define SEREMU_RX_INTERVAL    2\n  #define KEYBOARD_INTERFACE    0\t// Keyboard\n  #define KEYBOARD_ENDPOINT     3\n  #define KEYBOARD_SIZE         8\n  #define KEYBOARD_INTERVAL     1\n  #define MOUSE_INTERFACE       1\t// Mouse\n  #define MOUSE_ENDPOINT        5\n  #define MOUSE_SIZE            8\n  #define MOUSE_INTERVAL        1\n  #define JOYSTICK_INTERFACE    3\t// Joystick\n  #define JOYSTICK_ENDPOINT     4\n  #define JOYSTICK_SIZE         16\n  #define JOYSTICK_INTERVAL     2\n  #define ENDPOINT1_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n  #define ENDPOINT2_CONFIG\tENDPOINT_RECEIVE_ONLY\n  #define ENDPOINT3_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n  #define ENDPOINT4_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n  #define ENDPOINT5_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n\n#elif defined(USB_SERIAL_HID)\n  #define VENDOR_ID\t\t0x16C0\n  #define PRODUCT_ID\t\t0x0487\n  #define DEVICE_CLASS\t\t0xEF\n  #define DEVICE_SUBCLASS\t0x02\n  #define DEVICE_PROTOCOL\t0x01\n  #define MANUFACTURER_NAME\t{'T','e','e','n','s','y','d','u','i','n','o'}\n  #define MANUFACTURER_NAME_LEN\t11\n  #define PRODUCT_NAME\t\t{'S','e','r','i','a','l','/','K','e','y','b','o','a','r','d','/','M','o','u','s','e','/','J','o','y','s','t','i','c','k'}\n  #define PRODUCT_NAME_LEN\t30\n  #define EP0_SIZE\t\t64\n  #define NUM_ENDPOINTS\t\t6\n  #define NUM_USB_BUFFERS\t30\n  #define NUM_INTERFACE\t\t5\n  #define CDC_IAD_DESCRIPTOR\t1\n  #define CDC_STATUS_INTERFACE\t0\n  #define CDC_DATA_INTERFACE\t1\t// Serial\n  #define CDC_ACM_ENDPOINT\t2\n  #define CDC_RX_ENDPOINT       3\n  #define CDC_TX_ENDPOINT       4\n  #define CDC_ACM_SIZE          16\n  #define CDC_RX_SIZE           64\n  #define CDC_TX_SIZE           64\n  #define KEYBOARD_INTERFACE    2\t// Keyboard\n  #define KEYBOARD_ENDPOINT     1\n  #define KEYBOARD_SIZE         8\n  #define KEYBOARD_INTERVAL     1\n  #define MOUSE_INTERFACE       3\t// Mouse\n  #define MOUSE_ENDPOINT        5\n  #define MOUSE_SIZE            8\n  #define MOUSE_INTERVAL        2\n  #define JOYSTICK_INTERFACE    4\t// Joystick\n  #define JOYSTICK_ENDPOINT     6\n  #define JOYSTICK_SIZE         16\n  #define JOYSTICK_INTERVAL     1\n  #define ENDPOINT1_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n  #define ENDPOINT2_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n  #define ENDPOINT3_CONFIG\tENDPOINT_RECEIVE_ONLY\n  #define ENDPOINT4_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n  #define ENDPOINT5_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n  #define ENDPOINT6_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n\n#elif defined(USB_MIDI)\n  #define VENDOR_ID\t\t0x16C0\n  #define PRODUCT_ID\t\t0x0485\n  #define MANUFACTURER_NAME\t{'T','e','e','n','s','y','d','u','i','n','o'}\n  #define MANUFACTURER_NAME_LEN\t11\n  #define PRODUCT_NAME\t\t{'T','e','e','n','s','y',' ','M','I','D','I'}\n  #define PRODUCT_NAME_LEN\t11\n  #define EP0_SIZE\t\t64\n  #define NUM_ENDPOINTS         4\n  #define NUM_USB_BUFFERS\t16\n  #define NUM_INTERFACE\t\t2\n  #define SEREMU_INTERFACE      1\t// Serial emulation\n  #define SEREMU_TX_ENDPOINT    1\n  #define SEREMU_TX_SIZE        64\n  #define SEREMU_TX_INTERVAL    1\n  #define SEREMU_RX_ENDPOINT    2\n  #define SEREMU_RX_SIZE        32\n  #define SEREMU_RX_INTERVAL    2\n  #define MIDI_INTERFACE        0\t// MIDI\n  #define MIDI_TX_ENDPOINT      3\n  #define MIDI_TX_SIZE          64\n  #define MIDI_RX_ENDPOINT      4\n  #define MIDI_RX_SIZE          64\n  #define ENDPOINT1_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n  #define ENDPOINT2_CONFIG\tENDPOINT_RECEIVE_ONLY\n  #define ENDPOINT3_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n  #define ENDPOINT4_CONFIG\tENDPOINT_RECEIVE_ONLY\n\n#elif defined(USB_RAWHID)\n  #define VENDOR_ID\t\t0x16C0\n  #define PRODUCT_ID\t\t0x0486\n//  #define RAWHID_USAGE_PAGE\t0xFFAB  // recommended: 0xFF00 to 0xFFFF\n//  #define RAWHID_USAGE\t\t0x0200  // recommended: 0x0100 to 0xFFFF\n  #define RAWHID_USAGE_PAGE\t0xf1d0  // recommended: 0xFF00 to 0xFFFF\n  #define RAWHID_USAGE\t\t0x01  // recommended: 0x0100 to 0xFFFF\n\n  #define MANUFACTURER_NAME\t{'T','e','e','n','s','y','d','u','i','n','o'}\n  #define MANUFACTURER_NAME_LEN\t11\n  #define PRODUCT_NAME\t\t{'T','e','e','n','s','y','d','u','i','n','o',' ','U','2','F','H','I','D'}\n  #define PRODUCT_NAME_LEN\t18\n  #define EP0_SIZE\t\t64\n  #define NUM_ENDPOINTS         6\n  #define NUM_USB_BUFFERS\t12\n  #define NUM_INTERFACE\t\t2\n  #define RAWHID_INTERFACE      0\t// RawHID\n  #define RAWHID_TX_ENDPOINT    3\n  #define RAWHID_TX_SIZE        64\n  #define RAWHID_TX_INTERVAL    1\n  #define RAWHID_RX_ENDPOINT    4\n  #define RAWHID_RX_SIZE        64\n  #define RAWHID_RX_INTERVAL    1\n  #define SEREMU_INTERFACE      1\t// Serial emulation\n  #define SEREMU_TX_ENDPOINT    1\n  #define SEREMU_TX_SIZE        64\n  #define SEREMU_TX_INTERVAL    1\n  #define SEREMU_RX_ENDPOINT    2\n  #define SEREMU_RX_SIZE        32\n  #define SEREMU_RX_INTERVAL    2\n  #define ENDPOINT1_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n  #define ENDPOINT2_CONFIG\tENDPOINT_RECEIVE_ONLY\n  #define ENDPOINT3_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n  #define ENDPOINT4_CONFIG\tENDPOINT_RECEIVE_ONLY\n\n#elif defined(USB_FLIGHTSIM)\n  #define VENDOR_ID\t\t0x16C0\n  #define PRODUCT_ID\t\t0x0488\n  #define MANUFACTURER_NAME\t{'T','e','e','n','s','y','d','u','i','n','o'}\n  #define MANUFACTURER_NAME_LEN\t11\n  #define PRODUCT_NAME\t\t{'T','e','e','n','s','y',' ','F','l','i','g','h','t',' ','S','i','m',' ','C','o','n','t','r','o','l','s'}\n  #define PRODUCT_NAME_LEN\t26\n  #define EP0_SIZE\t\t64\n  #define NUM_ENDPOINTS         4\n  #define NUM_USB_BUFFERS\t20\n  #define NUM_INTERFACE\t\t2\n  #define FLIGHTSIM_INTERFACE\t0\t// Flight Sim Control\n  #define FLIGHTSIM_TX_ENDPOINT\t3\n  #define FLIGHTSIM_TX_SIZE\t64\n  #define FLIGHTSIM_TX_INTERVAL\t1\n  #define FLIGHTSIM_RX_ENDPOINT\t4\n  #define FLIGHTSIM_RX_SIZE\t64\n  #define FLIGHTSIM_RX_INTERVAL\t1\n  #define SEREMU_INTERFACE      1\t// Serial emulation\n  #define SEREMU_TX_ENDPOINT    1\n  #define SEREMU_TX_SIZE        64\n  #define SEREMU_TX_INTERVAL    1\n  #define SEREMU_RX_ENDPOINT    2\n  #define SEREMU_RX_SIZE        32\n  #define SEREMU_RX_INTERVAL    2\n  #define ENDPOINT1_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n  #define ENDPOINT2_CONFIG\tENDPOINT_RECEIVE_ONLY\n  #define ENDPOINT3_CONFIG\tENDPOINT_TRANSIMIT_ONLY\n  #define ENDPOINT4_CONFIG\tENDPOINT_RECEIVE_ONLY\n\n#endif\n\n#ifdef USB_DESC_LIST_DEFINE\n#if defined(NUM_ENDPOINTS) && NUM_ENDPOINTS > 0\n// NUM_ENDPOINTS = number of non-zero endpoints (0 to 15)\nextern const uint8_t usb_endpoint_config_table[NUM_ENDPOINTS];\n\ntypedef struct {\n\tuint16_t\twValue;\n\tuint16_t\twIndex;\n\tconst uint8_t\t*addr;\n\tuint16_t\tlength;\n} usb_descriptor_list_t;\n\nextern const usb_descriptor_list_t usb_descriptor_list[];\n#endif // NUM_ENDPOINTS\n#endif // USB_DESC_LIST_DEFINE\n\n#endif\n"
  }
]