summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Cprek <smcprek@us.ibm.com>2016-12-05 16:29:06 -0600
committerDaniel M. Crowell <dcrowell@us.ibm.com>2017-01-30 11:15:34 -0500
commitaff3f67b49b87d5e2755b364ecb512641bbb4540 (patch)
treee87cd2eb0afe2d3721ae2bfb7928c6a6b134e590
parent5784da25300866c71551f1f0411d469eb3a3c922 (diff)
downloadtalos-hostboot-aff3f67b49b87d5e2755b364ecb512641bbb4540.tar.gz
talos-hostboot-aff3f67b49b87d5e2755b364ecb512641bbb4540.zip
Add ROM code files in Hostboot
RTC: 143902 Change-Id: Iff00250b1dd36c301c311147a1540a5f3c33f19b Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/33607 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Nicholas E. Bofferding <bofferdn@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Reviewed-by: Michael Baiocchi <mbaiocch@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
-rw-r--r--src/include/securerom/ROM.H133
-rw-r--r--src/include/securerom/ecverify.H55
-rw-r--r--src/include/securerom/hw_utils.H430
-rw-r--r--src/include/securerom/sha512.H51
-rw-r--r--src/include/securerom/status_codes.H113
-rw-r--r--src/securerom.ld96
-rw-r--r--src/securerom/ROM.C579
-rw-r--r--src/securerom/branchtable.S98
-rw-r--r--src/securerom/ecverify.C1662
-rw-r--r--src/securerom/hw_utils.C222
-rw-r--r--src/securerom/inttypes.H41
-rw-r--r--src/securerom/makefile244
-rw-r--r--src/securerom/sha512.C482
13 files changed, 4206 insertions, 0 deletions
diff --git a/src/include/securerom/ROM.H b/src/include/securerom/ROM.H
new file mode 100644
index 000000000..315a436d0
--- /dev/null
+++ b/src/include/securerom/ROM.H
@@ -0,0 +1,133 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/include/securerom/ROM.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+/****************************************************************************
+ *
+ ****************************************************************************/
+#ifndef ROM_H
+#define ROM_H
+
+/****************************************************************************/
+#ifndef PHYPLIBFUNCTIONS
+#include <hw_utils.h>
+#endif
+#include <sha512.h>
+#include <ecverify.h>
+
+/****************************************************************************/
+#define CONTAINER_VERSION 1
+#define HEADER_VERSION 1
+#define HASH_ALG_SHA512 1
+#define SIG_ALG_ECDSA521 1
+
+#define HBI_BASE_SIGNING_KEY 0x80000000
+
+#define ROM_MAGIC_NUMBER 0x17082011
+
+typedef struct {
+ uint16_t version; // (1: see versions above)
+ uint8_t hash_alg; // (1: SHA-512)
+ uint8_t sig_alg; // (1: SHA-512/ECDSA-521)
+}__attribute__((packed)) ROM_version_raw;
+
+typedef struct {
+ uint32_t magic_number; // (17082011)
+ uint16_t version; // (1: see versions above)
+ uint64_t container_size; // filled by caller
+ uint64_t target_hrmor; // filled by caller
+ uint64_t stack_pointer; // filled by caller //bottom of stack -> 128k added by rom code to get real stack pointer
+ ecc_key_t hw_pkey_a;
+ ecc_key_t hw_pkey_b;
+ ecc_key_t hw_pkey_c;
+ uint64_t prefix; // prefix header place holder
+ // followed by sw header (if not special prefix)
+ // followed by optional unprotected payload data
+}__attribute__((packed)) ROM_container_raw;
+
+typedef struct {
+ ROM_version_raw ver_alg;
+ uint64_t code_start_offset;
+ uint64_t reserved;
+ uint32_t flags;
+ uint8_t sw_key_count;
+ uint64_t payload_size;
+ sha2_hash_t payload_hash;
+ uint8_t ecid_count;
+ uint8_t ecid[ECID_SIZE]; // optional ecid place holder ecid_count * ecid_size(128 bits)
+ // followed by prefix data (sig,keys) key raw
+}__attribute__((packed)) ROM_prefix_header_raw;
+
+#define PREFIX_HEADER_SIZE(_p) (sizeof(ROM_prefix_header_raw)+((_p->ecid_count-1)*ECID_SIZE))
+
+typedef struct {
+ ecc_signature_t hw_sig_a;
+ ecc_signature_t hw_sig_b;
+ ecc_signature_t hw_sig_c;
+ ecc_key_t sw_pkey_p;
+ ecc_key_t sw_pkey_q;
+ ecc_key_t sw_pkey_r;
+}__attribute__((packed)) ROM_prefix_data_raw;
+
+typedef struct {
+ ROM_version_raw ver_alg;
+ uint64_t code_start_offset;
+ uint64_t reserved;
+ uint32_t flags;
+ uint8_t reserved_0;
+ uint64_t payload_size;
+ sha2_hash_t payload_hash;
+ uint8_t ecid_count;
+ uint8_t ecid[ECID_SIZE]; // optional ecid place holder ecid_count * ecid_size(128 bits)
+ // followed by sw sig raw
+}__attribute__((packed)) ROM_sw_header_raw;
+
+#define SW_HEADER_SIZE(_p) (sizeof(ROM_sw_header_raw)+((_p->ecid_count-1)*ECID_SIZE))
+
+typedef struct {
+ ecc_signature_t sw_sig_p;
+ ecc_signature_t sw_sig_q;
+ ecc_signature_t sw_sig_r;
+ // followed by zero's padding to 4K
+ // followed by protected sw payload_data
+ // followed by unprotected sw payload_text
+}__attribute__((packed)) ROM_sw_sig_raw;
+
+/****************************************************************************/
+typedef enum { ROM_DONE, ROM_FAILED, PHYP_PARTIAL } ROM_response;
+
+#ifndef PHYPLIBFUNCTIONS
+typedef struct {
+ sha2_hash_t hw_key_hash;
+ uint8_t my_ecid[ECID_SIZE];
+ uint64_t entry_point;
+ uint64_t log;
+}__attribute__((packed)) ROM_hw_params;
+
+//extern void ROM_instruction_start (void);
+extern void ROM_sreset (void);
+extern ROM_response ROM_verify (ROM_container_raw* container,
+ ROM_hw_params* params);
+#endif
+
+#endif
diff --git a/src/include/securerom/ecverify.H b/src/include/securerom/ecverify.H
new file mode 100644
index 000000000..b7c707803
--- /dev/null
+++ b/src/include/securerom/ecverify.H
@@ -0,0 +1,55 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/include/securerom/ecverify.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+/*----------------------------------------------------------------------
+ * (C) COPYRIGHT INTERNATIONAL BUSINESS MACHINES CORPORATION 2010
+ * ALL RIGHTS RESERVED
+ * IBM Research, Zurich and IBM Crypto Competency Center, Copenhagen
+ *----------------------------------------------------------------------
+ * Author: Tamas Visegrady (tvi@zurich.ibm.com)
+ *----------------------------------------------------------------------*/
+
+#if !defined(__ECVERIFY_H__)
+#define __ECVERIFY_H__
+
+/** ECDSA verification on fixed curve
+ */
+
+#define EC_HASHBYTES 64 /* SHA-256 */
+#define EC_COORDBYTES 66 /* P-521 */
+
+typedef uint8_t ecc_key_t[2*EC_COORDBYTES];
+typedef uint8_t ecc_signature_t[2*EC_COORDBYTES];
+
+/** Returns positive if signature verified
+ * zero if parameters are valid but signature verification fails
+ * negative if parameters (such as point) are invalid
+ */
+int ec_verify (const uint8_t *publicpt, /* 2*EC_COORDBYTES */
+ const uint8_t *hash, /* EC_HASHBYTES */
+ const uint8_t *signature) ; /* 2*EC_COORDBYTES */
+
+#define NDEBUG
+
+#endif /* defined(__ECVERIFY_H__) */
diff --git a/src/include/securerom/hw_utils.H b/src/include/securerom/hw_utils.H
new file mode 100644
index 000000000..324cdfc25
--- /dev/null
+++ b/src/include/securerom/hw_utils.H
@@ -0,0 +1,430 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/include/securerom/hw_utils.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+/****************************************************************************
+ *
+ ****************************************************************************/
+#ifndef HW_UTILS_H
+#define HW_UTILS_H
+
+#include <stdint.h>
+
+#include "sha512.h"
+#include "status_codes.h"
+
+#define ECID_SIZE 16
+#define CACHE_LINE 128
+#define XSCOM_MASK 0x0003fe0000000000ull // bit 14:22 implemented
+#define HRMOR_MASK 0x0003fffffe000000ull // 32MB aligned
+#define STACK_MASK 0x0003fffffffff000ull // 4KB page aligned //WEH bug fix
+#define ENTRY_MASK 0x7ffffffffffffffCull // 4Byte page aligned
+
+#define HRMOR_IGNORE 0x8000000000000000ull
+#define HRMOR_RELATIVE(_a) ((_a)&~HRMOR_IGNORE)
+#define ABSOLUTE_ADDR(_a) ((_a)|HRMOR_IGNORE)
+
+
+#define CONTEXT 0
+
+#ifdef EMULATE_HW
+
+extern int FAIL;
+extern int GOOD;
+
+#define HOST_RESET_VECTOR 0x100
+
+#define TEST_SYSTEM_MEMORY (64*1024*1024)
+#define TRUSTED_MEMORY_BASE (8*1024*1024) // should be 256MB
+#define TOTAL_TEST_MEMORY (TEST_SYSTEM_MEMORY+4*1024)
+#define MEMORY_MASK 0x7fffffffffffffffull
+#define CACHE_MASK 0x7fffffffffffff80ull // 128B cache line aligned
+
+#define PHYSICAL(_a) ((_a)&MEMORY_MASK)
+
+#define LOG(_c) Log(CONTEXT|(_c))
+#define CHECK_STOP(_m) Check_Stop(_m)
+#define ERROR_STOP(_c,_m) Error_Stop(CONTEXT|(_c), _m)
+
+typedef struct {
+ uint64_t GPR[32];
+ uint64_t SCRATCH0;
+ uint64_t SCRATCH1;
+ uint64_t SCRATCH2;
+ uint64_t SCRATCH3;
+ uint64_t HRMOR;
+ struct {
+ uint64_t value;
+ uint64_t mask;
+ } FSP_BAR;
+ uint8_t ECID[ECID_SIZE];
+ sha2_hash_t PIBMEM_HW_KEY_HASH;
+ uint8_t* data; // 64M+4K malloc/mmap
+ uint8_t* memory; // 64M (4K aligned)
+ int mfd;
+} hw_settings;
+
+extern hw_settings HW;
+
+#define r1 HW.GPR[1]
+#define r2 HW.GPR[2]
+
+extern void HW_Init (void);
+extern void HW_Free (void);
+
+extern void Log (uint64_t code);
+extern void Error (uint64_t code);
+extern void Check_Stop (char* msg);
+extern void Error_Stop (uint64_t code, char* msg);
+
+extern void assem_DCBI (uint64_t addr);
+extern void assem_DCBZ (uint64_t addr);
+extern void assem_DCBST (uint8_t* addr);
+extern void assem_ICBI (uint64_t* addr);
+extern void assem_SYNC (void);
+extern void assem_ISYNC (void);
+
+extern void mtspr_HRMOR (uint64_t addr);
+//extern uint64_t mfspr_HRMOR (void);
+
+static inline uint64_t mfspr_SCRATCH0(void) {
+ return HW.SCRATCH0;
+}
+
+static inline void mtspr_SCRATCH0(uint64_t val) {
+ HW.SCRATCH0 = val;
+}
+
+static inline uint64_t mfspr_SCRATCH1(void) {
+ return HW.SCRATCH1;
+}
+
+static inline void mtspr_SCRATCH1(uint64_t val) {
+ HW.SCRATCH1 = val;
+}
+
+static inline void mtspr_SCRATCH2(uint64_t val) {
+ HW.SCRATCH2 = val;
+}
+
+static inline uint64_t mfspr_SCRATCH2(void) {
+ return HW.SCRATCH2;
+}
+
+static inline void mtspr_SCRATCH3(uint64_t val) {
+ HW.SCRATCH3 = val;
+}
+
+static inline uint64_t mfspr_SCRATCH3(void) {
+ return HW.SCRATCH3;
+}
+
+extern uint64_t getscom_FSP_BAR_value (uint64_t base);
+extern uint64_t getscom_FSP_BAR_mask (uint64_t base);
+
+extern void getscom_HW_ECID (uint64_t base, uint8_t* buf);
+extern void getscom_PIBMEM_HW_Key_Hash (uint64_t base, uint8_t* buf);
+
+extern uint64_t physical_addr (uint64_t addr);
+extern uint8_t* Convert_Mem_Addr (uint64_t);
+extern uint64_t Convert_Mem_Offset (uint8_t*);
+
+/****************************************************************************/
+extern uint16_t GET16 (uint16_t data);
+extern uint32_t GET32 (uint32_t data);
+extern uint64_t GET64 (uint64_t data);
+
+#else //emulate_hw
+
+/* SPRs numbers -- the wrong ones: */
+//#define SPRG0 272 /* Software Special Purpose Register 0 */
+//#define SPRG1 273 /* Software Special Purpose Register 1 */
+//#define SPRG2 274 /* Software Special Purpose Register 2 */
+//#define SPRG3 275 /* Software Special Purpose Register 3 */
+
+#define SPRC 276
+#define SPRC_SCRATCH0 0x0000000000000040
+#define SPRC_SCRATCH1 0x0000000000000048
+#define SPRC_SCRATCH2 0x0000000000000050
+#define SPRC_SCRATCH3 0x0000000000000058
+#define SPRC_AVP_out 0x00000000000001C8
+#define SPRD 277
+
+#define HRMOR 313
+
+#define HMER 336
+#define HMER_XSCOM_FAIL 0x0080000000000000 //Bit 8
+#define HMER_XSCOM_DONE 0x0040000000000000 //Bit 9
+#define HMER_XSCOM_RSLT 0x0000070000000000 //Bit 21-23
+#define HMER_XSCOM_RTRY 0x0000010000000000 //RSLT = 001 = retry
+
+/* SCOM Register addresses */
+#define OTP 0x00018000
+#define OTP_ECID OTP +0x0000
+#define PIBMEM 0x00080000
+#define PIBMEM_HW_KEY_HASH PIBMEM +0x0008
+
+#define ALTD_UNTRUSTED_BAR_ADDR_REG 0x02020015
+#define ALTD_UNTRUSTED_BAR_MASK_ADDR_REG 0x02020016
+#define PSIHB_NOTRUST_BAR0 0x02013f40
+#define PSIHB_NOTRUST_BAR0MASK 0x02013f42
+#define PSIHB_NOTRUST_BAR1 0x02013f41
+#define PSIHB_NOTRUST_BAR1MASK 0x02013f43
+
+/****************************************************************************/
+static inline void assem_DCBI(uint64_t addr) {
+ asm volatile(" dcbi 0,%0 " : : "r" (addr) : "memory");
+}
+/****************************************************************************/
+static inline void assem_DCBZ(uint64_t addr) {
+ asm volatile(" dcbz 0,%0 " : : "r" (addr) : "memory");
+}
+/****************************************************************************/
+static inline void assem_ICBI(uint64_t* addr) {
+ asm volatile(" icbi 0,%0 " : : "r" (addr) : "memory");
+}
+/****************************************************************************/
+static inline void assem_SYNC(void) {
+ asm volatile("sync 0":::"memory");
+}
+/****************************************************************************/
+static inline void assem_ISYNC(void) {
+ asm volatile("isync":::"memory");
+}
+/****************************************************************************/
+
+static inline uint64_t mfspr(int reg) {
+ unsigned long val;
+ asm volatile("mfspr %0, %1" : "=r" (val) : "i" (reg));
+ return val;
+}
+
+static inline void mtspr(int reg, uint64_t val) {
+ asm volatile("mtspr %0, %1" : : "i" (reg), "r" (val));
+}
+
+/****************************************************************************/
+//
+//static inline uint64_t mfspr_HRMOR(void) {
+// unsigned long val;
+// asm volatile("mfspr %0, %1" : "=r" (val) : "i" (HRMOR));
+// return val;
+//}
+
+static inline void mtspr_HRMOR(uint64_t addr) {
+ asm volatile("mtspr %0, %1" : : "i" (HRMOR), "r" (addr & HRMOR_MASK));
+}
+
+/****************************************************************************/
+#if !(CONFIG_MAMBO && CONFIG_MAMBO_WITHOUT_SCRATCH)
+
+static inline uint64_t mfspr_SCRATCH0(void) {
+ mtspr(SPRC,SPRC_SCRATCH0);
+ return mfspr(SPRD);
+}
+
+static inline void mtspr_SCRATCH0(uint64_t val) {
+ mtspr(SPRC,SPRC_SCRATCH0);
+ mtspr(SPRD,val);
+}
+
+static inline uint64_t mfspr_SCRATCH1(void) {
+ mtspr(SPRC,SPRC_SCRATCH1);
+ return mfspr(SPRD);
+}
+
+static inline void mtspr_SCRATCH1(uint64_t val) {
+ mtspr(SPRC,SPRC_SCRATCH1);
+ mtspr(SPRD,val);
+}
+
+static inline void mtspr_SCRATCH2(uint64_t val) {
+ mtspr(SPRC,SPRC_SCRATCH2);
+ mtspr(SPRD,val);
+}
+
+static inline void mtspr_SCRATCH3(uint64_t val) {
+ mtspr(SPRC,SPRC_SCRATCH3);
+ mtspr(SPRD,val);
+}
+
+#else
+
+ #define mfspr_SCRATCH0() ci_read( 0x80C0FFEE00000000ull)
+ #define mtspr_SCRATCH0(value) ci_write(0x80C0FFEE00000000ull,(value))
+ #define mfspr_SCRATCH1() ci_read( 0x80C0FFEE00000008ull)
+ #define mtspr_SCRATCH1(value) ci_write(0x80C0FFEE00000008ull,(value))
+ #define mfspr_SCRATCH2() ci_read( 0x80C0FFEE00000010ull)
+ #define mtspr_SCRATCH2(value) ci_write(0x80C0FFEE00000010ull,(value))
+ #define mfspr_SCRATCH3() ci_read( 0x80C0FFEE00000018ull)
+ #define mtspr_SCRATCH3(value) ci_write(0x80C0FFEE00000018ull,(value))
+
+#endif
+/****************************************************************************/
+
+void __attribute__((noreturn)) Check_Stop(void);
+
+/****************************************************************************/
+
+#define LOG(_c) mtspr_SCRATCH2(CONTEXT|(_c))
+#define ERROR_STOP(_c,_m) { mtspr_SCRATCH3(ERROR_EVENT|CONTEXT|(_c)); asm volatile("b .Check_Stop"); }
+
+
+/****************************************************************************/
+/* Bit 56, 61, 62, 63 is not used in XSCOM addresss and must be 0
+ */
+#define PCB2PBUS(scom_addr) \
+ ((((scom_addr) & 0x7FFFFFF0) << 4) | \
+ (((scom_addr) & 0x0000000F) << 3))
+
+
+static inline uint64_t ci_read(const uint64_t reg) {
+ unsigned long val;
+ asm volatile( "ldcix %0, 0, %1"
+ : "=r" (val) // output, %0
+ : "r" (reg) // input, %1
+ // no impacts
+ );
+ //old prism code:
+ //asm volatile( "ld %0, 0(%1)\n"
+ // "eieio"
+ // : "=r" (val) /* output */
+ // : "r" (reg) /* input */
+ // );
+ return val;
+}
+
+
+static inline void ci_write(const uint64_t reg, uint64_t val) {
+ asm volatile("stdcix %0, 0, %1"
+ : // no outputs
+ : "r" (val), "r" (reg) // inputs, %0, %1
+ : "memory" // affects memory
+ );
+ //old prism code:
+ //asm volatile("st %0, 0(%1)\n"
+ // "eieio"
+ // : /* output */
+ // : "r" (val) , "r" (reg) /* input */
+ // : "memory");
+}
+
+#ifndef CONFIG_MAMBO
+
+ #define getscom(a, b) _getscom((a)+PCB2PBUS(b))
+ static inline uint64_t _getscom(uint64_t addr) {
+ mtspr(HMER,0);
+ uint64_t value;
+ uint64_t rslt;
+ do {
+ value = ci_read(addr);
+ do {
+ rslt = mfspr(HMER)&(HMER_XSCOM_RSLT|HMER_XSCOM_DONE|HMER_XSCOM_FAIL);
+ } while( (rslt & HMER_XSCOM_DONE)==0 );
+ } while(rslt == (HMER_XSCOM_RTRY|HMER_XSCOM_DONE|HMER_XSCOM_FAIL) ); // 001 retry
+ if(rslt != HMER_XSCOM_DONE){
+ ERROR_STOP(XSCOM_ERROR,"XScom read returned unexpected result code");
+ }
+ return value;
+ }
+
+ #define putscom(xscom_base, scom_addr, value) _putscom(xscom_base + PCB2PBUS(scom_addr),value)
+ static inline void _putscom(uint64_t addr, uint64_t value) {
+ mtspr(HMER,0);
+ uint64_t rslt = -1;
+ do {
+ ci_write(addr,value);
+ do {
+ rslt = mfspr(HMER)&(HMER_XSCOM_RSLT|HMER_XSCOM_DONE|HMER_XSCOM_FAIL);
+ } while( (rslt & HMER_XSCOM_DONE)==0 );
+ } while(rslt == (HMER_XSCOM_RTRY|HMER_XSCOM_DONE|HMER_XSCOM_FAIL) ); // 001 retry
+ if(rslt != HMER_XSCOM_DONE){
+ ERROR_STOP(XSCOM_ERROR,"XScom write returned unexpected result code");
+ }
+ }
+
+#else
+
+ #define getscom(xscom_base, scom_addr) ci_read(xscom_base+scom_addr*8)
+ #define putscom(xscom_base, scom_addr, value) ci_write(xscom_base+scom_addr*8,value)
+
+#endif
+
+
+
+static inline uint64_t popcountll(uint64_t input) {
+ unsigned long result;
+ asm volatile("popcntd %0, %1" : "=r" (result) : "r" (input));
+ return result;
+}
+
+/****************************************************************************/
+static inline void getscom_HW_ECID(uint64_t base, uint8_t* buf) {
+ uint64_t* buf64 = (uint64_t *) buf;
+ unsigned int i;
+// uint64_t sum=0; // detect any change after fuse programming
+ for(i=0; i<ECID_SIZE/sizeof(uint64_t);i++) {
+ uint64_t val=getscom(base,OTP_ECID+i);
+// sum += popcountll(val);
+ buf64[i] = val;
+ }
+// const unsigned int count = sizeof(sha2_hash_t)/sizeof(uint64_t);
+// uint64_t lastval=getscom(base,OTP_HW_KEY_HASH+count);
+// if(((lastval & 0x00000000FFFF0000UL)>>16) != (~sum)) {
+// ERROR_STOP(OTP_ECID_INVPOPSUM_CHECK,"Inverted Populationcount of ECID does not match");
+// }
+}
+
+/****************************************************************************/
+static inline void getscom_PIBMEM_HW_Key_Hash(uint64_t base, uint8_t* buf) {
+
+ uint64_t* buf64 = (uint64_t *) buf;
+ unsigned int i;
+ const unsigned int count = sizeof(sha2_hash_t)/sizeof(uint64_t);
+ uint64_t sum=0; // detect any change after fuse programming
+ for(i=0; i<count;i++) {
+ uint64_t val=getscom(base,PIBMEM_HW_KEY_HASH+i);
+ sum += popcountll(val);
+ buf64[i] = val;
+ }
+ //uint64_t lastval=getscom(base,OTP_HW_KEY_HASH+count);
+ //sum += popcountll(lastval & 0xFFFFFFFFFFFF0000UL);
+ //if((lastval & 0x000000000000FFFFUL) != (~sum)) {
+ // ERROR_STOP(OTP_KEY_INVPOPSUM_CHECK,"Inverted Populationcount of ECID does not match");
+ //}
+}
+
+/****************************************************************************/
+
+#define Convert_Mem_Addr(_addr) ((uint8_t*) (_addr))
+#define Convert_Mem_Offset(_addr) ((uint64_t) (_addr))
+
+#define physical_addr(_addr) _addr
+
+#define GET16(_data) _data
+#define GET32(_data) _data
+#define GET64(_data) _data
+
+#endif //emulate_hw - else case
+
+#endif
diff --git a/src/include/securerom/sha512.H b/src/include/securerom/sha512.H
new file mode 100644
index 000000000..4a87aaf4e
--- /dev/null
+++ b/src/include/securerom/sha512.H
@@ -0,0 +1,51 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/include/securerom/sha512.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef SHA512_H
+#define SHA512_H
+
+#define SHA512_BLOCK_LENGTH 128
+#define SHA512_DIGEST_LENGTH 64
+
+#include <stdlib.h>
+
+typedef uint8_t __attribute__((aligned(8))) sha2_hash_t[ SHA512_DIGEST_LENGTH / sizeof(uint8_t) ];
+
+typedef uint8_t sha2_byte; /* Exactly 1 byte */
+typedef uint32_t sha2_word32; /* Exactly 4 bytes */
+typedef uint64_t sha2_word64; /* Exactly 8 bytes */
+
+typedef struct _SHA512_CTX {
+ uint64_t state[8];
+ uint64_t bitcount[2];
+ uint8_t buffer[SHA512_BLOCK_LENGTH];
+} SHA512_CTX;
+
+void SHA512_Init(SHA512_CTX* context);
+void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len);
+void SHA512_Final(SHA512_CTX* context, sha2_hash_t *result);
+
+void SHA512_Hash(const sha2_byte *data, size_t len, sha2_hash_t *result);
+
+#endif
diff --git a/src/include/securerom/status_codes.H b/src/include/securerom/status_codes.H
new file mode 100644
index 000000000..a2f94f597
--- /dev/null
+++ b/src/include/securerom/status_codes.H
@@ -0,0 +1,113 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/include/securerom/status_codes.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+/****************************************************************************
+ *
+ ****************************************************************************/
+#ifndef STATUS_CODES_H
+#define STATUS_CODES_H
+
+// Error extension code
+#ifndef EMULATE_HW
+#define ERROR_EVENT 0xFFFFFFFFFFFF8000
+#else
+#define ERROR_EVENT 0xFFFFFFFFFFFF8000ull
+#endif
+
+// context codes
+#define ROM_INSTRUCTION_START 0x0100
+#define C_INSTRUCTION_START 0x0200
+#define ROM_SELFTEST 0x0300
+#define ROM_VERIFY 0x0400
+// documentaion 0x0600 C_INSTRUCTION_START call of ROM_VERIFY
+#define ROM_SRESET 0x0E00
+
+#define PHYP_VERIFY 0x1500
+#define PHYP_SHA512_HASH 0x1600
+
+// progress/test codes
+#define BEGIN 0x0001
+
+#define TRUSTED_MEM_BAR 0x0012
+
+#define CONTAINER_LOW_TEST 0x0013
+
+#define XSCOM_LOW_TEST 0x0010
+#define XSCOM_VALID_TEST 0x0011
+
+#define MAGIC_NUMBER_TEST 0x0020
+#define CONTAINER_VERSION_TEST 0x0021
+#define PREFIX_VER_ALG_TEST 0x0022
+#define HEADER_VER_ALG_TEST 0x0023
+
+#define STACK_LOW_TEST 0x0030
+#define STACK_VALID_TEST 0x0031
+#define STACK_TRUST_TEST 0x0032
+#define STACK_ZERO_DONE 0x0033
+
+#define SHA_GOOD_TEST 0x0040
+#define SHA_BAD_TEST 0x0041
+#define ECDSA_GOOD_TEST 0x0042
+#define ECDSA_BAD_TEST 0x0043
+#define SELFTEST_DONE 0x0044
+
+#define TARGET_LOW_TEST 0x0050
+#define TARGET_VALID_TEST 0x0051
+#define TARGET_TRUST_TEST 0x0052
+#define STACK_VS_TARGET_TEST 0x0053
+#define TARGET_ZERO_DONE 0x0054
+#define CONTAINER_COPY_DONE 0x0055
+
+#define HBI_KEY_TEST 0x0056
+
+#define CONTAINER_VERIFY_DONE 0x0057
+#define STACK_CLEANUP_DONE 0x0058
+
+#define OTP_ECID_INVPOPSUM_CHECK 0x0059
+#define OTP_KEY_INVPOPSUM_CHECK 0x005A
+
+#define HW_KEY_HASH_TEST 0x0060
+#define HW_SIGNATURE_TEST 0x0061
+#define PREFIX_ECID_TEST 0x0062
+#define PREFIX_HASH_TEST 0x0063
+#define SPECIAL_NO_ECID_TEST 0x0064
+#define SPECIAL_SIZE_0_TEST 0x0065
+#define SW_KEY_PROTECTION_TEST 0x0066
+
+#define SW_SIGNATURE_TEST 0x0070
+#define HEADER_ECID_TEST 0x0071
+#define HEADER_HASH_TEST 0x0072
+#define CODE_PROTECTION_TEST 0x0073
+
+#define ENTRY_VALID_TEST 0x0080
+
+#define PARTIAL 0x0002
+#define COMPLETED 0x0003
+
+#define EXECUTION_ERROR 0x00EE
+#define XSCOM_ERROR 0xAFEE
+
+#define RETURNED_ERROR 0xD00F
+
+#endif
diff --git a/src/securerom.ld b/src/securerom.ld
new file mode 100644
index 000000000..10670afe9
--- /dev/null
+++ b/src/securerom.ld
@@ -0,0 +1,96 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/securerom.ld $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+/*****************************************************************************/
+/* linker script for low level firmware */
+/*****************************************************************************/
+
+/* PH: to use the same lds file for 32/64bit, don't specify
+ * OUTPUT_FORMAT, OUTPUT_ARCH here.
+ * /
+ OUTPUT_FORMAT("elf64-powerpc")
+ OUTPUT_ARCH(powerpc64:common)
+ */
+
+/* set the entry point */
+ENTRY(_instruction_start)
+
+MEMORY {
+ secure_boot_rom (IRX): ORIGIN = 0x80001C0000000000, LENGTH = 32K
+/* untrusted_memory (RW): ORIGIN = 0x8000000000000000, LENGTH = 0x0000000000800000
+* trusted_memory (RW): ORIGIN = 0x8000000000800000, LENGTH = 0x800000FFFF800000
+*/
+}
+
+
+SECTIONS {
+ . = 0x80001C0000000000; /* tbrom base address */
+
+ .branchtable : {
+ . = ALIGN(0x1000);
+ }>secure_boot_rom
+
+ .text : {
+ *(.text)
+ }>secure_boot_rom
+
+ . = ALIGN(8);
+
+ __toc_start = .;
+ .toc : {
+ *(.toc .got)
+ }>secure_boot_rom
+ . = ALIGN(8);
+ __toc_end = .;
+
+ .data : {
+ *(.data)
+ *(.rodata .rodata.*)
+ *(.got1)
+ *(.sdata)
+ }>secure_boot_rom
+
+ . = ALIGN(8);
+
+ /* PH: opd section must be separate, if i put it in .data,
+ * the C functions are not present in the generated file....
+ * If anybody can explain why, i'd be glad to hear...
+ * Note: the KEEP has been removed was: " KEEP (*(.opd)) "
+ */
+ .opd ALIGN(8) : {
+ *(.opd)
+ }>secure_boot_rom
+
+ . = ALIGN(8);
+ __bss_start = .;
+ .bss : {
+ *(.sbss) *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ }>secure_boot_rom
+ . = ALIGN(8);
+ __bss_end = .;
+ __bss_size = SIZEOF(.bss);
+
+}
diff --git a/src/securerom/ROM.C b/src/securerom/ROM.C
new file mode 100644
index 000000000..2f73a5da5
--- /dev/null
+++ b/src/securerom/ROM.C
@@ -0,0 +1,579 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/securerom/ROM.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+/****************************************************************************
+ *
+ ****************************************************************************/
+#ifndef PHYPLIBFUNCTIONS
+#include <ROM.h>
+#endif
+#include <ecverify.h>
+#include <status_codes.h>
+#include <string.h>
+
+/****************************************************************************/
+#define valid_magic_number(header) (GET32((header)->magic_number) == ROM_MAGIC_NUMBER)
+#define valid_container_version(header) (GET16((header)->version) == CONTAINER_VERSION)
+
+/****************************************************************************/
+static int valid_ver_alg(ROM_version_raw* ver_alg, uint8_t sig_alg) {
+ if (GET16(ver_alg->version) != HEADER_VERSION) return 0;
+ if (ver_alg->hash_alg != HASH_ALG_SHA512) return 0;
+ if (!sig_alg) return 1;
+ if (ver_alg->sig_alg != sig_alg) return 0;
+ return 1;
+}
+
+/****************************************************************************/
+static int valid_ecid(int ecid_count, uint8_t* ecids, uint8_t* hw_ecid) {
+ if (!ecid_count) return 1;
+ for (;ecid_count;ecid_count--,ecids+=ECID_SIZE)
+ if (!memcmp (hw_ecid, ecids, ECID_SIZE)) return 1;
+ return 0;
+}
+
+/****************************************************************************/
+static int multi_key_verify(uint8_t* digest, int key_count, uint8_t* keys, uint8_t* sigs) {
+ for (;key_count;key_count--,keys+=sizeof(ecc_key_t),sigs+=sizeof(ecc_signature_t))
+ if (ec_verify (keys, digest, sigs)<1) return 0;
+ return 1;
+}
+
+#ifndef PHYPLIBFUNCTIONS
+/****************************************************************************/
+static inline ROM_container_raw* cast_container(uint64_t addr) {
+ return (ROM_container_raw*) Convert_Mem_Addr(physical_addr(addr));
+}
+
+/****************************************************************************/
+static inline void ROM_init_cache_area(uint64_t target, uint64_t size) {
+ uint64_t i;
+ for (i=0;i<size;i+=CACHE_LINE) {
+ assem_DCBZ(target);
+ target+=CACHE_LINE;
+ }
+}
+
+/****************************************************************************/
+//static inline void ROM_invalidate_cache_area(uint64_t target, uint64_t size) {
+// uint64_t i;
+// for (i=0;i<size;i+=CACHE_LINE) {
+// assem_DCBI(target);
+// target+=CACHE_LINE;
+// }
+//}
+
+/****************************************************************************/
+static void ROM_memcpy_icbi (uint64_t* to, uint64_t* from, int64_t size) {
+ uint64_t* src=from;
+ uint64_t* dst=to;
+ for(;size>0;size-=sizeof(uint64_t)) {
+ *dst++ = *src++;
+ }
+ assem_SYNC(); //heavy weight form of sync instruction
+ //which ensures all stores have been performed
+ //prior to the subsequent icbi
+ assem_ICBI(to); //only need one of these to any address....
+ //this is only needed to set internal scoreboard bit
+ //to tell the processor to flush
+ //when it sees a subsequent isync
+ assem_ISYNC();
+}
+
+//extern void* __toc_start;
+
+#if 0
+
+#define STACK_ASSUMPTION 128*1024
+#define STACK_FRAME (2*8)
+/****************************************************************************/
+#undef CONTEXT
+#define CONTEXT ROM_INSTRUCTION_START
+/****************************************************************************/
+static inline void Create_C_Environment(uint64_t stack) {
+ #ifdef EMULATE_HW
+ printf ("Creating C Environment with stack pointer 0x%016llX\n",stack);
+ #else
+ // zero (create) stack area
+ ROM_init_cache_area(stack-STACK_ASSUMPTION, STACK_ASSUMPTION);
+ LOG(STACK_ZERO_DONE);
+
+ // set stackpointer
+ register volatile uint64_t r1 __asm__ ("r1"); // if you remove the volatile keyword then the compiler removes your code - grr
+ r1 = stack-8;
+ //*((uint64_t*)stack) = 0ull; -- end stackframe --already 0 by dcbz above
+
+ //setup initial stackframe
+ asm("stdu r1, -56(r1)");
+
+ #endif
+}
+
+static inline void initTOCpointer() {
+ #ifdef EMULATE_HW
+ printf ("Initialize r2 with TOC pointer\n");
+ #else
+ // set TOC pointer (unused because no global variables)
+ // register uint64_t r2 __asm__ ("r2");
+ // r2 = (uint64_t)__toc_start+0x8000; //only for one TOC
+ // r2 = ((uint64_t*)&ROM_instruction_start)[1]; //saver to get from { entry_point, toc_base, environment }
+ asm(
+ "springboard2: \n"
+ " b boingboing2 \n" // set CFAR
+ "boingboing2: \n"
+ " mfspr r2, 28 \n" // mfCFAR get address of springboard2
+ " addi r2, r2, 0x4000 \n" // adjust to __toc_start (part 1)
+ " addi r2, r2, (__toc_start+0x4000-springboard2)@l \n" // adjust to __toc_start (part 2)
+ );
+ #endif
+}
+
+/****************************************************************************/
+#undef CONTEXT
+#define CONTEXT ROM_SELFTEST
+/****************************************************************************/
+static void ROM_selftest(void) {
+#ifndef EMULATE_HW
+ selftest_t const *selftest_p;
+ asm volatile("li %0,(__toc_start)@l ### %0 := base+0x8000 \n\t" // because li does not work
+ "sub %0,r2,%0 \n\t" // because subi does not work
+ "addi %0,%0,(selftest-0x8000)@l" : "=r" (selftest_p) );
+#else
+ selftest_t const *selftest_p = &selftest; //this line would introduce a absolute address in the toc
+#endif
+
+ sha2_hash_t digest;
+ LOG(BEGIN);
+ // sha512 good selftest
+ SHA512_Hash((uint8_t*)&selftest_p->ec, sizeof(selftest_p->ec), &digest);
+ if(memcmp(digest, selftest_p->sha.hash, sizeof(sha2_hash_t)))
+ ERROR_STOP(SHA_GOOD_TEST,"sha512 good selftest failed");
+ // sha512 bad selftest
+ SHA512_Hash((uint8_t*)&selftest_p->ec, sizeof(selftest_p->ec)-1, &digest);
+ if(!memcmp (digest, selftest_p->sha.hash, sizeof(sha2_hash_t)))
+ ERROR_STOP(SHA_BAD_TEST,"sha512 bad selftest failed");
+ // ecdsa verify good selftest
+ if (ec_verify (selftest_p->ec.pkey, selftest_p->ec.hash, selftest_p->ec.sig)<1)
+ ERROR_STOP(ECDSA_GOOD_TEST,"ecdsa good selftest failed");
+ // ecdsa verify bad selftest (use digest from sha512 bad test)
+ if (ec_verify (selftest_p->ec.pkey, digest, selftest_p->ec.sig)!=0)
+ ERROR_STOP(ECDSA_BAD_TEST,"ecdsa bad selftest failed");
+}
+
+/****************************************************************************/
+#undef CONTEXT
+#define CONTEXT C_INSTRUCTION_START
+/****************************************************************************/
+uint64_t C_instruction_start( uint64_t xscom
+ , uint64_t fsp_bar
+ , uint64_t stack
+ , ROM_container_raw* container
+ ) {
+ LOG(BEGIN);
+
+ // run crypto selftests
+ ROM_selftest();
+ LOG(SELFTEST_DONE);
+
+ // test for valid target hrmor address in trusted memory (security checks)
+ uint64_t target_hrmor = GET64(container->target_hrmor);
+ if(target_hrmor < 4096)
+ ERROR_STOP(TARGET_LOW_TEST,"target hrmor too low");
+ if(target_hrmor & ~HRMOR_MASK)
+ ERROR_STOP(TARGET_VALID_TEST,"invalid target hrmor address");
+ if(physical_addr(target_hrmor-4096)<fsp_bar)
+ ERROR_STOP(TARGET_TRUST_TEST,"target hrmor in untrusted memory");
+ target_hrmor = ABSOLUTE_ADDR(target_hrmor); //WEH bug fix, moved to allow previous test to work
+
+ // test for stack and container collision
+ uint64_t size = GET64(container->container_size);
+ if( stack > target_hrmor-4096
+ && stack-STACK_ASSUMPTION <= target_hrmor+size
+ )
+ ERROR_STOP(STACK_VS_TARGET_TEST,"container vs stack collision");
+
+ mtspr_HRMOR(target_hrmor);
+
+ // clear ERATS because hrmor has changed
+ #ifdef EMULATE_HW
+ printf ("clear ERATS because hrmor has changed\n");
+ #else
+ asm volatile ("slbia");
+ #endif
+
+ // zero target area and copy container
+ ROM_init_cache_area(target_hrmor-4096, size);
+ LOG(TARGET_ZERO_DONE);
+ ROM_container_raw* target = cast_container(target_hrmor-4096);
+ ROM_memcpy_icbi((uint64_t*)target, (uint64_t*)container, size);
+ LOG(CONTAINER_COPY_DONE);
+
+ // test for prefix header with HBI base code (firmware) signing keys
+ ROM_prefix_header_raw* prefix = (ROM_prefix_header_raw*) &target->prefix;
+ if(!valid_ver_alg(&prefix->ver_alg, SIG_ALG_ECDSA521))
+ ERROR_STOP(PREFIX_VER_ALG_TEST,"bad prefix header version,alg's");
+ uint32_t flags = GET32 (prefix->flags);
+ if(!(flags & HBI_BASE_SIGNING_KEY))
+ ERROR_STOP(HBI_KEY_TEST,"not HBI base code key prefix");
+
+ // verify
+
+ // fill verify hw params
+ ROM_hw_params params;
+ getscom_PIBMEM_HW_Key_Hash(xscom, params.hw_key_hash);
+ getscom_HW_ECID(xscom, params.my_ecid);
+ if (ROM_verify(target,&params) != ROM_DONE)
+ ERROR_STOP(params.log,"see above"); // this will added C_INSTRUCTION_START to ROM_VERIFY for 0600
+ LOG(CONTAINER_VERIFY_DONE);
+
+ return HRMOR_RELATIVE(params.entry_point);
+}
+
+#endif
+
+/****************************************************************************/
+#undef CONTEXT
+#define CONTEXT ROM_SRESET
+/****************************************************************************/
+#ifdef EMULATE_HW
+void ROM_sreset (void) {
+#else
+void ROM_sreset(void) {
+ asm volatile (".globl rom_sreset\n rom_sreset:"); //skip prologue
+#endif
+ // should never get here unless started too soon by fsp/sbe, checkstop
+ ERROR_STOP(EXECUTION_ERROR,"sreset");
+}
+
+#if 0
+/****************************************************************************/
+#undef CONTEXT
+#define CONTEXT ROM_INSTRUCTION_START
+/****************************************************************************/
+//static inline void ROM_Cleanup_Stack(uint64_t stack) {
+//#ifdef EMULATE_HW
+// printf ("Cleaning up stack\n");
+//#endif
+// ROM_invalidate_cache_area(stack-STACK_ASSUMPTION, STACK_ASSUMPTION);
+//}
+
+/****************************************************************************/
+#ifdef EMULATE_HW
+static void Call_Entry_Point(uint64_t start) {
+ printf ("Branching to entry point 0x%016llX (PHY 0x%016llX)\n",start,physical_addr(start));
+ return;
+#else
+static void __attribute__((noreturn)) Call_Entry_Point(uint64_t start) {
+
+ asm volatile ( " mtctr %0 \n"
+ " bctr \n"
+ " nop "
+ : // no output
+ : "r" (start) // input, %0
+ // no impacts ?
+ );
+
+ ERROR_STOP(RETURNED_ERROR,"returned from Entry_Point");
+ #if !defined(_lint_)
+ for (;;);
+ #endif
+#endif
+}
+
+/* Check the maximum limit of a untrusted memory BAR
+ *
+ * A BAR are two SCOM register one containing a mask and the other the pattern
+ * the address is in the untrusted memory when this is true:
+ * (address & mask) == pattern
+ * If this is true then a untrusted PIB master (like FSI) can write it.
+ * Remark:
+ * If a mask bit is 0 and the coresponding pattern bit is 1 then it is always false.
+ *
+ * parameter:
+ * limit = previous limit from other BARs or 0
+ * xscom = the xscom base address
+ * bar = the pib address of the BAR register containing the pattern
+ * barMask = the pib address of the BAR register containing the mask
+ * return value:
+ * the new limit is the maximum from previous limit and the bars limit
+ */
+uint64_t check_bar(uint64_t limit, uint64_t xscom, uint64_t bar, uint64_t barMask) {
+ uint64_t barValue = getscom(xscom,bar);
+ uint64_t barMaskValue = getscom(xscom,barMask);
+
+ barMaskValue |= 0xFFFC000000000000; // bit 0:13 not implemented and must be '1'
+
+ uint64_t barLimit = (barValue | ~barMaskValue) + 1;
+ if( ( (barValue & ~barMaskValue) == 0)
+ && ( barLimit > limit)
+ ) {
+ limit=barLimit;
+ }
+ return limit;
+}
+
+#endif
+
+/****************************************************************************/
+#ifdef EMULATE_HW
+void ROM_instruction_start(void) {
+#else
+void __attribute__((noreturn)) ROM_instruction_start(void) {
+ asm volatile (".globl instruction_start\ninstruction_start:"); //skip prologue
+#endif
+
+#if 0
+
+ initTOCpointer();
+
+ LOG(BEGIN);
+
+ // test for reasonable xscom base address (security check)
+ register uint64_t xscom = mfspr_SCRATCH0();
+ if(!xscom) {
+ ERROR_STOP(XSCOM_LOW_TEST,"xscom base address too low");
+ }
+ if(xscom & ~XSCOM_MASK) {
+ ERROR_STOP(XSCOM_VALID_TEST,"invalid xscom base address");
+ }
+ xscom = ABSOLUTE_ADDR(xscom);
+
+#ifndef EMULATE_HW
+ // get trusted memory base
+ uint64_t fsp_bar=0;
+ fsp_bar = check_bar(fsp_bar, xscom, ALTD_UNTRUSTED_BAR_ADDR_REG, ALTD_UNTRUSTED_BAR_MASK_ADDR_REG);
+ fsp_bar = check_bar(fsp_bar, xscom, PSIHB_NOTRUST_BAR0, PSIHB_NOTRUST_BAR0MASK );
+ fsp_bar = check_bar(fsp_bar, xscom, PSIHB_NOTRUST_BAR1, PSIHB_NOTRUST_BAR1MASK );
+#else
+ // get trusted memory base
+ uint64_t fsp_bar = (getscom_FSP_BAR_value(xscom) | ~getscom_FSP_BAR_mask(xscom)) + 1;
+#endif
+
+ LOG(TRUSTED_MEM_BAR);
+
+ register uint64_t raw_container = mfspr_SCRATCH1();
+ if (raw_container < 4096) //must check for value that will wrap around
+ ERROR_STOP(CONTAINER_LOW_TEST,"container too low");
+ raw_container = ABSOLUTE_ADDR(raw_container)-4096;
+ ROM_container_raw* container = cast_container(raw_container);
+
+ // test for valid container magic number, version, hash & signature algorithms (sanity checks)
+ if(!valid_magic_number(container))
+ ERROR_STOP(MAGIC_NUMBER_TEST,"bad container magic number");
+ if (!valid_container_version (container))
+ ERROR_STOP(CONTAINER_VERSION_TEST,"bad container version");
+
+ // test for trusted memory stack pointer (assumes 8K max depth)
+ register uint64_t stack = GET64(container->stack_pointer);
+ stack += STACK_ASSUMPTION;
+ if(stack < STACK_ASSUMPTION) {
+ ERROR_STOP(STACK_LOW_TEST,"stack pointer too low");
+ }
+ if(stack & ~STACK_MASK)
+ ERROR_STOP(STACK_VALID_TEST,"invalid stack pointer address");
+ if(physical_addr(stack-STACK_ASSUMPTION)<fsp_bar)
+ ERROR_STOP(STACK_TRUST_TEST,"stack in untrusted memory");
+ stack = ABSOLUTE_ADDR(stack); //WEH bug fix, moved to allow previous test to work
+
+ // launch C environment (zero stack)
+ Create_C_Environment(stack);
+
+ // Jump to C code
+ register uint64_t entry = C_instruction_start(xscom,fsp_bar,stack,container);
+
+ // cleanup (invalidate) stack - no longer required HBI takes care
+ //ROM_Cleanup_Stack(stack);
+ //LOG(STACK_CLEANUP_DONE);
+
+ // clear scratch 0 and 1 reg - no longer required
+ //mtspr_SCRATCH0(0);
+ //mtspr_SCRATCH1(0);
+
+ LOG(COMPLETED);
+ Call_Entry_Point(entry); // never return from here!!!
+ #endif
+}
+
+/****************************************************************************/
+#endif
+
+#ifdef EMULATE_HW
+ #define FAILED(_c,_m) { params->log=ERROR_EVENT|CONTEXT|(_c); printf ("FAILED '%s'\n", (_m)); return ROM_FAILED; }
+#else
+ #define FAILED(_c,_m) { params->log=ERROR_EVENT|CONTEXT|(_c); return ROM_FAILED; }
+#endif
+
+//****************************************************************************
+#undef CONTEXT
+#ifndef PHYPLIBFUNCTIONS
+#define CONTEXT ROM_VERIFY
+//****************************************************************************
+// NOTE: ROM_verify is called with absolute addresses from c_instruction_start
+// and with hrmor relative addresses from Hostboot
+asm(".globl .L.ROM_verify");
+ROM_response ROM_verify( ROM_container_raw* container,
+ ROM_hw_params* params ) {
+#else
+#define CONTEXT PHYP_VERIFY
+//****************************************************************************
+// NOTE: PHYP_verify is called with hrmor relative addresses from PHYP
+ROM_response PHYP_verify( PHYP_command cmnd,
+ ROM_container_raw* container,
+ PHYP_hw_params* params,
+ PHYP_verify_state* state ) {
+#endif
+ sha2_hash_t digest;
+ ROM_prefix_header_raw* prefix;
+ ROM_prefix_data_raw* hw_data;
+ ROM_sw_header_raw* header;
+ ROM_sw_sig_raw* sw_sig;
+ uint64_t size;
+
+ params->log=CONTEXT|BEGIN;
+
+#ifdef PHYPLIBFUNCTIONS
+ if(cmnd != PHYP_CONTINUE) {
+#endif
+ // test for valid container magic number, version, hash & signature algorithms (sanity check)
+ if(!valid_magic_number(container))
+ FAILED(MAGIC_NUMBER_TEST,"bad container magic number");
+ if(!valid_container_version(container))
+ FAILED(CONTAINER_VERSION_TEST,"bad container version");
+#ifdef PHYPLIBFUNCTIONS
+ // initialize verify state
+ state->state = PHYP_START_VERIFY;
+ }
+
+ do {
+ switch(state->state) {
+ case PHYP_START_VERIFY:
+#endif
+ // process hw keys
+ // test for valid hw keys
+ SHA512_Hash(container->hw_pkey_a, 3*sizeof(ecc_key_t), &digest);
+ if(memcmp(params->hw_key_hash, digest, sizeof(sha2_hash_t)))
+ FAILED(HW_KEY_HASH_TEST,"invalid hw keys");
+
+ // process prefix header
+ prefix = (ROM_prefix_header_raw*) &container->prefix;
+ // test for valid header version, hash & signature algorithms (sanity check)
+ if(!valid_ver_alg(&prefix->ver_alg, SIG_ALG_ECDSA521))
+ FAILED(PREFIX_VER_ALG_TEST,"bad prefix header version,alg's");
+ // test for valid prefix header signatures (all)
+ hw_data = (ROM_prefix_data_raw*) (prefix->ecid + prefix->ecid_count*ECID_SIZE);
+ SHA512_Hash((uint8_t*)prefix, PREFIX_HEADER_SIZE(prefix), &digest);
+ if(!multi_key_verify(digest, 3, container->hw_pkey_a, hw_data->hw_sig_a))
+ FAILED(HW_SIGNATURE_TEST,"invalid hw signature");
+ // test for machine specific matching ecid
+ if(!valid_ecid(prefix->ecid_count, prefix->ecid, params->my_ecid))
+ FAILED(PREFIX_ECID_TEST,"unauthorized prefix ecid");
+ // test for valid prefix payload hash
+ size = GET64(prefix->payload_size);
+ SHA512_Hash(hw_data->sw_pkey_p, size, &digest);
+ if(memcmp(prefix->payload_hash, digest, sizeof(sha2_hash_t)))
+ FAILED(PREFIX_HASH_TEST,"invalid prefix payload hash");
+ // test for special prefix header
+ if(!prefix->sw_key_count) {
+ // finish processing special prefix header
+ // test for machine specfic (sanity check)
+ if(prefix->ecid_count == 0)
+ FAILED(SPECIAL_NO_ECID_TEST,"special prefix with ecid_count == 0");
+ // test for signing of keys only (sanity check)
+ if(size != 0)
+ FAILED(SPECIAL_SIZE_0_TEST,"special prefix with payload_size != 0");
+ // return hrmor relative code start address
+ params->entry_point = GET64(prefix->code_start_offset);
+ //check if the entry is HRMOR-relative and aligned
+ if(params->entry_point & ~(ENTRY_MASK))
+ FAILED(ENTRY_VALID_TEST,"entry is not HRMOR relative or not aligned");
+ params->log=CONTEXT|COMPLETED;
+ return ROM_DONE;
+ }
+ // finish processing prefix header
+ // test for protection of all sw key material (sanity check)
+ if(size != (prefix->sw_key_count * sizeof(ecc_key_t)))
+ FAILED(SW_KEY_PROTECTION_TEST,"incomplete sw key protection in prefix header");
+
+ // start processing sw header
+ header = (ROM_sw_header_raw*) (hw_data->sw_pkey_p + prefix->sw_key_count*sizeof(ecc_key_t));
+ // test for valid header version, hash & signature algorithms (sanity check)
+ if(!valid_ver_alg(&header->ver_alg, 0))
+ FAILED(HEADER_VER_ALG_TEST,"bad sw header version,alg");
+ // test for valid sw header signatures (all)
+ sw_sig = (ROM_sw_sig_raw*) (header->ecid + header->ecid_count*ECID_SIZE);
+ SHA512_Hash((uint8_t*)header, SW_HEADER_SIZE(header), &digest);
+ if(!multi_key_verify(digest, prefix->sw_key_count, hw_data->sw_pkey_p, sw_sig->sw_sig_p))
+ FAILED(SW_SIGNATURE_TEST,"invalid sw signature");
+ // test for machine specific matching ecid
+ if(!valid_ecid(header->ecid_count, header->ecid, params->my_ecid))
+ FAILED(HEADER_ECID_TEST,"unauthorized sw ecid");
+ // test for entry point within protected payload (sanity check)
+ params->entry_point = GET64(header->code_start_offset);
+ //check if the entry is HRMOR-relative and aligned
+ if(params->entry_point & ~(ENTRY_MASK))
+ FAILED(ENTRY_VALID_TEST,"entry is not HRMOR relative or not aligned");
+ size = GET64(header->payload_size);
+ if(params->entry_point+3 >= size) // must have full instruction (3 more bytes)
+ FAILED(CODE_PROTECTION_TEST,"unprotected code_start in sw header");
+ // begin test for valid sw payload hash
+#ifdef PHYPLIBFUNCTIONS
+ state->message = (uint8_t*)container + 4096;
+ state->remain = size;
+ SHA512_Init(&state->sha);
+ state->header = header;
+ state->state = PHYP_CONT_VERIFY;
+ params->log=CONTEXT|PARTIAL;
+ break;
+
+ case PHYP_CONT_VERIFY:
+ if(state->remain > params->max_hash) {
+ // continue test for valid sw payload hash
+ SHA512_Update(&state->sha, state->message, params->max_hash);
+ state->message += params->max_hash;
+ state->remain -= params->max_hash;
+ } else {
+ // finish test for valid sw payload hash
+ SHA512_Update(&state->sha, state->message, state->remain);
+ SHA512_Final(&state->sha, &digest);
+ header = state->header;
+#else
+ SHA512_Hash((uint8_t*)container + 4096, size, &digest);
+#endif
+ if(memcmp(header->payload_hash, digest, sizeof(sha2_hash_t)))
+ FAILED(HEADER_HASH_TEST,"invalid sw payload hash");
+ params->log=CONTEXT|COMPLETED;
+ return ROM_DONE;
+#ifdef PHYPLIBFUNCTIONS
+ }
+ break;
+
+ default:
+ FAILED(EXECUTION_ERROR,"bad internal state");
+ break;
+ }
+ } while (cmnd == PHYP_WHOLE);
+ params->log=CONTEXT|PARTIAL;
+ return PHYP_PARTIAL;
+#endif
+}
diff --git a/src/securerom/branchtable.S b/src/securerom/branchtable.S
new file mode 100644
index 000000000..d3c1c8608
--- /dev/null
+++ b/src/securerom/branchtable.S
@@ -0,0 +1,98 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/securerom/branchtable.S $
+#
+# OpenPOWER HostBoot Project
+#
+# Contributors Listed Below - COPYRIGHT 2016,2017
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+#****************************************************************************
+#* branch table - a more stable location for software entering rom code
+#****************************************************************************
+# adr function
+# 0 instruction_start
+# 2 .SHA512_Init
+# 4 .SHA512_Update
+# 6 .SHA512_Final
+# 8 .SHA512_Hash
+# A .ec_verify
+# C .ROM_verify
+# 100 rom_sreset
+
+branchtable:
+ .section ".branchtable","ax"
+
+ .globl _instruction_start
+_instruction_start:
+ b instruction_start
+ nop
+
+ .globl _SHA512_Init
+_SHA512_Init:
+ li r0, .L.SHA512_Init@l
+ b springboard
+
+ .globl _SHA512_Update
+_SHA512_Update:
+ li r0, .L.SHA512_Update@l
+ b springboard
+
+ .globl _SHA512_Final
+_SHA512_Final:
+ li r0, .L.SHA512_Final@l
+ b springboard
+
+ .globl _SHA512_Hash
+_SHA512_Hash:
+ li r0, .L.SHA512_Hash@l
+ b springboard
+
+ .globl _ec_verify
+_ec_verify:
+ li r0, .L.ec_verify@l
+ b springboard
+
+ .globl _ROM_verify
+_ROM_verify:
+ li r0, .L.ROM_verify@l
+ b springboard
+
+#define CFAR 28
+
+springboard:
+ b boingboing
+boingboing:
+ mfspr r2, CFAR // get address of springboard
+ addi r2, r2, _instruction_start-springboard // base address
+ add r0, r0, r2 // calculate entry relative
+ addi r2, r2, 0x4000 //TOC+0x8000 part 1
+ addi r2, r2, (__toc_start+0x4000)@l //TOC+0x8000 part 2
+ mtctr r0
+ bctr // jump
+
+# could put other assembly ocde routines here to conserver ROM space
+# including the sreset routine
+
+# need to align on bootrombase+0x100 !!!
+ .org .branchtable+0x100
+ .globl _rom_sreset
+_rom_sreset:
+ li r0, rom_sreset@l
+ b springboard
+ nop
diff --git a/src/securerom/ecverify.C b/src/securerom/ecverify.C
new file mode 100644
index 000000000..659d7d6fb
--- /dev/null
+++ b/src/securerom/ecverify.C
@@ -0,0 +1,1662 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/securerom/ecverify.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+/*----------------------------------------------------------------------
+ * (C) COPYRIGHT INTERNATIONAL BUSINESS MACHINES CORPORATION 2010
+ * ALL RIGHTS RESERVED
+ * IBM Research, Zurich and IBM Crypto Competency Center, Copenhagen
+ *----------------------------------------------------------------------
+ * Author: Tamas Visegrady (tvi@zurich.ibm.com)
+ * Change: W Eric Hall (wehall@us.ibm.com)
+ *----------------------------------------------------------------------*/
+
+/** ECDSA verification on fixed curve/s (currently, on NIST P-521)
+ * The code below works for a compile-time constant curve, and requires
+ * a single bignumber pair (public key) to specify a key
+ *
+ * Knowledge of our environment allows the following simplifications:
+ * - modular operations are always mod P
+ * - there (multiple) unused bits in the most significant word of bignums
+ * Further assumptions:
+ * - bignumber indices fit 7 bits (8-bit counter sufficient for double bn's)
+ * Search for "P521", which flags curve dependencies.
+ */
+
+
+#define __STDC_FORMAT_MACROS 1 /* add 64-bit printf modifiers */
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h> /* uint_fast8_t, uintN_t */
+#include <inttypes.h> /* PRIx64 used to format bn_t's */
+
+/**
+ * Define __LITTLE_ENDIAN or __BIG_ENDIAN for target.
+ */
+#if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN
+ #define __BIG_ENDIAN
+ #undef __LITTLE_ENDIAN
+#else
+ #undef __BIG_ENDIAN
+ #define __LITTLE_ENDIAN
+#endif
+
+#include "ecverify.h"
+
+
+#define EC_PRIMEBITS 521 /* P521 */
+
+//#define EC_DEBUG 1 /* needs libc (not in Prism version) */
+#define EC_STACKTRACE 1 /* debug only; currently, glibc */
+#define NO_EC_DOUBLE_XY 1 /* do not implement ec_double_xy */
+
+typedef uint64_t bn_t;
+typedef uint32_t hbn_t; /* half-bignumber */
+typedef uint_fast8_t bnindex_t;
+
+#define BN_FMT "%016" PRIx64 /* PRIx64 from inttypes.h */
+
+
+// show word boundaries in bignumbers (diagnostics dump only)
+// #define EC_DEBUG_WORDS 1
+
+
+// define this if we construct ec_prime[] on the fly
+// saves code, adds runtime static structs; check your compiler if useful
+// does not make sense if non-exec, read-only constants are cheap
+//
+// #define BN_PRIME_GENERATED 1
+
+
+//--- nothing user-servicable below ---------------------------------------
+
+#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
+#error "Please define target endianness (__LITTLE_ENDIAN or __BIG_ENDIAN)"
+#endif
+
+#if defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
+#error "Please define one target endianness (__LITTLE_ENDIAN or __BIG_ENDIAN)"
+#endif
+
+
+#define BN_BITS (8*sizeof(bn_t))
+#define HBN_BITS (8*sizeof(hbn_t))
+
+#define EC_PRIMEBYTES ((EC_PRIMEBITS +7) /8)
+
+#define BN_MAXBIT (((bn_t) 1) << (BN_BITS -1))
+
+#define BITS2BN(bits) \
+ (((bits) +BN_BITS -1) / BN_BITS)
+
+// we only deal with big numbers of fixed size
+#define NWORDS BITS2BN( EC_PRIMEBITS )
+#define BNBYTES (NWORDS*sizeof(bn_t))
+
+#define BN_MSW(p) ((p)[0])
+#define BN_LSW(p) ((p)[ NWORDS-1 ])
+#define bn_is_odd(p) (1 & BN_LSW(p))
+
+
+#ifndef BN_POWER64_CPY
+#define BN_COPY(dst, src) memcpy((dst), (src), NWORDS*sizeof(bn_t))
+#else
+static void __attribute__((noinline)) BN_COPY (bn_t *dst, const bn_t *src)
+{
+ size_t i;
+ for(i=0;i<NWORDS;i++) {
+ *dst++ = *src++;
+ }
+}
+#endif
+
+#ifdef BN_POWER64_DBG
+static void __attribute__((noinline)) BN_DUMP (int i, bn_t *top)
+{
+ asm volatile ("nop" : : "r" (i), "r" (top));
+}
+static void BN_EXIT (void)
+{
+ asm volatile("b .Check_Stop");
+}
+#else
+#define BN_DUMP(_i,_bn) ((void)0)
+#define BN_EXIT() ((void)0)
+#endif
+
+
+#if defined(EC_DEBUG)
+static void bn_print (const char *msg, const bn_t *m) ;
+static void bn_dprint (const char *msg, const bn_t *m) ;
+#else
+#define bn_print(msg, m) ((void) 0)
+#define bn_dprint(msg, m) ((void) 0)
+#endif
+
+#if !defined(NDEBUG)
+#define EC_ASSERT(cond) assert(cond)
+#define EC_DEVASSERT(cond) assert(cond)
+#else
+#define EC_ASSERT(cond) ((void) 0) // removed '((void) cond)' which still did the cond test
+#define EC_DEVASSERT(cond) ((void) 0) // removed '((void) cond)' which still did the cond test
+#endif
+
+
+
+static bn_t bn_sub (bn_t *a, const bn_t *b) ;
+static void bn_add (bn_t *a, const bn_t *b) ;
+static void bn_mul (bn_t *r, const bn_t *a, const bn_t *b) ;
+static void bn_modadd (bn_t *a, const bn_t *b) ;
+static void bn_modsub (bn_t *a, const bn_t *b) ;
+
+// static int bn_cmp (const bn_t *a, const bn_t *b) ;
+static int bn_cmp (const bn_t a[NWORDS], const bn_t b[NWORDS]) ;
+
+// P521: a==-3, fixed curve parameter
+//
+static int ec_double (bn_t *x, bn_t *y, bn_t *z) ;
+
+
+//============================================ prime-specific functions ====
+// this section contains all prime/order-specific functionality
+// if we ever need to support other curves, #ifdef their equivalent functions
+//
+// this code is limited to p = 2^521 -1 (P-521) and its order
+
+#define BN_PRIME_MSW 0x1ff
+#define BN_PRIME_MSW_MASK 0x1ff /* equal, as coincidence, for P521 */
+#define BN_PRIME_MSW_BITS (EC_PRIMEBITS % BN_BITS)
+
+
+typedef struct {
+ bn_t ec_prime[ NWORDS ];
+ bn_t ec_order[ NWORDS ];
+ bn_t prime_px[ NWORDS ];
+ bn_t prime_py[ NWORDS ];
+ bn_t ec_order_qn[ NWORDS ];
+} consts_t;
+const consts_t consts = {
+
+//const bn_t ec_prime[ NWORDS ] =
+ {
+ BN_PRIME_MSW,
+ 0xffffffffffffffffLL,
+ 0xffffffffffffffffLL,
+ 0xffffffffffffffffLL,
+ 0xffffffffffffffffLL,
+ 0xffffffffffffffffLL,
+ 0xffffffffffffffffLL,
+ 0xffffffffffffffffLL,
+ 0xffffffffffffffffLL,
+ },
+
+//-------------------------------------
+
+//const bn_t ec_order[ NWORDS ] =
+ {
+ 0x00000000000001ffLL,
+ 0xffffffffffffffffLL,
+ 0xffffffffffffffffLL,
+ 0xffffffffffffffffLL,
+ 0xfffffffffffffffaLL,
+ 0x51868783bf2f966bLL,
+ 0x7fcc0148f709a5d0LL,
+ 0x3bb5c9b8899c47aeLL,
+ 0xbb6fb71e91386409LL,
+ },
+
+//const bn_t prime_px[ NWORDS ] = {
+ {
+ 0x00000000000000c6LL,
+ 0x858e06b70404e9cdLL,
+ 0x9e3ecb662395b442LL,
+ 0x9c648139053fb521LL,
+ 0xf828af606b4d3dbaLL,
+ 0xa14b5e77efe75928LL,
+ 0xfe1dc127a2ffa8deLL,
+ 0x3348b3c1856a429bLL,
+ 0xf97e7e31c2e5bd66LL,
+ },
+
+//const bn_t prime_py[ NWORDS ] = {
+ {
+ 0x0000000000000118LL,
+ 0x39296a789a3bc004LL,
+ 0x5c8a5fb42c7d1bd9LL,
+ 0x98f54449579b4468LL,
+ 0x17afbd17273e662cLL,
+ 0x97ee72995ef42640LL,
+ 0xc550b9013fad0761LL,
+ 0x353c7086a272c240LL,
+ 0x88be94769fd16650LL,
+ },
+
+ //-------------------------- mod mul by order (n) -------
+ // MS 521 bits of Q/N, fractional part
+ //
+// static const bn_t ec_order_qn[ NWORDS ] =
+ {
+ 0LL,
+ 0LL,
+ 0LL,
+ 0LL,
+ 0x0000000000000005LL,
+ 0xae79787c40d06994LL,
+ 0x8033feb708f65a2fLL,
+ 0xc44a36477663b851LL,
+ 0x449048e16ec79bf6LL,
+ }
+} ;
+
+inline const consts_t* __attribute__((pure)) consts_p() {
+#ifdef EMULATE_HW
+ return &consts;
+#else
+ consts_t* result_consts_p;
+ asm("li %0,(__toc_start)@l ### %0 := base+0x8000 \n\t" // because li does not work
+ "sub %0,r2,%0 \n\t" // because subi does not work
+ "addi %0,%0,(consts-0x8000)@l" : "=r" (result_consts_p) );
+ return result_consts_p;
+#endif
+}
+
+//-------------------------------------
+
+
+#define bn_ge_prime(val) (bn_cmp((val), consts_p()->ec_prime) >= 0)
+#define bn_ge_order(val) (bn_cmp((val), consts_p()->ec_order) >= 0)
+
+
+//-------------------------------------
+// P521: MSW has unused bits
+#define BN_MSW_UNUSED_BITS (BN_BITS - BN_PRIME_MSW_BITS)
+#define BN_MSW_UNUSED_BYTES ((BN_MSW_UNUSED_BITS +7) >>3)
+#define BN_MSW_UNUSED_MASK ((((bn_t) 1) << BN_MSW_UNUSED_BITS) -1)
+
+// not general-purpose shl: we only need to shift products (2*NWORDS)
+// to two EC_PRIMEBITS, with BN_MSW_UNUSED_BITS
+//
+// acc contains MSW of lower half
+//
+static bn_t bn_shl (bn_t *a, bn_t acc)
+{
+ bnindex_t i = NWORDS;
+ bn_t cf = 0;
+
+ EC_ASSERT(NULL != a);
+ EC_ASSERT(0 == a[0]);
+
+ a += NWORDS;
+
+ while (0<i--) {
+ cf = *(--a);
+ *a <<= BN_MSW_UNUSED_BITS;
+ *a |= BN_MSW_UNUSED_MASK & (acc >> BN_PRIME_MSW_BITS);
+
+ acc = cf;
+ }
+
+ return cf;
+}
+
+
+//========================================================= diagnostics ====
+#if defined(EC_DEBUG)
+
+static void bn_printn (const char *msg, const bn_t *m, bnindex_t i)
+{
+ EC_ASSERT(NULL != m);
+
+ if (NULL != msg)
+ printf("%s", msg);
+
+ while (0 < i--) {
+#if defined(EC_DEBUG_WORDS)
+ if (i<NWORDS-1)
+ printf(".");
+#endif
+
+ printf(BN_FMT, *(m++));
+ }
+
+ printf("\n");
+}
+
+
+static void bn_print (const char *msg, const bn_t *m)
+{
+ bn_printn(msg, m, NWORDS);
+}
+
+
+static void bn_dprint (const char *msg, const bn_t *m)
+{
+ bn_printn(msg, m, NWORDS+NWORDS);
+}
+
+#endif /* defined(EC_DEBUG) */
+
+
+//============================================== modular multiplication ====
+// this section should be routed to hardware, when it becomes available
+
+#ifndef BN_POWER64_CLR
+#define bn_clear(n) memset((n), 0, BNBYTES)
+#define bn_dclear(n) memset((n), 0, 2*BNBYTES)
+#else
+#define bn_clear(n) bn_clr((n), NWORDS)
+#define bn_dclear(n) bn_clr((n), 2*NWORDS)
+static void __attribute__((noinline)) bn_clr (bn_t *dst, size_t s)
+{
+ size_t i;
+ dst--;
+ for(i=0;i<s;i++) {
+ *(++dst) = 0LL;
+ }
+}
+#endif
+
+#ifndef BN_POWER64_MUL
+// high bn_t of a*b
+// XXX use inline asm if possible; Intel code is enormous
+// XXX alternatively, replace with hbn_t-by-hbn_t-blocked multiplication
+//
+static bn_t bn_dmul (bn_t a, bn_t b)
+{
+#ifdef EC_POWER64_ASM
+ bn_t t;
+ asm("mulhdu %0,%1,%2" : "=r" (t) : "r" (a), "r" (b) );
+ return t;
+#else
+ hbn_t ah, al, bh, bl;
+ bn_t t;
+
+ al = a;
+ ah = (hbn_t) (a >> HBN_BITS);
+ bl = b;
+ bh = (hbn_t) (b >> HBN_BITS);
+
+ a = ((bn_t) ah) * bh; // collects high word
+ b = ((bn_t) al) * bl; // collects low word
+
+ t = ((bn_t) ah) * bl;
+ a += t >> HBN_BITS;
+ t <<= HBN_BITS;
+ if (b+t < t)
+ ++a;
+ b += t;
+
+ t = ((bn_t) al) * bh;
+ a += t >> HBN_BITS;
+ t <<= HBN_BITS;
+ if (b+t < t)
+ ++a;
+// b += t; // we don't actually need this, only its carry above
+ return a;
+#endif
+}
+
+
+//-------------------------------------
+/** multiply (a,NWORDS) by (b,NWORDS) into (r,2*NWORDS)
+ * we collect 2-word multiples, and carries across columns in two
+ * arrays:
+ *
+ * products
+ * a[0].b[0] a[1].b[0] a[2].b[0]
+ * a[0].b[1] a[1].b[1]
+ * a[0].b[2]
+ * carry in column to:
+ * carry[0] carry[1] carry[2]...
+ *
+ * delaying carry-collection simplifies multiply loop
+ */
+// XXX split to half-words' array; get rid of bn_dmul()
+//
+static void bn_mul (bn_t *r, const bn_t *a, const bn_t *b)
+{
+ unsigned char cf[ NWORDS+NWORDS ]; /* carry collector */
+ bnindex_t i, j;
+ bn_t ph, pl; /* product high,low words */
+
+ EC_ASSERT(NULL != r);
+ EC_ASSERT(NULL != a);
+ EC_ASSERT(NULL != b);
+
+ bn_dclear(r);
+ memset(cf, 0, sizeof(cf));
+
+ for (j=0; j<NWORDS; ++j) {
+ for (i=0; i<NWORDS; ++i) {
+ ph = bn_dmul(a[i], b[j]);
+ pl = a[i] * b[j];
+
+#ifdef EC_POWER64_ASM
+ asm("addc %0,%2,%4\n"
+ "addze %1,%3"
+ : "=r" (r[i+j]), "=r" (cf[i+j])
+ : "0" (r[i+j]), "1" (cf[i+j]), "r" (ph)
+ );
+ asm("addc %0,%2,%4\n"
+ "addze %1,%3"
+ : "=r" (r[i+j+1]), "=r" (cf[i+j+1])
+ : "0" (r[i+j+1]), "1" (cf[i+j+1]), "r" (pl)
+ );
+#else
+ r[i+j] += ph;
+ if (r[i+j] < ph) {
+ EC_ASSERT(i+j>0); // MSW can't carry to left
+ (cf[i+j-1])++;
+ }
+
+ r[i+j+1] += pl;
+ if (r[i+j+1] < pl)
+ (cf[i+j])++;
+#endif
+ }
+ }
+
+ // propagate carries (LS to MS)
+#ifdef EC_POWER64_ASM
+ i=NWORDS+NWORDS-2;
+ asm("addc %0,%1,%2"
+ : "=r" (r[i])
+ : "0" (r[i]), "r" (cf[i+1])
+ );
+ for ( ; 0<i; ) {
+ --i;
+ asm("adde %0,%1,%2"
+ : "=r" (r[i])
+ : "0" (r[i]), "r" (cf[i+1])
+ );
+#else
+ for (i=NWORDS+NWORDS; 0<i; ) {
+ if (cf[--i]) {
+ r[i] += cf[i];
+ if (r[i] < cf[i]) {
+ EC_ASSERT(0 < i);
+ cf[i-1]++;
+ }
+ }
+#endif
+ }
+}
+#else
+static void bn_mul (bn_t *r, const bn_t *a, const bn_t *b)
+{
+ bnindex_t i, j;
+ bn_t ph, pl, th, tb; /* product high,low words */
+
+ EC_ASSERT(NULL != r);
+ EC_ASSERT(NULL != a);
+ EC_ASSERT(NULL != b);
+
+ bn_dclear(r);
+
+ r += NWORDS;
+ b += NWORDS;
+ for (j=0; j<NWORDS; j++) {
+ th = 0LL;
+ tb = *(--b);
+ r += NWORDS;
+ a += NWORDS;
+ for (i=0; i<NWORDS; i++) {
+ asm("mulld %0,%1,%2" //pl = *(--a) * tb
+ : "=r" (pl)
+ : "r" (*(--a)), "r" (tb)
+ );
+ asm("mulhdu %0,%1,%2" //ph = *a * tb
+ : "=r" (ph)
+ : "r" (*a), "r" (tb)
+ );
+ asm("addc %1,%5,%4\n" //pl += *(--r)
+ "addze %2,%6\n" //ph += ca
+ "addc %0,%5,%7\n" //*r = pl + th
+ "addze %3,%6" //th = ph + ca
+ : "=r" (*r), "=r" (pl), "=r" (ph), "=r" (th)
+ : "0" (*(--r)), "1" (pl), "2" (ph), "3" (th)
+ );
+ }
+ *(--r) = th;
+ }
+}
+#endif
+
+#ifdef EC_POWER64_ALG
+#ifdef BN_POWER64_SQR
+static void bn_sqr (bn_t *r, const bn_t *a)
+{
+ bnindex_t i, j;
+ const bn_t *b; /* product high,low words */
+ bn_t *c, ph, pl, ta, t0, t1, t2; /* product high,low words */
+
+ EC_ASSERT(NULL != r);
+ EC_ASSERT(NULL != a);
+
+ bn_dclear(r);
+
+ r += 2*NWORDS;
+ a += NWORDS;
+ for (j=0; j<NWORDS-1; j++) {
+ ta = *(--a);
+ c = r;
+ b = a;
+ asm("mulld %0,%2,%2\n" //pl = ta * ta
+ "mulhdu %1,%2,%2" //ph = ta * ta
+ : "=r" (pl), "=r" (ph)
+ : "r" (ta)
+ );
+ asm("addc %0,%2,%4\n" //*r = *(--r) + pl
+ "addze %1,%3" //t0 = ph + ca
+ : "=r" (*c), "=r" (t0)
+ : "0" (*(--c)), "r" (ph), "r" (pl)
+ );
+ t1 = 0L;
+ for (i=j+1; i<NWORDS; i++) {
+ t2 = 0L;
+ asm("mulld %0,%1,%2" //pl = *(--b) * ta
+ : "=r" (pl)
+ : "r" (*(--b)), "r" (ta)
+ );
+ asm("mulhdu %0,%1,%2" //ph = *b * ta
+ : "=r" (ph)
+ : "r" (*b), "r" (ta)
+ );
+ asm("addc %1,%7,%7\n" //pl += pl
+ "adde %2,%8,%8\n" //ph += ph + ca
+ "addze %5,%11\n" //t2 += ca
+ "addc %1,%7,%9\n" //pl += t0
+ "adde %2,%8,%10\n" //ph += t1 + ca
+ "addze %5,%11\n" //t2 += ca
+ "addc %0,%6,%7\n" //*r = *(--r) + pl
+ "addze %3,%8\n" //t0 = ph + ca
+ "addze %4,%11" //t1 = t2 + ca
+ : "=r" (*c), "=r" (pl), "=r" (ph), "=r" (t0), "=r" (t1), "=r" (t2)
+ : "0" (*(--c)), "1" (pl), "2" (ph), "3" (t0), "4" (t1), "5" (t2)
+ );
+ }
+ asm("addc %0,%2,%4\n" //*r = *(--r) + t0
+ "addze %1,%3" //t1 += ca
+ : "=r" (*c), "=r" (t1)
+ : "0" (*(--c)), "1" (t1), "r" (t0)
+ );
+ *(--c) = t1;
+ r -= 2;
+ }
+ ta = *(--a);
+ asm("mulld %0,%2,%2\n" //pl = ta * ta
+ "mulhdu %1,%2,%2" //ph = ta * ta
+ : "=r" (pl), "=r" (ph)
+ : "r" (ta)
+ );
+ asm("addc %0,%2,%4\n" //*r = *(--r) + pl
+ "addze %1,%3" //ph += ca
+ : "=r" (*r), "=r" (ph)
+ : "0" (*(--r)), "1" (ph), "r" (pl)
+ );
+ *(--r) += ph;
+}
+#endif
+#endif
+
+//---------------- mod mul by generator prime (p) -------
+// we only need to reduce with two moduluses, ec_prime or ec_order
+// ec_prime has special form
+//
+// multiply to (prod,2*NWORDS), then reduce
+// we use specific primes, with specific (faster) mod reductions
+
+
+// a is double-length bignumber, i.e., 2*NWORDS
+// always produced by a modular product, i.e., <=2*EC_PRIMEBITS total
+//
+// P521: specific form
+// destroys LS bignumber of (a,2*NWORDS)
+//
+#ifndef EC_POWER64_RED
+static void bn_modred_p521 (bn_t *r, bn_t *a)
+{
+ bn_t *al;
+bn_t *rc = r;
+
+ EC_ASSERT(NULL != r);
+ EC_ASSERT(NULL != a);
+ EC_ASSERT((const bn_t *) r != a);
+
+ al = a+NWORDS;
+
+ // P521: product is 1042 bits, MSW of double-width bignum always 0
+ //
+ EC_ASSERT(0 == a[0]);
+
+ BN_COPY(rc, a);
+ bn_shl(rc, *al);
+
+ *al &= BN_PRIME_MSW_MASK;
+
+ if (bn_cmp(rc, consts_p()->ec_prime) >= 0)
+ bn_sub(rc, consts_p()->ec_prime); // XXX can this happen? (mod-based input)
+
+ if (bn_cmp(al, consts_p()->ec_prime) >= 0)
+ bn_sub(al, consts_p()->ec_prime);
+ EC_ASSERT(!bn_ge_prime(al)); // al must have bitlen <= ec_prime
+
+ bn_add(rc, al);
+ if (bn_cmp(rc, consts_p()->ec_prime) >= 0)
+ bn_sub(rc, consts_p()->ec_prime);
+}
+#else
+#ifdef BN_POWER64_SQR
+static void __attribute__((noinline)) bn_modred_fast (bn_t *r, bn_t *a)
+#else
+static void bn_modred_fast (bn_t *r, bn_t *a)
+#endif
+{
+ bn_t *ah = a + NWORDS;
+ bn_t *al = a + 2*NWORDS;
+ bn_t t0 = (*(a+1) >> 18) + (*ah >> 9);
+ bn_t t1, t2, t3=0;
+ size_t i;
+ r += NWORDS;
+ for (i=0; i<NWORDS-2; i++) {
+ t1 = *(--ah) << 55;
+ t2 = *ah >> 9;
+ asm("addc %3,%7,%5\n" //t3 = *(--al) + t0;
+ "addze %2,%6\n" //t2 += ca;
+ "addc %0,%4,%8\n" //*(--r) = t3 + t1;
+ "addze %1,%6" //t0 = t2 + ca;
+ : "=r" (*(--r)), "=r" (t0), "=r" (t2), "=r" (t3)
+ : "3" (t3), "1" (t0), "2" (t2), "r" (*(--al)), "r" (t1)
+ );
+ }
+ t1 = *(--ah) << 55;
+ t2 = (*ah >> 9)&BN_PRIME_MSW_MASK;
+ asm("addc %3,%7,%5\n" //t3 = *(--al) + t0;
+ "addze %2,%6\n" //t2 += ca;
+ "addc %0,%4,%8\n" //*(--r) = t3 + t1;
+ "addze %1,%6" //t0 = t2 + ca;
+ : "=r" (*(--r)), "=r" (t0), "=r" (t2), "=r" (t3)
+ : "3" (t3), "1" (t0), "2" (t2), "r" (*(--al)), "r" (t1)
+ );
+ *(--r) = (*(--al)&BN_PRIME_MSW_MASK) + t0;
+}
+
+static void __attribute__((noinline)) bn_modred_slow (bn_t *r)
+{
+ size_t i;
+ if (*r > BN_PRIME_MSW_MASK) {
+ bn_t t0 = *r >> 9;
+ *r &= BN_PRIME_MSW_MASK;
+ r += NWORDS;
+ asm("addc %0,%1,%2"
+ : "=r" (*r)
+ : "0" (*(--r)), "r" (t0)
+ );
+ for (i=0; i<NWORDS-1; i++) {
+ asm("addze %0,%1"
+ : "=r" (*r)
+ : "0" (*(--r))
+ );
+ }
+ }
+ if (bn_ge_prime(r))
+ bn_sub(r, consts_p()->ec_prime);
+}
+#endif
+
+
+static void bn_modmul_prime (bn_t *a, const bn_t *b)
+{
+ bn_t prod[ NWORDS+NWORDS ];
+
+ EC_ASSERT(NULL != a);
+ EC_ASSERT(NULL != b);
+
+ bn_mul(prod, a, b);
+#ifdef EC_POWER64_RED
+ bn_modred_fast(a, prod); // accepts upto 46 extra bits => outputs at most 1 extra bit (522)
+#else
+ bn_modred_p521(a, prod);
+#endif
+}
+
+#ifdef EC_POWER64_ALG
+static void bn_modsqr_prime (bn_t *a)
+{
+#ifdef BN_POWER64_SQR
+ bn_t prod[ NWORDS+NWORDS ];
+
+ EC_ASSERT(NULL != a);
+
+ bn_sqr(prod, a);
+#ifdef EC_POWER64_RED
+ bn_modred_fast(a, prod); // accepts upto 46 extra bits => outputs at most 1 extra bit (522)
+#else
+ bn_modred_p521(a, prod);
+#endif
+#else
+ bn_modmul_prime(a, a);
+#endif
+}
+#endif
+
+
+
+// mod reduce 2*NWORDS to NWORDS through approximate division
+//
+// input (a,2*NWORDS) <= N^2 -2*N +1
+//
+// N = 2^521 -Q (Q is approx 2^260)
+// A = AH * 2^521 + AL (AH < 2^251)
+// A/N = (AH*R + AL)/N = AH + (AH*Q + AL) /N ~ AH + (AH*Q /N)
+// AH*Q /N =~ AH* floor(Q/N)
+//
+// dividend may be two too low:
+// 1. we neglect AL/N, which may add add one (AL<N)
+// 2. we truncate the multiplication, possibly ignoring one carry from below
+// so, keep subtracting N until result <N; up to twice is enough
+//
+// r,a must not overlap
+//
+static void bn_modred_p521_order (bn_t *r, const bn_t *a)
+{
+ bn_t dbl[ NWORDS+NWORDS ];
+
+ EC_ASSERT(NULL != r);
+ EC_ASSERT(NULL != a);
+ EC_ASSERT((const bn_t *) r != a);
+// XXX full overlap check
+
+ // P521: product is 1042 bits, MSW of double-width bignum always 0
+ //
+ EC_ASSERT(0 == a[0]);
+
+ BN_COPY(r, a);
+ bn_shl(r, a[NWORDS]);
+
+ bn_mul(dbl, r, consts_p()->ec_order_qn);
+ bn_shl(dbl, dbl[NWORDS]); // MS 521 bits of product
+ bn_add(r, dbl);
+
+ bn_mul(dbl, r, consts_p()->ec_order); // N * floor(A / N)
+ EC_ASSERT(bn_cmp(dbl, a) <= 0);
+ EC_ASSERT(bn_cmp(dbl+NWORDS, a+NWORDS) <= 0);
+
+ BN_COPY(r, a+NWORDS);
+ bn_sub(r, dbl+NWORDS); // A - (N * floor(A/N))
+
+ if (bn_cmp(r, consts_p()->ec_order) >= 0)
+ bn_sub(r, consts_p()->ec_order);
+
+ if (bn_cmp(r, consts_p()->ec_order) >= 0)
+ bn_sub(r, consts_p()->ec_order); // XXX can this still be 2+ over?
+
+ EC_ASSERT(bn_cmp(r, consts_p()->ec_order) < 0);
+}
+
+
+static void bn_modmul_order (bn_t *a, const bn_t *b)
+{
+ bn_t prod[ NWORDS+NWORDS ];
+
+ EC_ASSERT(NULL != a);
+ EC_ASSERT(NULL != b);
+
+ bn_mul(prod, a, b);
+ bn_modred_p521_order(a, prod);
+}
+
+
+//-------------------------------------
+// negative,0,positive for a<b, a==b, a>b
+//
+#if defined(__BIG_ENDIAN) && !defined(BN_POWER64_CMP)
+
+static int bn_cmp (const bn_t *a, const bn_t *b)
+{
+ EC_ASSERT(NULL != a);
+ EC_ASSERT(NULL != b);
+
+ return memcmp(a, b, sizeof(bn_t)*NWORDS);
+}
+
+#else /* defined(__BIG_ENDIAN) */
+
+static int __attribute__((noinline)) bn_cmp (const bn_t *a, const bn_t *b)
+{
+ bnindex_t i;
+
+ EC_ASSERT(NULL != a);
+ EC_ASSERT(NULL != b);
+
+ for (i=0; i<NWORDS; ++i) {
+ if (a[i] != b[i])
+ return 1 - ((a[i] < b[i]) <<1);
+ }
+
+ return 0;
+}
+
+#endif /* defined(__BIG_ENDIAN) */
+
+
+
+//-------------------------------------
+//removed:
+//static const bn_t bn_zero[ NWORDS ];
+
+// mn: how many words to skip (least significant ones)
+//
+static int bn_is_zero (const bn_t *m, unsigned int mn)
+{
+ EC_ASSERT(NULL != m);
+ EC_ASSERT(mn < NWORDS);
+
+ const unsigned char *p2 = (const unsigned char *) m;
+ size_t n=sizeof(bn_t)*(NWORDS-mn);
+
+ while (n-- > 0) {
+ if (0 != *p2)
+ return !(0 - *p2);
+ p2 += 1;
+ }
+
+ return !0;
+
+// replaces:
+// return !memcmp(bn_zero, m, sizeof(bn_t)*(NWORDS-mn));
+}
+
+
+//-------------------------------------
+static void __attribute__((noinline)) bn_add (bn_t *a, const bn_t *b)
+{
+ bn_t aw, cf = 0; /* aw: copy of current word to allow a==b */
+ bnindex_t i = NWORDS;
+
+ EC_ASSERT(NULL != a);
+ EC_ASSERT(NULL != b);
+
+ a += NWORDS-1;
+ b += NWORDS-1;
+
+ while (0 < i--) {
+ aw = *a;
+ if (cf)
+ cf = (0 == ++aw);
+
+ aw += *b;
+ cf |= (aw < *(b--));
+ *(a--) = aw;
+ }
+}
+
+
+//-------------------------------------
+// a,b < prime
+// never with order as base
+//
+static void bn_modadd (bn_t *a, const bn_t *b)
+{
+ EC_ASSERT(NULL != a);
+ EC_ASSERT(NULL != b);
+ //EC_ASSERT(!bn_ge_prime(a));
+ //EC_ASSERT(!bn_ge_prime(b));
+
+ bn_add(a, b); // P521: can not generate carry (unused MSW bits)
+ // other curves need to handle this carry
+
+#ifndef EC_POWER64_RED
+ if (bn_ge_prime(a))
+ bn_sub(a, consts_p()->ec_prime);
+#endif
+}
+
+
+//-------------------------------------
+// never with order as base
+static bn_t bn_sub (bn_t *a, const bn_t *b)
+{
+ bnindex_t i = NWORDS;
+ bn_t bw, cf = 0;
+
+ EC_ASSERT(NULL != a);
+ EC_ASSERT(NULL != b);
+
+ a += NWORDS-1;
+ b += NWORDS-1;
+
+ while (0 < i--) {
+ if (cf)
+ cf = (0 == (*a)--);
+
+ bw = *b;
+ cf |= (*a < *(b--));
+ *(a--) -= bw;
+ }
+
+ return cf;
+}
+
+
+//-------------------------------------
+// never modular-subtracting with ec_order[], only with ec_prime[]
+// therefore, implicit modulus
+//
+static void bn_modsub (bn_t *a, const bn_t *b)
+{
+ EC_ASSERT(NULL != a);
+ EC_ASSERT(NULL != b);
+ //EC_ASSERT(!bn_ge_prime(a));
+ EC_ASSERT(!bn_ge_prime(b));
+
+ if (bn_sub(a, b))
+ bn_add(a, consts_p()->ec_prime);
+}
+
+
+
+//-------------------------------------
+// only rn LS words are touched
+//
+static void bn_shl_n (bn_t r[NWORDS], unsigned int rn, unsigned int bits)
+{
+ bn_t cf = 0, cfin;
+
+ EC_DEVASSERT(NULL != r);
+ EC_ASSERT(rn <= NWORDS);
+
+ r += NWORDS-rn;
+
+ if (bits >= BN_BITS) { // unlikely, most modinv shift is <5 bits
+ cfin = bits / BN_BITS; // whole words
+
+ memmove(r, r+cfin, (NWORDS-cfin)*sizeof(bn_t));
+#ifndef BN_POWER64_CLR
+ memset(r+NWORDS-cfin, 0, cfin*sizeof(bn_t));
+#else
+ bn_clr(r+NWORDS-cfin, cfin);
+#endif
+
+ bits %= BN_BITS;
+ }
+
+ if (bits) {
+ r += rn-1;
+
+ while (0<rn--) {
+ cfin = cf;
+ cf = (*r >> (BN_BITS - bits));
+
+ *r <<= bits;
+ *r |= cfin;
+ --r;
+ }
+ }
+}
+
+
+
+static unsigned int bn_bits (const bn_t *a)
+{
+ unsigned int full = 8*BNBYTES;
+ bnindex_t i;
+ bn_t an;
+
+ for (i=0; i<NWORDS; ++i) {
+ full -= BN_BITS;
+ an = a[i];
+
+ if (!an)
+ continue;
+
+ while (an > 0xff) {
+ full += 8;
+ an >>= 8;
+ }
+
+ while (an) {
+ ++full;
+ an >>= 1;
+ }
+
+ return full;
+ }
+
+ return 0;
+}
+
+
+// XXX route to bnt_msbit
+//
+#define bn_is_negative(p) (0x1000 & (*(p)))
+
+
+// inv stores S during run
+//
+static int bn_modinv(bn_t *inv, const bn_t *a, const bn_t *n)
+{
+ bn_t r[ NWORDS ], s[ NWORDS ], u[ NWORDS ], v[ NWORDS ],
+ ss[ NWORDS ], vs[ NWORDS ]; // shifted S,V
+ unsigned int shl, ub, vb; // shift amount; bitcount
+ bn_t *pr = r, *ps = s, *pu = u, *pv = v, *pt;
+
+ EC_ASSERT(NULL != inv);
+ EC_ASSERT(NULL != a);
+ EC_ASSERT(NULL != n);
+ EC_ASSERT(bn_cmp(a,n) < 0);
+ EC_ASSERT(!bn_is_zero(a,0));
+
+ // [1, a]
+ // [0, n]
+
+ bn_clear(r);
+ bn_clear(s);
+ BN_LSW(s) = 1;
+
+ BN_COPY(u, n);
+ BN_COPY(v, a);
+
+// bn_print("U ", u);
+// bn_print("V ", v);
+ // ub = bn_bits(u);
+ ub = EC_PRIMEBITS; // P521: only ec_prime or ec_order possible
+ vb = bn_bits(v);
+// printf("%d,%d\n", (int) ub, (int) vb);
+
+ while (1 < vb) {
+ EC_ASSERT(ub >= vb);
+ shl = ub-vb;
+// printf("< %d\n", shl);
+
+ BN_COPY(vs, pv);
+ BN_COPY(ss, ps);
+ if (shl) {
+ bn_shl_n(vs, NWORDS, shl);
+ bn_shl_n(ss, NWORDS, shl);
+ }
+
+ if (bn_is_negative(pv) == bn_is_negative(pu)) {
+ bn_sub(pu, vs);
+ bn_sub(pr, ss);
+ } else {
+ bn_add(pu, vs);
+ bn_add(pr, ss);
+ }
+
+// bn_print("u ", pu);
+// bn_print("r ", pr);
+ if (bn_is_negative(pu)) {
+ bn_clear(ss);
+ bn_sub(ss, pu);
+ ub = bn_bits(ss);
+ } else {
+ ub = bn_bits(pu);
+ }
+
+ if (ub < vb) {
+ shl = ub; // shl,ss used as swap-scratch
+ ub = vb;
+ vb = shl;
+
+ pt = pu;
+ pu = pv;
+ pv = pt;
+
+ pt = ps;
+ ps = pr;
+ pr = pt;
+ }
+// printf("\n");
+ }
+
+ if (bn_is_negative(pv)) {
+ BN_COPY(ss, ps);
+ bn_clear(ps);
+ bn_sub(ps, ss);
+ }
+
+ if (bn_is_negative(ps))
+ bn_add(ps, n);
+
+ if (bn_cmp(ps, n) >= 0)
+ bn_sub(ps, n);
+ BN_COPY(inv, ps);
+
+ return 1;
+}
+
+
+//-------------------------------------
+#if defined(__BIG_ENDIAN)
+
+
+static void bn_read_pt(bn_t *r, const unsigned char *data)
+{
+ EC_ASSERT(NULL != r);
+ EC_ASSERT(NULL != data);
+
+ r[0] = 0;
+ memmove(((unsigned char *) r) +BNBYTES-EC_PRIMEBYTES,
+ data, EC_PRIMEBYTES);
+}
+
+
+// P521: hash does not have unused MS words
+//
+static void bn_read_hash(bn_t *r, const unsigned char *data)
+{
+ EC_ASSERT(NULL != r);
+ EC_ASSERT(NULL != data);
+
+ r[0] = 0;
+ memmove(((unsigned char *) r) +BNBYTES-EC_HASHBYTES,
+ data, EC_HASHBYTES);
+}
+
+
+#else
+
+static void bn_read(bn_t *r, const unsigned char *data, size_t dlen)
+{
+ bnindex_t i, whole = dlen / sizeof(bn_t),
+ rem = dlen % sizeof(bn_t);
+ bn_t acc = 0;
+
+ EC_ASSERT(NULL != r);
+ EC_ASSERT(NULL != data);
+ EC_ASSERT(dlen <= EC_PRIMEBYTES);
+
+ acc = whole + (!!rem);
+ if (acc < NWORDS) { // unused MS words
+ acc = NWORDS - acc;
+#ifndef BN_POWER64_CLR
+ memset(r, 0, acc*sizeof(bn_t));
+#else
+ bn_clr(r, acc);
+#endif
+ r += acc;
+ }
+
+ acc = 0;
+ if (rem) {
+ ++whole;
+ } else {
+ rem = sizeof(bn_t);
+ }
+
+ while (0 < whole--) {
+ for (i=0; i<rem; ++i)
+ acc = (acc <<8) + *(data++);
+ *(r++) = acc;
+ acc = 0;
+ rem = sizeof(bn_t);
+ }
+}
+
+
+static void bn_read_pt(bn_t *r, const unsigned char *data)
+{
+ return bn_read(r, data, EC_PRIMEBYTES);
+}
+
+
+static void bn_read_hash(bn_t *r, const unsigned char *data)
+{
+ return bn_read(r, data, EC_HASHBYTES);
+}
+
+#endif /* defined(__BIG_ENDIAN) */
+
+
+//======================================================= EC primitives ====
+/* (0,0) is our infinity, since it's not a curve point */
+#define ec_is_infinity(px, py, pz) \
+ (bn_is_zero((px), 0) && bn_is_zero((py), 0))
+
+#define ec_set_infinity(p) bn_clear(p)
+
+
+//-------------------------------------
+// (x) is transformed back to affine from projective (X*Z)
+//
+static void ec_projective2affine (bn_t *x, const bn_t *z)
+{
+ bn_t zinv[ NWORDS ];
+
+ EC_ASSERT(NULL != x);
+ EC_ASSERT(NULL != z);
+
+ EC_ASSERT(!bn_ge_prime(x));
+ EC_ASSERT(!bn_ge_prime(z));
+
+ bn_modinv(zinv, z, consts_p()->ec_prime);
+ bn_modmul_prime(x, zinv);
+#ifdef EC_POWER64_RED
+ bn_modred_slow(x);
+#endif
+}
+
+
+// returns 1 if result is at infinity, 0 otherwise
+//
+static int ec_add (bn_t *x1, bn_t *y1, bn_t *z1,
+ const bn_t *x2, const bn_t *y2, const bn_t *z2)
+{
+ bn_t a[ NWORDS ], b[ NWORDS ], c[ NWORDS ],
+ bs[ NWORDS ], // B^2
+ t1[ NWORDS ], t2[ NWORDS ]; // XXX minimize these
+ int inf1, inf2;
+
+ EC_ASSERT(NULL != x1);
+ EC_ASSERT(NULL != y1);
+ EC_ASSERT(NULL != z1);
+ EC_ASSERT(NULL != x2);
+ EC_ASSERT(NULL != y2);
+ EC_ASSERT(NULL != z2);
+ EC_ASSERT(!bn_ge_prime(x1));
+ EC_ASSERT(!bn_ge_prime(y1));
+ EC_ASSERT(!bn_ge_prime(z1));
+ EC_ASSERT(!bn_ge_prime(x2));
+ EC_ASSERT(!bn_ge_prime(y2));
+ EC_ASSERT(!bn_ge_prime(z2));
+
+ inf1 = ec_is_infinity(x1, y1, z1);
+ inf2 = ec_is_infinity(x2, y2, z2);
+
+ if (inf2)
+ return inf1;
+
+ if (inf1) {
+ BN_COPY(x1, x2);
+ BN_COPY(y1, y2);
+ BN_COPY(z1, z2);
+ return 0; // (x1,y1,z1) not infinity (checked above)
+ }
+
+ if (!bn_cmp(x1, x2) && !bn_cmp(y1, y2))
+ return ec_double(x1, y1, z1);
+
+#ifdef EC_POWER64_ALG
+ BN_COPY(t1, y1);
+ bn_modmul_prime(t1, z2); // t1 = y1 * z2
+ BN_COPY(a, y2);
+ bn_modmul_prime(a, z1); // A = y2 * z1 - y1 * z2
+#ifdef EC_POWER64_RED
+ bn_modred_slow(t1);
+#endif
+ bn_modsub(a, t1);
+
+ bn_modmul_prime(x1, z2); // x1 := x1 * z2 orig x1 no longer used
+ BN_COPY(b, x2);
+ bn_modmul_prime(b, z1);
+#ifdef EC_POWER64_RED
+ bn_modred_slow(x1);
+#endif
+ bn_modsub(b, x1); // B = x2 * z1 - x1 * z2
+
+ BN_COPY(bs, b);
+ bn_modsqr_prime(bs); // B^2
+
+ BN_COPY(c, a);
+ bn_modsqr_prime(c);
+ bn_modmul_prime(z1, z2); // z1 = z1 * z2
+ bn_modmul_prime(c, z1); // c = A^2 * z1 * z2
+
+ bn_modmul_prime(x1, bs); // x1 = B^2 * x1 * z2
+ BN_COPY(t2, b);
+ bn_modmul_prime(t2, bs); // t2 = B^3
+#ifdef EC_POWER64_RED
+ bn_modred_slow(t2);
+ bn_modred_slow(x1);
+#endif
+ bn_modsub(c, t2);
+ bn_modsub(c, x1); // C = A^2 * z1 * z2 - B^3
+ bn_modsub(c, x1); // - 2 B^2 * x1 * z1
+
+ bn_modmul_prime(z1, t2); // z1 * z2 * B^3
+#ifdef EC_POWER64_RED
+ bn_modred_slow(z1);
+ bn_modred_slow(c);
+#endif
+
+ bn_modmul_prime(t1, t2); // (B^3 * y1 * z2)
+ // A(B 2 X1 Z2 ? C)
+ bn_modsub(x1, c);
+ bn_modmul_prime(x1, a); // A * (B^2 * x1 * z2 - C)
+#ifdef EC_POWER64_RED
+ bn_modred_slow(x1);
+ bn_modred_slow(t1);
+#endif
+ bn_modsub(x1, t1); // Y = A * (B^2 * x1 * z2 - C) - (B^3 * y1 * z2)
+ BN_COPY(y1, x1);
+
+ BN_COPY(x1, b);
+ bn_modmul_prime(x1, c); // X = B * C
+#ifdef EC_POWER64_RED
+ bn_modred_slow(x1);
+#endif
+
+#else // !EC_POWER64_ALG
+ BN_COPY(t1, y1);
+ bn_modmul_prime(t1, z2); // t1 = y1 * z2
+ BN_COPY(a, y2);
+ bn_modmul_prime(a, z1); // A = y2 * z1 - y1 * z2
+ bn_modsub(a, t1);
+
+ bn_modmul_prime(x1, z2); // x1 := x1 * z2 orig x1 no longer used
+ BN_COPY(b, x2);
+ bn_modmul_prime(b, z1);
+ bn_modsub(b, x1); // B = x2 * z1 - x1 * z2
+
+ BN_COPY(bs, b);
+ bn_modmul_prime(bs, bs); // B^2
+
+ BN_COPY(c, a);
+ bn_modmul_prime(c, c);
+ bn_modmul_prime(c, z1);
+ bn_modmul_prime(c, z2);
+
+ BN_COPY(t2, b);
+ bn_modadd(t2, x1);
+ bn_modadd(t2, x1);
+ bn_modmul_prime(t2, bs);
+ bn_modsub(c, t2); // C = A^2 * z1 * z2 - B^3
+ // - 2 B^2 * x1 * z1
+
+ bn_modmul_prime(z1, z2);
+ bn_modmul_prime(z1, b);
+ bn_modmul_prime(z1, bs); // z1 * z2 * B^3
+
+ bn_modmul_prime(t1, b);
+ bn_modmul_prime(t1, bs); // (B^3 * y1 * z2)
+ // A(B 2 X1 Z2 ? C)
+ bn_modmul_prime(x1, bs); // (B^2 * x1 * z2)
+ bn_modsub(x1, c);
+ bn_modmul_prime(x1, a); // A * (B^2 * x1 * z2 - C)
+ bn_modsub(x1, t1);
+ BN_COPY(y1, x1); // Y =
+
+ BN_COPY(x1, b);
+ bn_modmul_prime(x1, c); // X = B * C
+#endif
+
+ return 0;
+}
+
+
+
+
+//----------------------------------------------------------------------------
+// (x,y,z) in projective coordinates
+// P521: curve has a==-3
+//
+// return 1 if point in infinity
+//
+static int ec_double (bn_t *x, bn_t *y, bn_t *z)
+{
+ bn_t a[ NWORDS ], b[ NWORDS ], c[ NWORDS ], d[ NWORDS ], t[ NWORDS ];
+
+ EC_ASSERT(NULL != x);
+ EC_ASSERT(NULL != y);
+ EC_ASSERT(NULL != z);
+ EC_ASSERT(!bn_ge_prime(x));
+ EC_ASSERT(!bn_ge_prime(y));
+ EC_ASSERT(!bn_ge_prime(z));
+
+#ifdef EC_POWER64_ALG
+ BN_COPY(a, x);
+ BN_COPY(d, x);
+
+ bn_modadd(a, z);
+ bn_modsub(d, z);
+ bn_modmul_prime(a, d); // x^2 - z^2
+ BN_COPY(d, a);
+ bn_modadd(a, a);
+ bn_modadd(a, d); // A = 3 * (x^2 - z^2)
+ // P521: generally, A = 3 * x^2 - a * z^2
+
+ BN_COPY(b, z);
+ bn_modmul_prime(b, y); // B = y * z
+
+ BN_COPY(c, x);
+ bn_modmul_prime(y, b); // y = y * B
+ bn_modmul_prime(c, y); // C = x * y * B
+
+ BN_COPY(z, b);
+ bn_modsqr_prime(z);
+ bn_modmul_prime(z, b);
+ bn_modadd(z, z);
+ bn_modadd(z, z);
+ bn_modadd(z, z); // Z = 8 * B^3
+#ifdef EC_POWER64_RED
+ bn_modred_slow(z);
+#endif
+
+ BN_COPY(t, c);
+ bn_modadd(t, t);
+ bn_modadd(t, t);
+ bn_modadd(t, t);
+ BN_COPY(d, a);
+ bn_modsqr_prime(d);
+#ifdef EC_POWER64_RED
+ bn_modred_slow(t);
+#endif
+ bn_modsub(d, t); // D = A^2 - 8*C
+
+ BN_COPY(x, b);
+ bn_modmul_prime(x, d);
+ bn_modadd(x, x); // X = 2 * B * D
+#ifdef EC_POWER64_RED
+ bn_modred_slow(x);
+ bn_modred_slow(d);
+#endif
+
+ bn_modadd(c, c);
+ bn_modadd(c, c);
+ bn_modsub(c, d);
+ bn_modmul_prime(a, c); // (A * (4*C - D))
+
+ bn_modsqr_prime(y); // (y * B)^2
+ bn_modadd(y, y);
+ bn_modadd(y, y);
+ bn_modadd(y, y); // (8 * y^2 * B^2)
+#ifdef EC_POWER64_RED
+ bn_modred_slow(a);
+ bn_modred_slow(y);
+#endif
+ bn_modsub(a, y);
+ BN_COPY(y, a); // Y = A * (4*C - D) - 8 * y^2 * B^2
+
+#else // !EC_POWER64_ALG
+ BN_COPY(a, x);
+ BN_COPY(d, z);
+
+ bn_modmul_prime(a, x);
+ bn_modmul_prime(d, z);
+ bn_modsub(a, d);
+ BN_COPY(d, a);
+ bn_modadd(a, a);
+ bn_modadd(a, d); // A = 3 * (x^2 - z^2)
+ // P521: generally, A = 3 * x^2 - a * z^2
+
+ BN_COPY(b, z);
+ bn_modmul_prime(b, y); // B = y * z
+
+ BN_COPY(c, y);
+ bn_modmul_prime(c, b);
+ bn_modmul_prime(c, x); // C = x * y * B
+
+ BN_COPY(z, b);
+ bn_modmul_prime(z, b);
+ bn_modmul_prime(z, b);
+ bn_modadd(z, z);
+ bn_modadd(z, z);
+ bn_modadd(z, z); // Z = 8 * B^3
+
+ BN_COPY(t, c);
+ bn_modadd(t, t);
+ bn_modadd(t, t);
+ bn_modadd(t, t);
+ BN_COPY(d, a);
+ bn_modmul_prime(d, a);
+ bn_modsub(d, t); // D = A^2 - 8*C
+
+ BN_COPY(x, b);
+ bn_modmul_prime(x, d);
+ bn_modadd(x, x); // X = 2 * B * D
+
+ bn_modadd(c, c);
+ bn_modadd(c, c);
+ bn_modsub(c, d);
+ bn_modmul_prime(a, c); // (A * (4*C - D))
+
+ bn_modmul_prime(y, b);
+ bn_modmul_prime(y, y);
+ bn_modadd(y, y);
+ bn_modadd(y, y);
+ bn_modadd(y, y); // (8 * y^2 * B^2)
+ bn_modsub(a, y);
+ BN_COPY(y, a); // Y = A * (4*C - D) - 8 * y^2 * B^2
+#endif
+
+ return 0;
+}
+
+
+
+//-------------------------------------
+// (x,y) in affine coordinates; z is output only
+// returns (x,y,z) in projective coordinates
+//
+// we roll (x,y), updating (qx,qy) if necessary
+// finally, (x,y) := (qx,qy)
+//
+// LIMIT: processes up to EC_PRIMEBITS in coefficient
+// z and k must not overlap
+//
+static int ec_multiply (bn_t *x, bn_t *y, bn_t *z, const bn_t *k)
+{
+ bn_t px[ NWORDS ], py[ NWORDS ], pz[ NWORDS ];
+ unsigned int i;
+ bn_t mask = 1;
+
+ EC_ASSERT(NULL != x);
+ EC_ASSERT(NULL != y);
+ EC_ASSERT(NULL != k);
+ EC_ASSERT(!bn_ge_prime(x));
+ EC_ASSERT(!bn_ge_prime(y));
+
+ i=bn_bits(k);
+ k += NWORDS-1;
+
+ BN_COPY(px, x);
+ BN_COPY(py, y);
+ bn_clear(x);
+ bn_clear(y);
+
+ bn_clear(z);
+ BN_LSW(z) = 1; // (x,y) -> (x, y, 1) in projective coordinates
+ BN_COPY(pz, z); // (px,py) -> (px,py,1)
+
+ BN_DUMP(i,x);
+ BN_DUMP(i,y);
+ BN_DUMP(i,z);
+ BN_DUMP(i,px);
+ BN_DUMP(i,py);
+ BN_DUMP(i,pz);
+ while (0 < i--) {
+ if (mask & *k)
+ ec_add(x, y, z, px, py, pz);
+
+ if (0 < i)
+ ec_double(px, py, pz);
+
+ BN_DUMP(i,x);
+ BN_DUMP(i,y);
+ BN_DUMP(i,z);
+ BN_DUMP(i,px);
+ BN_DUMP(i,py);
+ BN_DUMP(i,pz);
+ mask <<= 1;
+ if (!mask) {
+ --k;
+ mask = 1;
+ }
+ }
+ BN_EXIT();
+
+ return 0;
+}
+
+
+//===================================================== public function ====
+asm(".globl .L.ec_verify");
+int ec_verify (const unsigned char *publicpt, /* 2*EC_COORDBYTES */
+ const unsigned char *hash, /* EC_HASHBYTES */
+ const unsigned char *signature) /* 2*EC_COORDBYTES */
+{
+ bn_t r[ NWORDS ], s[ NWORDS ], e[ NWORDS ],
+ px[ NWORDS ], py[ NWORDS ], pz[ NWORDS ],
+ u1[ NWORDS ], u2[ NWORDS ];
+
+ if ((NULL == publicpt) || (NULL == signature) || (NULL == hash))
+ return -1;
+
+ bn_read_pt (r, signature);
+ bn_read_pt (s, signature +EC_COORDBYTES);
+ bn_read_hash(e, hash);
+ bn_read_pt (px, publicpt);
+ bn_read_pt (py, publicpt +EC_COORDBYTES);
+
+ if (bn_ge_order(r) || bn_ge_order(s) ||
+ bn_is_zero(s,0) || bn_is_zero(r,0))
+ return 0; // assume user messed with signature
+
+ if (bn_ge_prime(px) || bn_ge_prime(py) ||
+ bn_is_zero(px,0) || bn_is_zero(py,0))
+ return -1; // admin fault; should not happen
+
+ bn_modinv(u1, s, consts_p()->ec_order); // s no longer needed (NLN)
+ BN_COPY(u2, r);
+ bn_modmul_order(u2, u1);
+ bn_modmul_order(u1, e); // e NLN
+
+ // reuse (e,s) for base multiplication
+ BN_COPY(e, consts_p()->prime_px); // (e,s) <- (base point)
+ BN_COPY(s, consts_p()->prime_py);
+
+ ec_multiply(px, py, pz, u2); // (px,py,pz) = u2 * (px,py); u2 NLN
+ ec_multiply(e, s, u2, u1); // (s, e, u2) = u1 * (gx,gy); u1 NLN
+
+ if (ec_add(px, py, pz, e, s, u2)) // u1 * base + u2 * public
+ return 0; // reached infinity (SNH with sig)
+
+ ec_projective2affine(px, pz);
+
+ if (bn_ge_order(px))
+ bn_sub(px, consts_p()->ec_order); // px mod order
+
+ return (! bn_cmp(r, px));
+}
+
diff --git a/src/securerom/hw_utils.C b/src/securerom/hw_utils.C
new file mode 100644
index 000000000..19d4ee947
--- /dev/null
+++ b/src/securerom/hw_utils.C
@@ -0,0 +1,222 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/securerom/hw_utils.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+/****************************************************************************
+ *
+ ****************************************************************************/
+#include <hw_utils.h>
+#include <status_codes.h>
+
+/****************************************************************************/
+
+#ifdef EMULATE_HW
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <limits.h>
+#include <stdint.h> /* uint_fast8_t, uintN_t */
+#include <inttypes.h>
+hw_settings HW;
+
+/****************************************************************************/
+void HW_Init (void) {
+ /* Open the file that will be used to fill the memory contents of the mmap */
+ HW.mfd = open ("/dev/zero", O_RDWR, 0);
+ if (HW.mfd < 0) {
+ printf ("HW_Init: can't create memory file");
+ exit(1);
+ }
+ /* Allocate Memory */
+#ifdef HOST_64
+ HW.data = (uint8_t*) mmap64 (0, TOTAL_TEST_MEMORY,
+ PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, HW.mfd, 0);
+#else
+ HW.data = (uint8_t*) mmap (0, TOTAL_TEST_MEMORY,
+ PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, HW.mfd, 0);
+#endif
+ if ((uint32_t) HW.data == -1) {
+ printf ("Unable to allocate HW Memory of size %d", TOTAL_TEST_MEMORY);
+ HW_Free();
+ exit(1);
+ }
+ HW.memory = HW.data+0x1000-((uint32_t)HW.data&0xfff);
+}
+
+/****************************************************************************/
+void HW_Free (void)
+{
+ close (HW.mfd);
+}
+
+/****************************************************************************/
+void Log (uint64_t code) {
+ mtspr_SCRATCH2 (code);
+}
+
+/****************************************************************************/
+void Check_Stop (char* msg) {
+ printf ("CHECK STOP '%s'\n", msg);
+ printf ("SCRATCH3= 0x%08llX\n", mfspr_SCRATCH3());
+ exit(FAIL);
+}
+
+/****************************************************************************/
+void Error_Stop (uint64_t code, char* msg) {
+ mtspr_SCRATCH3 (ERROR_EVENT|code);
+ Check_Stop (msg);
+}
+
+/****************************************************************************/
+void assem_DCBI (uint64_t addr) {
+ addr = physical_addr(addr)&CACHE_MASK;
+ memset(Convert_Mem_Addr(addr),0xff,CACHE_LINE); // destroys contents in model
+ }
+/****************************************************************************/
+void assem_DCBZ (uint64_t addr) {
+ addr = physical_addr(addr)&CACHE_MASK;
+ memset(Convert_Mem_Addr(addr),0,CACHE_LINE);
+}
+/****************************************************************************/
+void assem_DCBST (uint8_t* addr) {}
+/****************************************************************************/
+void assem_ICBI (uint64_t* addr) {}
+/****************************************************************************/
+void assem_SYNC (void) {}
+/****************************************************************************/
+void assem_ISYNC (void) {}
+
+/****************************************************************************/
+void mtspr_HRMOR (uint64_t addr) {
+ HW.HRMOR = addr & HRMOR_MASK;
+}
+
+/****************************************************************************/
+//uint64_t mfspr_HRMOR (void) {
+// return HW.HRMOR;
+//}
+
+/****************************************************************************/
+
+/****************************************************************************/
+uint64_t getscom_FSP_BAR_value (uint64_t base) {
+ return HW.FSP_BAR.value;
+}
+
+/****************************************************************************/
+uint64_t getscom_FSP_BAR_mask (uint64_t base) {
+ return HW.FSP_BAR.mask;
+}
+
+/****************************************************************************/
+void getscom_HW_ECID (uint64_t base, uint8_t* buf) {
+ memcpy(buf, HW.ECID, ECID_SIZE);
+}
+
+/****************************************************************************/
+void getscom_PIBMEM_HW_Key_Hash (uint64_t base, uint8_t* buf) {
+ memcpy(buf, HW.PIBMEM_HW_KEY_HASH, SHA512_DIGEST_SIZE);
+}
+
+/****************************************************************************/
+uint8_t* Convert_Mem_Addr (uint64_t addr) {
+ if (addr >= TEST_SYSTEM_MEMORY) return NULL;
+ return HW.memory+addr;
+}
+
+/****************************************************************************/
+uint64_t physical_addr (uint64_t addr) {
+ if (addr & HRMOR_IGNORE) addr = PHYSICAL(addr);
+ else addr = PHYSICAL(addr) | HW.HRMOR;
+ return addr;
+}
+
+/****************************************************************************/
+uint64_t Convert_Mem_Offset (uint8_t* addr) {
+ if (addr < HW.memory) return 0;
+ return (uint64_t)(uint32_t)(addr-HW.memory);
+}
+
+/****************************************************************************/
+uint16_t GET16(uint16_t data) {
+#ifdef __BIG_ENDIAN
+ return data;
+#endif
+#ifdef __LITTLE_ENDIAN
+ return ((data&0x00FF)<<8
+ |(data&0xFF00)>>8
+ );
+#endif
+}
+
+/****************************************************************************/
+uint32_t GET32 (uint32_t data) {
+#ifdef __BIG_ENDIAN
+ return data;
+#endif
+#ifdef __LITTLE_ENDIAN
+ return ((data&0x000000FF)<<24
+ |(data&0x0000FF00)<<8
+ |(data&0x00FF0000)>>8
+ |(data&0xFF000000)>>24
+ );
+#endif
+}
+
+/****************************************************************************/
+uint64_t GET64 (uint64_t data) {
+#ifdef __BIG_ENDIAN
+ return data;
+#endif
+#ifdef __LITTLE_ENDIAN
+ return ((data&0x00000000000000FFull)<<(7*8)
+ |(data&0x000000000000FF00ull)<<(5*8)
+ |(data&0x0000000000FF0000ull)<<(3*8)
+ |(data&0x00000000FF000000ull)<<(1*8)
+ |(data&0x000000FF00000000ull)>>(1*8)
+ |(data&0x0000FF0000000000ull)>>(3*8)
+ |(data&0x00FF000000000000ull)>>(5*8)
+ |(data&0xFF00000000000000ull)>>(7*8)
+ );
+#endif
+}
+
+#else
+
+void __attribute__((noreturn)) Check_Stop(void) {
+ //do not use XSCOM as the XSCOM base is not known for sure
+
+ //set AVP_out to (optionally) cause secure checkstop
+ mtspr(SPRC,SPRC_AVP_out);
+ mtspr(SPRD,-1LL);
+
+ asm volatile(" li 0,0 \n"
+ " mtmsr 0 \n" //ensure there is no error handler so it will checkstop instead
+ " lis 0,-1107 \n"
+ " stdcix 0,0,0 \n" //store to invalid address
+ " eieio ");
+ for(;;) {}
+}
+
+#endif //emulate_hw
diff --git a/src/securerom/inttypes.H b/src/securerom/inttypes.H
new file mode 100644
index 000000000..397732961
--- /dev/null
+++ b/src/securerom/inttypes.H
@@ -0,0 +1,41 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/securerom/inttypes.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#define uint_fast8_t uint8_t
+
+#ifndef BYTE_ORDER
+#error "BYTE_ORDER MUST BE DEFINED"
+#endif /* #ifndef BYTE_ORDER */
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#undef __BIG_ENDIAN
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN 4321
+#endif
+#else
+#undef __LITTLE_ENDIAN
+#ifndef __BIG_ENDIAN
+#define __BIG_ENDIAN 1234
+#endif
+#endif
diff --git a/src/securerom/makefile b/src/securerom/makefile
new file mode 100644
index 000000000..4b3a5a3cf
--- /dev/null
+++ b/src/securerom/makefile
@@ -0,0 +1,244 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/securerom/makefile $
+#
+# OpenPOWER HostBoot Project
+#
+# Contributors Listed Below - COPYRIGHT 2016,2017
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+
+bootrom := bootrom
+bootrom_bin = $(bootrom).bin
+bootrom_dis = $(bootrom).dis
+#bootrom_srec = $(bootrom).srec
+
+bootrom_vhdl = ../vhdl/tpc_secr_rom_pkg.vhdl
+
+bootrom_nm = $(bootrom).nm
+
+LDSCRIPT = bootrom.lds
+
+HOSTTYPE ?= $(shell uname -p)
+CELLSIZE ?= 64
+
+ifeq ($(HOSTTYPE),powerpc)
+CROSS ?= powerpc-ibm-aix6.1.0.0-
+ONLY_CC = $(CROSS)gcc -mpowerpc64 -maix64 -Wa,-mANY
+ONLY_AS = $(CROSS)as -m$(CELLSIZE)
+ONLY_LD = $(CROSS)ld -melf$(CELLSIZE)ppc
+OBJCOPY ?= $(CROSS)objcopy
+OBJDUMP ?= $(CROSS)objdump
+else
+CROSS ?= powerpc-linux-gnu-
+ONLY_CC = $(CROSS)gcc -m64 -Wa,-mregnames
+ONLY_AS = $(CROSS)as -m64 -mregnames
+ONLY_LD = $(CROSS)ld -melf64ppc
+OBJCOPY ?= $(CROSS)objcopy
+OBJDUMP ?= $(CROSS)objdump
+endif
+
+
+# Verbose level:
+# V=0 means completely silent
+# V=1 means brief output
+# V=2 means full verbose output
+V ?= 2
+
+ifeq ($(V),0)
+Q := @
+MAKEFLAGS += --silent
+MAKE += -s
+endif
+
+ifeq ($(V),1)
+MAKEFLAGS += --silent
+MAKE += -s
+CC = printf "\t[CC]\t$@\n"; $(ONLY_CC)
+AS = printf "\t[AS]\t$@\n"; $(ONLY_AS)
+LD = printf "\t[LD]\t$@\n"; $(ONLY_LD)
+CLEAN = printf "\t[CLEAN]\t%s\n" "$(DIRECTORY)$$dir"
+else
+CC = $(ONLY_CC)
+AS = $(ONLY_AS)
+LD = $(ONLY_LD)
+CLEAN = echo -n
+endif
+
+# need version >= 1_0_0
+#OPENSSL ?= ~/openssl/openssl-1.0.0/bin/openssl
+#SREC_CAT ?= srec_cat
+
+CPPFLAGS += -DCONFIG_AWAN \
+ -I./src/ -I./include/ \
+ -DCELLSIZE=$(CELLSIZE) \
+ -DBYTE_ORDER=BIG_ENDIAN \
+ -g \
+
+#CPPFLAGS += -DEC_POWER64_ASM
+CPPFLAGS += -DBN_POWER64_MUL
+CPPFLAGS += -DBN_POWER64_CMP
+CPPFLAGS += -DBN_POWER64_CPY
+CPPFLAGS += -DBN_POWER64_CLR
+CPPFLAGS += -DEC_POWER64_RED
+#CPPFLAGS += -DBN_POWER64_SQR
+CPPFLAGS += -DEC_POWER64_ALG
+#CPPFLAGS += -DBN_POWER64_DBG
+CPPFLAGS += -DSHA512_FIX
+
+OBJDIR = obj
+
+ifeq ($(MAMBO),yes)
+CPPFLAGS += -DCONFIG_MAMBO
+bootrom := bootrom_4mambo
+OBJDIR = mambo
+endif
+
+asm_srcs = src/branchtable.S
+c_srcs = src/ROM.c src/sha512.c src/ecverify.c
+c_srcs += src/memmove.c src/memcmp.c src/hw_utils.c
+#c_srcs += src/memset.c src/memcpy.c
+
+CPPFLAGS += -DCONFIG_SOFTWARE_CRYPTO
+
+srcs = $(asm_srcs) $(c_srcs)
+objs = $(subst src/,$(OBJDIR)/,$(asm_srcs:.S=.o) $(c_srcs:.c=.o))
+deps = $(subst src/,$(OBJDIR)/,$(asm_srcs:.S=.d) $(c_srcs:.c=.d))
+
+CFLAGS ?= -W -Os -fno-builtin -ffreestanding -nostdinc -mno-toc \
+ -msoft-float -mno-altivec -mabi=no-altivec -Wall -mregnames \
+ $(CPPFLAGS)
+
+ASFLAGS += $(CPPFLAGS) -Wa,-mregnames -D__ASSEMBLER__
+
+LDFLAGS = -nostdlib -N
+
+
+default:
+ $(MAKE) all
+ $(MAKE) MAMBO=yes bootrom_4mambo.dis bootrom_4mambo.bin
+
+$(OBJDIR):
+ @if [ -d $(OBJDIR) ] ; then true; else mkdir -p $(OBJDIR); fi
+
+all: $(bootrom_dis) $(bootrom_bin) $(bootrom_vhdl)
+
+
+NODEPS = clean distclean binclean
+ifeq (0, $(words $(findstring $(MAKECMDGOALS), $(NODEPS))))
+-include $(deps)
+endif
+
+
+## This was to create a selfsigned rom code but now it is no longer selfsigned :
+
+#ec_private_key.pem:
+# $(OPENSSL) ecparam -name secp521r1 -genkey -out ec_private_key.pem
+
+#ec_private_key.pem: ec_private_key.pkcs8
+# $(OPENSSL) pkcs8 -inform DER -nocrypt -in ec_private_key.pkcs8 -out ec_private_key.pem
+#ec_private_key.pkcs8:
+# ./ecdsasig.x86 -r -g x > ec_private_key.pkcs8
+
+#ec_public_key.der: ec_private_key.pem
+# $(OPENSSL) ec -in ec_private_key.pem -pubout -outform DER -out ec_public_key.der
+
+#$(bootrom).stage1: $(objs) $(gen_hdrs) $(prism_hdrs) src/dummy_header.o src/dummy_hash.o
+# $(LD) $(LDFLAGS) -o $@ $(objs) src/dummy_header.o src/dummy_hash.o
+
+#$(bootrom).signed.bin: $(bootrom).stage1
+# $(OBJCOPY) -j .text -j .data -O binary $^ $@
+
+#dummy_header.bin: $(bootrom).stage1
+# $(OBJCOPY) -j .image_header -O binary $^ $@
+
+#$(bootrom).signed.sig: $(bootrom).signed.bin ec_private_key.pem
+# $(OPENSSL) dgst -sign ec_private_key.pem -sha512 $^ > $@
+
+#image_header.bin: ec_public_key.der $(bootrom).signed.sig src/dummy_header.o dummy_header.bin
+# ./asn1extract_pubkey.pl ec_public_key.der > image_header.bin
+# dd bs=132 count=2 if=/dev/zero >> image_header.bin
+# ./asn1extract.pl bootrom.signed.sig | xxd -r -p >> image_header.bin
+# dd bs=132 count=2 if=/dev/zero >> image_header.bin
+# dd bs=1 skip=792 count=88 if=dummy_header.bin >> image_header.bin
+
+#image_header.o: image_header.bin
+# $(OBJCOPY) -I binary -O elf64-powerpc -B powerpc --rename-section .data=.image_header --redefine-sym _binary_image_header_bin_start=rom_image_header image_header.bin image_header.o
+
+#$(bootrom).stage2: $(objs) $(gen_hdrs) $(prism_hdrs) image_header.o src/dummy_hash.o
+# $(LD) $(LDFLAGS) -o $@ $(objs) image_header.o src/dummy_hash.o
+
+#bootrom.hashed.bin: $(bootrom).stage2
+# $(OBJCOPY) -j .image_hash -j .text -j .data -O binary $^ $@
+
+#bootrom.hashed.hash: bootrom.hashed.bin
+# $(OPENSSL) dgst -sha512 bootrom.hashed.bin | sed -e "s/.* //" | xxd -r -p > bootrom.hashed.hash
+
+#rom_hash.o: bootrom.hashed.hash
+# $(OBJCOPY) -I binary -O elf64-powerpc -B powerpc \
+# --rename-section .data=.rom_hash \
+# --redefine-sym _binary_bootrom_hashed_hash_start=rom_hash \
+# bootrom.hashed.hash rom_hash.o
+
+#$(bootrom): $(objs) $(gen_hdrs) $(prism_hdrs) image_header.o rom_hash.o
+# $(LD) $(LDFLAGS) -o $@ $(objs) image_header.o rom_hash.o
+
+$(bootrom): $(objs) $(LDSCRIPT)
+ $(LD) $(LDFLAGS) -T$(LDSCRIPT) -o $@ $(objs)
+
+$(bootrom_dis): $(bootrom)
+ $(OBJDUMP) -j .branchtable -j .text -j .data -j .toc --source $^ > $@
+
+#$(bootrom_srec): $(bootrom)
+# $(OBJCOPY) --change-addresses -0xff80000 $^ -O srec $@
+
+$(bootrom_bin): $(bootrom)
+ $(OBJCOPY) -j .branchtable -j .text -j .data -j .toc -O binary $^ $@
+
+$(bootrom_vhdl): $(bootrom_bin) convVhdl.pl
+ ./convVhdl.pl $^ > $@
+
+$(OBJDIR)/%.o: src/%.S $(OBJDIR)/%.d
+ $(CC) $(ASFLAGS) -c $< -o $@
+
+$(OBJDIR)/%.o: src/%.c $(OBJDIR)/%.d
+ $(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJDIR)/%.d: src/%.S Makefile $(OBJDIR)
+ $(CC) -MM $(ASFLAGS) $< | sed 's,\(\S*\)\.o[ :]*,$(OBJDIR)/\1.o $(OBJDIR)/\1.d : ,g' > $@
+
+$(OBJDIR)/%.d: src/%.c Makefile $(OBJDIR)
+ $(CC) -MM $(CFLAGS) $< | sed 's,\(\S*\)\.o[ :]*,$(OBJDIR)/\1.o $(OBJDIR)/\1.d : ,g' > $@
+
+#ecdsa: src/ecdsa.c src/ecverify.c
+# gcc -W -Os -fno-builtin -ffreestanding -nostdinc -msoft-float -mno-altivec -mabi=no-altivec -Wall -I./src/ -I./include/ -o ecdsa src/ecdsa.c src/ecverify.c
+
+clean:
+ $(RM) -r *~ obj mambo
+# ec_public_key.der \
+# $(bootrom).stage1 $(bootrom).signed.bin $(bootrom).signed.sig dummy_header.bin image_header.bin image_header.o\
+# $(bootrom).stage2 $(bootrom).hashed.bin $(bootrom).hashed.hash rom_hash.o
+
+distclean: clean
+ @$(MAKE) binclean
+ @$(MAKE) MAMBO=yes binclean
+
+binclean:
+ $(RM) $(bootrom) $(bootrom_bin) $(bootrom_dis)
+
+.PHONY: default all clean distclean binclean
diff --git a/src/securerom/sha512.C b/src/securerom/sha512.C
new file mode 100644
index 000000000..820ead264
--- /dev/null
+++ b/src/securerom/sha512.C
@@ -0,0 +1,482 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/securerom/sha512.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+/********************************************************************
+ * SHA-512 BIG-Endian Version
+ *
+ *******************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <sha512.h>
+
+
+/* Initial hash value HASH(32byte) for SHA-512 */
+const uint64_t sha512_initial_hash_value[8] = {
+ 0x6a09e667f3bcc908ULL,
+ 0xbb67ae8584caa73bULL,
+ 0x3c6ef372fe94f82bULL,
+ 0xa54ff53a5f1d36f1ULL,
+ 0x510e527fade682d1ULL,
+ 0x9b05688c2b3e6c1fULL,
+ 0x1f83d9abfb41bd6bULL,
+ 0x5be0cd19137e2179ULL
+};
+
+/* Hash constant words K for SHA-384 and SHA-512: */
+const uint64_t K512[80] = {
+ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
+ 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+ 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+ 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+ 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
+ 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+ 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
+ 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+ 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+ 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+ 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
+ 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+ 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
+ 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+ 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+ 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+ 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
+ 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+ 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
+ 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+ 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+ 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+ 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
+ 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+ 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
+ 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+ 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+ 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+ 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
+ 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+ 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
+ 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+ 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+ 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+ 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
+ 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+ 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
+ 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+ 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+ 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+
+
+#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16)
+
+
+
+/*
+ * Macro for incrementally adding the unsigned 64-bit integer n to the
+ * unsigned 128-bit integer (represented using a two-element array of
+ * 64-bit words):
+ */
+#define ADDINC128(w,n) { \
+ (w)[0] += (uint64_t)(n); \
+ if ((w)[0] < (n)) { \
+ (w)[1]++; \
+ } \
+}
+
+
+
+/* Shift-right (used in SHA-512): */
+#define R(b,x) ((x) >> (b))
+
+
+/* 64-bit Rotate-right (used in SHA-512): */
+#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b))))
+
+
+
+/* Two of six logical functions used in SHA-512: */
+#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+
+
+/* Four of six logical functions used in SHA-512: */
+#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))
+#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))
+#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x)))
+#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x)))
+
+static void SHA512_Last(SHA512_CTX*);
+static void SHA512_Transform(SHA512_CTX*, const uint64_t *);
+
+/*
+ * Constant used by SHA256/384/512_End() functions for converting the
+ * digest to a readable hexadecimal character string:
+ */
+
+static inline void bcopy(const void * SRC, void* DST, size_t length){
+ unsigned char * source = (unsigned char *) SRC;
+ unsigned char * destination = (unsigned char *) DST;
+ for( ; length ; length--){
+ *destination++ = *source++;
+ }
+}
+static inline void bzero(void * DST, size_t length){
+ unsigned char * destination = (unsigned char *) DST;
+ for( ; length ; length--){
+ *destination++=0x00;
+ }
+}
+
+// unused:
+//static inline int tstrlen(const void * SRC){
+// unsigned char * source = (unsigned char *) SRC;
+// int length=0;
+// while(source[length]!=0x00){
+// length++;
+// }
+// return length;
+//}
+
+
+/*** SHA-512: *********************************************************/
+asm(".globl .L.SHA512_Init");
+void SHA512_Init(SHA512_CTX* context) {
+ if (context == (SHA512_CTX*)0) {
+ return;
+ }
+
+ uint64_t* sha512_initial_hash_value_p;
+ #ifdef EMULATE_HW
+ sha512_initial_hash_value_p = sha512_initial_hash_value;
+ #else
+ //selftest_p = &selftest; //this line would introduce a absolute address in the toc
+ asm volatile("li %0,(__toc_start)@l ### %0 := base+0x8000 \n\t" // because li does not work
+ "sub %0,r2,%0 \n\t" // because subi does not work
+ "addi %0,%0,(sha512_initial_hash_value-0x8000)@l" : "=r" (sha512_initial_hash_value_p) );
+ #endif
+
+ bcopy(sha512_initial_hash_value_p, context->state, SHA512_DIGEST_LENGTH);
+ bzero(context->buffer, SHA512_BLOCK_LENGTH);
+ context->bitcount[0] = context->bitcount[1] = 0;
+}
+
+
+static void SHA512_Transform(SHA512_CTX* context, const uint64_t* data) {
+ uint64_t a, b, c, d, e, f, g, h, s0, s1;
+ uint64_t T1, T2, *W512 = (uint64_t*)context->buffer;
+ int j;
+
+ uint64_t* K512_p;
+ #ifdef EMULATE_HW
+ K512_p = K512;
+ #else
+ //selftest_p = &selftest; //this line would introduce a absolute address in the toc
+ asm volatile("li %0,(__toc_start)@l ### %0 := base+0x8000 \n\t" // because li does not work
+ "sub %0,r2,%0 \n\t" // because subi does not work
+ "addi %0,%0,(K512-0x8000)@l" : "=r" (K512_p) );
+ #endif
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+ /* Apply the SHA-512 compression function to update a..h with copy */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512_p[j] + (W512[j] = *data++);
+ T2 = Sigma0_512(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 16);
+
+ do {
+ /* Part of the message block expansion: */
+ s0 = W512[(j+1)&0x0f];
+ s0 = sigma0_512(s0);
+ s1 = W512[(j+14)&0x0f];
+ s1 = sigma1_512(s1);
+
+ /* Apply the SHA-512 compression function to update a..h */
+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512_p[j] +
+ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);
+ T2 = Sigma0_512(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 80);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+
+asm(".globl .L.SHA512_Update");
+void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) {
+ unsigned int freespace, usedspace;
+
+ if (len == 0) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ /* Sanity check: */
+ //assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0);
+
+ usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
+ if (usedspace > 0) {
+ /* Calculate how much free space is available in the buffer */
+ freespace = SHA512_BLOCK_LENGTH - usedspace;
+
+ if (len >= freespace) {
+ /* Fill the buffer completely and process it */
+ bcopy(data, &context->buffer[usedspace], freespace);
+ ADDINC128(context->bitcount, freespace << 3);
+ len -= freespace;
+ data += freespace;
+ SHA512_Transform(context, (uint64_t*)context->buffer);
+ } else {
+ /* The buffer is not yet full */
+ bcopy(data, &context->buffer[usedspace], len);
+ ADDINC128(context->bitcount, len << 3);
+ /* Clean up: */
+ usedspace = freespace = 0;
+ return;
+ }
+ }
+ while (len >= SHA512_BLOCK_LENGTH) {
+ /* Process as many complete blocks as we can */
+ SHA512_Transform(context, (const uint64_t*)data);
+ ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3);
+ len -= SHA512_BLOCK_LENGTH;
+ data += SHA512_BLOCK_LENGTH;
+ }
+ if (len > 0) {
+ /* There's left-overs, so save 'em */
+ bcopy(data, context->buffer, len);
+ ADDINC128(context->bitcount, len << 3);
+ }
+ /* Clean up: */
+ usedspace = freespace = 0;
+}
+
+static void SHA512_Last(SHA512_CTX* context) {
+ unsigned int usedspace;
+
+ usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
+ if (usedspace > 0) {
+ /* Begin padding with a 1 bit: */
+ context->buffer[usedspace++] = 0x80;
+
+#if SHA512_FIX
+ if (usedspace < SHA512_SHORT_BLOCK_LENGTH) {
+ /* Set-up for the last transform: */
+ bzero(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace);
+ } else if (usedspace > SHA512_SHORT_BLOCK_LENGTH) {
+ if (usedspace < SHA512_BLOCK_LENGTH) {
+ bzero(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace);
+ }
+ /* Do second-to-last transform: */
+ SHA512_Transform(context, (uint64_t*)context->buffer);
+
+ /* And set-up for the last transform: */
+ bzero(context->buffer, SHA512_SHORT_BLOCK_LENGTH);
+ }
+#else
+ if (usedspace < SHA512_SHORT_BLOCK_LENGTH) {
+ /* Set-up for the last transform: */
+ bzero(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace);
+ } else {
+ if (usedspace < SHA512_BLOCK_LENGTH) {
+ bzero(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace);
+ }
+ /* Do second-to-last transform: */
+ SHA512_Transform(context, (uint64_t*)context->buffer);
+
+ /* And set-up for the last transform: */
+ bzero(context->buffer, SHA512_BLOCK_LENGTH - 2);
+ }
+#endif
+ } else {
+ /* Prepare for final transform: */
+ bzero(context->buffer, SHA512_SHORT_BLOCK_LENGTH);
+
+ /* Begin padding with a 1 bit: */
+ *context->buffer = 0x80;
+ }
+ /* Store the length of input data (in bits): */
+ *(uint64_t*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1];
+ *(uint64_t*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0];
+
+ /* Final transform: */
+ SHA512_Transform(context, (uint64_t*)context->buffer);
+}
+
+asm(".globl .L.SHA512_Final");
+void SHA512_Final(SHA512_CTX* context, sha2_hash_t *result) {
+ /* Sanity check: */
+ //assert(context != (SHA512_CTX*)0);
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ SHA512_Last(context);
+
+ /* Save the hash data for output: */
+ bcopy(context->state, result, SHA512_DIGEST_LENGTH);
+
+ /* Zero out state data */
+ bzero(context, sizeof(context));
+}
+
+asm(".globl .L.SHA512_Hash");
+void SHA512_Hash(const sha2_byte* data, size_t len, sha2_hash_t *result) {
+ SHA512_CTX context;
+
+ SHA512_Init(&context);
+ SHA512_Update(&context, data, len);
+ SHA512_Final(&context, result);
+}
+
+/*
+int main( void ){
+ int i;
+ uint64_t hash[8] = {};
+ const sha2_byte text[]={"The quick brown fox jumps over the lazy dog"};
+
+ printf("SHA512 \"%s\"\n",text);
+ SHA512( text, tstrlen(text), hash );
+ for (i = 0; i < SHA512_DIGEST_LENGTH; i++) {
+ printf("%02x", hash[i]);
+ if( (i&3) ==3) printf(" ");
+ if( (i&31) ==31) printf("\n");
+ }
+
+ const sha2_byte text2[]={""};
+ printf("SHA512 \"%s\"\n",text2);
+ SHA512( text2, tstrlen(text2), hash );
+ for (i = 0; i < SHA512_DIGEST_LENGTH; i++) {
+ printf("%02x", hash[i]);
+ if( (i&3) ==3) printf(" ");
+ if( (i&31) ==31) printf("\n");
+ }
+
+}
+*/
+
+#if INCLUDE_SHA_TESTS
+/****************************************************************************/
+static uint8_t SHA512_Input[] = "abc";
+static uint64_t SHA512_Result[] = {
+ 0xddaf35a193617abaull, 0xcc417349ae204131ull, 0x12e6fa4e89a97ea2ull, 0x0a9eeee64b55d39aull,
+ 0x2192992a274fc1a8ull, 0x36ba3c23a3feebbdull, 0x454d4423643ce80eull, 0x2a9ac94fa54ca49full,
+};
+static uint8_t SHA512_Input2[] =
+ "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
+static uint64_t SHA512_Result2[] = {
+ 0x8e959b75dae313daull, 0x8cf4f72814fc143full, 0x8f7779c6eb9f7fa1ull, 0x7299aeadb6889018ull,
+ 0x501d289e4900f7e4ull, 0x331b99dec4b5433aull, 0xc7d329eeb6dd2654ull, 0x5e96e55b874be909ull,
+};
+#include <selftest.h>
+/****************************************************************************/
+void SHA512_Test (void)
+{
+ SHA512 sha;
+ SHA512_Init (&sha);
+ SHA512_Update (&sha, SHA512_Input, 3);
+ SHA512_Finish (&sha, NULL);
+ if (memcmp((uint8_t*)sha.H, (uint8_t*)SHA512_Result, SHA512_DIGEST_SIZE)) {
+ printf ("SHA512 Test 1 FAILED with bad digest (\n");
+ printf ("%016llx %016llx %016llx %016llx\n",sha.H[0],sha.H[1],sha.H[2],sha.H[3]);
+ printf ("%016llx %016llx %016llx %016llx\n",sha.H[4],sha.H[5],sha.H[6],sha.H[7]);
+ printf (")\n");
+ }
+ else {
+ printf ("SHA512 Test 1 Complete\n");
+ }
+ SHA512_Init (&sha);
+ SHA512_Update (&sha, SHA512_Input2, 112);
+ SHA512_Finish (&sha, NULL);
+ if (memcmp((uint8_t*)sha.H, (uint8_t*)SHA512_Result2, SHA512_DIGEST_SIZE)) {
+ printf ("SHA512 Test 2 FAILED with bad digest (\n");
+ printf ("%016llx %016llx %016llx %016llx\n",sha.H[0],sha.H[1],sha.H[2],sha.H[3]);
+ printf ("%016llx %016llx %016llx %016llx\n",sha.H[4],sha.H[5],sha.H[6],sha.H[7]);
+ printf (")\n");
+ }
+ else {
+ printf ("SHA512 Test 2 Complete\n");
+ }
+ SHA512_Hash (&sha, (uint8_t*)&selftest.ec, sizeof(selftest.ec), NULL);
+ sha.H[0] = BE2HO_8(sha.H[0]);
+ sha.H[1] = BE2HO_8(sha.H[1]);
+ sha.H[2] = BE2HO_8(sha.H[2]);
+ sha.H[3] = BE2HO_8(sha.H[3]);
+ sha.H[4] = BE2HO_8(sha.H[4]);
+ sha.H[5] = BE2HO_8(sha.H[5]);
+ sha.H[6] = BE2HO_8(sha.H[6]);
+ sha.H[7] = BE2HO_8(sha.H[7]);
+ if (memcmp((uint8_t*)sha.H, selftest.sha.hash, SHA512_DIGEST_SIZE)) {
+ printf ("SHA512 Test 3 FAILED with bad digest (\n");
+ printf ("%016llx %016llx %016llx %016llx\n",sha.H[0],sha.H[1],sha.H[2],sha.H[3]);
+ printf ("%016llx %016llx %016llx %016llx\n",sha.H[4],sha.H[5],sha.H[6],sha.H[7]);
+ printf (")\n");
+ }
+ else {
+ printf ("SHA512 Test 3 Complete\n");
+ }
+}
+#endif
OpenPOWER on IntegriCloud