/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */ /* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */ /*****************************************************************************/ /* STDINT.H */ /* */ /* Copyright (c) 2002 Texas Instruments Incorporated */ /* http://www.ti.com/ */ /* */ /* Redistribution and use in source and binary forms, with or without */ /* modification, are permitted provided that the following conditions */ /* are met: */ /* */ /* Redistributions of source code must retain the above copyright */ /* notice, this list of conditions and the following disclaimer. */ /* */ /* Redistributions in binary form must reproduce the above copyright */ /* notice, this list of conditions and the following disclaimer in */ /* the documentation and/or other materials provided with the */ /* distribution. */ /* */ /* Neither the name of Texas Instruments Incorporated nor the names */ /* of its contributors may be used to endorse or promote products */ /* derived from this software without specific prior written */ /* permission. */ /* */ /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* */ /*****************************************************************************/ /*****************************************************************************/ /* _ti_config.h */ /* */ /* Copyright (c) 2017 Texas Instruments Incorporated */ /* http://www.ti.com/ */ /* */ /* Redistribution and use in source and binary forms, with or without */ /* modification, are permitted provided that the following conditions */ /* are met: */ /* */ /* Redistributions of source code must retain the above copyright */ /* notice, this list of conditions and the following disclaimer. */ /* */ /* Redistributions in binary form must reproduce the above copyright */ /* notice, this list of conditions and the following disclaimer in */ /* the documentation and/or other materials provided with the */ /* distribution. */ /* */ /* Neither the name of Texas Instruments Incorporated nor the names */ /* of its contributors may be used to endorse or promote products */ /* derived from this software without specific prior written */ /* permission. */ /* */ /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* */ /*****************************************************************************/ /*Unsupported pragmas are omitted */ # pragma diag_push # pragma CHECK_MISRA("-19.7") # pragma CHECK_MISRA("-19.4") # pragma CHECK_MISRA("-19.1") # pragma CHECK_MISRA("-19.15") # pragma diag_pop _Pragma("diag_push") _Pragma("CHECK_MISRA(\"-19.4\")") _Pragma("CHECK_MISRA(\"-19.1\")") _Pragma("CHECK_MISRA(\"-19.6\")") /* Hide uses of the TI proprietary macros behind other macros. Implementations that don't implement these features should leave these macros undefined. */ /* Common definitions */ /* C */ /* C89/C99 */ /* _TI_NOEXCEPT_CPP14 is defined to noexcept only when compiling for C++14. It is intended to be used for functions like abort and atexit that are supposed to be declared noexcept only in C++14 mode. */ /* Target-specific definitions */ /*****************************************************************************/ /* linkage.h */ /* */ /* Copyright (c) 1998 Texas Instruments Incorporated */ /* http://www.ti.com/ */ /* */ /* Redistribution and use in source and binary forms, with or without */ /* modification, are permitted provided that the following conditions */ /* are met: */ /* */ /* Redistributions of source code must retain the above copyright */ /* notice, this list of conditions and the following disclaimer. */ /* */ /* Redistributions in binary form must reproduce the above copyright */ /* notice, this list of conditions and the following disclaimer in */ /* the documentation and/or other materials provided with the */ /* distribution. */ /* */ /* Neither the name of Texas Instruments Incorporated nor the names */ /* of its contributors may be used to endorse or promote products */ /* derived from this software without specific prior written */ /* permission. */ /* */ /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* */ /*****************************************************************************/ #pragma diag_push #pragma CHECK_MISRA("-19.4") /* No modifiers are needed to access code or data */ /*--------------------------------------------------------------------------*/ /* Define _IDECL ==> how inline functions are declared */ /*--------------------------------------------------------------------------*/ #pragma diag_pop _Pragma("diag_pop") _Pragma("diag_push") _Pragma("CHECK_MISRA(\"-19.1\")") /* no code before #include */ _Pragma("CHECK_MISRA(\"-19.7\")") /* prefer functions to macros */ /*****************************************************************************/ /* _STDINT40.H */ /* */ /* Copyright (c) 2018 Texas Instruments Incorporated */ /* http://www.ti.com/ */ /* */ /* Redistribution and use in source and binary forms, with or without */ /* modification, are permitted provided that the following conditions */ /* are met: */ /* */ /* Redistributions of source code must retain the above copyright */ /* notice, this list of conditions and the following disclaimer. */ /* */ /* Redistributions in binary form must reproduce the above copyright */ /* notice, this list of conditions and the following disclaimer in */ /* the documentation and/or other materials provided with the */ /* distribution. */ /* */ /* Neither the name of Texas Instruments Incorporated nor the names */ /* of its contributors may be used to endorse or promote products */ /* derived from this software without specific prior written */ /* permission. */ /* */ /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* */ /*****************************************************************************/ _Pragma("diag_push") _Pragma("CHECK_MISRA(\"-19.7\")") /* prefer functions to macros */ /* According to footnotes in the 1999 C standard, "C++ implementations should define these macros only when __STDC_LIMIT_MACROS is defined before is included." */ _Pragma("diag_pop") /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2001 Mike Barcroft * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Berkeley Software Design, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)cdefs.h 8.8 (Berkeley) 1/9/95 * $FreeBSD$ */ _Pragma("diag_push") _Pragma("CHECK_MISRA(\"none\")") /* * Testing against Clang-specific extensions. */ /* * This code has been put in place to help reduce the addition of * compiler specific defines in FreeBSD code. It helps to aid in * having a compiler-agnostic source tree. */ /* * Macro to test if we're using a specific version of gcc or later. */ /* * The __CONCAT macro is used to concatenate parts of symbol names, e.g. * with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces oldfoo. * The __CONCAT macro is a bit tricky to use if it must work in non-ANSI * mode -- there must be no spaces between its arguments, and for nested * __CONCAT's, all the __CONCAT's must be at the left. __CONCAT can also * concatenate double-quoted strings produced by the __STRING macro, but * this only works with ANSI C. * * __XSTRING is like __STRING, but it expands any macros in its argument * first. It is only available with ANSI C. */ /* * Compiler-dependent macros to help declare dead (non-returning) and * pure (no side effects) functions, and unused variables. They are * null except for versions of gcc that are known to support the features * properly (old versions of gcc-2 supported the dead and pure features * in a different (wrong) way). If we do not provide an implementation * for a given compiler, let the compile fail if it is told to use * a feature that we cannot live without. */ /* * TI ADD - check that __GNUC__ is defined before referencing it to avoid * generating an error when __GNUC__ treated as zero warning is * promoted to an error via -pdse195 option. */ /* * Keywords added in C11. */ /* * No native support for _Atomic(). Place object in structure to prevent * most forms of direct non-atomic access. */ /* * XXX: Some compilers (Clang 3.3, GCC 4.7) falsely announce C++11 mode * without actually supporting the thread_local keyword. Don't check for * the presence of C++11 when defining _Thread_local. */ /* * Emulation of C11 _Generic(). Unlike the previously defined C11 * keywords, it is not possible to implement this using exactly the same * syntax. Therefore implement something similar under the name * __generic(). Unlike _Generic(), this macro can only distinguish * between a single type, so it requires nested invocations to * distinguish multiple cases. */ /* * C99 Static array indices in function parameter declarations. Syntax such as: * void bar(int myArray[static 10]); * is allowed in C99 but not in C++. Define __min_size appropriately so * headers using it can be compiled in either language. Use like this: * void bar(int myArray[__min_size(10)]); */ /* XXX: should use `#if __STDC_VERSION__ < 199901'. */ /* C++11 exposes a load of C99 stuff */ /* * GCC 2.95 provides `__restrict' as an extension to C90 to support the * C99-specific `restrict' type qualifier. We happen to use `__restrict' as * a way to define the `restrict' type qualifier without disturbing older * software that is unaware of C99 keywords. * The TI compiler supports __restrict in all compilation modes. */ /* * GNU C version 2.96 adds explicit branch prediction so that * the CPU back-end can hint the processor and also so that * code blocks can be reordered such that the predicted path * sees a more linear flow, thus improving cache behavior, etc. * * The following two macros provide us with a way to utilize this * compiler feature. Use __predict_true() if you expect the expression * to evaluate to true, and __predict_false() if you expect the * expression to evaluate to false. * * A few notes about usage: * * * Generally, __predict_false() error condition checks (unless * you have some _strong_ reason to do otherwise, in which case * document it), and/or __predict_true() `no-error' condition * checks, assuming you want to optimize for the no-error case. * * * Other than that, if you don't know the likelihood of a test * succeeding from empirical or other `hard' evidence, don't * make predictions. * * * These are meant to be used in places that are run `a lot'. * It is wasteful to make predictions in code that is run * seldomly (e.g. at subsystem initialization time) as the * basic block reordering that this affects can often generate * larger code. */ /* * We define this here since , , and * require it. */ /* * Given the pointer x to the member m of the struct s, return * a pointer to the containing structure. When using GCC, we first * assign pointer x to a local variable, to check that its type is * compatible with member m. */ /* * Compiler-dependent macros to declare that functions take printf-like * or scanf-like arguments. They are null except for versions of gcc * that are known to support the features properly (old versions of gcc-2 * didn't permit keeping the keywords out of the application namespace). */ /* Compiler-dependent macros that rely on FreeBSD-specific extensions. */ /* * The following definition might not work well if used in header files, * but it should be better than nothing. If you want a "do nothing" * version, then it should generate some harmless declaration, such as: * #define __IDSTRING(name,string) struct __hack */ /* * Embed the rcs id of a source file in the resulting library. Note that in * more recent ELF binutils, we use .ident allowing the ID to be stripped. * Usage: * __FBSDID("$FreeBSD$"); */ /*- * The following definitions are an extension of the behavior originally * implemented in , but with a different level of granularity. * POSIX.1 requires that the macros we test be defined before any standard * header file is included. * * Here's a quick run-down of the versions: * defined(_POSIX_SOURCE) 1003.1-1988 * _POSIX_C_SOURCE == 1 1003.1-1990 * _POSIX_C_SOURCE == 2 1003.2-1992 C Language Binding Option * _POSIX_C_SOURCE == 199309 1003.1b-1993 * _POSIX_C_SOURCE == 199506 1003.1c-1995, 1003.1i-1995, * and the omnibus ISO/IEC 9945-1: 1996 * _POSIX_C_SOURCE == 200112 1003.1-2001 * _POSIX_C_SOURCE == 200809 1003.1-2008 * * In addition, the X/Open Portability Guide, which is now the Single UNIX * Specification, defines a feature-test macro which indicates the version of * that specification, and which subsumes _POSIX_C_SOURCE. * * Our macros begin with two underscores to avoid namespace screwage. */ /* Deal with IEEE Std. 1003.1-1990, in which _POSIX_C_SOURCE == 1. */ /* Deal with IEEE Std. 1003.2-1992, in which _POSIX_C_SOURCE == 2. */ /* Deal with various X/Open Portability Guides and Single UNIX Spec. */ /* * Deal with all versions of POSIX. The ordering relative to the tests above is * important. */ /*- * Deal with _ANSI_SOURCE: * If it is defined, and no other compilation environment is explicitly * requested, then define our internal feature-test macros to zero. This * makes no difference to the preprocessor (undefined symbols in preprocessing * expressions are defined to have value zero), but makes it more convenient for * a test program to print out the values. * * If a program mistakenly defines _ANSI_SOURCE and some other macro such as * _POSIX_C_SOURCE, we will assume that it wants the broader compilation * environment (and in fact we will never get here). */ /* User override __EXT1_VISIBLE */ /* * Old versions of GCC use non-standard ARM arch symbols; acle-compat.h * translates them to __ARM_ARCH and the modern feature symbols defined by ARM. */ /* * Nullability qualifiers: currently only supported by Clang. */ /* * Type Safety Checking * * Clang provides additional attributes to enable checking type safety * properties that cannot be enforced by the C type system. */ /* * Lock annotations. * * Clang provides support for doing basic thread-safety tests at * compile-time, by marking which locks will/should be held when * entering/leaving a functions. * * Furthermore, it is also possible to annotate variables and structure * members to enforce that they are only accessed when certain locks are * held. */ /* Structure implements a lock. */ /* Function acquires an exclusive or shared lock. */ /* Function attempts to acquire an exclusive or shared lock. */ /* Function releases a lock. */ /* Function asserts that an exclusive or shared lock is held. */ /* Function requires that an exclusive or shared lock is or is not held. */ /* Function should not be analyzed. */ /* Guard variables and structure members by lock. */ _Pragma("diag_pop") /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2002 Mike Barcroft * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /*****************************************************************************/ /* _TYPES.H */ /* */ /* Copyright (c) 2019 Texas Instruments Incorporated */ /* http://www.ti.com/ */ /* */ /* Redistribution and use in source and binary forms, with or without */ /* modification, are permitted provided that the following conditions */ /* are met: */ /* */ /* Redistributions of source code must retain the above copyright */ /* notice, this list of conditions and the following disclaimer. */ /* */ /* Redistributions in binary form must reproduce the above copyright */ /* notice, this list of conditions and the following disclaimer in */ /* the documentation and/or other materials provided with the */ /* distribution. */ /* */ /* Neither the name of Texas Instruments Incorporated nor the names */ /* of its contributors may be used to endorse or promote products */ /* derived from this software without specific prior written */ /* permission. */ /* */ /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* */ /*****************************************************************************/ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 2002 Mike Barcroft * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * From: @(#)ansi.h 8.2 (Berkeley) 1/4/94 * From: @(#)types.h 8.3 (Berkeley) 1/5/94 * $FreeBSD$ */ #pragma diag_push /* This file is required to use base types */ #pragma CHECK_MISRA("-6.3") /* * Basic types upon which most other types are built. */ typedef signed char __int8_t; typedef unsigned char __uint8_t; typedef short __int16_t; typedef unsigned short __uint16_t; typedef int __int32_t; typedef unsigned int __uint32_t; /* LONG */ typedef long __int64_t; /* LONG */ typedef unsigned long __uint64_t; /* * Standard type definitions. */ typedef __uint64_t __clock_t; /* clock()... */ typedef __int32_t __critical_t; typedef double __double_t; typedef float __float_t; typedef __int32_t __intfptr_t; typedef __int64_t __intmax_t; typedef __int64_t __intptr_t; typedef __int32_t __int_fast8_t; typedef __int32_t __int_fast16_t; typedef __int32_t __int_fast32_t; typedef __int64_t __int_fast64_t; typedef __int8_t __int_least8_t; typedef __int16_t __int_least16_t; typedef __int32_t __int_least32_t; typedef __int64_t __int_least64_t; typedef __int64_t __ptrdiff_t; /* ptr1 - ptr2 */ typedef __int64_t __register_t; typedef __int32_t __segsz_t; /* segment size (in pages) */ typedef __uint64_t __size_t; /* sizeof() */ typedef __int64_t __ssize_t; /* byte count or error */ typedef __int64_t __time_t; /* time()... */ typedef __uint32_t __uintfptr_t; typedef __uint64_t __uintmax_t; typedef __uint64_t __uintptr_t; typedef __uint32_t __uint_fast8_t; typedef __uint32_t __uint_fast16_t; typedef __uint32_t __uint_fast32_t; typedef __uint64_t __uint_fast64_t; typedef __uint8_t __uint_least8_t; typedef __uint16_t __uint_least16_t; typedef __uint32_t __uint_least32_t; typedef __uint64_t __uint_least64_t; typedef __uint64_t __u_register_t; typedef __uint32_t __vm_offset_t; typedef __uint64_t __vm_paddr_t; typedef __uint64_t __vm_size_t; typedef unsigned int ___wchar_t; /* * POSIX target specific _off_t type definition */ typedef long int _off_t; /* * Unusual type definitions. */ typedef char *__va_list; #pragma diag_pop _Pragma("diag_push") /* This file is required to use types without size and signedness */ _Pragma("CHECK_MISRA(\"-6.3\")") /* * Standard type definitions. */ typedef __int32_t __blksize_t; /* file block size */ typedef __int64_t __blkcnt_t; /* file block count */ typedef __int32_t __clockid_t; /* clock_gettime()... */ typedef __uint32_t __fflags_t; /* file flags */ typedef __uint64_t __fsblkcnt_t; typedef __uint64_t __fsfilcnt_t; typedef __uint32_t __gid_t; typedef __int64_t __id_t; /* can hold a gid_t, pid_t, or uid_t */ typedef __uint64_t __ino_t; /* inode number */ typedef long __key_t; /* IPC key (for Sys V IPC) */ typedef __int32_t __lwpid_t; /* Thread ID (a.k.a. LWP) */ typedef __uint16_t __mode_t; /* permissions */ typedef int __accmode_t; /* access permissions */ typedef int __nl_item; typedef __uint64_t __nlink_t; /* link count */ typedef _off_t __off_t; /* file offset (target-specific) */ typedef __int64_t __off64_t; /* file offset (always 64-bit) */ typedef __int32_t __pid_t; /* process [group] */ typedef __int64_t __rlim_t; /* resource limit - intentionally */ /* signed, because of legacy code */ /* that uses -1 for RLIM_INFINITY */ typedef __uint8_t __sa_family_t; typedef __uint32_t __socklen_t; typedef long __suseconds_t; /* microseconds (signed) */ typedef struct __timer *__timer_t; /* timer_gettime()... */ typedef struct __mq *__mqd_t; /* mq_open()... */ typedef __uint32_t __uid_t; typedef unsigned int __useconds_t; /* microseconds (unsigned) */ typedef int __cpuwhich_t; /* which parameter for cpuset. */ typedef int __cpulevel_t; /* level parameter for cpuset. */ typedef int __cpusetid_t; /* cpuset identifier. */ /* * Unusual type definitions. */ /* * rune_t is declared to be an ``int'' instead of the more natural * ``unsigned long'' or ``long''. Two things are happening here. It is not * unsigned so that EOF (-1) can be naturally assigned to it and used. Also, * it looks like 10646 will be a 31 bit standard. This means that if your * ints cannot hold 32 bits, you will be in trouble. The reason an int was * chosen over a long is that the is*() and to*() routines take ints (says * ANSI C), but they use __ct_rune_t instead of int. * * NOTE: rune_t is not covered by ANSI nor other standards, and should not * be instantiated outside of lib/libc/locale. Use wchar_t. wint_t and * rune_t must be the same type. Also, wint_t should be able to hold all * members of the largest character set plus one extra value (WEOF), and * must be at least 16 bits. */ typedef int __ct_rune_t; /* arg type for ctype funcs */ typedef __ct_rune_t __rune_t; /* rune_t (see above) */ typedef __ct_rune_t __wint_t; /* wint_t (see above) */ /* Clang already provides these types as built-ins, but only in C++ mode. */ typedef __uint_least16_t __char16_t; typedef __uint_least32_t __char32_t; /* In C++11, char16_t and char32_t are built-in types. */ typedef struct { long long __max_align1 __attribute__((aligned(__alignof__(long long)))); long double __max_align2 __attribute__((aligned(__alignof__(long double)))); } __max_align_t; typedef __uint64_t __dev_t; /* device number */ typedef __uint32_t __fixpt_t; /* fixed point number */ /* * mbstate_t is an opaque object to keep conversion state during multibyte * stream conversions. */ typedef int _Mbstatet; typedef _Mbstatet __mbstate_t; typedef __uintmax_t __rman_res_t; /* * When the following macro is defined, the system uses 64-bit inode numbers. * Programs can use this to avoid including , with its associated * namespace pollution. */ _Pragma("diag_pop") /*****************************************************************************/ /* _STDINT.H */ /* */ /* Copyright (c) 2019 Texas Instruments Incorporated */ /* http://www.ti.com/ */ /* */ /* Redistribution and use in source and binary forms, with or without */ /* modification, are permitted provided that the following conditions */ /* are met: */ /* */ /* Redistributions of source code must retain the above copyright */ /* notice, this list of conditions and the following disclaimer. */ /* */ /* Redistributions in binary form must reproduce the above copyright */ /* notice, this list of conditions and the following disclaimer in */ /* the documentation and/or other materials provided with the */ /* distribution. */ /* */ /* Neither the name of Texas Instruments Incorporated nor the names */ /* of its contributors may be used to endorse or promote products */ /* derived from this software without specific prior written */ /* permission. */ /* */ /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* */ /*****************************************************************************/ /*- * SPDX-License-Identifier: BSD-2-Clause-NetBSD * * Copyright (c) 2001, 2002 Mike Barcroft * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Klaus Klein. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #pragma diag_push /* 19.4 is issued for macros that are defined in terms of other macros. */ #pragma CHECK_MISRA("-19.4") /* The standard (C99 with TC1+TC2+TC3) now says "integer constant expressions," * not "integer constants." Not all ICE are suitable for use in preprocessor * macros. Any test that uses INTn_C in a preprocessor macro is legal C99, but * not necessarily legal C99+TC1+TC2+TC3 * * See Defect Report: * http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_209.htm * * Conclusion: In a pre-processor macro, UINT32_MAX may be used, but not * UINT32_C(1234) */ /* * ISO/IEC 9899:1999 * 7.18.2.1 Limits of exact-width integer types */ /* Minimum values of exact-width signed integer types. */ /* Maximum values of exact-width signed integer types. */ /* Maximum values of exact-width unsigned integer types. */ /* * ISO/IEC 9899:1999 * 7.18.2.2 Limits of minimum-width integer types */ /* Minimum values of minimum-width signed integer types. */ /* Maximum values of minimum-width signed integer types. */ /* Maximum values of minimum-width unsigned integer types. */ /* * ISO/IEC 9899:1999 * 7.18.2.3 Limits of fastest minimum-width integer types */ /* Minimum values of fastest minimum-width signed integer types. */ /* Maximum values of fastest minimum-width signed integer types. */ /* Maximum values of fastest minimum-width unsigned integer types. */ /* * ISO/IEC 9899:1999 * 7.18.2.4 Limits of integer types capable of holding object pointers */ /* * ISO/IEC 9899:1999 * 7.18.2.5 Limits of greatest-width integer types */ /* * ISO/IEC 9899:1999 * 7.18.3 Limits of other integer types */ /* Limits of ptrdiff_t. */ /* Limits of sig_atomic_t. */ /* Limit of size_t. */ /* Limits of wint_t. */ #pragma diag_pop /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2011 David E. O'Brien * Copyright (c) 2001 Mike Barcroft * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ typedef __int8_t int8_t; typedef __int16_t int16_t; typedef __int32_t int32_t; typedef __int64_t int64_t; typedef __uint8_t uint8_t; typedef __uint16_t uint16_t; typedef __uint32_t uint32_t; typedef __uint64_t uint64_t; typedef __intptr_t intptr_t; typedef __uintptr_t uintptr_t; typedef __intmax_t intmax_t; typedef __uintmax_t uintmax_t; typedef __int_least8_t int_least8_t; typedef __int_least16_t int_least16_t; typedef __int_least32_t int_least32_t; typedef __int_least64_t int_least64_t; typedef __uint_least8_t uint_least8_t; typedef __uint_least16_t uint_least16_t; typedef __uint_least32_t uint_least32_t; typedef __uint_least64_t uint_least64_t; typedef __int_fast8_t int_fast8_t; typedef __int_fast16_t int_fast16_t; typedef __int_fast32_t int_fast32_t; typedef __int_fast64_t int_fast64_t; typedef __uint_fast8_t uint_fast8_t; typedef __uint_fast16_t uint_fast16_t; typedef __uint_fast32_t uint_fast32_t; typedef __uint_fast64_t uint_fast64_t; _Pragma("diag_push") _Pragma("CHECK_MISRA(\"-10.1\")") /* GNU and Darwin define this and people seem to think it's portable */ _Pragma("diag_pop") _Pragma("diag_push") _Pragma("CHECK_MISRA(\"-19.4\")") /* Limits of wchar_t. */ _Pragma("diag_pop") /* ISO/IEC 9899:2011 K.3.4.4 */ _Pragma("diag_pop") /* Platform selection options. If uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros. Possible values for uECC_PLATFORM are defined below: */ /* If desired, you can define uECC_WORD_SIZE as appropriate for your platform (1, 4, or 8 bytes). If uECC_WORD_SIZE is not explicitly defined then it will be automatically set based on your platform. */ /* Optimization level; trade speed for code size. Larger values produce code that is faster but larger. Currently supported values are 0 - 4; 0 is unusably slow for most applications. Optimization level 4 currently only has an effect ARM platforms where more than one curve is enabled. */ /* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be used for (scalar) squaring instead of the generic multiplication function. This can make things faster somewhat faster, but increases the code size. */ /* uECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will switch to native little-endian format for *all* arrays passed in and out of the public API. This includes public and private keys, shared secrets, signatures and message hashes. Using this switch reduces the amount of call stack memory used by uECC, since less intermediate translations are required. Note that this will *only* work on native little-endian processors and it will treat the uint8_t arrays passed into the public API as word arrays, therefore requiring the provided byte arrays to be word aligned on architectures that do not support unaligned accesses. IMPORTANT: Keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible with keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use the same endianness. */ /* Curve support selection. Set to 0 to remove that curve. */ /* Specifies whether compressed point format is supported. Set to 0 to disable point compression/decompression functions. */ struct uECC_Curve_t; typedef const struct uECC_Curve_t * uECC_Curve; uECC_Curve uECC_secp160r1(void); uECC_Curve uECC_secp192r1(void); uECC_Curve uECC_secp224r1(void); uECC_Curve uECC_secp256r1(void); uECC_Curve uECC_secp256k1(void); /* uECC_RNG_Function type The RNG function should fill 'size' random bytes into 'dest'. It should return 1 if 'dest' was filled with random data, or 0 if the random data could not be generated. The filled-in values should be either truly random, or from a cryptographically-secure PRNG. A correctly functioning RNG function must be set (using uECC_set_rng()) before calling uECC_make_key() or uECC_sign(). Setting a correctly functioning RNG function improves the resistance to side-channel attacks for uECC_shared_secret() and uECC_sign_deterministic(). A correct RNG function is set by default when building for Windows, Linux, or OS X. If you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom, you can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined RNG function; you must provide your own. */ typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size); /* uECC_set_rng() function. Set the function that will be used to generate random bytes. The RNG function should return 1 if the random data was generated, or 0 if the random data could not be generated. On platforms where there is no predefined RNG function (eg embedded platforms), this must be called before uECC_make_key() or uECC_sign() are used. Inputs: rng_function - The function that will be used to generate random bytes. */ void uECC_set_rng(uECC_RNG_Function rng_function); /* uECC_get_rng() function. Returns the function that will be used to generate random bytes. */ uECC_RNG_Function uECC_get_rng(void); /* uECC_curve_private_key_size() function. Returns the size of a private key for the curve in bytes. */ int uECC_curve_private_key_size(uECC_Curve curve); /* uECC_curve_public_key_size() function. Returns the size of a public key for the curve in bytes. */ int uECC_curve_public_key_size(uECC_Curve curve); /* uECC_make_key() function. Create a public/private key pair. Outputs: public_key - Will be filled in with the public key. Must be at least 2 * the curve size (in bytes) long. For example, if the curve is secp256r1, public_key must be 64 bytes long. private_key - Will be filled in with the private key. Must be as long as the curve order; this is typically the same as the curve size, except for secp160r1. For example, if the curve is secp256r1, private_key must be 32 bytes long. For secp160r1, private_key must be 21 bytes long! Note that the first byte will almost always be 0 (there is about a 1 in 2^80 chance of it being non-zero). Returns 1 if the key pair was generated successfully, 0 if an error occurred. */ int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve); /* uECC_shared_secret() function. Compute a shared secret given your secret key and someone else's public key. If the public key is not from a trusted source and has not been previously verified, you should verify it first using uECC_valid_public_key(). Note: It is recommended that you hash the result of uECC_shared_secret() before using it for symmetric encryption or HMAC. Inputs: public_key - The public key of the remote party. private_key - Your private key. Outputs: secret - Will be filled in with the shared secret value. Must be the same size as the curve size; for example, if the curve is secp256r1, secret must be 32 bytes long. Returns 1 if the shared secret was generated successfully, 0 if an error occurred. */ int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key, uint8_t *secret, uECC_Curve curve); /* uECC_compress() function. Compress a public key. Inputs: public_key - The public key to compress. Outputs: compressed - Will be filled in with the compressed public key. Must be at least (curve size + 1) bytes long; for example, if the curve is secp256r1, compressed must be 33 bytes long. */ void uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve); /* uECC_decompress() function. Decompress a compressed public key. Inputs: compressed - The compressed public key. Outputs: public_key - Will be filled in with the decompressed public key. */ void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve); /* uECC_valid_public_key() function. Check to see if a public key is valid. Note that you are not required to check for a valid public key before using any other uECC functions. However, you may wish to avoid spending CPU time computing a shared secret or verifying a signature using an invalid public key. Inputs: public_key - The public key to check. Returns 1 if the public key is valid, 0 if it is invalid. */ int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve); /* uECC_compute_public_key() function. Compute the corresponding public key for a private key. Inputs: private_key - The private key to compute the public key for Outputs: public_key - Will be filled in with the corresponding public key Returns 1 if the key was computed successfully, 0 if an error occurred. */ int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve); /* uECC_sign() function. Generate an ECDSA signature for a given hash value. Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to this function along with your private key. Inputs: private_key - Your private key. message_hash - The hash of the message to sign. hash_size - The size of message_hash in bytes. Outputs: signature - Will be filled in with the signature value. Must be at least 2 * curve size long. For example, if the curve is secp256r1, signature must be 64 bytes long. Returns 1 if the signature generated successfully, 0 if an error occurred. */ int uECC_sign(const uint8_t *private_key, const uint8_t *message_hash, unsigned hash_size, uint8_t *signature, uECC_Curve curve); /* uECC_HashContext structure. This is used to pass in an arbitrary hash function to uECC_sign_deterministic(). The structure will be used for multiple hash computations; each time a new hash is computed, init_hash() will be called, followed by one or more calls to update_hash(), and finally a call to finish_hash() to produce the resulting hash. The intention is that you will create a structure that includes uECC_HashContext followed by any hash-specific data. For example: typedef struct SHA256_HashContext { uECC_HashContext uECC; SHA256_CTX ctx; } SHA256_HashContext; void init_SHA256(uECC_HashContext *base) { SHA256_HashContext *context = (SHA256_HashContext *)base; SHA256_Init(&context->ctx); } void update_SHA256(uECC_HashContext *base, const uint8_t *message, unsigned message_size) { SHA256_HashContext *context = (SHA256_HashContext *)base; SHA256_Update(&context->ctx, message, message_size); } void finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) { SHA256_HashContext *context = (SHA256_HashContext *)base; SHA256_Final(hash_result, &context->ctx); } ... when signing ... { uint8_t tmp[32 + 32 + 64]; SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}}; uECC_sign_deterministic(key, message_hash, &ctx.uECC, signature); } */ typedef struct uECC_HashContext { void (*init_hash)(const struct uECC_HashContext *context); void (*update_hash)(const struct uECC_HashContext *context, const uint8_t *message, unsigned message_size); void (*finish_hash)(const struct uECC_HashContext *context, uint8_t *hash_result); unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */ unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */ uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */ } uECC_HashContext; /* uECC_sign_deterministic() function. Generate an ECDSA signature for a given hash value, using a deterministic algorithm (see RFC 6979). You do not need to set the RNG using uECC_set_rng() before calling this function; however, if the RNG is defined it will improve resistance to side-channel attacks. Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it to this function along with your private key and a hash context. Note that the message_hash does not need to be computed with the same hash function used by hash_context. Inputs: private_key - Your private key. message_hash - The hash of the message to sign. hash_size - The size of message_hash in bytes. hash_context - A hash context to use. Outputs: signature - Will be filled in with the signature value. Returns 1 if the signature generated successfully, 0 if an error occurred. */ int uECC_sign_deterministic(const uint8_t *private_key, const uint8_t *message_hash, unsigned hash_size, const uECC_HashContext *hash_context, uint8_t *signature, uECC_Curve curve); /* uECC_verify() function. Verify an ECDSA signature. Usage: Compute the hash of the signed data using the same hash as the signer and pass it to this function along with the signer's public key and the signature values (r and s). Inputs: public_key - The signer's public key. message_hash - The hash of the signed data. hash_size - The size of message_hash in bytes. signature - The signature value. Returns 1 if the signature is valid, 0 if it is invalid. */ int uECC_verify(const uint8_t *public_key, const uint8_t *message_hash, unsigned hash_size, const uint8_t *signature, uECC_Curve curve); /* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ /* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ typedef int8_t wordcount_t; typedef int16_t bitcount_t; typedef int8_t cmpresult_t; typedef uint32_t uECC_word_t; typedef uint64_t uECC_dword_t; /* Functions for raw large-integer manipulation. These are only available if uECC.c is compiled with uECC_ENABLE_VLI_API defined to 1. */ /* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ struct uECC_Curve_t { wordcount_t num_words; wordcount_t num_bytes; bitcount_t num_n_bits; uECC_word_t p[8]; uECC_word_t n[8]; uECC_word_t G[8 * 2]; uECC_word_t b[8]; void (*double_jacobian)(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * Z1, uECC_Curve curve); void (*mod_sqrt)(uECC_word_t *a, uECC_Curve curve); void (*x_side)(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve); void (*mmod_fast)(uECC_word_t *result, uECC_word_t *product); }; static cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left, const uECC_word_t *right, wordcount_t num_words); static uECC_RNG_Function g_rng_function = 0; void uECC_set_rng(uECC_RNG_Function rng_function) { g_rng_function = rng_function; } uECC_RNG_Function uECC_get_rng(void) { return g_rng_function; } int uECC_curve_private_key_size(uECC_Curve curve) { return ((curve ->num_n_bits + 7) / 8); } int uECC_curve_public_key_size(uECC_Curve curve) { return 2 * curve->num_bytes; } static void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words) { wordcount_t i; for (i = 0; i < num_words; ++i) { vli[i] = 0; } } /* Constant-time comparison to zero - secure way to compare long integers */ /* Returns 1 if vli == 0, 0 otherwise. */ static uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words) { uECC_word_t bits = 0; wordcount_t i; for (i = 0; i < num_words; ++i) { bits |= vli[i]; } return (bits == 0); } /* Returns nonzero if bit 'bit' of vli is set. */ static uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit) { return (vli[bit >> 5] & ((uECC_word_t)1 << (bit & 0x01F))); } /* Counts the number of words in vli. */ static wordcount_t vli_numDigits(const uECC_word_t *vli, const wordcount_t max_words) { wordcount_t i; /* Search from the end until we find a non-zero digit. We do it in reverse because we expect that most digits will be nonzero. */ for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) { } return (i + 1); } /* Counts the number of bits required to represent vli. */ static bitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words) { uECC_word_t i; uECC_word_t digit; wordcount_t num_digits = vli_numDigits(vli, max_words); if (num_digits == 0) { return 0; } digit = vli[num_digits - 1]; for (i = 0; digit; ++i) { digit >>= 1; } return (((bitcount_t)(num_digits - 1) << 5) + i); } /* Sets dest = src. */ static void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words) { wordcount_t i; for (i = 0; i < num_words; ++i) { dest[i] = src[i]; } } /* Returns sign of left - right. */ static cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left, const uECC_word_t *right, wordcount_t num_words) { wordcount_t i; for (i = num_words - 1; i >= 0; --i) { if (left[i] > right[i]) { return 1; } else if (left[i] < right[i]) { return -1; } } return 0; } /* Constant-time comparison function - secure way to compare long integers */ /* Returns one if left == right, zero otherwise. */ static uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right, wordcount_t num_words) { uECC_word_t diff = 0; wordcount_t i; for (i = num_words - 1; i >= 0; --i) { diff |= (left[i] ^ right[i]); } return (diff == 0); } static uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right, wordcount_t num_words); /* Returns sign of left - right, in constant time. */ static cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right, wordcount_t num_words) { uECC_word_t tmp[8]; uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words); uECC_word_t equal = uECC_vli_isZero(tmp, num_words); return (!equal - 2 * neg); } /* Computes vli = vli >> 1. */ static void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words) { uECC_word_t *end = vli; uECC_word_t carry = 0; vli += num_words; while (vli-- > end) { uECC_word_t temp = *vli; *vli = (temp >> 1) | carry; carry = temp << (32 - 1); } } /* Computes result = left + right, returning carry. Can modify in place. */ static uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right, wordcount_t num_words) { uECC_word_t carry = 0; wordcount_t i; for (i = 0; i < num_words; ++i) { uECC_word_t sum = left[i] + right[i] + carry; if (sum != left[i]) { carry = (sum < left[i]); } result[i] = sum; } return carry; } /* Computes result = left - right, returning borrow. Can modify in place. */ static uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right, wordcount_t num_words) { uECC_word_t borrow = 0; wordcount_t i; for (i = 0; i < num_words; ++i) { uECC_word_t diff = left[i] - right[i] - borrow; if (diff != left[i]) { borrow = (diff > left[i]); } result[i] = diff; } return borrow; } static void muladd(uECC_word_t a, uECC_word_t b, uECC_word_t *r0, uECC_word_t *r1, uECC_word_t *r2) { uECC_dword_t p = (uECC_dword_t)a * b; uECC_dword_t r01 = ((uECC_dword_t)(*r1) << 32) | *r0; r01 += p; *r2 += (r01 < p); *r1 = r01 >> 32; *r0 = (uECC_word_t)r01; } static void uECC_vli_mult(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right, wordcount_t num_words) { uECC_word_t r0 = 0; uECC_word_t r1 = 0; uECC_word_t r2 = 0; wordcount_t i, k; /* Compute each digit of result in sequence, maintaining the carries. */ for (k = 0; k < num_words; ++k) { for (i = 0; i <= k; ++i) { muladd(left[i], right[k - i], &r0, &r1, &r2); } result[k] = r0; r0 = r1; r1 = r2; r2 = 0; } for (k = num_words; k < num_words * 2 - 1; ++k) { for (i = (k + 1) - num_words; i < num_words; ++i) { muladd(left[i], right[k - i], &r0, &r1, &r2); } result[k] = r0; r0 = r1; r1 = r2; r2 = 0; } result[num_words * 2 - 1] = r0; } /* Computes result = (left + right) % mod. Assumes that left < mod and right < mod, and that result does not overlap mod. */ static void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right, const uECC_word_t *mod, wordcount_t num_words) { uECC_word_t carry = uECC_vli_add(result, left, right, num_words); if (carry || uECC_vli_cmp_unsafe(mod, result, num_words) != 1) { /* result > mod (result = mod + remainder), so subtract mod to get remainder. */ uECC_vli_sub(result, result, mod, num_words); } } /* Computes result = (left - right) % mod. Assumes that left < mod and right < mod, and that result does not overlap mod. */ static void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right, const uECC_word_t *mod, wordcount_t num_words) { uECC_word_t l_borrow = uECC_vli_sub(result, left, right, num_words); if (l_borrow) { /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x, we can get the correct result from result + mod (with overflow). */ uECC_vli_add(result, result, mod, num_words); } } /* Computes result = product % mod, where product is 2N words long. */ /* Currently only designed to work for curve_p or curve_n. */ static void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product, const uECC_word_t *mod, wordcount_t num_words) { uECC_word_t mod_multiple[2 * 8]; uECC_word_t tmp[2 * 8]; uECC_word_t *v[2] = {tmp, product}; uECC_word_t index; /* Shift mod so its highest set bit is at the maximum position. */ bitcount_t shift = (num_words * 2 * 32) - uECC_vli_numBits(mod, num_words); wordcount_t word_shift = shift / 32; wordcount_t bit_shift = shift % 32; uECC_word_t carry = 0; uECC_vli_clear(mod_multiple, word_shift); if (bit_shift > 0) { for(index = 0; index < (uECC_word_t)num_words; ++index) { mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry; carry = mod[index] >> (32 - bit_shift); } } else { uECC_vli_set(mod_multiple + word_shift, mod, num_words); } for (index = 1; shift >= 0; --shift) { uECC_word_t borrow = 0; wordcount_t i; for (i = 0; i < num_words * 2; ++i) { uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow; if (diff != v[index][i]) { borrow = (diff > v[index][i]); } v[1 - index][i] = diff; } index = !(index ^ borrow); /* Swap the index if there was no borrow */ uECC_vli_rshift1(mod_multiple, num_words); mod_multiple[num_words - 1] |= mod_multiple[num_words] << (32 - 1); uECC_vli_rshift1(mod_multiple + num_words, num_words); } uECC_vli_set(result, v[index], num_words); } /* Computes result = (left * right) % mod. */ static void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right, const uECC_word_t *mod, wordcount_t num_words) { uECC_word_t product[2 * 8]; uECC_vli_mult(product, left, right, num_words); uECC_vli_mmod(result, product, mod, num_words); } static void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left, const uECC_word_t *right, uECC_Curve curve) { uECC_word_t product[2 * 8]; uECC_vli_mult(product, left, right, curve->num_words); curve->mmod_fast(result, product); } static void uECC_vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left, uECC_Curve curve) { uECC_vli_modMult_fast(result, left, left, curve); } static void vli_modInv_update(uECC_word_t *uv, const uECC_word_t *mod, wordcount_t num_words) { uECC_word_t carry = 0; if (!(!(uv[0] & 1))) { carry = uECC_vli_add(uv, uv, mod, num_words); } uECC_vli_rshift1(uv, num_words); if (carry) { uv[num_words - 1] |= 0x80000000; } } /* Computes result = (1 / input) % mod. All VLIs are the same size. See "From Euclid's GCD to Montgomery Multiplication to the Great Divide" */ static void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input, const uECC_word_t *mod, wordcount_t num_words) { uECC_word_t a[8], b[8], u[8], v[8]; cmpresult_t cmpResult; if (uECC_vli_isZero(input, num_words)) { uECC_vli_clear(result, num_words); return; } uECC_vli_set(a, input, num_words); uECC_vli_set(b, mod, num_words); uECC_vli_clear(u, num_words); u[0] = 1; uECC_vli_clear(v, num_words); while ((cmpResult = uECC_vli_cmp_unsafe(a, b, num_words)) != 0) { if ((!(a[0] & 1))) { uECC_vli_rshift1(a, num_words); vli_modInv_update(u, mod, num_words); } else if ((!(b[0] & 1))) { uECC_vli_rshift1(b, num_words); vli_modInv_update(v, mod, num_words); } else if (cmpResult > 0) { uECC_vli_sub(a, a, b, num_words); uECC_vli_rshift1(a, num_words); if (uECC_vli_cmp_unsafe(u, v, num_words) < 0) { uECC_vli_add(u, u, mod, num_words); } uECC_vli_sub(u, u, v, num_words); vli_modInv_update(u, mod, num_words); } else { uECC_vli_sub(b, b, a, num_words); uECC_vli_rshift1(b, num_words); if (uECC_vli_cmp_unsafe(v, u, num_words) < 0) { uECC_vli_add(v, v, mod, num_words); } uECC_vli_sub(v, v, u, num_words); vli_modInv_update(v, mod, num_words); } } uECC_vli_set(result, u, num_words); } /* ------ Point operations ------ */ /* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ static void double_jacobian_default(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * Z1, uECC_Curve curve) { /* t1 = X, t2 = Y, t3 = Z */ uECC_word_t t4[8]; uECC_word_t t5[8]; wordcount_t num_words = curve->num_words; if (uECC_vli_isZero(Z1, num_words)) { return; } uECC_vli_modSquare_fast(t4, Y1, curve); /* t4 = y1^2 */ uECC_vli_modMult_fast(t5, X1, t4, curve); /* t5 = x1*y1^2 = A */ uECC_vli_modSquare_fast(t4, t4, curve); /* t4 = y1^4 */ uECC_vli_modMult_fast(Y1, Y1, Z1, curve); /* t2 = y1*z1 = z3 */ uECC_vli_modSquare_fast(Z1, Z1, curve); /* t3 = z1^2 */ uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = x1 + z1^2 */ uECC_vli_modAdd(Z1, Z1, Z1, curve->p, num_words); /* t3 = 2*z1^2 */ uECC_vli_modSub(Z1, X1, Z1, curve->p, num_words); /* t3 = x1 - z1^2 */ uECC_vli_modMult_fast(X1, X1, Z1, curve); /* t1 = x1^2 - z1^4 */ uECC_vli_modAdd(Z1, X1, X1, curve->p, num_words); /* t3 = 2*(x1^2 - z1^4) */ uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = 3*(x1^2 - z1^4) */ if (uECC_vli_testBit(X1, 0)) { uECC_word_t l_carry = uECC_vli_add(X1, X1, curve->p, num_words); uECC_vli_rshift1(X1, num_words); X1[num_words - 1] |= l_carry << (32 - 1); } else { uECC_vli_rshift1(X1, num_words); } /* t1 = 3/2*(x1^2 - z1^4) = B */ uECC_vli_modSquare_fast(Z1, X1, curve); /* t3 = B^2 */ uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - A */ uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - 2A = x3 */ uECC_vli_modSub(t5, t5, Z1, curve->p, num_words); /* t5 = A - x3 */ uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = B * (A - x3) */ uECC_vli_modSub(t4, X1, t4, curve->p, num_words); /* t4 = B * (A - x3) - y1^4 = y3 */ uECC_vli_set(X1, Z1, num_words); uECC_vli_set(Z1, Y1, num_words); uECC_vli_set(Y1, t4, num_words); } /* Computes result = x^3 + ax + b. result must not overlap x. */ static void x_side_default(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) { uECC_word_t _3[8] = {3}; /* -a = 3 */ wordcount_t num_words = curve->num_words; uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */ uECC_vli_modSub(result, result, _3, curve->p, num_words); /* r = x^2 - 3 */ uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 - 3x */ uECC_vli_modAdd(result, result, curve->b, curve->p, num_words); /* r = x^3 - 3x + b */ } /* Compute a = sqrt(a) (mod curve_p). */ static void mod_sqrt_default(uECC_word_t *a, uECC_Curve curve) { bitcount_t i; uECC_word_t p1[8] = {1}; uECC_word_t l_result[8] = {1}; wordcount_t num_words = curve->num_words; /* When curve->p == 3 (mod 4), we can compute sqrt(a) = a^((curve->p + 1) / 4) (mod curve->p). */ uECC_vli_add(p1, curve->p, p1, num_words); /* p1 = curve_p + 1 */ for (i = uECC_vli_numBits(p1, num_words) - 1; i > 1; --i) { uECC_vli_modSquare_fast(l_result, l_result, curve); if (uECC_vli_testBit(p1, i)) { uECC_vli_modMult_fast(l_result, l_result, a, curve); } } uECC_vli_set(a, l_result, num_words); } static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product); static const struct uECC_Curve_t curve_secp160r1 = { 5, 20, 161, /* num_n_bits */ { 0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, { 0xCA752257, 0xF927AED3, 0x0001F4C8, 0x00000000, 0x00000000, 0x00000001 }, { 0x13CBFC82, 0x68C38BB9, 0x46646989, 0x8EF57328, 0x4A96B568, 0x7AC5FB32, 0x04235137, 0x59DCC912, 0x3168947D, 0x23A62855 }, { 0xC565FA45, 0x81D4D4AD, 0x65ACF89F, 0x54BD7A8B, 0x1C97BEFC }, &double_jacobian_default, &mod_sqrt_default, &x_side_default, &vli_mmod_fast_secp160r1 }; uECC_Curve uECC_secp160r1(void) { return &curve_secp160r1; } /* Computes result = product % curve_p see http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf page 354 Note that this only works if log2(omega) < log2(p) / 2 */ static void omega_mult_secp160r1(uECC_word_t *result, const uECC_word_t *right); static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product) { uECC_word_t tmp[2 * 5]; uECC_word_t carry; uECC_vli_clear(tmp, 5); uECC_vli_clear(tmp + 5, 5); omega_mult_secp160r1(tmp, product + 5); /* (Rq, q) = q * c */ carry = uECC_vli_add(result, product, tmp, 5); /* (C, r) = r + q */ uECC_vli_clear(product, 5); omega_mult_secp160r1(product, tmp + 5); /* Rq*c */ carry += uECC_vli_add(result, result, product, 5); /* (C1, r) = r + Rq*c */ while (carry > 0) { --carry; uECC_vli_sub(result, result, curve_secp160r1.p, 5); } if (uECC_vli_cmp_unsafe(result, curve_secp160r1.p, 5) > 0) { uECC_vli_sub(result, result, curve_secp160r1.p, 5); } } static void omega_mult_secp160r1(uint32_t *result, const uint32_t *right) { uint32_t carry; unsigned i; /* Multiply by (2^31 + 1). */ uECC_vli_set(result + 1, right, 5); /* 2^32 */ uECC_vli_rshift1(result + 1, 5); /* 2^31 */ result[0] = right[0] << 31; /* get last bit from shift */ carry = uECC_vli_add(result, result, right, 5); /* 2^31 + 1 */ for (i = 5; carry; ++i) { uint64_t sum = (uint64_t)result[i] + carry; result[i] = (uint32_t)sum; carry = sum >> 32; } } static void vli_mmod_fast_secp192r1(uECC_word_t *result, uECC_word_t *product); static const struct uECC_Curve_t curve_secp192r1 = { 6, 24, 192, /* num_n_bits */ { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, { 0xB4D22831, 0x146BC9B1, 0x99DEF836, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, { 0x82FF1012, 0xF4FF0AFD, 0x43A18800, 0x7CBF20EB, 0xB03090F6, 0x188DA80E, 0x1E794811, 0x73F977A1, 0x6B24CDD5, 0x631011ED, 0xFFC8DA78, 0x07192B95 }, { 0xC146B9B1, 0xFEB8DEEC, 0x72243049, 0x0FA7E9AB, 0xE59C80E7, 0x64210519 }, &double_jacobian_default, &mod_sqrt_default, &x_side_default, &vli_mmod_fast_secp192r1 }; uECC_Curve uECC_secp192r1(void) { return &curve_secp192r1; } /* Computes result = product % curve_p. See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf */ static void vli_mmod_fast_secp192r1(uint32_t *result, uint32_t *product) { uint32_t tmp[6]; int carry; uECC_vli_set(result, product, 6); uECC_vli_set(tmp, &product[6], 6); carry = uECC_vli_add(result, result, tmp, 6); tmp[0] = tmp[1] = 0; tmp[2] = product[6]; tmp[3] = product[7]; tmp[4] = product[8]; tmp[5] = product[9]; carry += uECC_vli_add(result, result, tmp, 6); tmp[0] = tmp[2] = product[10]; tmp[1] = tmp[3] = product[11]; tmp[4] = tmp[5] = 0; carry += uECC_vli_add(result, result, tmp, 6); while (carry || uECC_vli_cmp_unsafe(curve_secp192r1.p, result, 6) != 1) { carry -= uECC_vli_sub(result, result, curve_secp192r1.p, 6); } } static void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve); static void vli_mmod_fast_secp224r1(uECC_word_t *result, uECC_word_t *product); static const struct uECC_Curve_t curve_secp224r1 = { 7, 28, 224, /* num_n_bits */ { 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, { 0x5C5C2A3D, 0x13DD2945, 0xE0B8F03E, 0xFFFF16A2, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, { 0x115C1D21, 0x343280D6, 0x56C21122, 0x4A03C1D3, 0x321390B9, 0x6BB4BF7F, 0xB70E0CBD, 0x85007E34, 0x44D58199, 0x5A074764, 0xCD4375A0, 0x4C22DFE6, 0xB5F723FB, 0xBD376388 }, { 0x2355FFB4, 0x270B3943, 0xD7BFD8BA, 0x5044B0B7, 0xF5413256, 0x0C04B3AB, 0xB4050A85 }, &double_jacobian_default, &mod_sqrt_secp224r1, &x_side_default, &vli_mmod_fast_secp224r1 }; uECC_Curve uECC_secp224r1(void) { return &curve_secp224r1; } /* Routine 3.2.4 RS; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ static void mod_sqrt_secp224r1_rs(uECC_word_t *d1, uECC_word_t *e1, uECC_word_t *f1, const uECC_word_t *d0, const uECC_word_t *e0, const uECC_word_t *f0) { uECC_word_t t[7]; uECC_vli_modSquare_fast(t, d0, &curve_secp224r1); /* t <-- d0 ^ 2 */ uECC_vli_modMult_fast(e1, d0, e0, &curve_secp224r1); /* e1 <-- d0 * e0 */ uECC_vli_modAdd(d1, t, f0, curve_secp224r1.p, 7); /* d1 <-- t + f0 */ uECC_vli_modAdd(e1, e1, e1, curve_secp224r1.p, 7); /* e1 <-- e1 + e1 */ uECC_vli_modMult_fast(f1, t, f0, &curve_secp224r1); /* f1 <-- t * f0 */ uECC_vli_modAdd(f1, f1, f1, curve_secp224r1.p, 7); /* f1 <-- f1 + f1 */ uECC_vli_modAdd(f1, f1, f1, curve_secp224r1.p, 7); /* f1 <-- f1 + f1 */ } /* Routine 3.2.5 RSS; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ static void mod_sqrt_secp224r1_rss(uECC_word_t *d1, uECC_word_t *e1, uECC_word_t *f1, const uECC_word_t *d0, const uECC_word_t *e0, const uECC_word_t *f0, const bitcount_t j) { bitcount_t i; uECC_vli_set(d1, d0, 7); /* d1 <-- d0 */ uECC_vli_set(e1, e0, 7); /* e1 <-- e0 */ uECC_vli_set(f1, f0, 7); /* f1 <-- f0 */ for (i = 1; i <= j; i++) { mod_sqrt_secp224r1_rs(d1, e1, f1, d1, e1, f1); /* RS (d1,e1,f1,d1,e1,f1) */ } } /* Routine 3.2.6 RM; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ static void mod_sqrt_secp224r1_rm(uECC_word_t *d2, uECC_word_t *e2, uECC_word_t *f2, const uECC_word_t *c, const uECC_word_t *d0, const uECC_word_t *e0, const uECC_word_t *d1, const uECC_word_t *e1) { uECC_word_t t1[7]; uECC_word_t t2[7]; uECC_vli_modMult_fast(t1, e0, e1, &curve_secp224r1); /* t1 <-- e0 * e1 */ uECC_vli_modMult_fast(t1, t1, c, &curve_secp224r1); /* t1 <-- t1 * c */ /* t1 <-- p - t1 */ uECC_vli_modSub(t1, curve_secp224r1.p, t1, curve_secp224r1.p, 7); uECC_vli_modMult_fast(t2, d0, d1, &curve_secp224r1); /* t2 <-- d0 * d1 */ uECC_vli_modAdd(t2, t2, t1, curve_secp224r1.p, 7); /* t2 <-- t2 + t1 */ uECC_vli_modMult_fast(t1, d0, e1, &curve_secp224r1); /* t1 <-- d0 * e1 */ uECC_vli_modMult_fast(e2, d1, e0, &curve_secp224r1); /* e2 <-- d1 * e0 */ uECC_vli_modAdd(e2, e2, t1, curve_secp224r1.p, 7); /* e2 <-- e2 + t1 */ uECC_vli_modSquare_fast(f2, e2, &curve_secp224r1); /* f2 <-- e2^2 */ uECC_vli_modMult_fast(f2, f2, c, &curve_secp224r1); /* f2 <-- f2 * c */ /* f2 <-- p - f2 */ uECC_vli_modSub(f2, curve_secp224r1.p, f2, curve_secp224r1.p, 7); uECC_vli_set(d2, t2, 7); /* d2 <-- t2 */ } /* Routine 3.2.7 RP; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ static void mod_sqrt_secp224r1_rp(uECC_word_t *d1, uECC_word_t *e1, uECC_word_t *f1, const uECC_word_t *c, const uECC_word_t *r) { wordcount_t i; wordcount_t pow2i = 1; uECC_word_t d0[7]; uECC_word_t e0[7] = {1}; /* e0 <-- 1 */ uECC_word_t f0[7]; uECC_vli_set(d0, r, 7); /* d0 <-- r */ /* f0 <-- p - c */ uECC_vli_modSub(f0, curve_secp224r1.p, c, curve_secp224r1.p, 7); for (i = 0; i <= 6; i++) { mod_sqrt_secp224r1_rss(d1, e1, f1, d0, e0, f0, pow2i); /* RSS (d1,e1,f1,d0,e0,f0,2^i) */ mod_sqrt_secp224r1_rm(d1, e1, f1, c, d1, e1, d0, e0); /* RM (d1,e1,f1,c,d1,e1,d0,e0) */ uECC_vli_set(d0, d1, 7); /* d0 <-- d1 */ uECC_vli_set(e0, e1, 7); /* e0 <-- e1 */ uECC_vli_set(f0, f1, 7); /* f0 <-- f1 */ pow2i *= 2; } } /* Compute a = sqrt(a) (mod curve_p). */ /* Routine 3.2.8 mp_mod_sqrt_224; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ static void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve) { bitcount_t i; uECC_word_t e1[7]; uECC_word_t f1[7]; uECC_word_t d0[7]; uECC_word_t e0[7]; uECC_word_t f0[7]; uECC_word_t d1[7]; /* s = a; using constant instead of random value */ mod_sqrt_secp224r1_rp(d0, e0, f0, a, a); /* RP (d0, e0, f0, c, s) */ mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0); /* RS (d1, e1, f1, d0, e0, f0) */ for (i = 1; i <= 95; i++) { uECC_vli_set(d0, d1, 7); /* d0 <-- d1 */ uECC_vli_set(e0, e1, 7); /* e0 <-- e1 */ uECC_vli_set(f0, f1, 7); /* f0 <-- f1 */ mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0); /* RS (d1, e1, f1, d0, e0, f0) */ if (uECC_vli_isZero(d1, 7)) { /* if d1 == 0 */ break; } } uECC_vli_modInv(f1, e0, curve_secp224r1.p, 7); /* f1 <-- 1 / e0 */ uECC_vli_modMult_fast(a, d0, f1, &curve_secp224r1); /* a <-- d0 / e0 */ } /* Computes result = product % curve_p from http://www.nsa.gov/ia/_files/nist-routines.pdf */ static void vli_mmod_fast_secp224r1(uint32_t *result, uint32_t *product) { uint32_t tmp[7]; int carry; /* t */ uECC_vli_set(result, product, 7); /* s1 */ tmp[0] = tmp[1] = tmp[2] = 0; tmp[3] = product[7]; tmp[4] = product[8]; tmp[5] = product[9]; tmp[6] = product[10]; carry = uECC_vli_add(result, result, tmp, 7); /* s2 */ tmp[3] = product[11]; tmp[4] = product[12]; tmp[5] = product[13]; tmp[6] = 0; carry += uECC_vli_add(result, result, tmp, 7); /* d1 */ tmp[0] = product[7]; tmp[1] = product[8]; tmp[2] = product[9]; tmp[3] = product[10]; tmp[4] = product[11]; tmp[5] = product[12]; tmp[6] = product[13]; carry -= uECC_vli_sub(result, result, tmp, 7); /* d2 */ tmp[0] = product[11]; tmp[1] = product[12]; tmp[2] = product[13]; tmp[3] = tmp[4] = tmp[5] = tmp[6] = 0; carry -= uECC_vli_sub(result, result, tmp, 7); if (carry < 0) { do { carry += uECC_vli_add(result, result, curve_secp224r1.p, 7); } while (carry < 0); } else { while (carry || uECC_vli_cmp_unsafe(curve_secp224r1.p, result, 7) != 1) { carry -= uECC_vli_sub(result, result, curve_secp224r1.p, 7); } } } static void vli_mmod_fast_secp256r1(uECC_word_t *result, uECC_word_t *product); static const struct uECC_Curve_t curve_secp256r1 = { 8, 32, 256, /* num_n_bits */ { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF }, { 0xFC632551, 0xF3B9CAC2, 0xA7179E84, 0xBCE6FAAD, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF }, { 0xD898C296, 0xF4A13945, 0x2DEB33A0, 0x77037D81, 0x63A440F2, 0xF8BCE6E5, 0xE12C4247, 0x6B17D1F2, 0x37BF51F5, 0xCBB64068, 0x6B315ECE, 0x2BCE3357, 0x7C0F9E16, 0x8EE7EB4A, 0xFE1A7F9B, 0x4FE342E2 }, { 0x27D2604B, 0x3BCE3C3E, 0xCC53B0F6, 0x651D06B0, 0x769886BC, 0xB3EBBD55, 0xAA3A93E7, 0x5AC635D8 }, &double_jacobian_default, &mod_sqrt_default, &x_side_default, &vli_mmod_fast_secp256r1 }; uECC_Curve uECC_secp256r1(void) { return &curve_secp256r1; } /* Computes result = product % curve_p from http://www.nsa.gov/ia/_files/nist-routines.pdf */ static void vli_mmod_fast_secp256r1(uint32_t *result, uint32_t *product) { uint32_t tmp[8]; int carry; /* t */ uECC_vli_set(result, product, 8); /* s1 */ tmp[0] = tmp[1] = tmp[2] = 0; tmp[3] = product[11]; tmp[4] = product[12]; tmp[5] = product[13]; tmp[6] = product[14]; tmp[7] = product[15]; carry = uECC_vli_add(tmp, tmp, tmp, 8); carry += uECC_vli_add(result, result, tmp, 8); /* s2 */ tmp[3] = product[12]; tmp[4] = product[13]; tmp[5] = product[14]; tmp[6] = product[15]; tmp[7] = 0; carry += uECC_vli_add(tmp, tmp, tmp, 8); carry += uECC_vli_add(result, result, tmp, 8); /* s3 */ tmp[0] = product[8]; tmp[1] = product[9]; tmp[2] = product[10]; tmp[3] = tmp[4] = tmp[5] = 0; tmp[6] = product[14]; tmp[7] = product[15]; carry += uECC_vli_add(result, result, tmp, 8); /* s4 */ tmp[0] = product[9]; tmp[1] = product[10]; tmp[2] = product[11]; tmp[3] = product[13]; tmp[4] = product[14]; tmp[5] = product[15]; tmp[6] = product[13]; tmp[7] = product[8]; carry += uECC_vli_add(result, result, tmp, 8); /* d1 */ tmp[0] = product[11]; tmp[1] = product[12]; tmp[2] = product[13]; tmp[3] = tmp[4] = tmp[5] = 0; tmp[6] = product[8]; tmp[7] = product[10]; carry -= uECC_vli_sub(result, result, tmp, 8); /* d2 */ tmp[0] = product[12]; tmp[1] = product[13]; tmp[2] = product[14]; tmp[3] = product[15]; tmp[4] = tmp[5] = 0; tmp[6] = product[9]; tmp[7] = product[11]; carry -= uECC_vli_sub(result, result, tmp, 8); /* d3 */ tmp[0] = product[13]; tmp[1] = product[14]; tmp[2] = product[15]; tmp[3] = product[8]; tmp[4] = product[9]; tmp[5] = product[10]; tmp[6] = 0; tmp[7] = product[12]; carry -= uECC_vli_sub(result, result, tmp, 8); /* d4 */ tmp[0] = product[14]; tmp[1] = product[15]; tmp[2] = 0; tmp[3] = product[9]; tmp[4] = product[10]; tmp[5] = product[11]; tmp[6] = 0; tmp[7] = product[13]; carry -= uECC_vli_sub(result, result, tmp, 8); if (carry < 0) { do { carry += uECC_vli_add(result, result, curve_secp256r1.p, 8); } while (carry < 0); } else { while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, 8) != 1) { carry -= uECC_vli_sub(result, result, curve_secp256r1.p, 8); } } } static void double_jacobian_secp256k1(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * Z1, uECC_Curve curve); static void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve); static void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product); static const struct uECC_Curve_t curve_secp256k1 = { 8, 32, 256, /* num_n_bits */ { 0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, { 0xD0364141, 0xBFD25E8C, 0xAF48A03B, 0xBAAEDCE6, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, { 0x16F81798, 0x59F2815B, 0x2DCE28D9, 0x029BFCDB, 0xCE870B07, 0x55A06295, 0xF9DCBBAC, 0x79BE667E, 0xFB10D4B8, 0x9C47D08F, 0xA6855419, 0xFD17B448, 0x0E1108A8, 0x5DA4FBFC, 0x26A3C465, 0x483ADA77 }, { 0x00000007, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, &double_jacobian_secp256k1, &mod_sqrt_default, &x_side_secp256k1, &vli_mmod_fast_secp256k1 }; uECC_Curve uECC_secp256k1(void) { return &curve_secp256k1; } /* Double in place */ static void double_jacobian_secp256k1(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * Z1, uECC_Curve curve) { /* t1 = X, t2 = Y, t3 = Z */ uECC_word_t t4[8]; uECC_word_t t5[8]; if (uECC_vli_isZero(Z1, 8)) { return; } uECC_vli_modSquare_fast(t5, Y1, curve); /* t5 = y1^2 */ uECC_vli_modMult_fast(t4, X1, t5, curve); /* t4 = x1*y1^2 = A */ uECC_vli_modSquare_fast(X1, X1, curve); /* t1 = x1^2 */ uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = y1^4 */ uECC_vli_modMult_fast(Z1, Y1, Z1, curve); /* t3 = y1*z1 = z3 */ uECC_vli_modAdd(Y1, X1, X1, curve->p, 8); /* t2 = 2*x1^2 */ uECC_vli_modAdd(Y1, Y1, X1, curve->p, 8); /* t2 = 3*x1^2 */ if (uECC_vli_testBit(Y1, 0)) { uECC_word_t carry = uECC_vli_add(Y1, Y1, curve->p, 8); uECC_vli_rshift1(Y1, 8); Y1[8 - 1] |= carry << (32 - 1); } else { uECC_vli_rshift1(Y1, 8); } /* t2 = 3/2*(x1^2) = B */ uECC_vli_modSquare_fast(X1, Y1, curve); /* t1 = B^2 */ uECC_vli_modSub(X1, X1, t4, curve->p, 8); /* t1 = B^2 - A */ uECC_vli_modSub(X1, X1, t4, curve->p, 8); /* t1 = B^2 - 2A = x3 */ uECC_vli_modSub(t4, t4, X1, curve->p, 8); /* t4 = A - x3 */ uECC_vli_modMult_fast(Y1, Y1, t4, curve); /* t2 = B * (A - x3) */ uECC_vli_modSub(Y1, Y1, t5, curve->p, 8); /* t2 = B * (A - x3) - y1^4 = y3 */ } /* Computes result = x^3 + b. result must not overlap x. */ static void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) { uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */ uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 */ uECC_vli_modAdd(result, result, curve->b, curve->p, 8); /* r = x^3 + b */ } static void omega_mult_secp256k1(uECC_word_t *result, const uECC_word_t *right); static void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product) { uECC_word_t tmp[2 * 8]; uECC_word_t carry; uECC_vli_clear(tmp, 8); uECC_vli_clear(tmp + 8, 8); omega_mult_secp256k1(tmp, product + 8); /* (Rq, q) = q * c */ carry = uECC_vli_add(result, product, tmp, 8); /* (C, r) = r + q */ uECC_vli_clear(product, 8); omega_mult_secp256k1(product, tmp + 8); /* Rq*c */ carry += uECC_vli_add(result, result, product, 8); /* (C1, r) = r + Rq*c */ while (carry > 0) { --carry; uECC_vli_sub(result, result, curve_secp256k1.p, 8); } if (uECC_vli_cmp_unsafe(result, curve_secp256k1.p, 8) > 0) { uECC_vli_sub(result, result, curve_secp256k1.p, 8); } } static void omega_mult_secp256k1(uint32_t * result, const uint32_t * right) { /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ uint32_t carry = 0; wordcount_t k; for (k = 0; k < 8; ++k) { uint64_t p = (uint64_t)0x3D1 * right[k] + carry; result[k] = (uint32_t) p; carry = p >> 32; } result[8] = carry; /* add the 2^32 multiple */ result[1 + 8] = uECC_vli_add(result + 1, result + 1, right, 8); } /* Returns 1 if 'point' is the point at infinity, 0 otherwise. */ /* Point multiplication algorithm using Montgomery's ladder with co-Z coordinates. From http://eprint.iacr.org/2011/338.pdf */ /* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */ static void apply_z(uECC_word_t * X1, uECC_word_t * Y1, const uECC_word_t * const Z, uECC_Curve curve) { uECC_word_t t1[8]; uECC_vli_modSquare_fast(t1, Z, curve); /* z^2 */ uECC_vli_modMult_fast(X1, X1, t1, curve); /* x1 * z^2 */ uECC_vli_modMult_fast(t1, t1, Z, curve); /* z^3 */ uECC_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */ } /* P = (x1, y1) => 2P, (x2, y2) => P' */ static void XYcZ_initial_double(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * X2, uECC_word_t * Y2, const uECC_word_t * const initial_Z, uECC_Curve curve) { uECC_word_t z[8]; wordcount_t num_words = curve->num_words; if (initial_Z) { uECC_vli_set(z, initial_Z, num_words); } else { uECC_vli_clear(z, num_words); z[0] = 1; } uECC_vli_set(X2, X1, num_words); uECC_vli_set(Y2, Y1, num_words); apply_z(X1, Y1, z, curve); curve->double_jacobian(X1, Y1, z, curve); apply_z(X2, Y2, z, curve); } /* Input P = (x1, y1, Z), Q = (x2, y2, Z) Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) or P => P', Q => P + Q sub = x1' - x3 (used for subsequent call to XYcZ_addC()). */ static void XYcZ_add(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * X2, uECC_word_t * Y2, uECC_word_t * sub, uECC_Curve curve) { /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ uECC_word_t t5[8]; wordcount_t num_words = curve->num_words; uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ uECC_vli_modMult_fast(X1, X1, t5, curve); /* x1' = x1*A = B */ uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ uECC_vli_modSquare_fast(t5, Y2, curve); /* t5 = (y2 - y1)^2 = D */ uECC_vli_modSub(t5, t5, X1, curve->p, num_words); /* t5 = D - B */ uECC_vli_modSub(t5, t5, X2, curve->p, num_words); /* t5 = D - B - C = x3 */ uECC_vli_modSub(X2, X2, X1, curve->p, num_words); /* t3 = C - B */ uECC_vli_modMult_fast(Y1, Y1, X2, curve); /* y1' = y1*(C - B) */ uECC_vli_modSub(sub, X1, t5, curve->p, num_words); /* s = B - x3 */ uECC_vli_modMult_fast(Y2, Y2, sub, curve); /* t4 = (y2 - y1)*(B - x3) */ uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y3 */ uECC_vli_set(X2, t5, num_words); /* move x3 to output */ } /* Input P = (x1, y1, Z), Q = (x2, y2, Z), sub = x1 - x2 Output P - Q = (x3', y3', Z3), P + Q = (x3, y3, Z3) or P => P - Q, Q => P + Q */ static void XYcZ_addC(uECC_word_t * X1, uECC_word_t * Y1, uECC_word_t * X2, uECC_word_t * Y2, uECC_word_t * sub, uECC_Curve curve) { /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ uECC_word_t t5[8]; uECC_word_t t6[8]; uECC_word_t t7[8]; wordcount_t num_words = curve->num_words; uECC_vli_modSquare_fast(t5, sub, curve); /* t5 = (x2 - x1)^2 = A */ uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ uECC_vli_modAdd(t5, Y2, Y1, curve->p, num_words); /* t5 = y2 + y1 */ uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ uECC_vli_modSub(t6, X2, X1, curve->p, num_words); /* t6 = C - B */ uECC_vli_modMult_fast(Y1, Y1, t6, curve); /* t2 = y1 * (C - B) = E */ uECC_vli_modAdd(t6, X1, X2, curve->p, num_words); /* t6 = B + C */ uECC_vli_modSquare_fast(X2, Y2, curve); /* t3 = (y2 - y1)^2 = D */ uECC_vli_modSub(X2, X2, t6, curve->p, num_words); /* t3 = D - (B + C) = x3 */ uECC_vli_modSub(t7, X1, X2, curve->p, num_words); /* t7 = B - x3 */ uECC_vli_modMult_fast(Y2, Y2, t7, curve); /* t4 = (y2 - y1)*(B - x3) */ uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = (y2 - y1)*(B - x3) - E = y3 */ uECC_vli_modSquare_fast(t7, t5, curve); /* t7 = (y2 + y1)^2 = F */ uECC_vli_modSub(t7, t7, t6, curve->p, num_words); /* t7 = F - (B + C) = x3' */ uECC_vli_modSub(t6, t7, X1, curve->p, num_words); /* t6 = x3' - B */ uECC_vli_modMult_fast(t6, t6, t5, curve); /* t6 = (y2+y1)*(x3' - B) */ uECC_vli_modSub(Y1, t6, Y1, curve->p, num_words); /* t2 = (y2+y1)*(x3' - B) - E = y3' */ uECC_vli_set(X1, t7, num_words); /* move x3' to output */ } /* result may overlap point. */ static void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point, const uECC_word_t * scalar, const uECC_word_t * initial_Z, bitcount_t num_bits, uECC_Curve curve) { /* R0 and R1 */ uECC_word_t Rx[2][8]; uECC_word_t Ry[2][8]; uECC_word_t z[8]; uECC_word_t sub[8]; bitcount_t i; uECC_word_t nb; wordcount_t num_words = curve->num_words; uECC_vli_set(Rx[1], point, num_words); uECC_vli_set(Ry[1], point + num_words, num_words); XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z, curve); uECC_vli_modSub(sub, Rx[0], Rx[1], curve->p, num_words); for (i = num_bits - 2; i > 0; --i) { nb = !uECC_vli_testBit(scalar, i); XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], sub, curve); XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], sub, curve); } nb = !uECC_vli_testBit(scalar, 0); XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], sub, curve); /* Find final 1/Z value. */ uECC_vli_modSub(z, Rx[1], Rx[0], curve->p, num_words); /* X1 - X0 */ uECC_vli_modMult_fast(z, z, Ry[1 - nb], curve); /* Yb * (X1 - X0) */ uECC_vli_modMult_fast(z, z, point, curve); /* xP * Yb * (X1 - X0) */ uECC_vli_modInv(z, z, curve->p, num_words); /* 1 / (xP * Yb * (X1 - X0)) */ uECC_vli_modMult_fast(z, z, point + num_words, curve); /* yP / (xP * Yb * (X1 - X0)) */ uECC_vli_modMult_fast(z, z, Rx[1 - nb], curve); /* Xb * yP / (xP * Yb * (X1 - X0)) */ /* End 1/Z calculation */ XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], sub, curve); apply_z(Rx[0], Ry[0], z, curve); uECC_vli_set(result, Rx[0], num_words); uECC_vli_set(result + num_words, Ry[0], num_words); } static uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0, uECC_word_t *k1, uECC_Curve curve) { wordcount_t num_n_words = ((curve ->num_n_bits + ((4 * 8) - 1)) / (4 * 8)); bitcount_t num_n_bits = curve->num_n_bits; uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) || (num_n_bits < ((bitcount_t)num_n_words * 4 * 8) && uECC_vli_testBit(k0, num_n_bits)); uECC_vli_add(k1, k0, curve->n, num_n_words); return carry; } /* Generates a random integer in the range 0 < random < top. Both random and top have num_words words. */ static int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top, wordcount_t num_words) { uECC_word_t mask = (uECC_word_t)-1; uECC_word_t tries; bitcount_t num_bits = uECC_vli_numBits(top, num_words); if (!g_rng_function) { return 0; } for (tries = 0; tries < 64; ++tries) { if (!g_rng_function((uint8_t *)random, num_words * 4)) { return 0; } random[num_words - 1] &= mask >> ((bitcount_t)(num_words * 4 * 8 - num_bits)); if (!uECC_vli_isZero(random, num_words) && uECC_vli_cmp(top, random, num_words) == 1) { return 1; } } return 0; } static uECC_word_t EccPoint_compute_public_key(uECC_word_t *result, uECC_word_t *private_key, uECC_Curve curve) { uECC_word_t tmp1[8]; uECC_word_t tmp2[8]; uECC_word_t *p2[2] = {tmp1, tmp2}; uECC_word_t *initial_Z = 0; uECC_word_t carry; /* Regularize the bitcount for the private key so that attackers cannot use a side channel attack to learn the number of leading zeros. */ carry = regularize_k(private_key, tmp1, tmp2, curve); /* If an RNG function was specified, try to get a random initial Z value to improve protection against side-channel attacks. */ if (g_rng_function) { if (!uECC_generate_random_int(p2[carry], curve->p, curve->num_words)) { return 0; } initial_Z = p2[carry]; } EccPoint_mult(result, curve->G, p2[!carry], initial_Z, curve->num_n_bits + 1, curve); if (uECC_vli_isZero((result), (curve)->num_words * 2)) { return 0; } return 1; } static void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes, const uECC_word_t *native) { int i; for (i = 0; i < num_bytes; ++i) { unsigned b = num_bytes - 1 - i; bytes[i] = native[b / 4] >> (8 * (b % 4)); } } static void uECC_vli_bytesToNative(uECC_word_t *native, const uint8_t *bytes, int num_bytes) { int i; uECC_vli_clear(native, (num_bytes + (4 - 1)) / 4); for (i = 0; i < num_bytes; ++i) { unsigned b = num_bytes - 1 - i; native[b / 4] |= (uECC_word_t)bytes[i] << (8 * (b % 4)); } } int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve) { uECC_word_t _private[8]; uECC_word_t _public[8 * 2]; uECC_word_t tries; for (tries = 0; tries < 64; ++tries) { if (!uECC_generate_random_int(_private, curve->n, ((curve ->num_n_bits + ((4 * 8) - 1)) / (4 * 8)))) { return 0; } if (EccPoint_compute_public_key(_public, _private, curve)) { uECC_vli_nativeToBytes(private_key, ((curve ->num_n_bits + 7) / 8), _private); uECC_vli_nativeToBytes(public_key, curve->num_bytes, _public); uECC_vli_nativeToBytes( public_key + curve->num_bytes, curve->num_bytes, _public + curve->num_words); return 1; } } return 0; } int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key, uint8_t *secret, uECC_Curve curve) { uECC_word_t _public[8 * 2]; uECC_word_t _private[8]; uECC_word_t tmp[8]; uECC_word_t *p2[2] = {_private, tmp}; uECC_word_t *initial_Z = 0; uECC_word_t carry; wordcount_t num_words = curve->num_words; wordcount_t num_bytes = curve->num_bytes; uECC_vli_bytesToNative(_private, private_key, ((curve ->num_n_bits + 7) / 8)); uECC_vli_bytesToNative(_public, public_key, num_bytes); uECC_vli_bytesToNative(_public + num_words, public_key + num_bytes, num_bytes); /* Regularize the bitcount for the private key so that attackers cannot use a side channel attack to learn the number of leading zeros. */ carry = regularize_k(_private, _private, tmp, curve); /* If an RNG function was specified, try to get a random initial Z value to improve protection against side-channel attacks. */ if (g_rng_function) { if (!uECC_generate_random_int(p2[carry], curve->p, num_words)) { return 0; } initial_Z = p2[carry]; } EccPoint_mult(_public, _public, p2[!carry], initial_Z, curve->num_n_bits + 1, curve); uECC_vli_nativeToBytes(secret, num_bytes, _public); return !uECC_vli_isZero((_public), (curve)->num_words * 2); } void uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve) { wordcount_t i; for (i = 0; i < curve->num_bytes; ++i) { compressed[i+1] = public_key[i]; } compressed[0] = 2 + (public_key[curve->num_bytes * 2 - 1] & 0x01); } void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve) { uECC_word_t point[8 * 2]; uECC_word_t *y = point + curve->num_words; uECC_vli_bytesToNative(point, compressed + 1, curve->num_bytes); curve->x_side(y, point, curve); curve->mod_sqrt(y, curve); if ((y[0] & 0x01) != (compressed[0] & 0x01)) { uECC_vli_sub(y, curve->p, y, curve->num_words); } uECC_vli_nativeToBytes(public_key, curve->num_bytes, point); uECC_vli_nativeToBytes(public_key + curve->num_bytes, curve->num_bytes, y); } static int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) { uECC_word_t tmp1[8]; uECC_word_t tmp2[8]; wordcount_t num_words = curve->num_words; /* The point at infinity is invalid. */ if (uECC_vli_isZero((point), (curve)->num_words * 2)) { return 0; } /* x and y must be smaller than p. */ if (uECC_vli_cmp_unsafe(curve->p, point, num_words) != 1 || uECC_vli_cmp_unsafe(curve->p, point + num_words, num_words) != 1) { return 0; } uECC_vli_modSquare_fast(tmp1, point + num_words, curve); curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */ /* Make sure that y^2 == x^3 + ax + b */ return (int)(uECC_vli_equal(tmp1, tmp2, num_words)); } int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve) { uECC_word_t _public[8 * 2]; uECC_vli_bytesToNative(_public, public_key, curve->num_bytes); uECC_vli_bytesToNative( _public + curve->num_words, public_key + curve->num_bytes, curve->num_bytes); return uECC_valid_point(_public, curve); } int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve) { uECC_word_t _private[8]; uECC_word_t _public[8 * 2]; uECC_vli_bytesToNative(_private, private_key, ((curve ->num_n_bits + 7) / 8)); /* Make sure the private key is in the range [1, n-1]. */ if (uECC_vli_isZero(_private, ((curve ->num_n_bits + ((4 * 8) - 1)) / (4 * 8)))) { return 0; } if (uECC_vli_cmp(curve->n, _private, ((curve ->num_n_bits + ((4 * 8) - 1)) / (4 * 8))) != 1) { return 0; } /* Compute public key. */ if (!EccPoint_compute_public_key(_public, _private, curve)) { return 0; } uECC_vli_nativeToBytes(public_key, curve->num_bytes, _public); uECC_vli_nativeToBytes( public_key + curve->num_bytes, curve->num_bytes, _public + curve->num_words); return 1; } /* -------- ECDSA code -------- */ static void bits2int(uECC_word_t *native, const uint8_t *bits, unsigned bits_size, uECC_Curve curve) { unsigned num_n_bytes = ((curve ->num_n_bits + 7) / 8); unsigned num_n_words = ((curve ->num_n_bits + ((4 * 8) - 1)) / (4 * 8)); int shift; uECC_word_t carry; uECC_word_t *ptr; if (bits_size > num_n_bytes) { bits_size = num_n_bytes; } uECC_vli_clear(native, num_n_words); uECC_vli_bytesToNative(native, bits, bits_size); if (bits_size * 8 <= (unsigned)curve->num_n_bits) { return; } shift = bits_size * 8 - curve->num_n_bits; carry = 0; ptr = native + num_n_words; while (ptr-- > native) { uECC_word_t temp = *ptr; *ptr = (temp >> shift) | carry; carry = temp << (32 - shift); } /* Reduce mod curve_n */ if (uECC_vli_cmp_unsafe(curve->n, native, num_n_words) != 1) { uECC_vli_sub(native, native, curve->n, num_n_words); } } static int uECC_sign_with_k_internal(const uint8_t *private_key, const uint8_t *message_hash, unsigned hash_size, uECC_word_t *k, uint8_t *signature, uECC_Curve curve) { uECC_word_t tmp[8]; uECC_word_t s[8]; uECC_word_t *k2[2] = {tmp, s}; uECC_word_t *initial_Z = 0; uECC_word_t p[8 * 2]; uECC_word_t carry; wordcount_t num_words = curve->num_words; wordcount_t num_n_words = ((curve ->num_n_bits + ((4 * 8) - 1)) / (4 * 8)); bitcount_t num_n_bits = curve->num_n_bits; /* Make sure 0 < k < curve_n */ if (uECC_vli_isZero(k, num_words) || uECC_vli_cmp(curve->n, k, num_n_words) != 1) { return 0; } carry = regularize_k(k, tmp, s, curve); /* If an RNG function was specified, try to get a random initial Z value to improve protection against side-channel attacks. */ if (g_rng_function) { if (!uECC_generate_random_int(k2[carry], curve->p, num_words)) { return 0; } initial_Z = k2[carry]; } EccPoint_mult(p, curve->G, k2[!carry], initial_Z, num_n_bits + 1, curve); if (uECC_vli_isZero(p, num_words)) { return 0; } /* If an RNG function was specified, get a random number to prevent side channel analysis of k. */ if (!g_rng_function) { uECC_vli_clear(tmp, num_n_words); tmp[0] = 1; } else if (!uECC_generate_random_int(tmp, curve->n, num_n_words)) { return 0; } /* Prevent side channel analysis of uECC_vli_modInv() to determine bits of k / the private key by premultiplying by a random number */ uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */ uECC_vli_modInv(k, k, curve->n, num_n_words); /* k = 1 / k' */ uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k = 1 / k */ uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r */ uECC_vli_bytesToNative(tmp, private_key, ((curve ->num_n_bits + 7) / 8)); /* tmp = d */ s[num_n_words - 1] = 0; uECC_vli_set(s, p, num_words); uECC_vli_modMult(s, tmp, s, curve->n, num_n_words); /* s = r*d */ bits2int(tmp, message_hash, hash_size, curve); uECC_vli_modAdd(s, tmp, s, curve->n, num_n_words); /* s = e + r*d */ uECC_vli_modMult(s, s, k, curve->n, num_n_words); /* s = (e + r*d) / k */ if (uECC_vli_numBits(s, num_n_words) > (bitcount_t)curve->num_bytes * 8) { return 0; } uECC_vli_nativeToBytes(signature + curve->num_bytes, curve->num_bytes, s); return 1; } /* For testing - sign with an explicitly specified k value */ int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash, unsigned hash_size, const uint8_t *k, uint8_t *signature, uECC_Curve curve) { uECC_word_t k2[8]; bits2int(k2, k, ((curve ->num_n_bits + 7) / 8), curve); return uECC_sign_with_k_internal(private_key, message_hash, hash_size, k2, signature, curve); } int uECC_sign(const uint8_t *private_key, const uint8_t *message_hash, unsigned hash_size, uint8_t *signature, uECC_Curve curve) { uECC_word_t k[8]; uECC_word_t tries; for (tries = 0; tries < 64; ++tries) { if (!uECC_generate_random_int(k, curve->n, ((curve ->num_n_bits + ((4 * 8) - 1)) / (4 * 8)))) { return 0; } if (uECC_sign_with_k_internal(private_key, message_hash, hash_size, k, signature, curve)) { return 1; } } return 0; } /* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always the same size as the hash result size. */ static void HMAC_init(const uECC_HashContext *hash_context, const uint8_t *K) { uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; unsigned i; for (i = 0; i < hash_context->result_size; ++i) pad[i] = K[i] ^ 0x36; for (; i < hash_context->block_size; ++i) pad[i] = 0x36; hash_context->init_hash(hash_context); hash_context->update_hash(hash_context, pad, hash_context->block_size); } static void HMAC_update(const uECC_HashContext *hash_context, const uint8_t *message, unsigned message_size) { hash_context->update_hash(hash_context, message, message_size); } static void HMAC_finish(const uECC_HashContext *hash_context, const uint8_t *K, uint8_t *result) { uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; unsigned i; for (i = 0; i < hash_context->result_size; ++i) pad[i] = K[i] ^ 0x5c; for (; i < hash_context->block_size; ++i) pad[i] = 0x5c; hash_context->finish_hash(hash_context, result); hash_context->init_hash(hash_context); hash_context->update_hash(hash_context, pad, hash_context->block_size); hash_context->update_hash(hash_context, result, hash_context->result_size); hash_context->finish_hash(hash_context, result); } /* V = HMAC_K(V) */ static void update_V(const uECC_HashContext *hash_context, uint8_t *K, uint8_t *V) { HMAC_init(hash_context, K); HMAC_update(hash_context, V, hash_context->result_size); HMAC_finish(hash_context, K, V); } /* Deterministic signing, similar to RFC 6979. Differences are: * We just use H(m) directly rather than bits2octets(H(m)) (it is not reduced modulo curve_n). * We generate a value for k (aka T) directly rather than converting endianness. Layout of hash_context->tmp: | | (1 byte overlapped 0x00 or 0x01) / */ int uECC_sign_deterministic(const uint8_t *private_key, const uint8_t *message_hash, unsigned hash_size, const uECC_HashContext *hash_context, uint8_t *signature, uECC_Curve curve) { uint8_t *K = hash_context->tmp; uint8_t *V = K + hash_context->result_size; wordcount_t num_bytes = curve->num_bytes; wordcount_t num_n_words = ((curve ->num_n_bits + ((4 * 8) - 1)) / (4 * 8)); bitcount_t num_n_bits = curve->num_n_bits; uECC_word_t tries; unsigned i; for (i = 0; i < hash_context->result_size; ++i) { V[i] = 0x01; K[i] = 0; } /* K = HMAC_K(V || 0x00 || int2octets(x) || h(m)) */ HMAC_init(hash_context, K); V[hash_context->result_size] = 0x00; HMAC_update(hash_context, V, hash_context->result_size + 1); HMAC_update(hash_context, private_key, num_bytes); HMAC_update(hash_context, message_hash, hash_size); HMAC_finish(hash_context, K, K); update_V(hash_context, K, V); /* K = HMAC_K(V || 0x01 || int2octets(x) || h(m)) */ HMAC_init(hash_context, K); V[hash_context->result_size] = 0x01; HMAC_update(hash_context, V, hash_context->result_size + 1); HMAC_update(hash_context, private_key, num_bytes); HMAC_update(hash_context, message_hash, hash_size); HMAC_finish(hash_context, K, K); update_V(hash_context, K, V); for (tries = 0; tries < 64; ++tries) { uECC_word_t T[8]; uint8_t *T_ptr = (uint8_t *)T; wordcount_t T_bytes = 0; for (;;) { update_V(hash_context, K, V); for (i = 0; i < hash_context->result_size; ++i) { T_ptr[T_bytes++] = V[i]; if (T_bytes >= num_n_words * 4) { goto filled; } } } filled: if ((bitcount_t)num_n_words * 4 * 8 > num_n_bits) { uECC_word_t mask = (uECC_word_t)-1; T[num_n_words - 1] &= mask >> ((bitcount_t)(num_n_words * 4 * 8 - num_n_bits)); } if (uECC_sign_with_k_internal(private_key, message_hash, hash_size, T, signature, curve)) { return 1; } /* K = HMAC_K(V || 0x00) */ HMAC_init(hash_context, K); V[hash_context->result_size] = 0x00; HMAC_update(hash_context, V, hash_context->result_size + 1); HMAC_finish(hash_context, K, K); update_V(hash_context, K, V); } return 0; } static bitcount_t smax(bitcount_t a, bitcount_t b) { return (a > b ? a : b); } int uECC_verify(const uint8_t *public_key, const uint8_t *message_hash, unsigned hash_size, const uint8_t *signature, uECC_Curve curve) { uECC_word_t u1[8], u2[8]; uECC_word_t z[8]; uECC_word_t sum[8 * 2]; uECC_word_t rx[8]; uECC_word_t ry[8]; uECC_word_t tx[8]; uECC_word_t ty[8]; uECC_word_t tz[8]; const uECC_word_t *points[4]; const uECC_word_t *point; bitcount_t num_bits; bitcount_t i; uECC_word_t _public[8 * 2]; uECC_word_t r[8], s[8]; wordcount_t num_words = curve->num_words; wordcount_t num_n_words = ((curve ->num_n_bits + ((4 * 8) - 1)) / (4 * 8)); rx[num_n_words - 1] = 0; r[num_n_words - 1] = 0; s[num_n_words - 1] = 0; uECC_vli_bytesToNative(_public, public_key, curve->num_bytes); uECC_vli_bytesToNative( _public + num_words, public_key + curve->num_bytes, curve->num_bytes); uECC_vli_bytesToNative(r, signature, curve->num_bytes); uECC_vli_bytesToNative(s, signature + curve->num_bytes, curve->num_bytes); /* r, s must not be 0. */ if (uECC_vli_isZero(r, num_words) || uECC_vli_isZero(s, num_words)) { return 0; } /* r, s must be < n. */ if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 || uECC_vli_cmp_unsafe(curve->n, s, num_n_words) != 1) { return 0; } /* Calculate u1 and u2. */ uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */ u1[num_n_words - 1] = 0; bits2int(u1, message_hash, hash_size, curve); uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */ uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */ /* Calculate sum = G + Q. */ uECC_vli_set(sum, _public, num_words); uECC_vli_set(sum + num_words, _public + num_words, num_words); uECC_vli_set(tx, curve->G, num_words); uECC_vli_set(ty, curve->G + num_words, num_words); uECC_vli_modSub(z, sum, tx, curve->p, num_words); /* z = x2 - x1 */ /* Note: safe to use tx for 'sub' param, since tx is not used after XYcZ_add. */ XYcZ_add(tx, ty, sum, sum + num_words, tx, curve); uECC_vli_modInv(z, z, curve->p, num_words); /* z = 1/z */ apply_z(sum, sum + num_words, z, curve); /* Use Shamir's trick to calculate u1*G + u2*Q */ points[0] = 0; points[1] = curve->G; points[2] = _public; points[3] = sum; num_bits = smax(uECC_vli_numBits(u1, num_n_words), uECC_vli_numBits(u2, num_n_words)); point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) | ((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)]; uECC_vli_set(rx, point, num_words); uECC_vli_set(ry, point + num_words, num_words); uECC_vli_clear(z, num_words); z[0] = 1; for (i = num_bits - 2; i >= 0; --i) { uECC_word_t index; curve->double_jacobian(rx, ry, z, curve); index = (!!uECC_vli_testBit(u1, i)) | ((!!uECC_vli_testBit(u2, i)) << 1); point = points[index]; if (point) { uECC_vli_set(tx, point, num_words); uECC_vli_set(ty, point + num_words, num_words); apply_z(tx, ty, z, curve); uECC_vli_modSub(tz, rx, tx, curve->p, num_words); /* Z = x2 - x1 */ XYcZ_add(tx, ty, rx, ry, tx, curve); uECC_vli_modMult_fast(z, z, tz, curve); } } uECC_vli_modInv(z, z, curve->p, num_words); /* Z = 1/Z */ apply_z(rx, ry, z, curve); /* v = x1 (mod n) */ if (uECC_vli_cmp_unsafe(curve->n, rx, num_n_words) != 1) { uECC_vli_sub(rx, rx, curve->n, num_n_words); } /* Accept only if v == r. */ return (int)(uECC_vli_equal(rx, r, num_words)); }