From 5d01db976bb8eba2197f116f271f86a3ab1a1b77 Mon Sep 17 00:00:00 2001 From: ZhaoXi Date: Tue, 19 Mar 2024 19:49:41 +0800 Subject: [PATCH 1/2] add patch for penglai-enclave 2403 Signed-off-by: ZhaoXi --- 0001-Penglai-supports-2403.patch | 20550 +++++++++++++++++++++++++++++ opensbi.spec | 2 + 2 files changed, 20552 insertions(+) create mode 100644 0001-Penglai-supports-2403.patch diff --git a/0001-Penglai-supports-2403.patch b/0001-Penglai-supports-2403.patch new file mode 100644 index 0000000..3a0b66e --- /dev/null +++ b/0001-Penglai-supports-2403.patch @@ -0,0 +1,20550 @@ +From fb0e70f84d5e278abc9b498e9068bb90078bcc25 Mon Sep 17 00:00:00 2001 +From: ZhaoXi +Date: Tue, 19 Mar 2024 19:42:24 +0800 +Subject: [PATCH] update for patch + +--- + include/sbi/riscv_encoding.h | 19 + + include/sbi/riscv_locks.h | 1 + + include/sbi/sbi_console.h | 2 + + include/sbi/sbi_ecall.h | 12 + + include/sbi/sbi_ecall_interface.h | 4 + + include/sbi/sbi_hart.h | 2 + + include/sbi/sbi_ipi.h | 5 + + include/sbi/sbi_platform.h | 2 +- + include/sbi/sbi_pmp.h | 10 + + include/sm/attest.h | 16 + + include/sm/enclave.h | 115 + + include/sm/enclave_args.h | 94 + + include/sm/gm/SM2_sv.h | 62 + + include/sm/gm/SM3.h | 67 + + include/sm/gm/miracl/miracl.h | 1563 ++++++++++++ + include/sm/gm/miracl/mirdef.h | 24 + + include/sm/math.h | 78 + + include/sm/platform/pmp/enclave_mm.h | 84 + + include/sm/platform/pmp/platform.h | 9 + + include/sm/platform/pmp/platform_thread.h | 13 + + include/sm/platform/spmp/enclave_mm.h | 67 + + include/sm/platform/spmp/ipi_handler.h | 6 + + include/sm/platform/spmp/platform.h | 11 + + include/sm/platform/spmp/platform_thread.h | 18 + + include/sm/platform/spmp/spmp.h | 85 + + include/sm/pmp.h | 71 + + include/sm/print.h | 15 + + include/sm/sm.h | 101 + + include/sm/thread.h | 86 + + include/sm/utils.h | 10 + + include/sm/vm.h | 45 + + lib/sbi/objects.mk | 28 + + lib/sbi/riscv_locks.c | 14 +- + lib/sbi/sbi_ecall.c | 53 +- + lib/sbi/sbi_ecall_penglai.c | 118 + + lib/sbi/sbi_hart.c | 4 + + lib/sbi/sbi_init.c | 31 +- + lib/sbi/sbi_ipi.c | 8 +- + lib/sbi/sbi_pmp.c | 192 ++ + lib/sbi/sbi_tlb.c | 18 +- + lib/sbi/sbi_trap.c | 58 +- + lib/sbi/sm/.gitignore | 1 + + lib/sbi/sm/attest.c | 145 ++ + lib/sbi/sm/enclave.c | 1126 +++++++++ + lib/sbi/sm/gm/SM2_sv.c | 692 ++++++ + lib/sbi/sm/gm/SM3.c | 399 ++++ + lib/sbi/sm/gm/miracl/mrarth0.c | 321 +++ + lib/sbi/sm/gm/miracl/mrarth1.c | 1058 +++++++++ + lib/sbi/sm/gm/miracl/mrarth2.c | 1578 ++++++++++++ + lib/sbi/sm/gm/miracl/mrarth3.c | 231 ++ + lib/sbi/sm/gm/miracl/mrbits.c | 244 ++ + lib/sbi/sm/gm/miracl/mrcore.c | 2290 ++++++++++++++++++ + lib/sbi/sm/gm/miracl/mrcurve.c | 2501 ++++++++++++++++++++ + lib/sbi/sm/gm/miracl/mrjack.c | 342 +++ + lib/sbi/sm/gm/miracl/mrlucas.c | 157 ++ + lib/sbi/sm/gm/miracl/mrmonty.c | 1411 +++++++++++ + lib/sbi/sm/gm/miracl/mrrand.c | 110 + + lib/sbi/sm/gm/miracl/mrsroot.c | 188 ++ + lib/sbi/sm/gm/miracl/mrxgcd.c | 495 ++++ + lib/sbi/sm/platform/README.md | 9 + + lib/sbi/sm/platform/pmp/enclave_mm.c | 1291 ++++++++++ + lib/sbi/sm/platform/pmp/platform.c | 46 + + lib/sbi/sm/platform/pmp/platform_thread.c | 31 + + lib/sbi/sm/platform/spmp/enclave_mm.c | 692 ++++++ + lib/sbi/sm/platform/spmp/ipi_handler.c | 21 + + lib/sbi/sm/platform/spmp/platform.c | 42 + + lib/sbi/sm/platform/spmp/platform_thread.c | 34 + + lib/sbi/sm/platform/spmp/spmp.c | 171 ++ + lib/sbi/sm/pmp.c | 321 +++ + lib/sbi/sm/sm.ac | 3 + + lib/sbi/sm/sm.c | 390 +++ + lib/sbi/sm/sm.mk.in | 25 + + lib/sbi/sm/thread.c | 67 + + lib/sbi/sm/utils.c | 40 + + 74 files changed, 19667 insertions(+), 26 deletions(-) + create mode 100644 include/sbi/sbi_pmp.h + create mode 100644 include/sm/attest.h + create mode 100644 include/sm/enclave.h + create mode 100644 include/sm/enclave_args.h + create mode 100644 include/sm/gm/SM2_sv.h + create mode 100644 include/sm/gm/SM3.h + create mode 100644 include/sm/gm/miracl/miracl.h + create mode 100644 include/sm/gm/miracl/mirdef.h + create mode 100644 include/sm/math.h + create mode 100644 include/sm/platform/pmp/enclave_mm.h + create mode 100644 include/sm/platform/pmp/platform.h + create mode 100644 include/sm/platform/pmp/platform_thread.h + create mode 100644 include/sm/platform/spmp/enclave_mm.h + create mode 100644 include/sm/platform/spmp/ipi_handler.h + create mode 100644 include/sm/platform/spmp/platform.h + create mode 100644 include/sm/platform/spmp/platform_thread.h + create mode 100644 include/sm/platform/spmp/spmp.h + create mode 100644 include/sm/pmp.h + create mode 100644 include/sm/print.h + create mode 100644 include/sm/sm.h + create mode 100644 include/sm/thread.h + create mode 100644 include/sm/utils.h + create mode 100644 include/sm/vm.h + create mode 100644 lib/sbi/sbi_ecall_penglai.c + create mode 100644 lib/sbi/sbi_pmp.c + create mode 100644 lib/sbi/sm/.gitignore + create mode 100644 lib/sbi/sm/attest.c + create mode 100644 lib/sbi/sm/enclave.c + create mode 100644 lib/sbi/sm/gm/SM2_sv.c + create mode 100644 lib/sbi/sm/gm/SM3.c + create mode 100644 lib/sbi/sm/gm/miracl/mrarth0.c + create mode 100644 lib/sbi/sm/gm/miracl/mrarth1.c + create mode 100644 lib/sbi/sm/gm/miracl/mrarth2.c + create mode 100644 lib/sbi/sm/gm/miracl/mrarth3.c + create mode 100644 lib/sbi/sm/gm/miracl/mrbits.c + create mode 100644 lib/sbi/sm/gm/miracl/mrcore.c + create mode 100644 lib/sbi/sm/gm/miracl/mrcurve.c + create mode 100644 lib/sbi/sm/gm/miracl/mrjack.c + create mode 100644 lib/sbi/sm/gm/miracl/mrlucas.c + create mode 100644 lib/sbi/sm/gm/miracl/mrmonty.c + create mode 100644 lib/sbi/sm/gm/miracl/mrrand.c + create mode 100644 lib/sbi/sm/gm/miracl/mrsroot.c + create mode 100644 lib/sbi/sm/gm/miracl/mrxgcd.c + create mode 100644 lib/sbi/sm/platform/README.md + create mode 100644 lib/sbi/sm/platform/pmp/enclave_mm.c + create mode 100644 lib/sbi/sm/platform/pmp/platform.c + create mode 100644 lib/sbi/sm/platform/pmp/platform_thread.c + create mode 100644 lib/sbi/sm/platform/spmp/enclave_mm.c + create mode 100644 lib/sbi/sm/platform/spmp/ipi_handler.c + create mode 100644 lib/sbi/sm/platform/spmp/platform.c + create mode 100644 lib/sbi/sm/platform/spmp/platform_thread.c + create mode 100644 lib/sbi/sm/platform/spmp/spmp.c + create mode 100644 lib/sbi/sm/pmp.c + create mode 100644 lib/sbi/sm/sm.ac + create mode 100644 lib/sbi/sm/sm.c + create mode 100644 lib/sbi/sm/sm.mk.in + create mode 100644 lib/sbi/sm/thread.c + create mode 100644 lib/sbi/sm/utils.c + +diff --git a/include/sbi/riscv_encoding.h b/include/sbi/riscv_encoding.h +index b0f08c8..4d9cdb5 100644 +--- a/include/sbi/riscv_encoding.h ++++ b/include/sbi/riscv_encoding.h +@@ -157,6 +157,22 @@ + #define PMP_ADDR_MASK _UL(0xFFFFFFFF) + #endif + ++/* page table entry (PTE) fields */ ++#define PTE_V _UL(0x001) /* Valid */ ++#define PTE_R _UL(0x002) /* Read */ ++#define PTE_W _UL(0x004) /* Write */ ++#define PTE_X _UL(0x008) /* Execute */ ++#define PTE_U _UL(0x010) /* User */ ++#define PTE_G _UL(0x020) /* Global */ ++#define PTE_A _UL(0x040) /* Accessed */ ++#define PTE_D _UL(0x080) /* Dirty */ ++#define PTE_SOFT _UL(0x300) /* Reserved for Software */ ++ ++#define PTE_PPN_SHIFT 10 ++ ++#define PTE_TABLE(PTE) \ ++ (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) ++ + #if __riscv_xlen == 64 + #define MSTATUS_SD MSTATUS64_SD + #define SSTATUS_SD SSTATUS64_SD +@@ -177,6 +193,9 @@ + #define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT + #endif + ++#define RISCV_PGSHIFT 12 ++#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) ++ + #define TOPI_IID_SHIFT 16 + #define TOPI_IID_MASK 0xfff + #define TOPI_IPRIO_MASK 0xff +diff --git a/include/sbi/riscv_locks.h b/include/sbi/riscv_locks.h +index 38d9cbe..f8629a5 100644 +--- a/include/sbi/riscv_locks.h ++++ b/include/sbi/riscv_locks.h +@@ -10,6 +10,7 @@ + + #include + ++#define LOCK_DEBUG 0 + #define TICKET_SHIFT 16 + + typedef struct { +diff --git a/include/sbi/sbi_console.h b/include/sbi/sbi_console.h +index e15b55d..91d94cc 100644 +--- a/include/sbi/sbi_console.h ++++ b/include/sbi/sbi_console.h +@@ -41,6 +41,8 @@ int __printf(3, 4) sbi_snprintf(char *out, u32 out_sz, const char *format, ...); + + int __printf(1, 2) sbi_printf(const char *format, ...); + ++int __printf(1, 2) sbi_printf_nolock(const char *format, ...); ++ + int __printf(1, 2) sbi_dprintf(const char *format, ...); + + void __printf(1, 2) __attribute__((noreturn)) sbi_panic(const char *format, ...); +diff --git a/include/sbi/sbi_ecall.h b/include/sbi/sbi_ecall.h +index ff9bf8e..46927f0 100644 +--- a/include/sbi/sbi_ecall.h ++++ b/include/sbi/sbi_ecall.h +@@ -31,6 +31,18 @@ struct sbi_ecall_extension { + struct sbi_trap_info *out_trap); + }; + ++extern struct sbi_ecall_extension ecall_base; ++extern struct sbi_ecall_extension ecall_legacy; ++extern struct sbi_ecall_extension ecall_time; ++extern struct sbi_ecall_extension ecall_rfence; ++extern struct sbi_ecall_extension ecall_ipi; ++extern struct sbi_ecall_extension ecall_vendor; ++extern struct sbi_ecall_extension ecall_hsm; ++extern struct sbi_ecall_extension ecall_srst; ++extern struct sbi_ecall_extension ecall_pmu; ++extern struct sbi_ecall_extension ecall_penglai_host; ++extern struct sbi_ecall_extension ecall_penglai_enclave; ++ + u16 sbi_ecall_version_major(void); + + u16 sbi_ecall_version_minor(void); +diff --git a/include/sbi/sbi_ecall_interface.h b/include/sbi/sbi_ecall_interface.h +index a3f2bf4..9c2bba2 100644 +--- a/include/sbi/sbi_ecall_interface.h ++++ b/include/sbi/sbi_ecall_interface.h +@@ -30,6 +30,10 @@ + #define SBI_EXT_SRST 0x53525354 + #define SBI_EXT_PMU 0x504D55 + ++//Penglai ++#define SBI_EXT_PENGLAI_HOST 0x100100 ++#define SBI_EXT_PENGLAI_ENCLAVE 0x100101 ++ + /* SBI function IDs for BASE extension*/ + #define SBI_EXT_BASE_GET_SPEC_VERSION 0x0 + #define SBI_EXT_BASE_GET_IMP_ID 0x1 +diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h +index 95b40e7..b251a2f 100644 +--- a/include/sbi/sbi_hart.h ++++ b/include/sbi/sbi_hart.h +@@ -12,6 +12,8 @@ + + #include + ++#define MAX_HARTS 8 ++ + /** Possible privileged specification versions of a hart */ + enum sbi_hart_priv_versions { + /** Unknown privileged specification */ +diff --git a/include/sbi/sbi_ipi.h b/include/sbi/sbi_ipi.h +index f6ac807..fae73c2 100644 +--- a/include/sbi/sbi_ipi.h ++++ b/include/sbi/sbi_ipi.h +@@ -17,6 +17,11 @@ + #define SBI_IPI_EVENT_MAX __riscv_xlen + + /* clang-format on */ ++#define SYNC_DEBUG 0 ++#define MAX_HARTS 8 ++#define IPI_NONE 0 ++#define IPI_TLB 1 ++#define IPI_PMP 2 + + /** IPI hardware device */ + struct sbi_ipi_device { +diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h +index 722f27a..8f95953 100644 +--- a/include/sbi/sbi_platform.h ++++ b/include/sbi/sbi_platform.h +@@ -133,7 +133,7 @@ struct sbi_platform_operations { + }; + + /** Platform default per-HART stack size for exception/interrupt handling */ +-#define SBI_PLATFORM_DEFAULT_HART_STACK_SIZE 8192 ++#define SBI_PLATFORM_DEFAULT_HART_STACK_SIZE 8192*8 + + /** Representation of a platform */ + struct sbi_platform { +diff --git a/include/sbi/sbi_pmp.h b/include/sbi/sbi_pmp.h +new file mode 100644 +index 0000000..c6ef1fc +--- /dev/null ++++ b/include/sbi/sbi_pmp.h +@@ -0,0 +1,10 @@ ++#ifndef __SBI_PMP_H__ ++#define __SBI_PMP_H__ ++ ++#include ++#include ++#include ++struct sbi_scratch; ++int sbi_pmp_init(struct sbi_scratch *scratch, bool cold_boot); ++int sbi_send_pmp(ulong hmask, ulong hbase, struct pmp_data_t* pmp_data); ++#endif +diff --git a/include/sm/attest.h b/include/sm/attest.h +new file mode 100644 +index 0000000..84f4949 +--- /dev/null ++++ b/include/sm/attest.h +@@ -0,0 +1,16 @@ ++#ifndef _ATTEST_H ++#define _ATTEST_H ++ ++#include "sm/enclave.h" ++ ++void attest_init(); ++ ++void hash_enclave(struct enclave_t* enclave, void* hash, uintptr_t nonce); ++ ++void update_enclave_hash(char *output, void* hash, uintptr_t nonce_arg); ++ ++void sign_enclave(void* signature, unsigned char *message, int len); ++ ++int verify_enclave(void* signature, unsigned char *message, int len); ++ ++#endif /* _ATTEST_H */ +diff --git a/include/sm/enclave.h b/include/sm/enclave.h +new file mode 100644 +index 0000000..0d0969a +--- /dev/null ++++ b/include/sm/enclave.h +@@ -0,0 +1,115 @@ ++#ifndef _ENCLAVE_H ++#define _ENCLAVE_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ENCLAVES_PER_METADATA_REGION 128 ++#define ENCLAVE_METADATA_REGION_SIZE ((sizeof(struct enclave_t)) * ENCLAVES_PER_METADATA_REGION) ++ ++#define ENCLAVE_MODE 1 ++ ++// define the time slice for an enclave ++#define ENCLAVE_TIME_CREDITS 100000 ++ ++struct link_mem_t ++{ ++ unsigned long mem_size; ++ unsigned long slab_size; ++ unsigned long slab_num; ++ char* addr; ++ struct link_mem_t* next_link_mem; ++}; ++ ++typedef enum ++{ ++ DESTROYED = -1, ++ INVALID = 0, ++ FRESH = 1, ++ RUNNABLE, ++ RUNNING, ++ STOPPED, ++} enclave_state_t; ++ ++/* ++ * enclave memory [paddr, paddr + size] ++ * free_mem @ unused memory address in enclave mem ++ */ ++struct enclave_t ++{ ++ unsigned int eid; ++ enclave_state_t state; ++ ++ //memory region of enclave ++ unsigned long paddr; ++ unsigned long size; ++ ++ //address of left available memory in memory region ++ unsigned long free_mem; ++ ++ //TODO: dynamically allocated memory ++ unsigned long* enclave_mem_metadata_page; ++ ++ //root page table of enclave ++ unsigned long* root_page_table; ++ //root page table register for host ++ unsigned long host_ptbr; ++ //entry point of enclave ++ unsigned long entry_point; ++ ++ //shared mem with kernel ++ unsigned long kbuffer; ++ unsigned long kbuffer_paddr; ++ unsigned long kbuffer_size; ++ ++ unsigned long* ocall_func_id; ++ unsigned long* ocall_arg0; ++ unsigned long* ocall_arg1; ++ unsigned long* ocall_syscall_num; ++ ++ //shared memory with host ++ unsigned long untrusted_ptr; ++ unsigned long untrusted_ptr_paddr; ++ unsigned long untrusted_size; ++ // enclave measurement ++ unsigned char hash[HASH_SIZE]; ++ // hash of enclave developer's public key ++ unsigned char signer[HASH_SIZE]; ++ ++ //enclave thread context ++ //TODO: support multiple threads ++ struct thread_state_t thread_context; ++}; ++ ++struct cpu_state_t ++{ ++ int in_enclave; ++ int eid; ++}; ++ ++uintptr_t create_enclave(struct enclave_sbi_param_t create_args, int retry); ++uintptr_t run_enclave(uintptr_t* regs, unsigned int eid); ++uintptr_t stop_enclave(uintptr_t* regs, unsigned int eid); ++uintptr_t destroy_enclave(uintptr_t* regs, unsigned int eid); ++uintptr_t resume_enclave(uintptr_t* regs, unsigned int eid); ++uintptr_t resume_from_stop(uintptr_t* regs, unsigned int eid); ++uintptr_t attest_enclave(uintptr_t eid, uintptr_t report_ptr, uintptr_t nonce); ++uintptr_t exit_enclave(uintptr_t* regs, unsigned long retval); ++uintptr_t do_timer_irq(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc); ++uintptr_t free_enclave_metadata(); ++ ++uintptr_t resume_from_ocall(uintptr_t* regs, unsigned int eid); ++uintptr_t enclave_sys_write(uintptr_t *regs); ++uintptr_t enclave_user_defined_ocall(uintptr_t *regs, uintptr_t ocall_buf_size); ++uintptr_t enclave_derive_seal_key(uintptr_t* regs, uintptr_t salt_va, ++ uintptr_t salt_len, uintptr_t key_buf_va, uintptr_t key_buf_len); ++ ++int check_in_enclave_world(); ++ ++#endif /* _ENCLAVE_H */ +diff --git a/include/sm/enclave_args.h b/include/sm/enclave_args.h +new file mode 100644 +index 0000000..7f53870 +--- /dev/null ++++ b/include/sm/enclave_args.h +@@ -0,0 +1,94 @@ ++#ifndef _ENCLAVE_ARGS_H ++#define _ENCLAVE_ARGS_H ++#include "thread.h" ++#define HASH_SIZE 32 ++#define PRIVATE_KEY_SIZE 32 ++#define PUBLIC_KEY_SIZE 64 ++#define SIGNATURE_SIZE 64 ++ ++#define MANU_PUB_KEY (void*)((unsigned long)0x801ff000) ++#define DEV_PUB_KEY (MANU_PUB_KEY + PUBLIC_KEY_SIZE) ++#define DEV_PRI_KEY (DEV_PUB_KEY + PUBLIC_KEY_SIZE) ++#define SM_PUB_KEY (DEV_PRI_KEY + PRIVATE_KEY_SIZE) ++#define SM_PRI_KEY (SM_PUB_KEY + PUBLIC_KEY_SIZE) ++#define SM_HASH (SM_PRI_KEY + PRIVATE_KEY_SIZE) ++#define SM_SIGNATURE (SM_HASH + HASH_SIZE) ++ ++struct mm_alloc_arg_t ++{ ++ unsigned long req_size; ++ uintptr_t resp_addr; ++ unsigned long resp_size; ++}; ++ ++struct mm_reclaim_arg_t ++{ ++ unsigned long req_size; ++ uintptr_t req_addr; ++ unsigned long resp_size; ++}; ++ ++// Attestation-related report ++struct sm_report_t ++{ ++ unsigned char hash[HASH_SIZE]; ++ unsigned char signature[SIGNATURE_SIZE]; ++ unsigned char sm_pub_key[PUBLIC_KEY_SIZE]; ++}; ++ ++struct enclave_report_t ++{ ++ unsigned char hash[HASH_SIZE]; ++ unsigned char signature[SIGNATURE_SIZE]; ++ uintptr_t nonce; ++}; ++ ++struct report_t ++{ ++ struct sm_report_t sm; ++ struct enclave_report_t enclave; ++ unsigned char dev_pub_key[PUBLIC_KEY_SIZE]; ++}; ++ ++struct prikey_t ++{ ++ unsigned char dA[PRIVATE_KEY_SIZE]; ++}; ++ ++struct pubkey_t ++{ ++ unsigned char xA[PUBLIC_KEY_SIZE/2]; ++ unsigned char yA[PUBLIC_KEY_SIZE/2]; ++}; ++ ++struct signature_t ++{ ++ unsigned char r[PUBLIC_KEY_SIZE/2]; ++ unsigned char s[PUBLIC_KEY_SIZE/2]; ++}; ++ ++/* ++ * enclave memory [paddr, paddr + size] ++ * free_mem @ unused memory address in enclave mem ++ */ ++struct enclave_sbi_param_t ++{ ++ unsigned int * eid_ptr; ++ unsigned long paddr; ++ unsigned long size; ++ unsigned long entry_point; ++ unsigned long untrusted_ptr; ++ unsigned long untrusted_paddr; ++ unsigned long untrusted_size; ++ unsigned long free_mem; ++ //enclave shared mem with kernel ++ unsigned long kbuffer; ++ unsigned long kbuffer_paddr; ++ unsigned long kbuffer_size; ++ unsigned long *ecall_arg0; ++ unsigned long *ecall_arg1; ++ unsigned long *ecall_arg2; ++ unsigned long *ecall_arg3; ++}; ++ ++#endif /* _ENCLAVE_ARGS_H */ +diff --git a/include/sm/gm/SM2_sv.h b/include/sm/gm/SM2_sv.h +new file mode 100644 +index 0000000..e7efb1c +--- /dev/null ++++ b/include/sm/gm/SM2_sv.h +@@ -0,0 +1,62 @@ ++/************************************************************************ ++ Copyright (c) IPADS@SJTU 2021. Modification to support Penglai (RISC-V TEE) ++ ++ This file contains GM/T SM2 standard implementation, provided by the Commercial ++ Cryptography Testing Center, see for more infomation. ++ ++ File name: SM2_sv.c ++ Version: SM2_sv_V1.0 ++ Date: Sep 27,2016 ++ Description: implementation of SM2 signature algorithm and verification algorithm ++ Function List: ++ 1.SM2_Init //initiate SM2 curve ++ 2.Test_Point //test if the given point is on SM2 curve ++ 3.Test_PubKey //test if the given public key is valid ++ 4.Test_Zero //test if the big x equals zero ++ 5.Test_n //test if the big x equals n ++ 6.Test_Range //test if the big x belong to the range[1,n-1] ++ 7.SM2_KeyGeneration //generate SM2 key pair ++ 8.SM2_Sign //SM2 signature algorithm ++ 9.SM2_Verify //SM2 verification ++ 10.SM2_SelfCheck() //SM2 self-check ++ 11.SM3_256() //this function can be found in SM3.c and SM3.h ++ ++ Additional Functions Added By PENGLAI Enclave: ++ 1.MIRACL_Init //init miracl system ++ 2.SM2_make_prikey //generate a SM2 private key ++ 3.SM2_make_pubkey //generate a SM2 public Key out of a private Key ++ 4.SM2_gen_random //generate a random number K lies in [1,n-1] ++ 5.SM2_compute_ZA //compute ZA out of a given pubkey ++**************************************************************************/ ++ ++#pragma once ++ ++#include "sm/gm/miracl/miracl.h" ++ ++#define SM2_WORDSIZE 8 ++#define SM2_NUMBITS 256 ++#define SM2_NUMWORD (SM2_NUMBITS / SM2_WORDSIZE) ++ ++#define ERR_ECURVE_INIT 0x00000001 ++#define ERR_INFINITY_POINT 0x00000002 ++#define ERR_NOT_VALID_POINT 0x00000003 ++#define ERR_ORDER 0x00000004 ++#define ERR_NOT_VALID_ELEMENT 0x00000005 ++#define ERR_GENERATE_R 0x00000006 ++#define ERR_GENERATE_S 0x00000007 ++#define ERR_OUTRANGE_R 0x00000008 ++#define ERR_OUTRANGE_S 0x00000009 ++#define ERR_GENERATE_T 0x0000000A ++#define ERR_PUBKEY_INIT 0x0000000B ++#define ERR_DATA_MEMCMP 0x0000000C ++ ++int SM2_Init(); ++int Test_Point(epoint *point); ++int Test_PubKey(epoint *pubKey); ++int Test_Zero(big x); ++int Test_n(big x); ++int Test_Range(big x); ++int SM2_KeyGeneration(unsigned char PriKey[], unsigned char Px[], unsigned char Py[]); ++int SM2_Sign(unsigned char *message, int len, unsigned char d[], unsigned char R[], unsigned char S[]); ++int SM2_Verify(unsigned char *message, int len, unsigned char Px[], unsigned char Py[], unsigned char R[], unsigned char S[]); ++int SM2_SelfCheck(); +diff --git a/include/sm/gm/SM3.h b/include/sm/gm/SM3.h +new file mode 100644 +index 0000000..a19c1e6 +--- /dev/null ++++ b/include/sm/gm/SM3.h +@@ -0,0 +1,67 @@ ++/************************************************************************ ++ Copyright (c) IPADS@SJTU 2021. Modification to support Penglai (RISC-V TEE) ++ ++ This file contains GM/T SM2 standard implementation, provided by the Commercial ++ Cryptography Testing Center, see for more infomation. ++ ++ File name: SM3.c ++ Version: SM3_V1.1 ++ Date: Sep 18,2016 ++ Description: to calculate a hash message from a given message ++ Function List: ++ 1.SM3_256 //calls SM3_init, SM3_process and SM3_done to calculate hash value ++ 2.SM3_init //init the SM3 state ++ 3.SM3_process //compress the the first len/64 blocks of the message ++ 4.SM3_done //compress the rest message and output the hash value ++ 5.SM3_compress //called by SM3_process and SM3_done, compress a single block of message ++ 6.BiToW //called by SM3_compress,to calculate W from Bi ++ 7.WToW1 //called by SM3_compress, calculate W' from W ++ 8.CF //called by SM3_compress, to calculate CF function. ++ 9.BigEndian //called by SM3_compress and SM3_done.GM/T 0004-2012 requires to use big-endian. ++ //if CPU uses little-endian, BigEndian function is a necessary call to change the ++ //little-endian format into big-endian format. ++ 10.SM3_SelfTest //test whether the SM3 calculation is correct by comparing the hash result with the standard data ++**************************************************************************/ ++ ++#pragma once ++ ++#define SM3_len 256 ++#define SM3_T1 0x79CC4519 ++#define SM3_T2 0x7A879D8A ++#define SM3_IVA 0x7380166f ++#define SM3_IVB 0x4914b2b9 ++#define SM3_IVC 0x172442d7 ++#define SM3_IVD 0xda8a0600 ++#define SM3_IVE 0xa96f30bc ++#define SM3_IVF 0x163138aa ++#define SM3_IVG 0xe38dee4d ++#define SM3_IVH 0xb0fb0e4e ++ ++/* Various logical functions */ ++#define SM3_p1(x) (x ^ SM3_rotl32(x, 15) ^ SM3_rotl32(x, 23)) ++#define SM3_p0(x) (x ^ SM3_rotl32(x, 9) ^ SM3_rotl32(x, 17)) ++#define SM3_ff0(a, b, c) (a ^ b ^ c) ++#define SM3_ff1(a, b, c) ((a & b) | (a & c) | (b & c)) ++#define SM3_gg0(e, f, g) (e ^ f ^ g) ++#define SM3_gg1(e, f, g) ((e & f) | ((~e) & g)) ++#define SM3_rotl32(x, n) ((((unsigned int)x) << n) | (((unsigned int)x) >> (32 - n))) ++#define SM3_rotr32(x, n) ((((unsigned int)x) >> n) | (((unsigned int)x) << (32 - n))) ++ ++typedef struct ++{ ++ unsigned int state[8]; ++ unsigned int length; ++ unsigned int curlen; ++ unsigned char buf[64]; ++} SM3_STATE; ++ ++void BiToWj(unsigned int Bi[], unsigned int Wj[]); ++void WjToWj1(unsigned int Wj[], unsigned int Wj1[]); ++void CF(unsigned int Wj[], unsigned int Wj1[], unsigned int V[]); ++void BigEndian(unsigned char src[], unsigned int bytelen, unsigned char des[]); ++void SM3_init(SM3_STATE *md); ++void SM3_compress(SM3_STATE *md); ++void SM3_process(SM3_STATE *md, unsigned char buf[], int len); ++void SM3_done(SM3_STATE *md, unsigned char *hash); ++void SM3_256(unsigned char buf[], int len, unsigned char hash[]); ++int SM3_SelfTest(); +diff --git a/include/sm/gm/miracl/miracl.h b/include/sm/gm/miracl/miracl.h +new file mode 100644 +index 0000000..558d19c +--- /dev/null ++++ b/include/sm/gm/miracl/miracl.h +@@ -0,0 +1,1563 @@ ++/*************************************************************************** ++ * ++Copyright 2013 CertiVox UK Ltd. * ++ * ++This file is part of CertiVox MIRACL Crypto SDK. * ++ * ++The CertiVox MIRACL Crypto SDK provides developers with an * ++extensive and efficient set of cryptographic functions. * ++For further information about its features and functionalities please * ++refer to http://www.certivox.com * ++ * ++* The CertiVox MIRACL Crypto SDK is free software: you can * ++ redistribute it and/or modify it under the terms of the * ++ GNU Affero General Public License as published by the * ++ Free Software Foundation, either version 3 of the License, * ++ or (at your option) any later version. * ++ * ++* The CertiVox MIRACL Crypto SDK is distributed in the hope * ++ that it will be useful, but WITHOUT ANY WARRANTY; without even the * ++ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * ++ See the GNU Affero General Public License for more details. * ++ * ++* You should have received a copy of the GNU Affero General Public * ++ License along with CertiVox MIRACL Crypto SDK. * ++ If not, see . * ++ * ++You can be released from the requirements of the license by purchasing * ++a commercial license. Buying such a license is mandatory as soon as you * ++develop commercial activities involving the CertiVox MIRACL Crypto SDK * ++without disclosing the source code of your own applications, or shipping * ++the CertiVox MIRACL Crypto SDK with a closed source product. * ++ * ++***************************************************************************/ ++ ++#ifndef MIRACL_H ++#define MIRACL_H ++ ++/* ++ * main MIRACL header - miracl.h. ++ */ ++ ++#include "mirdef.h" ++ ++/* Some modifiable defaults... */ ++ ++/* Use a smaller buffer if space is limited, don't be so wasteful! */ ++ ++#ifdef MR_STATIC ++#define MR_DEFAULT_BUFFER_SIZE 260 ++#else ++#define MR_DEFAULT_BUFFER_SIZE 1024 ++#endif ++ ++/* see mrgf2m.c */ ++ ++#ifndef MR_KARATSUBA ++#define MR_KARATSUBA 2 ++#endif ++ ++#ifndef MR_DOUBLE_BIG ++ ++#ifdef MR_KCM ++ #ifdef MR_FLASH ++ #define MR_SPACES 32 ++ #else ++ #define MR_SPACES 31 ++ #endif ++#else ++ #ifdef MR_FLASH ++ #define MR_SPACES 28 ++ #else ++ #define MR_SPACES 27 ++ #endif ++#endif ++ ++#else ++ ++#ifdef MR_KCM ++ #ifdef MR_FLASH ++ #define MR_SPACES 44 ++ #else ++ #define MR_SPACES 43 ++ #endif ++#else ++ #ifdef MR_FLASH ++ #define MR_SPACES 40 ++ #else ++ #define MR_SPACES 39 ++ #endif ++#endif ++ ++#endif ++ ++/* To avoid name clashes - undefine this */ ++ ++/* #define compare mr_compare */ ++ ++#ifdef MR_AVR ++#include ++#endif ++ ++/* size of bigs and elliptic curve points for memory allocation from stack or heap */ ++ ++#define MR_ROUNDUP(a,b) ((a)-1)/(b)+1 ++ ++#define MR_SL sizeof(long) ++ ++#ifdef MR_STATIC ++ ++#define MR_SIZE (((sizeof(struct bigtype)+(MR_STATIC+2)*sizeof(mr_utype))-1)/MR_SL+1)*MR_SL ++#define MR_BIG_RESERVE(n) ((n)*MR_SIZE+MR_SL) ++ ++#ifdef MR_AFFINE_ONLY ++#define MR_ESIZE (((sizeof(epoint)+MR_BIG_RESERVE(2))-1)/MR_SL+1)*MR_SL ++#else ++#define MR_ESIZE (((sizeof(epoint)+MR_BIG_RESERVE(3))-1)/MR_SL+1)*MR_SL ++#endif ++#define MR_ECP_RESERVE(n) ((n)*MR_ESIZE+MR_SL) ++ ++#define MR_ESIZE_A (((sizeof(epoint)+MR_BIG_RESERVE(2))-1)/MR_SL+1)*MR_SL ++#define MR_ECP_RESERVE_A(n) ((n)*MR_ESIZE_A+MR_SL) ++ ++ ++#endif ++ ++/* useful macro to convert size of big in words, to size of required structure */ ++ ++#define mr_size(n) (((sizeof(struct bigtype)+((n)+2)*sizeof(mr_utype))-1)/MR_SL+1)*MR_SL ++#define mr_big_reserve(n,m) ((n)*mr_size(m)+MR_SL) ++ ++#define mr_esize_a(n) (((sizeof(epoint)+mr_big_reserve(2,(n)))-1)/MR_SL+1)*MR_SL ++#define mr_ecp_reserve_a(n,m) ((n)*mr_esize_a(m)+MR_SL) ++ ++#ifdef MR_AFFINE_ONLY ++#define mr_esize(n) (((sizeof(epoint)+mr_big_reserve(2,(n)))-1)/MR_SL+1)*MR_SL ++#else ++#define mr_esize(n) (((sizeof(epoint)+mr_big_reserve(3,(n)))-1)/MR_SL+1)*MR_SL ++#endif ++#define mr_ecp_reserve(n,m) ((n)*mr_esize(m)+MR_SL) ++ ++ ++/* if basic library is static, make sure and use static C++ */ ++ ++#ifdef MR_STATIC ++ #ifndef BIGS ++ #define BIGS MR_STATIC ++ #endif ++ #ifndef ZZNS ++ #define ZZNS MR_STATIC ++ #endif ++ #ifndef GF2MS ++ #define GF2MS MR_STATIC ++ #endif ++#endif ++ ++#ifdef __ia64__ ++#if MIRACL==64 ++#define MR_ITANIUM ++#include ++#endif ++#endif ++ ++#ifdef _M_X64 ++#ifdef _WIN64 ++#if MIRACL==64 ++#define MR_WIN64 ++#include ++#endif ++#endif ++#endif ++ ++#ifndef MR_NO_FILE_IO ++#include ++#endif ++ /* error returns */ ++ ++#define MR_ERR_BASE_TOO_BIG 1 ++#define MR_ERR_DIV_BY_ZERO 2 ++#define MR_ERR_OVERFLOW 3 ++#define MR_ERR_NEG_RESULT 4 ++#define MR_ERR_BAD_FORMAT 5 ++#define MR_ERR_BAD_BASE 6 ++#define MR_ERR_BAD_PARAMETERS 7 ++#define MR_ERR_OUT_OF_MEMORY 8 ++#define MR_ERR_NEG_ROOT 9 ++#define MR_ERR_NEG_POWER 10 ++#define MR_ERR_BAD_ROOT 11 ++#define MR_ERR_INT_OP 12 ++#define MR_ERR_FLASH_OVERFLOW 13 ++#define MR_ERR_TOO_BIG 14 ++#define MR_ERR_NEG_LOG 15 ++#define MR_ERR_DOUBLE_FAIL 16 ++#define MR_ERR_IO_OVERFLOW 17 ++#define MR_ERR_NO_MIRSYS 18 ++#define MR_ERR_BAD_MODULUS 19 ++#define MR_ERR_NO_MODULUS 20 ++#define MR_ERR_EXP_TOO_BIG 21 ++#define MR_ERR_NOT_SUPPORTED 22 ++#define MR_ERR_NOT_DOUBLE_LEN 23 ++#define MR_ERR_NOT_IRREDUC 24 ++#define MR_ERR_NO_ROUNDING 25 ++#define MR_ERR_NOT_BINARY 26 ++#define MR_ERR_NO_BASIS 27 ++#define MR_ERR_COMPOSITE_MODULUS 28 ++#define MR_ERR_DEV_RANDOM 29 ++ ++ /* some useful definitions */ ++ ++#define forever for(;;) ++ ++#define mr_abs(x) ((x)<0? (-(x)) : (x)) ++ ++#ifndef TRUE ++ #define TRUE 1 ++#endif ++#ifndef FALSE ++ #define FALSE 0 ++#endif ++ ++#define OFF 0 ++#define ON 1 ++#define PLUS 1 ++#define MINUS (-1) ++ ++#define M1 (MIRACL-1) ++#define M2 (MIRACL-2) ++#define M3 (MIRACL-3) ++#define M4 (MIRACL-4) ++#define TOPBIT ((mr_small)1<= MR_IBITS ++#define MR_TOOBIG (1<<(MR_IBITS-2)) ++#else ++#define MR_TOOBIG (1<<(MIRACL-1)) ++#endif ++ ++#ifdef MR_FLASH ++#define MR_EBITS (8*sizeof(double) - MR_FLASH) ++ /* no of Bits per double exponent */ ++#define MR_BTS 16 ++#define MR_MSK 0xFFFF ++ ++#endif ++ ++/* Default Hash function output size in bytes */ ++#define MR_HASH_BYTES 32 ++ ++/* Marsaglia & Zaman Random number generator */ ++/* constants alternatives */ ++#define NK 37 /* 21 */ ++#define NJ 24 /* 6 */ ++#define NV 14 /* 8 */ ++ ++/* Use smaller values if memory is precious */ ++ ++#ifdef mr_dltype ++ ++#ifdef MR_LITTLE_ENDIAN ++#define MR_BOT 0 ++#define MR_TOP 1 ++#endif ++#ifdef MR_BIG_ENDIAN ++#define MR_BOT 1 ++#define MR_TOP 0 ++#endif ++ ++union doubleword ++{ ++ mr_large d; ++ mr_small h[2]; ++}; ++ ++#endif ++ ++/* chinese remainder theorem structures */ ++ ++typedef struct { ++big *C; ++big *V; ++big *M; ++int NP; ++} big_chinese; ++ ++typedef struct { ++mr_utype *C; ++mr_utype *V; ++mr_utype *M; ++int NP; ++} small_chinese; ++ ++/* Cryptographically strong pseudo-random number generator */ ++ ++typedef struct { ++mr_unsign32 ira[NK]; /* random number... */ ++int rndptr; /* ...array & pointer */ ++mr_unsign32 borrow; ++int pool_ptr; ++char pool[MR_HASH_BYTES]; /* random pool */ ++} csprng; ++ ++/* secure hash Algorithm structure */ ++ ++typedef struct { ++mr_unsign32 length[2]; ++mr_unsign32 h[8]; ++mr_unsign32 w[80]; ++} sha256; ++ ++typedef sha256 sha; ++ ++#ifdef mr_unsign64 ++ ++typedef struct { ++mr_unsign64 length[2]; ++mr_unsign64 h[8]; ++mr_unsign64 w[80]; ++} sha512; ++ ++typedef sha512 sha384; ++ ++typedef struct { ++mr_unsign64 length; ++mr_unsign64 S[5][5]; ++int rate,len; ++} sha3; ++ ++#endif ++ ++/* Symmetric Encryption algorithm structure */ ++ ++#define MR_ECB 0 ++#define MR_CBC 1 ++#define MR_CFB1 2 ++#define MR_CFB2 3 ++#define MR_CFB4 5 ++#define MR_PCFB1 10 ++#define MR_PCFB2 11 ++#define MR_PCFB4 13 ++#define MR_OFB1 14 ++#define MR_OFB2 15 ++#define MR_OFB4 17 ++#define MR_OFB8 21 ++#define MR_OFB16 29 ++ ++typedef struct { ++int Nk,Nr; ++int mode; ++mr_unsign32 fkey[60]; ++mr_unsign32 rkey[60]; ++char f[16]; ++} aes; ++ ++/* AES-GCM suppport. See mrgcm.c */ ++ ++#define GCM_ACCEPTING_HEADER 0 ++#define GCM_ACCEPTING_CIPHER 1 ++#define GCM_NOT_ACCEPTING_MORE 2 ++#define GCM_FINISHED 3 ++#define GCM_ENCRYPTING 0 ++#define GCM_DECRYPTING 1 ++ ++typedef struct { ++mr_unsign32 table[128][4]; /* 2k bytes */ ++MR_BYTE stateX[16]; ++MR_BYTE Y_0[16]; ++mr_unsign32 counter; ++mr_unsign32 lenA[2],lenC[2]; ++int status; ++aes a; ++} gcm; ++ ++ /* Elliptic curve point status */ ++ ++#define MR_EPOINT_GENERAL 0 ++#define MR_EPOINT_NORMALIZED 1 ++#define MR_EPOINT_INFINITY 2 ++ ++#define MR_NOTSET 0 ++#define MR_PROJECTIVE 0 ++#define MR_AFFINE 1 ++#define MR_BEST 2 ++#define MR_TWIST 8 ++ ++#define MR_OVER 0 ++#define MR_ADD 1 ++#define MR_DOUBLE 2 ++ ++/* Twist type */ ++ ++#define MR_QUADRATIC 2 ++#define MR_CUBIC_M 0x3A ++#define MR_CUBIC_D 0x3B ++#define MR_QUARTIC_M 0x4A ++#define MR_QUARTIC_D 0x4B ++#define MR_SEXTIC_M 0x6A ++#define MR_SEXTIC_D 0x6B ++ ++ ++/* Fractional Sliding Windows for ECC - how much precomputation storage to use ? */ ++/* Note that for variable point multiplication there is an optimal value ++ which can be reduced if space is short. For fixed points its a matter of ++ how much ROM is available to store precomputed points. ++ We are storing the k points (P,3P,5P,7P,...,[2k-1].P) */ ++ ++/* These values can be manually tuned for optimal performance... */ ++ ++#ifdef MR_SMALL_EWINDOW ++#define MR_ECC_STORE_N 3 /* point store for ecn variable point multiplication */ ++#define MR_ECC_STORE_2M 3 /* point store for ec2m variable point multiplication */ ++#define MR_ECC_STORE_N2 3 /* point store for ecn2 variable point multiplication */ ++#else ++#define MR_ECC_STORE_N 8 /* 8/9 is close to optimal for 256 bit exponents */ ++#define MR_ECC_STORE_2M 9 ++#define MR_ECC_STORE_N2 8 ++#endif ++ ++/*#define MR_ECC_STORE_N2_PRECOMP MR_ECC_STORE_N2 */ ++ /* Might want to make this bigger.. */ ++ ++/* If multi-addition is of m points, and s precomputed values are required, this is max of m*s (=4.10?) */ ++#define MR_MAX_M_T_S 64 ++ ++/* Elliptic Curve epoint structure. Uses projective (X,Y,Z) co-ordinates */ ++ ++typedef struct { ++int marker; ++big X; ++big Y; ++#ifndef MR_AFFINE_ONLY ++big Z; ++#endif ++} epoint; ++ ++ ++/* Structure for Comb method for finite * ++ field exponentiation with precomputation */ ++ ++typedef struct { ++#ifdef MR_STATIC ++ const mr_small *table; ++#else ++ mr_small *table; ++#endif ++ big n; ++ int window; ++ int max; ++} brick; ++ ++/* Structure for Comb method for elliptic * ++ curve exponentiation with precomputation */ ++ ++typedef struct { ++#ifdef MR_STATIC ++ const mr_small *table; ++#else ++ mr_small *table; ++#endif ++ big a,b,n; ++ int window; ++ int max; ++} ebrick; ++ ++typedef struct { ++#ifdef MR_STATIC ++ const mr_small *table; ++#else ++ mr_small *table; ++#endif ++ big a6,a2; ++ int m,a,b,c; ++ int window; ++ int max; ++} ebrick2; ++ ++typedef struct ++{ ++ big a; ++ big b; ++} zzn2; ++ ++typedef struct ++{ ++ zzn2 a; ++ zzn2 b; ++ BOOL unitary; ++} zzn4; ++ ++typedef struct ++{ ++ int marker; ++ zzn2 x; ++ zzn2 y; ++#ifndef MR_AFFINE_ONLY ++ zzn2 z; ++#endif ++ ++} ecn2; ++ ++typedef struct ++{ ++ big a; ++ big b; ++ big c; ++} zzn3; ++ ++typedef struct ++{ ++ zzn2 a; ++ zzn2 b; ++ zzn2 c; ++} zzn6_3x2; ++ ++/* main MIRACL instance structure */ ++ ++/* ------------------------------------------------------------------------*/ ++ ++typedef struct { ++mr_small base; /* number base */ ++mr_small apbase; /* apparent base */ ++int pack; /* packing density */ ++int lg2b; /* bits in base */ ++mr_small base2; /* 2^mr_lg2b */ ++BOOL (*user)(void); /* pointer to user supplied function */ ++ ++int nib; /* length of bigs */ ++#ifndef MR_STRIPPED_DOWN ++int depth; /* error tracing ..*/ ++int trace[MR_MAXDEPTH]; /* .. mechanism */ ++#endif ++BOOL check; /* overflow check */ ++BOOL fout; /* Output to file */ ++BOOL fin; /* Input from file */ ++BOOL active; ++ ++#ifndef MR_NO_FILE_IO ++ ++FILE *infile; /* Input file */ ++FILE *otfile; /* Output file */ ++ ++#endif ++ ++ ++#ifndef MR_NO_RAND ++mr_unsign32 ira[NK]; /* random number... */ ++int rndptr; /* ...array & pointer */ ++mr_unsign32 borrow; ++#endif ++ ++ /* Montgomery constants */ ++mr_small ndash; ++big modulus; ++big pR; ++BOOL ACTIVE; ++BOOL MONTY; ++ ++ /* Elliptic Curve details */ ++#ifndef MR_NO_SS ++BOOL SS; /* True for Super-Singular */ ++#endif ++#ifndef MR_NOKOBLITZ ++BOOL KOBLITZ; /* True for a Koblitz curve */ ++#endif ++#ifndef MR_AFFINE_ONLY ++int coord; ++#endif ++int Asize,Bsize; ++ ++int M,AA,BB,CC; /* for GF(2^m) curves */ ++ ++/* ++mr_small pm,mask; ++int e,k,Me,m; for GF(p^m) curves */ ++ ++ ++#ifndef MR_STATIC ++ ++int logN; /* constants for fast fourier fft multiplication */ ++int nprimes,degree; ++mr_utype *prime,*cr; ++mr_utype *inverse,**roots; ++small_chinese chin; ++mr_utype const1,const2,const3; ++mr_small msw,lsw; ++mr_utype **s1,**s2; /* pre-computed tables for polynomial reduction */ ++mr_utype **t; /* workspace */ ++mr_utype *wa; ++mr_utype *wb; ++mr_utype *wc; ++ ++#endif ++ ++BOOL same; ++BOOL first_one; ++BOOL debug; ++ ++big w0; /* workspace bigs */ ++big w1,w2,w3,w4; ++big w5,w6,w7; ++big w8,w9,w10,w11; ++big w12,w13,w14,w15; ++big sru; ++big one; ++ ++#ifdef MR_KCM ++big big_ndash; ++big ws,wt; ++#endif ++ ++big A,B; ++ ++/* User modifiables */ ++ ++#ifndef MR_SIMPLE_IO ++int IOBSIZ; /* size of i/o buffer */ ++#endif ++BOOL ERCON; /* error control */ ++int ERNUM; /* last error code */ ++int NTRY; /* no. of tries for probablistic primality testing */ ++#ifndef MR_SIMPLE_IO ++int INPLEN; /* input length */ ++#ifndef MR_SIMPLE_BASE ++int IOBASE; /* base for input and output */ ++ ++#endif ++#endif ++#ifdef MR_FLASH ++BOOL EXACT; /* exact flag */ ++BOOL RPOINT; /* =ON for radix point, =OFF for fractions in output */ ++#endif ++#ifndef MR_STRIPPED_DOWN ++BOOL TRACER; /* turns trace tracker on/off */ ++#endif ++ ++#ifdef MR_STATIC ++const int *PRIMES; /* small primes array */ ++#ifndef MR_SIMPLE_IO ++char IOBUFF[MR_DEFAULT_BUFFER_SIZE]; /* i/o buffer */ ++#endif ++#else ++int *PRIMES; /* small primes array */ ++#ifndef MR_SIMPLE_IO ++char *IOBUFF; /* i/o buffer */ ++#endif ++#endif ++ ++#ifdef MR_FLASH ++int workprec; ++int stprec; /* start precision */ ++ ++int RS,RD; ++double D; ++ ++double db,n,p; ++int a,b,c,d,r,q,oldn,ndig; ++mr_small u,v,ku,kv; ++ ++BOOL last,carryon; ++flash pi; ++ ++#endif ++ ++#ifdef MR_FP_ROUNDING ++mr_large inverse_base; ++#endif ++ ++#ifndef MR_STATIC ++char *workspace; ++#else ++char workspace[MR_BIG_RESERVE(MR_SPACES)]; ++#endif ++ ++int TWIST; /* set to twisted curve */ ++int qnr; /* a QNR -1 for p=3 mod 4, -2 for p=5 mod 8, 0 otherwise */ ++int cnr; /* a cubic non-residue */ ++int pmod8; ++int pmod9; ++BOOL NO_CARRY; ++} miracl; ++ ++/* ------------------------------------------------------------------------*/ ++ ++ ++#ifndef MR_GENERIC_MT ++ ++#ifdef MR_WINDOWS_MT ++#define MR_OS_THREADS ++#endif ++ ++#ifdef MR_UNIX_MT ++#define MR_OS_THREADS ++#endif ++ ++#ifdef MR_OPENMP_MT ++#define MR_OS_THREADS ++#endif ++ ++ ++#ifndef MR_OS_THREADS ++ ++extern miracl *mr_mip; /* pointer to MIRACL's only global variable */ ++ ++#endif ++ ++#endif ++ ++#ifdef MR_GENERIC_MT ++ ++#ifdef MR_STATIC ++#define MR_GENERIC_AND_STATIC ++#endif ++ ++#define _MIPT_ miracl *, ++#define _MIPTO_ miracl * ++#define _MIPD_ miracl *mr_mip, ++#define _MIPDO_ miracl *mr_mip ++#define _MIPP_ mr_mip, ++#define _MIPPO_ mr_mip ++ ++#else ++ ++#define _MIPT_ ++#define _MIPTO_ void ++#define _MIPD_ ++#define _MIPDO_ void ++#define _MIPP_ ++#define _MIPPO_ ++ ++#endif ++ ++/* Preamble and exit code for MIRACL routines. * ++ * Not used if MR_STRIPPED_DOWN is defined */ ++ ++#ifdef MR_STRIPPED_DOWN ++#define MR_OUT ++#define MR_IN(N) ++#else ++#define MR_OUT mr_mip->depth--; ++#define MR_IN(N) mr_mip->depth++; if (mr_mip->depthtrace[mr_mip->depth]=(N); if (mr_mip->TRACER) mr_track(_MIPPO_); } ++#endif ++ ++/* Function definitions */ ++ ++/* Group 0 - Internal routines */ ++ ++extern void mr_berror(_MIPT_ int); ++extern mr_small mr_shiftbits(mr_small,int); ++extern mr_small mr_setbase(_MIPT_ mr_small); ++extern void mr_track(_MIPTO_ ); ++extern void mr_lzero(big); ++extern BOOL mr_notint(flash); ++extern int mr_lent(flash); ++extern void mr_padd(_MIPT_ big,big,big); ++extern void mr_psub(_MIPT_ big,big,big); ++extern void mr_pmul(_MIPT_ big,mr_small,big); ++#ifdef MR_FP_ROUNDING ++extern mr_large mr_invert(mr_small); ++extern mr_small imuldiv(mr_small,mr_small,mr_small,mr_small,mr_large,mr_small *); ++extern mr_small mr_sdiv(_MIPT_ big,mr_small,mr_large,big); ++#else ++extern mr_small mr_sdiv(_MIPT_ big,mr_small,big); ++extern void mr_and(big,big,big); ++extern void mr_xor(big,big,big); ++#endif ++extern void mr_shift(_MIPT_ big,int,big); ++extern miracl *mr_first_alloc(void); ++extern void *mr_alloc(_MIPT_ int,int); ++extern void mr_free(void *); ++extern void set_user_function(_MIPT_ BOOL (*)(void)); ++extern void set_io_buffer_size(_MIPT_ int); ++extern int mr_testbit(_MIPT_ big,int); ++extern void mr_addbit(_MIPT_ big,int); ++extern int recode(_MIPT_ big ,int ,int ,int ); ++extern int mr_window(_MIPT_ big,int,int *,int *,int); ++extern int mr_window2(_MIPT_ big,big,int,int *,int *); ++extern int mr_naf_window(_MIPT_ big,big,int,int *,int *,int); ++ ++extern int mr_fft_init(_MIPT_ int,big,big,BOOL); ++extern void mr_dif_fft(_MIPT_ int,int,mr_utype *); ++extern void mr_dit_fft(_MIPT_ int,int,mr_utype *); ++extern void fft_reset(_MIPTO_); ++ ++extern int mr_poly_mul(_MIPT_ int,big*,int,big*,big*); ++extern int mr_poly_sqr(_MIPT_ int,big*,big*); ++extern void mr_polymod_set(_MIPT_ int,big*,big*); ++extern int mr_poly_rem(_MIPT_ int,big *,big *); ++ ++extern int mr_ps_big_mul(_MIPT_ int,big *,big *,big *); ++extern int mr_ps_zzn_mul(_MIPT_ int,big *,big *,big *); ++ ++extern mr_small muldiv(mr_small,mr_small,mr_small,mr_small,mr_small *); ++extern mr_small muldvm(mr_small,mr_small,mr_small,mr_small *); ++extern mr_small muldvd(mr_small,mr_small,mr_small,mr_small *); ++extern void muldvd2(mr_small,mr_small,mr_small *,mr_small *); ++ ++extern flash mirvar_mem_variable(char *,int,int); ++extern epoint* epoint_init_mem_variable(_MIPT_ char *,int,int); ++ ++/* Group 1 - General purpose, I/O and basic arithmetic routines */ ++ ++extern unsigned int igcd(unsigned int,unsigned int); ++extern unsigned long lgcd(unsigned long,unsigned long); ++extern mr_small sgcd(mr_small,mr_small); ++extern unsigned int isqrt(unsigned int,unsigned int); ++extern unsigned long mr_lsqrt(unsigned long,unsigned long); ++extern void irand(_MIPT_ mr_unsign32); ++extern mr_small brand(_MIPTO_ ); ++extern void zero(flash); ++extern void convert(_MIPT_ int,big); ++extern void uconvert(_MIPT_ unsigned int,big); ++extern void lgconv(_MIPT_ long,big); ++extern void ulgconv(_MIPT_ unsigned long,big); ++extern void tconvert(_MIPT_ mr_utype,big); ++ ++#ifdef mr_dltype ++extern void dlconv(_MIPT_ mr_dltype,big); ++#endif ++ ++extern flash mirvar(_MIPT_ int); ++extern flash mirvar_mem(_MIPT_ char *,int); ++extern void mirkill(big); ++extern void *memalloc(_MIPT_ int); ++extern void memkill(_MIPT_ char *,int); ++extern void mr_init_threading(void); ++extern void mr_end_threading(void); ++extern miracl *get_mip(void ); ++extern void set_mip(miracl *); ++#ifdef MR_GENERIC_AND_STATIC ++extern miracl *mirsys(miracl *,int,mr_small); ++#else ++extern miracl *mirsys(int,mr_small); ++#endif ++extern miracl *mirsys_basic(miracl *,int,mr_small); ++extern void mirexit(_MIPTO_ ); ++extern int exsign(flash); ++extern void insign(int,flash); ++extern int getdig(_MIPT_ big,int); ++extern int numdig(_MIPT_ big); ++extern void putdig(_MIPT_ int,big,int); ++extern void copy(flash,flash); ++extern void negify(flash,flash); ++extern void absol(flash,flash); ++extern int size(big); ++extern int mr_compare(big,big); ++extern void add(_MIPT_ big,big,big); ++extern void subtract(_MIPT_ big,big,big); ++extern void incr(_MIPT_ big,int,big); ++extern void decr(_MIPT_ big,int,big); ++extern void premult(_MIPT_ big,int,big); ++extern int subdiv(_MIPT_ big,int,big); ++extern BOOL subdivisible(_MIPT_ big,int); ++extern int remain(_MIPT_ big,int); ++extern void bytes_to_big(_MIPT_ int,const char *,big); ++extern int big_to_bytes(_MIPT_ int,big,char *,BOOL); ++extern mr_small normalise(_MIPT_ big,big); ++extern void multiply(_MIPT_ big,big,big); ++extern void fft_mult(_MIPT_ big,big,big); ++extern BOOL fastmultop(_MIPT_ int,big,big,big); ++extern void divide(_MIPT_ big,big,big); ++extern BOOL divisible(_MIPT_ big,big); ++extern void mad(_MIPT_ big,big,big,big,big,big); ++extern int instr(_MIPT_ flash,char *); ++extern int otstr(_MIPT_ flash,char *); ++extern int cinstr(_MIPT_ flash,char *); ++extern int cotstr(_MIPT_ flash,char *); ++extern epoint* epoint_init(_MIPTO_ ); ++extern epoint* epoint_init_mem(_MIPT_ char *,int); ++extern void* ecp_memalloc(_MIPT_ int); ++void ecp_memkill(_MIPT_ char *,int); ++BOOL init_big_from_rom(big,int,const mr_small *,int ,int *); ++BOOL init_point_from_rom(epoint *,int,const mr_small *,int,int *); ++ ++#ifndef MR_NO_FILE_IO ++ ++extern int innum(_MIPT_ flash,FILE *); ++extern int otnum(_MIPT_ flash,FILE *); ++extern int cinnum(_MIPT_ flash,FILE *); ++extern int cotnum(_MIPT_ flash,FILE *); ++ ++#endif ++ ++/* Group 2 - Advanced arithmetic routines */ ++ ++extern mr_small smul(mr_small,mr_small,mr_small); ++extern mr_small spmd(mr_small,mr_small,mr_small); ++extern mr_small invers(mr_small,mr_small); ++extern mr_small sqrmp(mr_small,mr_small); ++extern int jac(mr_small,mr_small); ++ ++extern void gprime(_MIPT_ int); ++extern int jack(_MIPT_ big,big); ++extern int egcd(_MIPT_ big,big,big); ++extern int xgcd(_MIPT_ big,big,big,big,big); ++extern int invmodp(_MIPT_ big,big,big); ++extern int logb2(_MIPT_ big); ++extern int hamming(_MIPT_ big); ++extern void expb2(_MIPT_ int,big); ++extern void bigbits(_MIPT_ int,big); ++extern void expint(_MIPT_ int,int,big); ++extern void sftbit(_MIPT_ big,int,big); ++extern void power(_MIPT_ big,long,big,big); ++extern void powmod(_MIPT_ big,big,big,big); ++extern void powmod2(_MIPT_ big,big,big,big,big,big); ++extern void powmodn(_MIPT_ int,big *,big *,big,big); ++extern int powltr(_MIPT_ int,big,big,big); ++extern BOOL double_inverse(_MIPT_ big,big,big,big,big); ++extern BOOL multi_inverse(_MIPT_ int,big*,big,big*); ++extern void lucas(_MIPT_ big,big,big,big,big); ++extern BOOL nroot(_MIPT_ big,int,big); ++extern BOOL sqroot(_MIPT_ big,big,big); ++extern void bigrand(_MIPT_ big,big); ++extern void bigdig(_MIPT_ int,int,big); ++extern int trial_division(_MIPT_ big,big); ++extern BOOL isprime(_MIPT_ big); ++extern BOOL nxprime(_MIPT_ big,big); ++extern BOOL nxsafeprime(_MIPT_ int,int,big,big); ++extern BOOL crt_init(_MIPT_ big_chinese *,int,big *); ++extern void crt(_MIPT_ big_chinese *,big *,big); ++extern void crt_end(big_chinese *); ++extern BOOL scrt_init(_MIPT_ small_chinese *,int,mr_utype *); ++extern void scrt(_MIPT_ small_chinese*,mr_utype *,big); ++extern void scrt_end(small_chinese *); ++#ifndef MR_STATIC ++extern BOOL brick_init(_MIPT_ brick *,big,big,int,int); ++extern void brick_end(brick *); ++#else ++extern void brick_init(brick *,const mr_small *,big,int,int); ++#endif ++extern void pow_brick(_MIPT_ brick *,big,big); ++#ifndef MR_STATIC ++extern BOOL ebrick_init(_MIPT_ ebrick *,big,big,big,big,big,int,int); ++extern void ebrick_end(ebrick *); ++#else ++extern void ebrick_init(ebrick *,const mr_small *,big,big,big,int,int); ++#endif ++extern int mul_brick(_MIPT_ ebrick*,big,big,big); ++#ifndef MR_STATIC ++extern BOOL ebrick2_init(_MIPT_ ebrick2 *,big,big,big,big,int,int,int,int,int,int); ++extern void ebrick2_end(ebrick2 *); ++#else ++extern void ebrick2_init(ebrick2 *,const mr_small *,big,big,int,int,int,int,int,int); ++#endif ++extern int mul2_brick(_MIPT_ ebrick2*,big,big,big); ++ ++/* Montgomery stuff */ ++ ++extern mr_small prepare_monty(_MIPT_ big); ++extern void kill_monty(_MIPTO_ ); ++extern void nres(_MIPT_ big,big); ++extern void redc(_MIPT_ big,big); ++ ++extern void nres_negate(_MIPT_ big,big); ++extern void nres_modadd(_MIPT_ big,big,big); ++extern void nres_modsub(_MIPT_ big,big,big); ++extern void nres_lazy(_MIPT_ big,big,big,big,big,big); ++extern void nres_complex(_MIPT_ big,big,big,big); ++extern void nres_double_modadd(_MIPT_ big,big,big); ++extern void nres_double_modsub(_MIPT_ big,big,big); ++extern void nres_premult(_MIPT_ big,int,big); ++extern void nres_modmult(_MIPT_ big,big,big); ++extern int nres_moddiv(_MIPT_ big,big,big); ++extern void nres_dotprod(_MIPT_ int,big *,big *,big); ++extern void nres_powmod(_MIPT_ big,big,big); ++extern void nres_powltr(_MIPT_ int,big,big); ++extern void nres_powmod2(_MIPT_ big,big,big,big,big); ++extern void nres_powmodn(_MIPT_ int,big *,big *,big); ++extern BOOL nres_sqroot(_MIPT_ big,big); ++extern void nres_lucas(_MIPT_ big,big,big,big); ++extern BOOL nres_double_inverse(_MIPT_ big,big,big,big); ++extern BOOL nres_multi_inverse(_MIPT_ int,big *,big *); ++extern void nres_div2(_MIPT_ big,big); ++extern void nres_div3(_MIPT_ big,big); ++extern void nres_div5(_MIPT_ big,big); ++ ++extern void shs_init(sha *); ++extern void shs_process(sha *,int); ++extern void shs_hash(sha *,char *); ++ ++extern void shs256_init(sha256 *); ++extern void shs256_process(sha256 *,int); ++extern void shs256_hash(sha256 *,char *); ++ ++#ifdef mr_unsign64 ++ ++extern void shs512_init(sha512 *); ++extern void shs512_process(sha512 *,int); ++extern void shs512_hash(sha512 *,char *); ++ ++extern void shs384_init(sha384 *); ++extern void shs384_process(sha384 *,int); ++extern void shs384_hash(sha384 *,char *); ++ ++extern void sha3_init(sha3 *,int); ++extern void sha3_process(sha3 *,int); ++extern void sha3_hash(sha3 *,char *); ++ ++#endif ++ ++extern BOOL aes_init(aes *,int,int,char *,char *); ++extern void aes_getreg(aes *,char *); ++extern void aes_ecb_encrypt(aes *,MR_BYTE *); ++extern void aes_ecb_decrypt(aes *,MR_BYTE *); ++extern mr_unsign32 aes_encrypt(aes *,char *); ++extern mr_unsign32 aes_decrypt(aes *,char *); ++extern void aes_reset(aes *,int,char *); ++extern void aes_end(aes *); ++ ++extern void gcm_init(gcm *,int,char *,int,char *); ++extern BOOL gcm_add_header(gcm *,char *,int); ++extern BOOL gcm_add_cipher(gcm *,int,char *,int,char *); ++extern void gcm_finish(gcm *,char *); ++ ++extern void FPE_encrypt(int ,aes *,mr_unsign32 ,mr_unsign32 ,char *,int); ++extern void FPE_decrypt(int ,aes *,mr_unsign32 ,mr_unsign32 ,char *,int); ++ ++extern void strong_init(csprng *,int,char *,mr_unsign32); ++extern int strong_rng(csprng *); ++extern void strong_bigrand(_MIPT_ csprng *,big,big); ++extern void strong_bigdig(_MIPT_ csprng *,int,int,big); ++extern void strong_kill(csprng *); ++ ++/* special modular multipliers */ ++ ++extern void comba_mult(big,big,big); ++extern void comba_square(big,big); ++extern void comba_redc(_MIPT_ big,big); ++extern void comba_modadd(_MIPT_ big,big,big); ++extern void comba_modsub(_MIPT_ big,big,big); ++extern void comba_double_modadd(_MIPT_ big,big,big); ++extern void comba_double_modsub(_MIPT_ big,big,big); ++extern void comba_negate(_MIPT_ big,big); ++extern void comba_add(big,big,big); ++extern void comba_sub(big,big,big); ++extern void comba_double_add(big,big,big); ++extern void comba_double_sub(big,big,big); ++ ++extern void comba_mult2(_MIPT_ big,big,big); ++ ++extern void fastmodmult(_MIPT_ big,big,big); ++extern void fastmodsquare(_MIPT_ big,big); ++ ++extern void kcm_mul(_MIPT_ big,big,big); ++extern void kcm_sqr(_MIPT_ big,big); ++extern void kcm_redc(_MIPT_ big,big); ++ ++extern void kcm_multiply(_MIPT_ int,big,big,big); ++extern void kcm_square(_MIPT_ int,big,big); ++extern BOOL kcm_top(_MIPT_ int,big,big,big); ++ ++/* elliptic curve stuff */ ++ ++extern BOOL point_at_infinity(epoint *); ++ ++extern void mr_jsf(_MIPT_ big,big,big,big,big,big); ++ ++extern void ecurve_init(_MIPT_ big,big,big,int); ++extern int ecurve_add(_MIPT_ epoint *,epoint *); ++extern int ecurve_sub(_MIPT_ epoint *,epoint *); ++extern void ecurve_double_add(_MIPT_ epoint *,epoint *,epoint *,epoint *,big *,big *); ++extern void ecurve_multi_add(_MIPT_ int,epoint **,epoint **); ++extern void ecurve_double(_MIPT_ epoint*); ++extern int ecurve_mult(_MIPT_ big,epoint *,epoint *); ++extern void ecurve_mult2(_MIPT_ big,epoint *,big,epoint *,epoint *); ++extern void ecurve_multn(_MIPT_ int,big *,epoint**,epoint *); ++ ++extern BOOL epoint_x(_MIPT_ big); ++extern BOOL epoint_set(_MIPT_ big,big,int,epoint*); ++extern int epoint_get(_MIPT_ epoint*,big,big); ++extern void epoint_getxyz(_MIPT_ epoint *,big,big,big); ++extern BOOL epoint_norm(_MIPT_ epoint *); ++extern BOOL epoint_multi_norm(_MIPT_ int,big *,epoint **); ++extern void epoint_free(epoint *); ++extern void epoint_copy(epoint *,epoint *); ++extern BOOL epoint_comp(_MIPT_ epoint *,epoint *); ++extern void epoint_negate(_MIPT_ epoint *); ++ ++extern BOOL ecurve2_init(_MIPT_ int,int,int,int,big,big,BOOL,int); ++extern big ecurve2_add(_MIPT_ epoint *,epoint *); ++extern big ecurve2_sub(_MIPT_ epoint *,epoint *); ++extern void ecurve2_multi_add(_MIPT_ int,epoint **,epoint **); ++extern void ecurve2_mult(_MIPT_ big,epoint *,epoint *); ++extern void ecurve2_mult2(_MIPT_ big,epoint *,big,epoint *,epoint *); ++extern void ecurve2_multn(_MIPT_ int,big *,epoint**,epoint *); ++ ++extern epoint* epoint2_init(_MIPTO_ ); ++extern BOOL epoint2_set(_MIPT_ big,big,int,epoint*); ++extern int epoint2_get(_MIPT_ epoint*,big,big); ++extern void epoint2_getxyz(_MIPT_ epoint *,big,big,big); ++extern int epoint2_norm(_MIPT_ epoint *); ++extern void epoint2_free(epoint *); ++extern void epoint2_copy(epoint *,epoint *); ++extern BOOL epoint2_comp(_MIPT_ epoint *,epoint *); ++extern void epoint2_negate(_MIPT_ epoint *); ++ ++/* GF(2) stuff */ ++ ++extern BOOL prepare_basis(_MIPT_ int,int,int,int,BOOL); ++extern int parity2(big); ++extern BOOL multi_inverse2(_MIPT_ int,big *,big *); ++extern void add2(big,big,big); ++extern void incr2(big,int,big); ++extern void reduce2(_MIPT_ big,big); ++extern void multiply2(_MIPT_ big,big,big); ++extern void modmult2(_MIPT_ big,big,big); ++extern void modsquare2(_MIPT_ big,big); ++extern void power2(_MIPT_ big,int,big); ++extern void sqroot2(_MIPT_ big,big); ++extern void halftrace2(_MIPT_ big,big); ++extern BOOL quad2(_MIPT_ big,big); ++extern BOOL inverse2(_MIPT_ big,big); ++extern void karmul2(int,mr_small *,mr_small *,mr_small *,mr_small *); ++extern void karmul2_poly(_MIPT_ int,big *,big *,big *,big *); ++extern void karmul2_poly_upper(_MIPT_ int,big *,big *,big *,big *); ++extern void gf2m_dotprod(_MIPT_ int,big *,big *,big); ++extern int trace2(_MIPT_ big); ++extern void rand2(_MIPT_ big); ++extern void gcd2(_MIPT_ big,big,big); ++extern int degree2(big); ++ ++/* zzn2 stuff */ ++ ++extern BOOL zzn2_iszero(zzn2 *); ++extern BOOL zzn2_isunity(_MIPT_ zzn2 *); ++extern void zzn2_from_int(_MIPT_ int,zzn2 *); ++extern void zzn2_from_ints(_MIPT_ int,int,zzn2 *); ++extern void zzn2_copy(zzn2 *,zzn2 *); ++extern void zzn2_zero(zzn2 *); ++extern void zzn2_negate(_MIPT_ zzn2 *,zzn2 *); ++extern void zzn2_conj(_MIPT_ zzn2 *,zzn2 *); ++extern void zzn2_add(_MIPT_ zzn2 *,zzn2 *,zzn2 *); ++extern void zzn2_sub(_MIPT_ zzn2 *,zzn2 *,zzn2 *); ++extern void zzn2_smul(_MIPT_ zzn2 *,big,zzn2 *); ++extern void zzn2_mul(_MIPT_ zzn2 *,zzn2 *,zzn2 *); ++extern void zzn2_sqr(_MIPT_ zzn2 *,zzn2 *); ++extern void zzn2_inv(_MIPT_ zzn2 *); ++extern void zzn2_timesi(_MIPT_ zzn2 *); ++extern void zzn2_powl(_MIPT_ zzn2 *,big,zzn2 *); ++extern void zzn2_from_zzns(big,big,zzn2 *); ++extern void zzn2_from_bigs(_MIPT_ big,big,zzn2 *); ++extern void zzn2_from_zzn(big,zzn2 *); ++extern void zzn2_from_big(_MIPT_ big, zzn2 *); ++extern void zzn2_sadd(_MIPT_ zzn2 *,big,zzn2 *); ++extern void zzn2_ssub(_MIPT_ zzn2 *,big,zzn2 *); ++extern void zzn2_div2(_MIPT_ zzn2 *); ++extern void zzn2_div3(_MIPT_ zzn2 *); ++extern void zzn2_div5(_MIPT_ zzn2 *); ++extern void zzn2_imul(_MIPT_ zzn2 *,int,zzn2 *); ++extern BOOL zzn2_compare(zzn2 *,zzn2 *); ++extern void zzn2_txx(_MIPT_ zzn2 *); ++extern void zzn2_txd(_MIPT_ zzn2 *); ++extern BOOL zzn2_sqrt(_MIPT_ zzn2 *,zzn2 *); ++extern BOOL zzn2_qr(_MIPT_ zzn2 *); ++extern BOOL zzn2_multi_inverse(_MIPT_ int,zzn2 *,zzn2 *); ++ ++ ++/* zzn3 stuff */ ++ ++extern void zzn3_set(_MIPT_ int,big); ++extern BOOL zzn3_iszero(zzn3 *); ++extern BOOL zzn3_isunity(_MIPT_ zzn3 *); ++extern void zzn3_from_int(_MIPT_ int,zzn3 *); ++extern void zzn3_from_ints(_MIPT_ int,int,int,zzn3 *); ++extern void zzn3_copy(zzn3 *,zzn3 *); ++extern void zzn3_zero(zzn3 *); ++extern void zzn3_negate(_MIPT_ zzn3 *,zzn3 *); ++extern void zzn3_powq(_MIPT_ zzn3 *,zzn3 *); ++extern void zzn3_add(_MIPT_ zzn3 *,zzn3 *,zzn3 *); ++extern void zzn3_sub(_MIPT_ zzn3 *,zzn3 *,zzn3 *); ++extern void zzn3_smul(_MIPT_ zzn3 *,big,zzn3 *); ++extern void zzn3_mul(_MIPT_ zzn3 *,zzn3 *,zzn3 *); ++extern void zzn3_inv(_MIPT_ zzn3 *); ++extern void zzn3_timesi(_MIPT_ zzn3 *); ++extern void zzn3_timesi2(_MIPT_ zzn3 *); ++extern void zzn3_powl(_MIPT_ zzn3 *,big,zzn3 *); ++extern void zzn3_from_zzns(big,big,big,zzn3 *); ++extern void zzn3_from_bigs(_MIPT_ big,big,big,zzn3 *); ++extern void zzn3_from_zzn(big,zzn3 *); ++extern void zzn3_from_zzn_1(big,zzn3 *); ++extern void zzn3_from_zzn_2(big,zzn3 *); ++extern void zzn3_from_big(_MIPT_ big, zzn3 *); ++extern void zzn3_sadd(_MIPT_ zzn3 *,big,zzn3 *); ++extern void zzn3_ssub(_MIPT_ zzn3 *,big,zzn3 *); ++extern void zzn3_div2(_MIPT_ zzn3 *); ++extern void zzn3_imul(_MIPT_ zzn3 *,int,zzn3 *); ++extern BOOL zzn3_compare(zzn3 *,zzn3 *); ++ ++/* zzn4 stuff */ ++ ++extern BOOL zzn4_iszero(zzn4 *); ++extern BOOL zzn4_isunity(_MIPT_ zzn4 *); ++extern void zzn4_from_int(_MIPT_ int,zzn4 *); ++extern void zzn4_copy(zzn4 *,zzn4 *); ++extern void zzn4_zero(zzn4 *); ++extern void zzn4_negate(_MIPT_ zzn4 *,zzn4 *); ++extern void zzn4_powq(_MIPT_ zzn2 *,zzn4 *); ++extern void zzn4_add(_MIPT_ zzn4 *,zzn4 *,zzn4 *); ++extern void zzn4_sub(_MIPT_ zzn4 *,zzn4 *,zzn4 *); ++extern void zzn4_smul(_MIPT_ zzn4 *,zzn2 *,zzn4 *); ++extern void zzn4_sqr(_MIPT_ zzn4 *,zzn4 *); ++extern void zzn4_mul(_MIPT_ zzn4 *,zzn4 *,zzn4 *); ++extern void zzn4_inv(_MIPT_ zzn4 *); ++extern void zzn4_timesi(_MIPT_ zzn4 *); ++extern void zzn4_tx(_MIPT_ zzn4 *); ++extern void zzn4_from_zzn2s(zzn2 *,zzn2 *,zzn4 *); ++extern void zzn4_from_zzn2(zzn2 *,zzn4 *); ++extern void zzn4_from_zzn2h(zzn2 *,zzn4 *); ++extern void zzn4_from_zzn(big,zzn4 *); ++extern void zzn4_from_big(_MIPT_ big , zzn4 *); ++extern void zzn4_sadd(_MIPT_ zzn4 *,zzn2 *,zzn4 *); ++extern void zzn4_ssub(_MIPT_ zzn4 *,zzn2 *,zzn4 *); ++extern void zzn4_div2(_MIPT_ zzn4 *); ++extern void zzn4_conj(_MIPT_ zzn4 *,zzn4 *); ++extern void zzn4_imul(_MIPT_ zzn4 *,int,zzn4 *); ++extern void zzn4_lmul(_MIPT_ zzn4 *,big,zzn4 *); ++extern BOOL zzn4_compare(zzn4 *,zzn4 *); ++ ++/* ecn2 stuff */ ++ ++extern BOOL ecn2_iszero(ecn2 *); ++extern void ecn2_copy(ecn2 *,ecn2 *); ++extern void ecn2_zero(ecn2 *); ++extern BOOL ecn2_compare(_MIPT_ ecn2 *,ecn2 *); ++extern void ecn2_norm(_MIPT_ ecn2 *); ++extern void ecn2_get(_MIPT_ ecn2 *,zzn2 *,zzn2 *,zzn2 *); ++extern void ecn2_getxy(ecn2 *,zzn2 *,zzn2 *); ++extern void ecn2_getx(ecn2 *,zzn2 *); ++extern void ecn2_getz(_MIPT_ ecn2 *,zzn2 *); ++extern void ecn2_rhs(_MIPT_ zzn2 *,zzn2 *); ++extern BOOL ecn2_set(_MIPT_ zzn2 *,zzn2 *,ecn2 *); ++extern BOOL ecn2_setx(_MIPT_ zzn2 *,ecn2 *); ++extern void ecn2_setxyz(_MIPT_ zzn2 *,zzn2 *,zzn2 *,ecn2 *); ++extern void ecn2_negate(_MIPT_ ecn2 *,ecn2 *); ++extern BOOL ecn2_add3(_MIPT_ ecn2 *,ecn2 *,zzn2 *,zzn2 *,zzn2 *); ++extern BOOL ecn2_add2(_MIPT_ ecn2 *,ecn2 *,zzn2 *,zzn2 *); ++extern BOOL ecn2_add1(_MIPT_ ecn2 *,ecn2 *,zzn2 *); ++extern BOOL ecn2_add(_MIPT_ ecn2 *,ecn2 *); ++extern BOOL ecn2_sub(_MIPT_ ecn2 *,ecn2 *); ++extern BOOL ecn2_add_sub(_MIPT_ ecn2 *,ecn2 *,ecn2 *,ecn2 *); ++extern int ecn2_mul2_jsf(_MIPT_ big,ecn2 *,big,ecn2 *,ecn2 *); ++extern int ecn2_mul(_MIPT_ big,ecn2 *); ++extern void ecn2_psi(_MIPT_ zzn2 *,ecn2 *); ++extern BOOL ecn2_multi_norm(_MIPT_ int ,zzn2 *,ecn2 *); ++extern int ecn2_mul4_gls_v(_MIPT_ big *,int,ecn2 *,big *,ecn2 *,zzn2 *,ecn2 *); ++extern int ecn2_muln_engine(_MIPT_ int,int,int,int,big *,big *,big *,big *,ecn2 *,ecn2 *,ecn2 *); ++extern void ecn2_precomp_gls(_MIPT_ int,BOOL,ecn2 *,zzn2 *,ecn2 *); ++extern int ecn2_mul2_gls(_MIPT_ big *,ecn2 *,zzn2 *,ecn2 *); ++extern void ecn2_precomp(_MIPT_ int,BOOL,ecn2 *,ecn2 *); ++extern int ecn2_mul2(_MIPT_ big,int,ecn2 *,big,ecn2 *,ecn2 *); ++#ifndef MR_STATIC ++extern BOOL ecn2_brick_init(_MIPT_ ebrick *,zzn2 *,zzn2 *,big,big,big,int,int); ++extern void ecn2_brick_end(ebrick *); ++#else ++extern void ebrick_init(ebrick *,const mr_small *,big,big,big,int,int); ++#endif ++extern void ecn2_mul_brick_gls(_MIPT_ ebrick *B,big *,zzn2 *,zzn2 *,zzn2 *); ++extern void ecn2_multn(_MIPT_ int,big *,ecn2 *,ecn2 *); ++extern void ecn2_mult4(_MIPT_ big *,ecn2 *,ecn2 *); ++/* Group 3 - Floating-slash routines */ ++ ++#ifdef MR_FLASH ++extern void fpack(_MIPT_ big,big,flash); ++extern void numer(_MIPT_ flash,big); ++extern void denom(_MIPT_ flash,big); ++extern BOOL fit(big,big,int); ++extern void build(_MIPT_ flash,int (*)(_MIPT_ big,int)); ++extern void mround(_MIPT_ big,big,flash); ++extern void flop(_MIPT_ flash,flash,int *,flash); ++extern void fmul(_MIPT_ flash,flash,flash); ++extern void fdiv(_MIPT_ flash,flash,flash); ++extern void fadd(_MIPT_ flash,flash,flash); ++extern void fsub(_MIPT_ flash,flash,flash); ++extern int fcomp(_MIPT_ flash,flash); ++extern void fconv(_MIPT_ int,int,flash); ++extern void frecip(_MIPT_ flash,flash); ++extern void ftrunc(_MIPT_ flash,big,flash); ++extern void fmodulo(_MIPT_ flash,flash,flash); ++extern void fpmul(_MIPT_ flash,int,int,flash); ++extern void fincr(_MIPT_ flash,int,int,flash); ++extern void dconv(_MIPT_ double,flash); ++extern double fdsize(_MIPT_ flash); ++extern void frand(_MIPT_ flash); ++ ++/* Group 4 - Advanced Flash routines */ ++ ++extern void fpower(_MIPT_ flash,int,flash); ++extern BOOL froot(_MIPT_ flash,int,flash); ++extern void fpi(_MIPT_ flash); ++extern void fexp(_MIPT_ flash,flash); ++extern void flog(_MIPT_ flash,flash); ++extern void fpowf(_MIPT_ flash,flash,flash); ++extern void ftan(_MIPT_ flash,flash); ++extern void fatan(_MIPT_ flash,flash); ++extern void fsin(_MIPT_ flash,flash); ++extern void fasin(_MIPT_ flash,flash); ++extern void fcos(_MIPT_ flash,flash); ++extern void facos(_MIPT_ flash,flash); ++extern void ftanh(_MIPT_ flash,flash); ++extern void fatanh(_MIPT_ flash,flash); ++extern void fsinh(_MIPT_ flash,flash); ++extern void fasinh(_MIPT_ flash,flash); ++extern void fcosh(_MIPT_ flash,flash); ++extern void facosh(_MIPT_ flash,flash); ++#endif ++ ++ ++/* Test predefined Macros to determine compiler type, and hopefully ++ selectively use fast in-line assembler (or other compiler specific ++ optimisations. Note I am unsure of Microsoft version numbers. So I ++ suspect are Microsoft. ++ ++ Note: It seems to be impossible to get the 16-bit Microsoft compiler ++ to allow inline 32-bit op-codes. So I suspect that INLINE_ASM == 2 will ++ never work with it. Pity. ++ ++#define INLINE_ASM 1 -> generates 8086 inline assembly ++#define INLINE_ASM 2 -> generates mixed 8086 & 80386 inline assembly, ++ so you can get some benefit while running in a ++ 16-bit environment on 32-bit hardware (DOS, Windows ++ 3.1...) ++#define INLINE_ASM 3 -> generate true 80386 inline assembly - (Using DOS ++ extender, Windows '95/Windows NT) ++ Actually optimised for Pentium ++ ++#define INLINE_ASM 4 -> 80386 code in the GNU style (for (DJGPP) ++ ++Small, medium, compact and large memory models are supported for the ++first two of the above. ++ ++*/ ++ ++/* To allow for inline assembly */ ++ ++#ifdef __GNUC__ ++ #define ASM __asm__ __volatile__ ++#endif ++ ++#ifdef __TURBOC__ ++ #define ASM asm ++#endif ++ ++#ifdef _MSC_VER ++ #define ASM _asm ++#endif ++ ++#ifndef MR_NOASM ++ ++/* Win64 - inline the time critical function */ ++#ifndef MR_NO_INTRINSICS ++ #ifdef MR_WIN64 ++ #define muldvd(a,b,c,rp) (*(rp)=_umul128((a),(b),&(tm)),*(rp)+=(c),tm+=(*(rp)<(c)),tm) ++ #define muldvd2(a,b,c,rp) (tr=_umul128((a),(b),&(tm)),tr+=(*(c)),tm+=(tr<(*(c))),tr+=(*(rp)),tm+=(tr<(*(rp))),*(rp)=tr,*(c)=tm) ++ #endif ++ ++/* Itanium - inline the time-critical functions */ ++ ++ #ifdef MR_ITANIUM ++ #define muldvd(a,b,c,rp) (tm=_m64_xmahu((a),(b),(c)),*(rp)=_m64_xmalu((a),(b),(c)),tm) ++ #define muldvd2(a,b,c,rp) (tm=_m64_xmalu((a),(b),(*(c))),*(c)=_m64_xmahu((a),(b),(*(c))),tm+=*(rp),*(c)+=(tm<*(rp)),*(rp)=tm) ++ #endif ++#endif ++/* ++ ++SSE2 code. Works as for itanium - but in fact it is slower than the regular code so not recommended ++Would require a call to emmintrin.h or xmmintrin.h, and an __m128i variable tm to be declared in effected ++functions. But it works! ++ ++ #define muldvd(a,b,c,rp) (tm=_mm_add_epi64(_mm_mul_epu32(_mm_cvtsi32_si128((a)),_mm_cvtsi32_si128((b))),_mm_cvtsi32_si128((c))),*(rp)=_mm_cvtsi128_si32(tm),_mm_cvtsi128_si32(_mm_shuffle_epi32(tm,_MM_SHUFFLE(3,2,0,1))) ) ++ #define muldvd2(a,b,c,rp) (tm=_mm_add_epi64(_mm_add_epi64(_mm_mul_epu32(_mm_cvtsi32_si128((a)),_mm_cvtsi32_si128((b))),_mm_cvtsi32_si128(*(c))),_mm_cvtsi32_si128(*(rp))),*(rp)=_mm_cvtsi128_si32(tm),*(c)=_mm_cvtsi128_si32( _mm_shuffle_epi32(tm,_MM_SHUFFLE(3,2,0,1)) ) ++*/ ++ ++/* Borland C/Turbo C */ ++ ++ #ifdef __TURBOC__ ++ #ifndef __HUGE__ ++ #if defined(__COMPACT__) || defined(__LARGE__) ++ #define MR_LMM ++ #endif ++ ++ #if MIRACL==16 ++ #define INLINE_ASM 1 ++ #endif ++ ++ #if __TURBOC__>=0x410 ++ #if MIRACL==32 ++#if defined(__SMALL__) || defined(__MEDIUM__) || defined(__LARGE__) || defined(__COMPACT__) ++ #define INLINE_ASM 2 ++ #else ++ #define INLINE_ASM 3 ++ #endif ++ #endif ++ #endif ++ #endif ++ #endif ++ ++/* Microsoft C */ ++ ++ #ifdef _MSC_VER ++ #ifndef M_I86HM ++ #if defined(M_I86CM) || defined(M_I86LM) ++ #define MR_LMM ++ #endif ++ #if _MSC_VER>=600 ++ #if _MSC_VER<1200 ++ #if MIRACL==16 ++ #define INLINE_ASM 1 ++ #endif ++ #endif ++ #endif ++ #if _MSC_VER>=1000 ++ #if _MSC_VER<1500 ++ #if MIRACL==32 ++ #define INLINE_ASM 3 ++ #endif ++ #endif ++ #endif ++ #endif ++ #endif ++ ++/* DJGPP GNU C */ ++ ++ #ifdef __GNUC__ ++ #ifdef i386 ++ #if MIRACL==32 ++ #define INLINE_ASM 4 ++ #endif ++ #endif ++ #endif ++ ++#endif ++ ++ ++ ++/* ++ The following contribution is from Tielo Jongmans, Netherlands ++ These inline assembler routines are suitable for Watcom 10.0 and up ++ ++ Added into miracl.h. Notice the override of the original declarations ++ of these routines, which should be removed. ++ ++ The following pragma is optional, it is dangerous, but it saves a ++ calling sequence ++*/ ++ ++/* ++ ++#pragma off (check_stack); ++ ++extern unsigned int muldiv(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int *); ++#pragma aux muldiv= \ ++ "mul edx" \ ++ "add eax,ebx" \ ++ "adc edx,0" \ ++ "div ecx" \ ++ "mov [esi],edx" \ ++ parm [eax] [edx] [ebx] [ecx] [esi] \ ++ value [eax] \ ++ modify [eax edx]; ++ ++extern unsigned int muldvm(unsigned int, unsigned int, unsigned int, unsigned int *); ++#pragma aux muldvm= \ ++ "div ebx" \ ++ "mov [ecx],edx" \ ++ parm [edx] [eax] [ebx] [ecx] \ ++ value [eax] \ ++ modify [eax edx]; ++ ++extern unsigned int muldvd(unsigned int, unsigned int, unsigned int, unsigned int *); ++#pragma aux muldvd= \ ++ "mul edx" \ ++ "add eax,ebx" \ ++ "adc edx,0" \ ++ "mov [ecx],eax" \ ++ "mov eax,edx" \ ++ parm [eax] [edx] [ebx] [ecx] \ ++ value [eax] \ ++ modify [eax edx]; ++ ++*/ ++ ++ ++#endif ++ ++ +diff --git a/include/sm/gm/miracl/mirdef.h b/include/sm/gm/miracl/mirdef.h +new file mode 100644 +index 0000000..a2c395f +--- /dev/null ++++ b/include/sm/gm/miracl/mirdef.h +@@ -0,0 +1,24 @@ ++/* ++ * MIRACL compiler/hardware definitions - mirdef.h ++ */ ++#define MR_LITTLE_ENDIAN ++#define MIRACL 32 ++#define mr_utype int ++#define mr_dltype long ++#define MR_IBITS 32 ++#define MR_LBITS 64 ++#define mr_unsign32 unsigned int ++#define mr_unsign64 unsigned long ++#define MR_STRIPPED_DOWN ++#define MR_NO_STANDARD_IO ++#define MR_NO_FILE_IO ++#define MAXBASE ((mr_small)1<<(MIRACL-1)) ++#define MR_BITSINCHAR 8 ++#define MR_SMALL_AES ++ ++// #define MR_GENERIC_MT ++#define MR_STATIC 20 ++#define MR_ALWAYS_BINARY ++#define MR_SIMPLE_BASE ++#define MR_SIMPLE_IO ++#define MR_NOASM +diff --git a/include/sm/math.h b/include/sm/math.h +new file mode 100644 +index 0000000..7a665b2 +--- /dev/null ++++ b/include/sm/math.h +@@ -0,0 +1,78 @@ ++#ifndef _MATH_H ++#define _MATH_H ++ ++#define ilog2(n) \ ++( \ ++ (n) < 2 ? 0 : \ ++ (n) & (1ULL << 63) ? 63 : \ ++ (n) & (1ULL << 62) ? 62 : \ ++ (n) & (1ULL << 61) ? 61 : \ ++ (n) & (1ULL << 60) ? 60 : \ ++ (n) & (1ULL << 59) ? 59 : \ ++ (n) & (1ULL << 58) ? 58 : \ ++ (n) & (1ULL << 57) ? 57 : \ ++ (n) & (1ULL << 56) ? 56 : \ ++ (n) & (1ULL << 55) ? 55 : \ ++ (n) & (1ULL << 54) ? 54 : \ ++ (n) & (1ULL << 53) ? 53 : \ ++ (n) & (1ULL << 52) ? 52 : \ ++ (n) & (1ULL << 51) ? 51 : \ ++ (n) & (1ULL << 50) ? 50 : \ ++ (n) & (1ULL << 49) ? 49 : \ ++ (n) & (1ULL << 48) ? 48 : \ ++ (n) & (1ULL << 47) ? 47 : \ ++ (n) & (1ULL << 46) ? 46 : \ ++ (n) & (1ULL << 45) ? 45 : \ ++ (n) & (1ULL << 44) ? 44 : \ ++ (n) & (1ULL << 43) ? 43 : \ ++ (n) & (1ULL << 42) ? 42 : \ ++ (n) & (1ULL << 41) ? 41 : \ ++ (n) & (1ULL << 40) ? 40 : \ ++ (n) & (1ULL << 39) ? 39 : \ ++ (n) & (1ULL << 38) ? 38 : \ ++ (n) & (1ULL << 37) ? 37 : \ ++ (n) & (1ULL << 36) ? 36 : \ ++ (n) & (1ULL << 35) ? 35 : \ ++ (n) & (1ULL << 34) ? 34 : \ ++ (n) & (1ULL << 33) ? 33 : \ ++ (n) & (1ULL << 32) ? 32 : \ ++ (n) & (1ULL << 31) ? 31 : \ ++ (n) & (1ULL << 30) ? 30 : \ ++ (n) & (1ULL << 29) ? 29 : \ ++ (n) & (1ULL << 28) ? 28 : \ ++ (n) & (1ULL << 27) ? 27 : \ ++ (n) & (1ULL << 26) ? 26 : \ ++ (n) & (1ULL << 25) ? 25 : \ ++ (n) & (1ULL << 24) ? 24 : \ ++ (n) & (1ULL << 23) ? 23 : \ ++ (n) & (1ULL << 22) ? 22 : \ ++ (n) & (1ULL << 21) ? 21 : \ ++ (n) & (1ULL << 20) ? 20 : \ ++ (n) & (1ULL << 19) ? 19 : \ ++ (n) & (1ULL << 18) ? 18 : \ ++ (n) & (1ULL << 17) ? 17 : \ ++ (n) & (1ULL << 16) ? 16 : \ ++ (n) & (1ULL << 15) ? 15 : \ ++ (n) & (1ULL << 14) ? 14 : \ ++ (n) & (1ULL << 13) ? 13 : \ ++ (n) & (1ULL << 12) ? 12 : \ ++ (n) & (1ULL << 11) ? 11 : \ ++ (n) & (1ULL << 10) ? 10 : \ ++ (n) & (1ULL << 9) ? 9 : \ ++ (n) & (1ULL << 8) ? 8 : \ ++ (n) & (1ULL << 7) ? 7 : \ ++ (n) & (1ULL << 6) ? 6 : \ ++ (n) & (1ULL << 5) ? 5 : \ ++ (n) & (1ULL << 4) ? 4 : \ ++ (n) & (1ULL << 3) ? 3 : \ ++ (n) & (1ULL << 2) ? 2 : \ ++ 1 \ ++) ++ ++#define power_2_align(n) (1 << (ilog2(n-1)+1)) ++ ++#define size_down_align(n, size) (n - ((n) % (size))) ++ ++#define size_up_align(n, size) (size_down_align(n, size) + ((n) % (size) ? (size) : 0)) ++ ++#endif /* _MATH_H */ +diff --git a/include/sm/platform/pmp/enclave_mm.h b/include/sm/platform/pmp/enclave_mm.h +new file mode 100644 +index 0000000..cfcdb1f +--- /dev/null ++++ b/include/sm/platform/pmp/enclave_mm.h +@@ -0,0 +1,84 @@ ++#ifndef _ENCLAVE_MM_H ++#define _ENCLAVE_MM_H ++ ++#include ++#include ++#include ++#include ++ ++#define N_PMP_REGIONS (NPMP - 3) ++ ++#define REGION_TO_PMP(region_idx) (region_idx + 2) //from the 3rd to the N-1 regions ++#define PMP_TO_REGION(pmp_idx) (pmp_idx - 2) ++ ++/* ++ * Layout of free memory chunk ++ * | struct mm_list_head_t | struct mm_list_t | 00...0 | ++ * | struct mm_list_head_t | struct mm_list_t | 00...0 | ++ * | struct mm_list_head_t | struct mm_list_t | 00...0 | ++ */ ++struct mm_list_t ++{ ++ int order; ++ struct mm_list_t *prev_mm; ++ struct mm_list_t *next_mm; ++}; ++ ++struct mm_list_head_t ++{ ++ int order; ++ struct mm_list_head_t *prev_list_head; ++ struct mm_list_head_t *next_list_head; ++ struct mm_list_t *mm_list; ++}; ++ ++#define MM_LIST_2_PADDR(mm_list) ((void*)(mm_list) - sizeof(struct mm_list_head_t)) ++#define PADDR_2_MM_LIST(paddr) ((void*)(paddr) + sizeof(struct mm_list_head_t)) ++ ++struct mm_region_t ++{ ++ int valid; ++ uintptr_t paddr; ++ unsigned long size; ++ struct mm_list_head_t *mm_list_head; ++}; ++ ++#define region_overlap(pa0, size0, pa1, size1) (((pa0<=pa1) && ((pa0+size0)>pa1)) \ ++ || ((pa1<=pa0) && ((pa1+size1)>pa0))) ++ ++#define region_contain(pa0, size0, pa1, size1) (((unsigned long)(pa0) <= (unsigned long)(pa1)) \ ++ && (((unsigned long)(pa0) + (unsigned long)(size0)) >= ((unsigned long)(pa1) + (unsigned long)(size1)))) ++ ++uintptr_t copy_from_host(void* dest, void* src, size_t size); ++ ++uintptr_t copy_to_host(void* dest, void* src, size_t size); ++ ++int copy_word_to_host(unsigned int* ptr, uintptr_t value); ++ ++uintptr_t copy_from_enclave(pte_t *enclave_root_pt, void* dest_pa, void* src_enclave_va, size_t size); ++ ++uintptr_t copy_to_enclave(pte_t *enclave_root_pt, void* dest_enclave_va, void* src_pa, size_t size); ++ ++int check_enclave_pt(struct enclave_t *enclave); ++ ++int grant_kernel_access(void* paddr, unsigned long size); ++ ++int grant_enclave_access(struct enclave_t* enclave); ++ ++int retrieve_kernel_access(void* paddr, unsigned long size); ++ ++int retrieve_enclave_access(struct enclave_t *enclave); ++ ++uintptr_t mm_init(uintptr_t paddr, unsigned long size); ++ ++void* mm_alloc(unsigned long req_size, unsigned long* resp_size); ++ ++int mm_free(void* paddr, unsigned long size); ++ ++int memory_reclaim(unsigned long* resp_size); ++ ++int mm_free_clear(void* paddr, unsigned long size); ++ ++void print_buddy_system(); ++ ++#endif /* _ENCLAVE_MM_H */ +diff --git a/include/sm/platform/pmp/platform.h b/include/sm/platform/pmp/platform.h +new file mode 100644 +index 0000000..cb891e2 +--- /dev/null ++++ b/include/sm/platform/pmp/platform.h +@@ -0,0 +1,9 @@ ++#ifndef _PLATFORM_H ++#define _PLATFORM_H ++ ++#include "enclave_mm.h" ++#include "platform_thread.h" ++ ++int platform_init(); ++ ++#endif /* _PLATFORM_H */ +diff --git a/include/sm/platform/pmp/platform_thread.h b/include/sm/platform/pmp/platform_thread.h +new file mode 100644 +index 0000000..6fcf6ec +--- /dev/null ++++ b/include/sm/platform/pmp/platform_thread.h +@@ -0,0 +1,13 @@ ++#ifndef _PLATFORM_THREAD_H ++#define _PLATFORM_THREAD_H ++ ++#include ++ ++void platform_enter_enclave_world(); ++void platform_exit_enclave_world(); ++int platform_check_in_enclave_world(); ++int platform_check_enclave_authentication(struct enclave_t* enclave); ++void platform_switch_to_enclave_ptbr(struct thread_state_t* thread, uintptr_t ptbr); ++void platform_switch_to_host_ptbr(struct thread_state_t* thread, uintptr_t ptbr); ++ ++#endif /* _PLATFORM_THREAD_H */ +diff --git a/include/sm/platform/spmp/enclave_mm.h b/include/sm/platform/spmp/enclave_mm.h +new file mode 100644 +index 0000000..4ceb050 +--- /dev/null ++++ b/include/sm/platform/spmp/enclave_mm.h +@@ -0,0 +1,67 @@ ++#ifndef _ENCLAVE_MM_H ++#define _ENCLAVE_MM_H ++ ++#include ++#include ++#include ++ ++#define N_PMP_REGIONS (NPMP - 3) ++ ++#define REGION_TO_PMP(region_idx) (region_idx + 1) ++#define PMP_TO_REGION(pmp_idx) (pmp_idx - 1) ++ ++/* ++ * Layout of free memory chunk ++ * | struct mm_list_head_t | struct mm_list_t | 00...0 | ++ * | struct mm_list_head_t | struct mm_list_t | 00...0 | ++ * | struct mm_list_head_t | struct mm_list_t | 00...0 | ++ */ ++struct mm_list_t ++{ ++ int order; ++ struct mm_list_t *prev_mm; ++ struct mm_list_t *next_mm; ++}; ++ ++struct mm_list_head_t ++{ ++ int order; ++ struct mm_list_head_t *prev_list_head; ++ struct mm_list_head_t *next_list_head; ++ struct mm_list_t *mm_list; ++}; ++ ++#define MM_LIST_2_PADDR(mm_list) ((void*)(mm_list) - sizeof(struct mm_list_head_t)) ++#define PADDR_2_MM_LIST(paddr) ((void*)(paddr) + sizeof(struct mm_list_head_t)) ++ ++struct mm_region_t ++{ ++ int valid; ++ uintptr_t paddr; ++ unsigned long size; ++ struct mm_list_head_t *mm_list_head; ++}; ++ ++#define region_overlap(pa0, size0, pa1, size1) (((pa0<=pa1) && ((pa0+size0)>pa1)) \ ++ || ((pa1<=pa0) && ((pa1+size1)>pa0))) ++ ++#define region_contain(pa0, size0, pa1, size1) (((unsigned long)(pa0) <= (unsigned long)(pa1)) \ ++ && (((unsigned long)(pa0) + (unsigned long)(size0)) >= ((unsigned long)(pa1) + (unsigned long)(size1)))) ++ ++int grant_kernel_access(void* paddr, unsigned long size); ++ ++int grant_enclave_access(struct enclave_t* enclave); ++ ++int retrieve_kernel_access(void* paddr, unsigned long size); ++ ++int retrieve_enclave_access(struct enclave_t *enclave); ++ ++uintptr_t mm_init(uintptr_t paddr, unsigned long size); ++ ++void* mm_alloc(unsigned long req_size, unsigned long* resp_size); ++ ++int mm_free(void* paddr, unsigned long size); ++ ++void print_buddy_system(); ++ ++#endif /* _ENCLAVE_MM_H */ +diff --git a/include/sm/platform/spmp/ipi_handler.h b/include/sm/platform/spmp/ipi_handler.h +new file mode 100644 +index 0000000..cf662b5 +--- /dev/null ++++ b/include/sm/platform/spmp/ipi_handler.h +@@ -0,0 +1,6 @@ ++#ifndef _IPI_HANDLER_H ++#define _IPI_HANDLER_H ++ ++void handle_ipi_mail(); ++ ++#endif /* _IPI_HANDLER_H */ +diff --git a/include/sm/platform/spmp/platform.h b/include/sm/platform/spmp/platform.h +new file mode 100644 +index 0000000..d09353f +--- /dev/null ++++ b/include/sm/platform/spmp/platform.h +@@ -0,0 +1,11 @@ ++#ifndef _PLATFORM_H ++#define _PLATFORM_H ++ ++#include "spmp.h" ++#include "enclave_mm.h" ++#include "ipi_handler.h" ++#include "platform_thread.h" ++ ++int platform_init(); ++ ++#endif /* _PLATFORM_H */ +diff --git a/include/sm/platform/spmp/platform_thread.h b/include/sm/platform/spmp/platform_thread.h +new file mode 100644 +index 0000000..d1189a7 +--- /dev/null ++++ b/include/sm/platform/spmp/platform_thread.h +@@ -0,0 +1,18 @@ ++#ifndef _PLATFORM_THREAD_H ++#define _PLATFORM_THREAD_H ++ ++#include ++ ++void platform_enter_enclave_world(); ++ ++void platform_exit_enclave_world(); ++ ++int platform_check_in_enclave_world(); ++ ++int platform_check_enclave_authentication(struct enclave_t* enclave); ++ ++void platform_switch_to_enclave_ptbr(struct thread_state_t* thread, uintptr_t ptbr); ++ ++void platform_switch_to_host_ptbr(struct thread_state_t* thread, uintptr_t ptbr); ++ ++#endif /* _PLATFORM_THREAD_H */ +diff --git a/include/sm/platform/spmp/spmp.h b/include/sm/platform/spmp/spmp.h +new file mode 100644 +index 0000000..c92627d +--- /dev/null ++++ b/include/sm/platform/spmp/spmp.h +@@ -0,0 +1,85 @@ ++#ifndef _SPMP_H ++#define _SPMP_H ++#define SPMP_ENABLED ++ ++#include ++#include ++ ++//number of PMP registers ++#define NSPMP 8 ++ ++//R/W/X/A/L field in PMP configuration registers ++#define SPMP_R 0x01 ++#define SPMP_W 0x02 ++#define SPMP_X 0x04 ++#define SPMP_A 0x18 ++#define SPMP_L 0x80 ++ ++//encoding of A field in PMP configuration registers ++#define SPMP_TOR 0x08 ++#define SPMP_NA4 0x10 ++#define SPMP_NAPOT 0x18 ++#define SPMP_OFF 0x00 ++#define SPMP_NO_PERM 0 ++ ++//encoding of csr code ++#define spmpaddr0 0x1b0 ++#define spmpaddr1 0x1b1 ++#define spmpaddr2 0x1b2 ++#define spmpaddr3 0x1b3 ++#define spmpaddr4 0x1b4 ++#define spmpaddr5 0x1b5 ++#define spmpaddr6 0x1b6 ++#define spmpaddr7 0x1b7 ++#define spmpcfg0 0x1a0 ++ ++//set to 1 when spmp trap happened, remember to clear it after handle the trap ++#define spmpexpt 0x145 ++ ++//read spmpcfg & spmpaddr ++#define read_spmpcfg(pmpc) read_csr(pmpc) ++#define read_spmpaddr(addr) read_csr(addr) ++#define read_spmpexpt(r) read_csr(r) ++#define set_spmpexpt(r, v) write_csr(r, v) ++ ++//spmpfcg register's structure ++//|63 56|55 48|47 40|39 32|31 24|23 16|15 8|7 0| ++//|spmp7cfg|spmp6cfg|spmp5cfg|spmp4cfg|spmp3cfg|spmp2cfg|spmp1cfg|spmp1cfg| ++#define SPMP_PER_CFG_REG 8 ++#define SPMPCFG_BIT_NUM 8 ++#define SPMPCFG_BITS 0xFF ++ ++#define _SPMP_SET(n, g, addr, pmpc) do { \ ++ asm volatile ("la t0, 1f\n\t" \ ++ "csrrw t0, mtvec, t0\n\t" \ ++ "csrw "#n", %0\n\t" \ ++ "csrw "#g", %1\n\t" \ ++ "sfence.vma\n\t"\ ++ ".align 2\n\t" \ ++ "1: csrw mtvec, t0 \n\t" \ ++ : : "r" (addr), "r" (pmpc) : "t0"); \ ++} while(0) ++ ++#define _SPMP_READ(n, g, addr, pmpc) do { \ ++ asm volatile("csrr %0, "#n : "=r"(addr) :); \ ++ asm volatile("csrr %0, "#g : "=r"(pmpc) :); \ ++} while(0) ++ ++#define SPMP_SET(n, g, addr, pmpc) _SPMP_SET(n, g, addr, pmpc) ++#define SPMP_READ(n, g, addr, pmpc) _SPMP_READ(n, g, addr, pmpc) ++ ++struct spmp_config_t ++{ ++ uintptr_t paddr; ++ unsigned long size; ++ uintptr_t perm; ++ uintptr_t mode; ++}; ++ ++void set_spmp(int spmp_idx, struct spmp_config_t); ++ ++void clear_spmp(int spmp_idx); ++ ++struct spmp_config_t get_spmp(int spmp_idx); ++ ++#endif /* _SPMP_H */ +diff --git a/include/sm/pmp.h b/include/sm/pmp.h +new file mode 100644 +index 0000000..a88371f +--- /dev/null ++++ b/include/sm/pmp.h +@@ -0,0 +1,71 @@ ++#ifndef _PMP_H ++#define _PMP_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++//number of PMP registers ++#define NPMP 16 ++ ++#define PMP_OFF 0x00 ++#define PMP_NO_PERM 0 ++ ++//pmpfcg register's structure ++//|63 56|55 48|47 40|39 32|31 24|23 16|15 8|7 0| ++//| pmp7cfg | pmp6cfg | pmp5cfg | pmp4cfg | pmp3cfg | pmp2cfg | pmp1cfg | pmp1cfg | ++#define PMP_PER_CFG_REG 8 ++#define PMPCFG_BIT_NUM 8 ++#define PMPCFG_BITS 0xFF ++ ++#define PMP_SET(num, cfg_index, pmpaddr, pmpcfg) do { \ ++ uintptr_t oldcfg = csr_read(CSR_PMPCFG##cfg_index); \ ++ pmpcfg |= (oldcfg & ~((uintptr_t)PMPCFG_BITS << (uintptr_t)PMPCFG_BIT_NUM*(num%PMP_PER_CFG_REG))); \ ++ asm volatile ("la t0, 1f\n\t" \ ++ "csrrw t0, mtvec, t0\n\t" \ ++ "csrw pmpaddr"#num", %0\n\t" \ ++ "csrw pmpcfg"#cfg_index", %1\n\t" \ ++ "sfence.vma\n\t"\ ++ ".align 2\n\t" \ ++ "1: csrw mtvec, t0 \n\t" \ ++ : : "r" (pmpaddr), "r" (pmpcfg) : "t0"); \ ++} while(0) ++ ++#define PMP_READ(num, cfg_index, pmpaddr, pmpcfg) do { \ ++ asm volatile("csrr %0, pmpaddr"#num : "=r"(pmpaddr) :); \ ++ asm volatile("csrr %0, pmpcfg"#cfg_index : "=r"(pmpcfg) :); \ ++} while(0) ++ ++struct pmp_config_t ++{ ++ uintptr_t paddr; ++ unsigned long size; ++ uintptr_t perm; ++ uintptr_t mode; ++}; ++ ++struct pmp_data_t ++{ ++ struct pmp_config_t pmp_config_arg; ++ int pmp_idx_arg; ++ struct sbi_hartmask smask; ++}; ++ ++#define SBI_PMP_DATA_INIT(__ptr, __pmp_config_arg, __pmp_idx_arg, __src) \ ++do { \ ++ (__ptr)->pmp_config_arg = (__pmp_config_arg); \ ++ (__ptr)->pmp_idx_arg = (__pmp_idx_arg); \ ++ SBI_HARTMASK_INIT_EXCEPT(&(__ptr)->smask, (__src)); \ ++} while (0) ++ ++ ++void set_pmp_and_sync(int pmp_idx, struct pmp_config_t); ++void clear_pmp_and_sync(int pmp_idx); ++void set_pmp(int pmp_idx, struct pmp_config_t); ++void clear_pmp(int pmp_idx); ++struct pmp_config_t get_pmp(int pmp_idx); ++void dump_pmps(void); ++ ++#endif /* _PMP_H */ +diff --git a/include/sm/print.h b/include/sm/print.h +new file mode 100644 +index 0000000..18568dd +--- /dev/null ++++ b/include/sm/print.h +@@ -0,0 +1,15 @@ ++#ifndef SM_PRINT_H ++#define SM_PRINT_H ++ ++#include ++// #define PENGLAI_DEBUG ++#ifdef PENGLAI_DEBUG ++#define printm(...) sbi_printf(__VA_ARGS__) ++#else ++#define printm(...) ++#endif ++ ++//For report error messages, always enabled ++#define printm_err(...) sbi_printf(__VA_ARGS__) ++ ++#endif +diff --git a/include/sm/sm.h b/include/sm/sm.h +new file mode 100644 +index 0000000..d4f1d8d +--- /dev/null ++++ b/include/sm/sm.h +@@ -0,0 +1,101 @@ ++#ifndef _SM_H ++#define _SM_H ++ ++//#ifndef TARGET_PLATFORM_HEADER ++//#error "SM requires to specify a certain platform" ++//#endif ++ ++//#include TARGET_PLATFORM_HEADER ++#include ++#include ++#include ++#include ++ ++extern uintptr_t _fw_start[], _fw_end[]; ++ ++#define SM_BASE ((uintptr_t) _fw_start) ++#define SM_SIZE (((uintptr_t) _fw_end) - ((uintptr_t) _fw_start)) ++ ++#define MAX_HARTS 8 ++ ++//Host SBI numbers ++#define SBI_MM_INIT 100 ++#define SBI_CREATE_ENCLAVE 99 ++#define SBI_ATTEST_ENCLAVE 98 ++#define SBI_RUN_ENCLAVE 97 ++#define SBI_STOP_ENCLAVE 96 ++#define SBI_RESUME_ENCLAVE 95 ++#define SBI_DESTROY_ENCLAVE 94 ++#define SBI_ALLOC_ENCLAVE_MM 93 ++#define SBI_MEMORY_EXTEND 92 ++#define SBI_MEMORY_RECLAIM 91 ++#define SBI_FREE_ENCLAVE_MEM 90 ++#define SBI_DEBUG_PRINT 88 ++ ++//Enclave SBI numbers ++#define SBI_EXIT_ENCLAVE 99 ++#define SBI_ENCLAVE_OCALL 98 ++#define SBI_GET_KEY 88 ++ ++//Error code of SBI_ALLOC_ENCLAVE_MEM ++#define RETRY_SPIN_LOCK -3 ++#define ENCLAVE_NO_MEMORY -2 ++#define ENCLAVE_ERROR -1 ++#define ENCLAVE_SUCCESS 0 ++#define ENCLAVE_TIMER_IRQ 1 ++#define ENCLAVE_OCALL 2 ++ ++//ENCLAVE OCALL NUMBERS ++#define OCALL_SYS_WRITE 3 ++#define OCALL_USER_DEFINED 9 ++ ++//error code of SBI_RESUME_RNCLAVE ++#define RESUME_FROM_TIMER_IRQ 2000 ++#define RESUME_FROM_STOP 2003 ++#define RESUME_FROM_OCALL 2 ++ ++#define FLAG_DESTROY 0 ++#define DIRECT_DESTROY 1 ++#define FREE_MAX_MEMORY 2 ++#define FREE_SPEC_MEMORY 3 ++ ++#define RETRY_TIMES 5 ++ ++void sm_init(); ++ ++uintptr_t sm_mm_init(uintptr_t paddr, unsigned long size); ++ ++uintptr_t sm_mm_extend(uintptr_t paddr, unsigned long size); ++ ++uintptr_t sm_alloc_enclave_mem(uintptr_t mm_alloc_arg); ++ ++uintptr_t sm_free_enclave_mem(uintptr_t size_ptr,unsigned long flag); ++ ++uintptr_t sm_memory_reclaim(uintptr_t enclave_id, unsigned long eid); ++ ++uintptr_t sm_create_enclave(uintptr_t enclave_create_args, bool retry); ++ ++uintptr_t sm_attest_enclave(uintptr_t enclave_id, uintptr_t report, uintptr_t nonce); ++ ++uintptr_t sm_run_enclave(uintptr_t *regs, uintptr_t enclave_id); ++ ++uintptr_t sm_debug_print(uintptr_t *regs, uintptr_t enclave_id); ++ ++uintptr_t sm_stop_enclave(uintptr_t *regs, uintptr_t enclave_id); ++ ++uintptr_t sm_resume_enclave(uintptr_t *regs, uintptr_t enclave_id); ++ ++uintptr_t sm_destroy_enclave(uintptr_t *regs, uintptr_t enclave_id); ++ ++uintptr_t sm_enclave_ocall(uintptr_t *regs, uintptr_t ocall_func_id, uintptr_t arg0, uintptr_t arg1); ++ ++uintptr_t sm_enclave_get_key(uintptr_t* regs, uintptr_t salt_va, uintptr_t salt_len, ++ uintptr_t key_buf_va, uintptr_t key_buf_len); ++ ++uintptr_t sm_exit_enclave(uintptr_t *regs, unsigned long retval); ++ ++uintptr_t sm_do_timer_irq(uintptr_t *regs, uintptr_t mcause, uintptr_t mepc); ++ ++int check_in_enclave_world(); ++ ++#endif /* _SM_H */ +diff --git a/include/sm/thread.h b/include/sm/thread.h +new file mode 100644 +index 0000000..1d3db91 +--- /dev/null ++++ b/include/sm/thread.h +@@ -0,0 +1,86 @@ ++#ifndef __THREAD_H__ ++#define __THREAD_H__ ++ ++#include ++ ++//default layout of enclave ++//##################### ++//# reserved for # ++//# s mode # ++//##################### 0xffffffe000000000 ++//# hole # ++//##################### 0x0000004000000000 ++//# stack # ++//# # ++//# heap # ++//##################### 0x0000002000000000 ++//# untrusted memory # ++//# shared with host # ++//##################### 0x0000001000000000 ++//# code & data # ++//##################### 0x0000000000001000 ++//# hole # ++//##################### 0x0 ++ ++#define ENCLAVE_DEFAULT_STACK 0x0000004000000000; ++ ++#define N_GENERAL_REGISTERS 32 ++ ++struct general_registers_t ++{ ++ uintptr_t slot; ++ uintptr_t ra; ++ uintptr_t sp; ++ uintptr_t gp; ++ uintptr_t tp; ++ uintptr_t t0; ++ uintptr_t t1; ++ uintptr_t t2; ++ uintptr_t s0; ++ uintptr_t s1; ++ uintptr_t a0; ++ uintptr_t a1; ++ uintptr_t a2; ++ uintptr_t a3; ++ uintptr_t a4; ++ uintptr_t a5; ++ uintptr_t a6; ++ uintptr_t a7; ++ uintptr_t s2; ++ uintptr_t s3; ++ uintptr_t s4; ++ uintptr_t s5; ++ uintptr_t s6; ++ uintptr_t s7; ++ uintptr_t s8; ++ uintptr_t s9; ++ uintptr_t s10; ++ uintptr_t s11; ++ uintptr_t t3; ++ uintptr_t t4; ++ uintptr_t t5; ++ uintptr_t t6; ++}; ++ ++/* enclave thread state */ ++struct thread_state_t ++{ ++ uintptr_t encl_ptbr; ++ uintptr_t prev_stvec; ++ uintptr_t prev_mie; ++ uintptr_t prev_mideleg; ++ uintptr_t prev_medeleg; ++ uintptr_t prev_mepc; ++ uintptr_t prev_cache_binding; ++ struct general_registers_t prev_state; ++}; ++ ++/* swap previous and current thread states */ ++void swap_prev_state(struct thread_state_t* state, uintptr_t* regs); ++void swap_prev_mepc(struct thread_state_t* state, uintptr_t mepc); ++void swap_prev_stvec(struct thread_state_t* state, uintptr_t stvec); ++void swap_prev_cache_binding(struct thread_state_t* state, uintptr_t cache_binding); ++void swap_prev_mie(struct thread_state_t* state, uintptr_t mie); ++void swap_prev_mideleg(struct thread_state_t* state, uintptr_t mideleg); ++void swap_prev_medeleg(struct thread_state_t* state, uintptr_t medeleg); ++#endif /* thread */ +diff --git a/include/sm/utils.h b/include/sm/utils.h +new file mode 100644 +index 0000000..e3f2fab +--- /dev/null ++++ b/include/sm/utils.h +@@ -0,0 +1,10 @@ ++// See LICENSE for license details. ++ ++#ifndef _RISCV_SM_UTILS_H ++#define _RISCV_SM_UTILS_H ++ ++#include ++ ++void dump_pt(unsigned long *page_table, int level); ++ ++#endif +diff --git a/include/sm/vm.h b/include/sm/vm.h +new file mode 100644 +index 0000000..1293ff0 +--- /dev/null ++++ b/include/sm/vm.h +@@ -0,0 +1,45 @@ ++#ifndef _VM_H ++#define _VM_H ++ ++#include ++#include ++ ++#define MEGAPAGE_SIZE ((uintptr_t)(RISCV_PGSIZE << RISCV_PGLEVEL_BITS)) ++ ++#if __riscv_xlen == 64 ++ ++# define SATP_MODE_CHOICE INSERT_FIELD(0, SATP64_MODE, SATP_MODE_SV39) ++# define VA_BITS 39 ++# define GIGAPAGE_SIZE (MEGAPAGE_SIZE << RISCV_PGLEVEL_BITS) ++# define MSTATUS_SD MSTATUS64_SD ++# define SSTATUS_SD SSTATUS64_SD ++# define RISCV_PGLEVEL_BITS 9 ++# define SATP_MODE SATP64_MODE ++#else ++# define MSTATUS_SD MSTATUS32_SD ++# define SSTATUS_SD SSTATUS32_SD ++# define RISCV_PGLEVEL_BITS 10 ++# define SATP_MODE SATP32_MODE ++# define SATP_MODE_CHOICE INSERT_FIELD(0, SATP32_MODE, SATP_MODE_SV32) ++# define VA_BITS 32 ++#endif ++ ++typedef uintptr_t pte_t; ++extern pte_t* root_page_table; ++ ++static inline void flush_tlb() ++{ ++ asm volatile ("sfence.vma"); ++} ++ ++static inline pte_t pte_create(uintptr_t ppn, int type) ++{ ++ return (ppn << PTE_PPN_SHIFT) | PTE_V | type; ++} ++ ++static inline pte_t ptd_create(uintptr_t ppn) ++{ ++ return pte_create(ppn, PTE_V); ++} ++ ++#endif +diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk +index c774ebb..10bd9eb 100644 +--- a/lib/sbi/objects.mk ++++ b/lib/sbi/objects.mk +@@ -68,3 +68,31 @@ libsbi-objs-y += sbi_tlb.o + libsbi-objs-y += sbi_trap.o + libsbi-objs-y += sbi_unpriv.o + libsbi-objs-y += sbi_expected_trap.o ++libsbi-objs-y += sbi_pmp.o ++ ++## Add by Dong Du ++# The Penglai related files here ++libsbi-objs-y += sbi_ecall_penglai.o ++libsbi-objs-y += sm/enclave.o ++libsbi-objs-y += sm/pmp.o ++libsbi-objs-y += sm/sm.o ++libsbi-objs-y += sm/thread.o ++libsbi-objs-y += sm/utils.o ++libsbi-objs-y += sm/platform/pmp/platform.o ++libsbi-objs-y += sm/attest.o ++ ++libsbi-objs-y += sm/gm/miracl/mrcore.o ++libsbi-objs-y += sm/gm/miracl/mrarth0.o ++libsbi-objs-y += sm/gm/miracl/mrarth1.o ++libsbi-objs-y += sm/gm/miracl/mrarth2.o ++libsbi-objs-y += sm/gm/miracl/mrcurve.o ++libsbi-objs-y += sm/gm/miracl/mrxgcd.o ++libsbi-objs-y += sm/gm/miracl/mrarth3.o ++libsbi-objs-y += sm/gm/miracl/mrjack.o ++libsbi-objs-y += sm/gm/miracl/mrbits.o ++libsbi-objs-y += sm/gm/miracl/mrmonty.o ++libsbi-objs-y += sm/gm/miracl/mrrand.o ++libsbi-objs-y += sm/gm/miracl/mrsroot.o ++libsbi-objs-y += sm/gm/miracl/mrlucas.o ++libsbi-objs-y += sm/gm/SM2_sv.o ++libsbi-objs-y += sm/gm/SM3.o +diff --git a/lib/sbi/riscv_locks.c b/lib/sbi/riscv_locks.c +index acab776..1721f07 100644 +--- a/lib/sbi/riscv_locks.c ++++ b/lib/sbi/riscv_locks.c +@@ -7,6 +7,10 @@ + + #include + #include ++#include ++#include ++#define MAX_HARTS 8 ++volatile long waiting_for_spinlock[MAX_HARTS] = { 0 }; + + static inline bool spin_lock_unlocked(spinlock_t lock) + { +@@ -47,10 +51,14 @@ bool spin_trylock(spinlock_t *lock) + + void spin_lock(spinlock_t *lock) + { +- unsigned long inc = 1u << TICKET_SHIFT; ++ //for lock debug ++ unsigned long inc = 1u << TICKET_SHIFT; + unsigned long mask = 0xffffu; + u32 l0, tmp1, tmp2; ++ ulong hartid = csr_read(CSR_MHARTID); + ++ // 正在尝试获取锁之前标记 ++ waiting_for_spinlock[hartid] = 1; + __asm__ __volatile__( + /* Atomically increment the next ticket. */ + " amoadd.w.aqrl %0, %4, %3\n" +@@ -69,9 +77,13 @@ void spin_lock(spinlock_t *lock) + : "=&r"(l0), "=&r"(tmp1), "=&r"(tmp2), "+A"(*lock) + : "r"(inc), "r"(mask), "I"(TICKET_SHIFT) + : "memory"); ++ ++ waiting_for_spinlock[hartid] = 0; + } + + void spin_unlock(spinlock_t *lock) + { ++ ulong hartid = csr_read(CSR_MHARTID); ++ waiting_for_spinlock[hartid] = 0; + __smp_store_release(&lock->owner, lock->owner + 1); + } +diff --git a/lib/sbi/sbi_ecall.c b/lib/sbi/sbi_ecall.c +index 25dd78c..6caadea 100644 +--- a/lib/sbi/sbi_ecall.c ++++ b/lib/sbi/sbi_ecall.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include "sm/enclave.h" + + extern struct sbi_ecall_extension *sbi_ecall_exts[]; + extern unsigned long sbi_ecall_exts_size; +@@ -119,6 +120,16 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs) + if (ret == SBI_ETRAP) { + trap.epc = regs->mepc; + sbi_trap_redirect(regs, &trap); ++ } else if (extension_id == SBI_EXT_PENGLAI_HOST || ++ extension_id == SBI_EXT_PENGLAI_ENCLAVE) { ++ //FIXME: update the return value assignment when we update enclave side SBI routines ++ regs->a0 = out_val; ++ if (!is_0_1_spec){ ++ if(check_in_enclave_world() == -1){ ++ regs->a0 = ret; ++ regs->a1 = out_val; ++ } ++ } + } else { + if (ret < SBI_LAST_ERR) { + sbi_printf("%s: Invalid error %d for ext=0x%lx " +@@ -147,15 +158,47 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs) + int sbi_ecall_init(void) + { + int ret; +- struct sbi_ecall_extension *ext; +- unsigned long i; ++ // struct sbi_ecall_extension *ext; ++ // unsigned long i; + +- for (i = 0; i < sbi_ecall_exts_size; i++) { ++ /* for (i = 0; i < sbi_ecall_exts_size; i++) { + ext = sbi_ecall_exts[i]; + ret = sbi_ecall_register_extension(ext); + if (ret) + return ret; +- } +- ++ } */ ++ ret = sbi_ecall_register_extension(&ecall_time); ++ if (ret) ++ return ret; ++ ret = sbi_ecall_register_extension(&ecall_rfence); ++ if (ret) ++ return ret; ++ ret = sbi_ecall_register_extension(&ecall_ipi); ++ if (ret) ++ return ret; ++ ret = sbi_ecall_register_extension(&ecall_base); ++ if (ret) ++ return ret; ++ ret = sbi_ecall_register_extension(&ecall_hsm); ++ if (ret) ++ return ret; ++ ret = sbi_ecall_register_extension(&ecall_srst); ++ if (ret) ++ return ret; ++ ret = sbi_ecall_register_extension(&ecall_pmu); ++ if (ret) ++ return ret; ++ ret = sbi_ecall_register_extension(&ecall_legacy); ++ if (ret) ++ return ret; ++ ret = sbi_ecall_register_extension(&ecall_vendor); ++ if (ret) ++ return ret; ++ ret = sbi_ecall_register_extension(&ecall_penglai_host); ++ if (ret) ++ return ret; ++ ret = sbi_ecall_register_extension(&ecall_penglai_enclave); ++ if (ret) ++ return ret; + return 0; + } +diff --git a/lib/sbi/sbi_ecall_penglai.c b/lib/sbi/sbi_ecall_penglai.c +new file mode 100644 +index 0000000..2834e36 +--- /dev/null ++++ b/lib/sbi/sbi_ecall_penglai.c +@@ -0,0 +1,118 @@ ++/* ++ * Authors: ++ * Dong Du ++ * Erhu Feng <2748250768@qq.com> ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++// static spinlock_t sm_big_lock = SPIN_LOCK_INITIALIZER; ++ ++static int sbi_ecall_penglai_host_handler(unsigned long extid, unsigned long funcid, ++ const struct sbi_trap_regs *regs, unsigned long *out_val, ++ struct sbi_trap_info *out_trap) ++{ ++ uintptr_t ret = 0; ++ printm("[Penglai KModule@%u] %s invoked,funcid=%ld\r\n", ++ current_hartid(), __func__, funcid); ++ //csr_write(CSR_MEPC, regs->mepc + 4); ++ ((struct sbi_trap_regs *)regs)->mepc += 4; ++ // spin_lock(&sm_big_lock); ++ switch (funcid) { ++ // The following is the Penglai's Handler ++ case SBI_MM_INIT: ++ ret = sm_mm_init(regs->a0, regs->a1); ++ break; ++ case SBI_MEMORY_EXTEND: ++ ret = sm_mm_extend(regs->a0, regs->a1); ++ break; ++ case SBI_ALLOC_ENCLAVE_MM: ++ ret = sm_alloc_enclave_mem(regs->a0); ++ break; ++ case SBI_CREATE_ENCLAVE: ++ ret = sm_create_enclave(regs->a0, regs->a1); ++ break; ++ case SBI_RUN_ENCLAVE: ++ ret = sm_run_enclave((uintptr_t *)regs, regs->a0); ++ break; ++ case SBI_ATTEST_ENCLAVE: ++ ret = sm_attest_enclave(regs->a0, regs->a1, regs->a2); ++ break; ++ case SBI_STOP_ENCLAVE: ++ ret = sm_stop_enclave((uintptr_t *)regs, regs->a0); ++ break; ++ case SBI_RESUME_ENCLAVE: ++ ret = sm_resume_enclave((uintptr_t *)regs, regs->a0); ++ break; ++ case SBI_DESTROY_ENCLAVE: ++ ret = sm_destroy_enclave((uintptr_t *)regs, regs->a0); ++ break; ++ case SBI_MEMORY_RECLAIM: ++ ret=sm_memory_reclaim(regs->a0, regs->a1); ++ break; ++ case SBI_FREE_ENCLAVE_MEM: ++ ret= sm_free_enclave_mem(regs->a0, regs->a1); ++ break; ++ default: ++ sbi_printf("[Penglai@Monitor] host interface(funcid:%ld) not supported yet\n", funcid); ++ ret = SBI_ENOTSUPP; ++ } ++ //((struct sbi_trap_regs *)regs)->mepc = csr_read(CSR_MEPC); ++ //((struct sbi_trap_regs *)regs)->mstatus = csr_read(CSR_MSTATUS); ++ *out_val = ret; ++ // spin_unlock(&sm_big_lock); ++ printm("[Penglai KModule@%u] %s return %ld, funcid=%ld\r\n", ++ current_hartid(), __func__, ret, funcid); ++ return ret; ++} ++ ++struct sbi_ecall_extension ecall_penglai_host = { ++ .extid_start = SBI_EXT_PENGLAI_HOST, ++ .extid_end = SBI_EXT_PENGLAI_HOST, ++ .handle = sbi_ecall_penglai_host_handler, ++}; ++ ++static int sbi_ecall_penglai_enclave_handler(unsigned long extid, unsigned long funcid, ++ const struct sbi_trap_regs *regs, unsigned long *out_val, ++ struct sbi_trap_info *out_trap) ++{ ++ uintptr_t ret = 0; ++ // spin_lock(&sm_big_lock); ++ //csr_write(CSR_MEPC, regs->mepc + 4); ++ ((struct sbi_trap_regs *)regs)->mepc += 4; ++ printm("[Penglai KModule@%u] %s invoked,funcid=%ld\r\n", ++ current_hartid(), __func__, funcid); ++ switch (funcid) { ++ // The following is the Penglai's Handler ++ case SBI_EXIT_ENCLAVE://99 ++ ret = sm_exit_enclave((uintptr_t *)regs, regs->a0); ++ break; ++ case SBI_ENCLAVE_OCALL://98 ++ ret = sm_enclave_ocall((uintptr_t *)regs, regs->a0, regs->a1, regs->a2); ++ break; ++ case SBI_GET_KEY://88 ++ ret = sm_enclave_get_key((uintptr_t *)regs, regs->a0, regs->a1, regs->a2, regs->a3); ++ break; ++ default: ++ sbi_printf("[Penglai@Monitor] enclave interface(funcid:%ld) not supported yet\n", funcid); ++ ret = SBI_ENOTSUPP; ++ } ++ printm("[Penglai KModule@%u] %s return %ld,funcid=%ld\r\n", current_hartid(), __func__,ret , funcid); ++ // spin_unlock(&sm_big_lock); ++ *out_val = ret; ++ return ret; ++} ++ ++struct sbi_ecall_extension ecall_penglai_enclave = { ++ .extid_start = SBI_EXT_PENGLAI_ENCLAVE, ++ .extid_end = SBI_EXT_PENGLAI_ENCLAVE, ++ .handle = sbi_ecall_penglai_enclave_handler, ++}; +diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c +index 5447c52..f0de75f 100644 +--- a/lib/sbi/sbi_hart.c ++++ b/lib/sbi/sbi_hart.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + extern void __sbi_expected_trap(void); + extern void __sbi_expected_trap_hext(void); +@@ -755,6 +756,7 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1, + unsigned long next_addr, unsigned long next_mode, + bool next_virt) + { ++ printm("[Penglai Monitor] %s invoked\r\n",__func__); + #if __riscv_xlen == 32 + unsigned long val, valH; + #else +@@ -804,6 +806,8 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1, + csr_write(CSR_UIE, 0); + } + } ++ //Init Penglai SM here ++ sm_init(); + + register unsigned long a0 asm("a0") = arg0; + register unsigned long a1 asm("a1") = arg1; +diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c +index a8500e5..6808e59 100644 +--- a/lib/sbi/sbi_init.c ++++ b/lib/sbi/sbi_init.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + + #define BANNER \ +@@ -43,9 +44,9 @@ static void sbi_boot_print_banner(struct sbi_scratch *scratch) + return; + + #ifdef OPENSBI_VERSION_GIT +- sbi_printf("\nOpenSBI %s\n", OPENSBI_VERSION_GIT); ++ sbi_printf("\nOpenSBI %s (with Penglai TEE)\n", OPENSBI_VERSION_GIT); + #else +- sbi_printf("\nOpenSBI v%d.%d\n", OPENSBI_VERSION_MAJOR, ++ sbi_printf("\nOpenSBI v%d.%d (with Penglai TEE)\n", OPENSBI_VERSION_MAJOR, + OPENSBI_VERSION_MINOR); + #endif + +@@ -296,6 +297,14 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) + sbi_hart_hang(); + } + ++ /* Penglai PMP init for synchronize PMP settings among Harts */ ++ rc = sbi_pmp_init(scratch, TRUE); ++ if (rc) { ++ sbi_printf("%s: (penglai) pmp init failed (error %d)\n", __func__, rc); ++ sbi_hart_hang(); ++ } ++ ++ + rc = sbi_timer_init(scratch, TRUE); + if (rc) { + sbi_printf("%s: timer init failed (error %d)\n", __func__, rc); +@@ -321,6 +330,11 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) + sbi_hart_hang(); + } + ++ /* ++ * Note (DD): ++ * In our case, the PMP set by domain will be erased, as penglai ++ * will take control of PMP ++ * */ + rc = sbi_hart_pmp_configure(scratch); + if (rc) { + sbi_printf("%s: PMP configure failed (error %d)\n", +@@ -344,6 +358,8 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) + sbi_boot_print_domains(scratch); + + sbi_boot_print_hart(scratch, hartid); ++ ++ sbi_printf("[Penglai] Penglai Enclave Preparing\n"); + + wake_coldboot_harts(scratch, hartid); + +@@ -392,10 +408,21 @@ static void init_warm_startup(struct sbi_scratch *scratch, u32 hartid) + if (rc) + sbi_hart_hang(); + ++ rc = sbi_pmp_init(scratch, FALSE); ++ if (rc) { ++ sbi_printf("%s: (penglai) pmp init failed (error %d)\n", __func__, rc); ++ sbi_hart_hang(); ++ } ++ + rc = sbi_timer_init(scratch, FALSE); + if (rc) + sbi_hart_hang(); + ++ /* ++ * Note (DD): ++ * In our case, the PMP set by domain will be erased, as penglai ++ * will take control of PMP ++ * */ + rc = sbi_hart_pmp_configure(scratch); + if (rc) + sbi_hart_hang(); +diff --git a/lib/sbi/sbi_ipi.c b/lib/sbi/sbi_ipi.c +index 7aafbbd..5b40f53 100644 +--- a/lib/sbi/sbi_ipi.c ++++ b/lib/sbi/sbi_ipi.c +@@ -23,6 +23,9 @@ + #include + #include + ++volatile unsigned long wait_for_sync[MAX_HARTS] = { IPI_NONE }; ++volatile unsigned long skip_for_wait[MAX_HARTS][MAX_HARTS] = {{0}}; ++ + struct sbi_ipi_data { + unsigned long ipi_type; + }; +@@ -64,9 +67,10 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid, + atomic_raw_set_bit(event, &ipi_data->ipi_type); + smp_wmb(); + +- if (ipi_dev && ipi_dev->ipi_send) +- ipi_dev->ipi_send(remote_hartid); ++ if (ipi_dev && ipi_dev->ipi_send) { + ++ ipi_dev->ipi_send(remote_hartid); ++ } + sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_SENT); + + if (ipi_ops->sync) +diff --git a/lib/sbi/sbi_pmp.c b/lib/sbi/sbi_pmp.c +new file mode 100644 +index 0000000..ca33361 +--- /dev/null ++++ b/lib/sbi/sbi_pmp.c +@@ -0,0 +1,192 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAGIC_NUM 30; ++extern volatile unsigned long waiting_for_spinlock[MAX_HARTS]; ++extern volatile unsigned long wait_for_sync[MAX_HARTS]; ++extern volatile int skip_for_wait[MAX_HARTS][MAX_HARTS]; //slot: mark which rhart no reply ++extern volatile int print_m_mode; ++static unsigned long pmp_data_offset; ++static unsigned long pmp_sync_offset; ++static volatile u32 curr_skip_hartid =-1; //0:cur_remotehartid, 1:skip_hartid ++ ++ ++static void sbi_process_pmp(struct sbi_scratch *scratch) ++{ ++ struct pmp_data_t *data = sbi_scratch_offset_ptr(scratch, pmp_data_offset); ++ struct pmp_config_t pmp_config = *(struct pmp_config_t*)(data); ++ struct sbi_scratch *rscratch = NULL; ++ u32 rhartid; ++ unsigned long *pmp_sync = NULL; ++ int pmp_idx = data->pmp_idx_arg; ++ set_pmp(pmp_idx, pmp_config); ++ ++ ulong hartid = csr_read(CSR_MHARTID); ++ //sync ++ sbi_hartmask_for_each_hart(rhartid, &data->smask) { ++ rscratch = sbi_hartid_to_scratch(rhartid); ++ if (!rscratch) ++ continue; ++ if(print_m_mode && SYNC_DEBUG) sbi_printf("hart %ld process sync pmp\n", hartid); ++ pmp_sync = sbi_scratch_offset_ptr(rscratch, pmp_sync_offset); ++ if (skip_for_wait[rhartid][hartid] == 1) ++ { ++ *pmp_sync = 0; ++ if (SYNC_DEBUG) ++ sbi_printf("hart %ld no reply sync_pmp to %d\n", ++ hartid, rhartid); ++ skip_for_wait[rhartid][hartid] = 0; ++ continue; ++ } ++ ++ while (atomic_raw_xchg_ulong(pmp_sync, 1)); ++ } ++} ++ ++static int sbi_update_pmp(struct sbi_scratch *scratch, ++ struct sbi_scratch *remote_scratch, ++ u32 remote_hartid, void *data) ++{ ++ struct pmp_data_t *pmp_data = NULL; ++ int pmp_idx = 0; ++ u32 curr_hartid = current_hartid(); ++ ++ if (remote_hartid == curr_hartid) { ++ //update the pmp register locally ++ struct pmp_config_t pmp_config = *(struct pmp_config_t*)(data); ++ pmp_idx = ((struct pmp_data_t *)data)->pmp_idx_arg; ++ set_pmp(pmp_idx, pmp_config); ++ return -1; ++ } ++ ++ wait_for_sync[curr_hartid] = IPI_PMP; ++ curr_skip_hartid = remote_hartid; ++ pmp_data = sbi_scratch_offset_ptr(remote_scratch, pmp_data_offset); ++ //update the remote hart pmp data ++ sbi_memcpy(pmp_data, data, sizeof(struct pmp_data_t)); ++ ++ return 0; ++} ++ ++static void sbi_pmp_sync(struct sbi_scratch *scratch) ++{ ++ unsigned long *pmp_sync = ++ sbi_scratch_offset_ptr(scratch, pmp_sync_offset); ++ ulong hartid = csr_read(CSR_MHARTID); ++ wait_for_sync[hartid] = IPI_PMP; ++ ++ u32 remote_hartid = curr_skip_hartid; ++ ++ // if (remote_hartid != -1UL && (wait_for_sync[remote_hartid] == IPI_TLB || wait_for_sync[remote_hartid] == IPI_PMP)){ ++ if (remote_hartid != -1 && (wait_for_sync[remote_hartid] == IPI_TLB || waiting_for_spinlock[remote_hartid] == 1)){ ++ if (SYNC_DEBUG) ++ sbi_printf("hart %ld skip wait %u sync pmp\n", hartid, ++ remote_hartid); ++ curr_skip_hartid = -1; ++ atomic_raw_xchg_ulong(pmp_sync, 0); ++ skip_for_wait[hartid][remote_hartid] = 1; ++ } else { ++ if (SYNC_DEBUG) ++ sbi_printf("hart %ld wait %d sync pmp\n", hartid, ++ curr_skip_hartid); ++ //wait the remote hart process the pmp signal ++ int retry = MAGIC_NUM; ++ while (!atomic_raw_xchg_ulong(pmp_sync, 0)) { ++ /** ++ * This is used to handle the situation ++ * where the remote enters m mode before ++ * sending pmp sync, and the remote is in spin ++ * lock after sending ipi. ++ */ ++ retry--; ++ if (retry == 0) { ++ retry = MAGIC_NUM; ++ if (remote_hartid != -1 && ++ (wait_for_sync[remote_hartid] == IPI_TLB || ++ waiting_for_spinlock[remote_hartid] == 1)) { ++ if (SYNC_DEBUG) ++ sbi_printf( ++ "hart %ld skip wait %u sync pmp\n", ++ hartid, remote_hartid); ++ curr_skip_hartid = -1; ++ atomic_raw_xchg_ulong(pmp_sync, 0); ++ skip_for_wait[hartid][remote_hartid] = 1; ++ break; ++ } ++ } ++ if (SYNC_DEBUG) ++ sbi_printf("hart %ld wait %u sync pmp\n", ++ hartid, remote_hartid); ++ }; ++ } ++ wait_for_sync[hartid] = IPI_NONE; ++ return; ++} ++ ++static struct sbi_ipi_event_ops pmp_ops = { ++ .name = "IPI_PMP", ++ .update = sbi_update_pmp, ++ .sync = sbi_pmp_sync, ++ .process = sbi_process_pmp, ++}; ++ ++static u32 pmp_event = SBI_IPI_EVENT_MAX; ++ ++int sbi_send_pmp(ulong hmask, ulong hbase, struct pmp_data_t* pmp_data) ++{ ++ ulong hartid = csr_read(CSR_MHARTID); ++ wait_for_sync[hartid] = IPI_PMP; ++ if (SYNC_DEBUG) ++ sbi_printf("hart %ld begin sync pmp\n", hartid); ++ return sbi_ipi_send_many(hmask, hbase, pmp_event, pmp_data); ++} ++ ++int sbi_pmp_init(struct sbi_scratch *scratch, bool cold_boot) ++{ ++ int ret; ++ struct pmp_data_t *pmpdata; ++ unsigned long *pmp_sync; ++ ++ if (cold_boot) { ++ //Define the pmp data offset in the scratch ++ pmp_data_offset = sbi_scratch_alloc_offset(sizeof(*pmpdata)); ++ if (!pmp_data_offset) ++ return SBI_ENOMEM; ++ ++ pmp_sync_offset = sbi_scratch_alloc_offset(sizeof(*pmp_sync)); ++ if (!pmp_sync_offset) ++ return SBI_ENOMEM; ++ ++ pmpdata = sbi_scratch_offset_ptr(scratch, ++ pmp_data_offset); ++ ++ pmp_sync = sbi_scratch_offset_ptr(scratch, ++ pmp_sync_offset); ++ ++ *pmp_sync = 0; ++ ++ ret = sbi_ipi_event_create(&pmp_ops); ++ if (ret < 0) { ++ sbi_scratch_free_offset(pmp_data_offset); ++ return ret; ++ } ++ pmp_event = ret; ++ } else { ++ //do nothing for warmboot ++ } ++ ++ return 0; ++} +diff --git a/lib/sbi/sbi_tlb.c b/lib/sbi/sbi_tlb.c +index 4c142ea..96dce3f 100644 +--- a/lib/sbi/sbi_tlb.c ++++ b/lib/sbi/sbi_tlb.c +@@ -23,6 +23,9 @@ + #include + #include + ++extern volatile unsigned long wait_for_sync[MAX_HARTS]; ++extern volatile int print_m_mode; ++ + static unsigned long tlb_sync_off; + static unsigned long tlb_fifo_off; + static unsigned long tlb_fifo_mem_off; +@@ -260,6 +263,10 @@ static void tlb_sync(struct sbi_scratch *scratch) + unsigned long *tlb_sync = + sbi_scratch_offset_ptr(scratch, tlb_sync_off); + ++ ulong hartid = csr_read(CSR_MHARTID); ++ wait_for_sync[hartid] = IPI_TLB; ++ ++ + while (!atomic_raw_xchg_ulong(tlb_sync, 0)) { + /* + * While we are waiting for remote hart to set the sync, +@@ -268,6 +275,9 @@ static void tlb_sync(struct sbi_scratch *scratch) + tlb_process_count(scratch, 1); + } + ++// no_wait: ++ wait_for_sync[hartid] = IPI_NONE; ++ if(print_m_mode && SYNC_DEBUG) sbi_printf("hart %ld wait sync_tlb success!\n", hartid); + return; + } + +@@ -365,6 +375,7 @@ static int tlb_update(struct sbi_scratch *scratch, + tinfo->local_fn(tinfo); + return -1; + } ++ wait_for_sync[curr_hartid] = IPI_TLB; + + tlb_fifo_r = sbi_scratch_offset_ptr(remote_scratch, tlb_fifo_off); + +@@ -372,7 +383,8 @@ static int tlb_update(struct sbi_scratch *scratch, + if (ret != SBI_FIFO_UNCHANGED) { + return 1; + } +- ++ ulong hartid = csr_read(CSR_MHARTID); ++ if(SYNC_DEBUG) sbi_printf("hart %ld begin wait %d sync_tlb\n", hartid, remote_hartid); + while (sbi_fifo_enqueue(tlb_fifo_r, data) < 0) { + /** + * For now, Busy loop until there is space in the fifo. +@@ -405,7 +417,9 @@ int sbi_tlb_request(ulong hmask, ulong hbase, struct sbi_tlb_info *tinfo) + return SBI_EINVAL; + + tlb_pmu_incr_fw_ctr(tinfo); +- ++ ulong hartid = csr_read(CSR_MHARTID); ++ if(print_m_mode && SYNC_DEBUG) sbi_printf("hart %ld begin sync tlb\n", hartid); ++ wait_for_sync[hartid] = IPI_TLB; + return sbi_ipi_send_many(hmask, hbase, tlb_event, tinfo); + } + +diff --git a/lib/sbi/sbi_trap.c b/lib/sbi/sbi_trap.c +index c875c90..4a7ff93 100644 +--- a/lib/sbi/sbi_trap.c ++++ b/lib/sbi/sbi_trap.c +@@ -23,6 +23,11 @@ + #include + #include + ++#include ++ ++int m_mode_status[MAX_HARTS]; ++volatile int print_m_mode = 0; ++ + static void __noreturn sbi_trap_error(const char *msg, int rc, + ulong mcause, ulong mtval, ulong mtval2, + ulong mtinst, struct sbi_trap_regs *regs) +@@ -198,7 +203,7 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs, + return 0; + } + +-static int sbi_trap_nonaia_irq(struct sbi_trap_regs *regs, ulong mcause) ++/* static int sbi_trap_nonaia_irq(struct sbi_trap_regs *regs, ulong mcause) + { + mcause &= ~(1UL << (__riscv_xlen - 1)); + switch (mcause) { +@@ -215,9 +220,9 @@ static int sbi_trap_nonaia_irq(struct sbi_trap_regs *regs, ulong mcause) + }; + + return 0; +-} ++} */ + +-static int sbi_trap_aia_irq(struct sbi_trap_regs *regs, ulong mcause) ++/* static int sbi_trap_aia_irq(struct sbi_trap_regs *regs, ulong mcause) + { + int rc; + unsigned long mtopi; +@@ -242,7 +247,7 @@ static int sbi_trap_aia_irq(struct sbi_trap_regs *regs, ulong mcause) + } + + return 0; +-} ++} */ + + /** + * Handle trap/interrupt +@@ -272,18 +277,33 @@ struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs) + mtval2 = csr_read(CSR_MTVAL2); + mtinst = csr_read(CSR_MTINST); + } ++ int hartid = csr_read(CSR_MHARTID); ++ m_mode_status[hartid] = 1; + + if (mcause & (1UL << (__riscv_xlen - 1))) { +- if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(), +- SBI_HART_EXT_SMAIA)) +- rc = sbi_trap_aia_irq(regs, mcause); +- else +- rc = sbi_trap_nonaia_irq(regs, mcause); +- if (rc) { +- msg = "unhandled local interrupt"; ++ mcause &= ~(1UL << (__riscv_xlen - 1)); ++ switch (mcause) { ++ case IRQ_M_TIMER: ++ if (check_in_enclave_world() >= 0) { //handle timer for enclaves ++ sm_do_timer_irq((uintptr_t *)regs, mcause, regs->mepc); ++ }else{ ++ sbi_timer_process(); ++ } ++ break; ++ case IRQ_M_SOFT: ++ sbi_ipi_process(); ++ break; ++ case IRQ_M_EXT: ++ rc = sbi_irqchip_process(regs); ++ if (rc) ++ goto trap_error; ++ default: ++ msg = "unhandled external interrupt"; + goto trap_error; +- } +- return regs; ++ }; ++ hartid = csr_read(CSR_MHARTID); ++ m_mode_status[hartid] = 0; ++ return regs; + } + + switch (mcause) { +@@ -299,8 +319,18 @@ struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs) + rc = sbi_misaligned_store_handler(mtval, mtval2, mtinst, regs); + msg = "misaligned store handler failed"; + break; ++ case CAUSE_USER_ECALL: ++ //The only case for USER_ECALL is issued by Penglai Enclave now ++ if (check_in_enclave_world() <0) { ++ sbi_printf("[Penglai] Error, user ecall not in enclaves\n"); ++ rc = -1; ++ break; ++ } else {// continue to sbi_ecall_handler ++ //sbi_printf("[Penglai] ecall from enclaves\n"); ++ } + case CAUSE_SUPERVISOR_ECALL: + case CAUSE_MACHINE_ECALL: ++ + rc = sbi_ecall_handler(regs); + msg = "ecall handler failed"; + break; +@@ -325,6 +355,8 @@ struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs) + trap_error: + if (rc) + sbi_trap_error(msg, rc, mcause, mtval, mtval2, mtinst, regs); ++ hartid = csr_read(CSR_MHARTID); ++ m_mode_status[hartid] = 0; + return regs; + } + +diff --git a/lib/sbi/sm/.gitignore b/lib/sbi/sm/.gitignore +new file mode 100644 +index 0000000..751553b +--- /dev/null ++++ b/lib/sbi/sm/.gitignore +@@ -0,0 +1 @@ ++*.bak +diff --git a/lib/sbi/sm/attest.c b/lib/sbi/sm/attest.c +new file mode 100644 +index 0000000..2d959fc +--- /dev/null ++++ b/lib/sbi/sm/attest.c +@@ -0,0 +1,145 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int hash_enclave_mem(SM3_STATE *hash_ctx, pte_t* ptes, int level, ++ uintptr_t va, int hash_va) ++{ ++ uintptr_t pte_per_page = RISCV_PGSIZE/sizeof(pte_t); ++ pte_t *pte; ++ uintptr_t i = 0; ++ int hash_curr_va = hash_va; ++ ++ //should never happen ++ if(level <= 0) ++ return 1; ++ ++ for(pte = ptes, i = 0; i < pte_per_page; pte += 1, i += 1) ++ { ++ if(!(*pte & PTE_V)) ++ { ++ hash_curr_va = 1; ++ continue; ++ } ++ ++ uintptr_t curr_va = 0; ++ if(level == ((VA_BITS - RISCV_PGSHIFT) / RISCV_PGLEVEL_BITS)) ++ curr_va = (uintptr_t)(-1UL << VA_BITS) + ++ (i << (VA_BITS - RISCV_PGLEVEL_BITS)); ++ else ++ curr_va = va + ++ (i << ((level-1) * RISCV_PGLEVEL_BITS + RISCV_PGSHIFT)); ++ uintptr_t pa = (*pte >> PTE_PPN_SHIFT) << RISCV_PGSHIFT; ++ ++ //found leaf pte ++ if((*pte & PTE_R) || (*pte & PTE_X)) ++ { ++ if(hash_curr_va) ++ { ++ SM3_process(hash_ctx, (unsigned char*)&curr_va, ++ sizeof(uintptr_t)); ++ //update hash with page attribution ++ SM3_process(hash_ctx, (unsigned char*)pte, 1); ++ hash_curr_va = 0; ++ } ++ ++ //4K page ++ if(level == 1) ++ { ++ SM3_process(hash_ctx, (void*)pa, 1 << RISCV_PGSHIFT); ++ } ++ //2M page ++ else if(level == 2) ++ { ++ SM3_process(hash_ctx, (void*)pa, ++ 1 << (RISCV_PGSHIFT + RISCV_PGLEVEL_BITS)); ++ } ++ } ++ else ++ { ++ hash_curr_va = hash_enclave_mem(hash_ctx, (pte_t*)pa, level - 1, ++ curr_va, hash_curr_va); ++ } ++ } ++ ++ return hash_curr_va; ++} ++ ++void hash_enclave(struct enclave_t *enclave, void* hash, uintptr_t nonce_arg) ++{ ++ SM3_STATE hash_ctx; ++ uintptr_t nonce = nonce_arg; ++ ++ SM3_init(&hash_ctx); ++ ++ // entry point ++ SM3_process(&hash_ctx, (unsigned char*)(&(enclave->entry_point)), ++ sizeof(unsigned long)); ++ // configuration parameters ++ SM3_process(&hash_ctx, (unsigned char*)(&(enclave->untrusted_ptr)), ++ sizeof(unsigned long)); ++ SM3_process(&hash_ctx, (unsigned char*)(&(enclave->untrusted_size)), ++ sizeof(unsigned long)); ++ SM3_process(&hash_ctx, (unsigned char*)(&(enclave->kbuffer)), ++ sizeof(unsigned long)); ++ SM3_process(&hash_ctx, (unsigned char*)(&(enclave->kbuffer_size)), ++ sizeof(unsigned long)); ++ hash_enclave_mem( ++ &hash_ctx, ++ (pte_t*)(enclave->thread_context.encl_ptbr << RISCV_PGSHIFT), ++ (VA_BITS - RISCV_PGSHIFT) / RISCV_PGLEVEL_BITS, 0, 1 ++ ); ++ SM3_process(&hash_ctx, (unsigned char*)(&nonce), sizeof(uintptr_t)); ++ SM3_done(&hash_ctx, hash); ++} ++ ++void update_enclave_hash(char *output, void* hash, uintptr_t nonce_arg) ++{ ++ SM3_STATE hash_ctx; ++ uintptr_t nonce = nonce_arg; ++ ++ SM3_init(&hash_ctx); ++ SM3_process(&hash_ctx, (unsigned char*)(hash), HASH_SIZE); ++ SM3_process(&hash_ctx, (unsigned char*)(&nonce), sizeof(uintptr_t)); ++ SM3_done(&hash_ctx, hash); ++ ++ sbi_memcpy(output, hash, HASH_SIZE); ++} ++ ++// initailize Secure Monitor's private key and public key. ++void attest_init() ++{ ++ int i; ++ struct prikey_t *sm_prikey = (struct prikey_t *)SM_PRI_KEY; ++ struct pubkey_t *sm_pubkey = (struct pubkey_t *)SM_PUB_KEY; ++ ++ i = SM2_Init(); ++ if(i) ++ printm("SM2_Init failed with ret value: %d\n", i); ++ ++ i = SM2_KeyGeneration(sm_prikey->dA, sm_pubkey->xA, sm_pubkey->yA); ++ if(i) ++ printm("SM2_KeyGeneration failed with ret value: %d\n", i); ++} ++ ++void sign_enclave(void* signature_arg, unsigned char *message, int len) ++{ ++ struct signature_t *signature = (struct signature_t*)signature_arg; ++ struct prikey_t *sm_prikey = (struct prikey_t *)SM_PRI_KEY; ++ ++ SM2_Sign(message, len, sm_prikey->dA, (unsigned char *)(signature->r), ++ (unsigned char *)(signature->s)); ++} ++ ++int verify_enclave(void* signature_arg, unsigned char *message, int len) ++{ ++ int ret = 0; ++ struct signature_t *signature = (struct signature_t*)signature_arg; ++ struct pubkey_t *sm_pubkey = (struct pubkey_t *)SM_PUB_KEY; ++ ret = SM2_Verify(message, len, sm_pubkey->xA, sm_pubkey->yA, ++ (unsigned char *)(signature->r), (unsigned char *)(signature->s)); ++ return ret; ++} +diff --git a/lib/sbi/sm/enclave.c b/lib/sbi/sm/enclave.c +new file mode 100644 +index 0000000..b730315 +--- /dev/null ++++ b/lib/sbi/sm/enclave.c +@@ -0,0 +1,1126 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static struct cpu_state_t cpus[MAX_HARTS] = {{0,}, }; ++static volatile int eids_num = 0; ++//spinlock ++static spinlock_t enclave_metadata_lock = SPIN_LOCK_INITIALIZER; ++ ++//enclave metadata ++struct link_mem_t* enclave_metadata_head = NULL; ++struct link_mem_t* enclave_metadata_tail = NULL; ++ ++void acquire_big_metadata_lock(const char * str) ++{ ++ if (LOCK_DEBUG) ++ printm("[PENGLAI SM@%s_%d] %s try lock\n", __func__, current_hartid(), str); ++ spin_lock(&enclave_metadata_lock); ++ if (LOCK_DEBUG) ++ printm("[PENGLAI SM@%s_%d] %s get lock\n", __func__, current_hartid(), str); ++} ++bool try_big_metadata_lock(const char * str) ++{ ++ //spin_lock(&enclave_metadata_lock); ++ bool res; ++ res=spin_trylock(&enclave_metadata_lock); ++ if (LOCK_DEBUG) ++ printm("[PENGLAI SM@%s_%d] %s try get lock,res=%d\n", __func__, current_hartid(), str, res); ++ return res; ++} ++ ++void release_big_metadata_lock(const char *str) ++{ ++ spin_unlock(&enclave_metadata_lock); ++ if (LOCK_DEBUG) ++ printm("[PENGLAI SM@%s %d] %s release lock\n", __func__, current_hartid(), str); ++} ++ ++static void enter_enclave_world(int eid) ++{ ++ cpus[csr_read(CSR_MHARTID)].in_enclave = ENCLAVE_MODE; ++ cpus[csr_read(CSR_MHARTID)].eid = eid; ++ ++ platform_enter_enclave_world(); ++} ++ ++static int get_enclave_id() ++{ ++ return cpus[csr_read(CSR_MHARTID)].eid; ++} ++ ++static void exit_enclave_world() ++{ ++ cpus[csr_read(CSR_MHARTID)].in_enclave = 0; ++ cpus[csr_read(CSR_MHARTID)].eid = -1; ++ ++ platform_exit_enclave_world(); ++} ++ ++int check_in_enclave_world() ++{ ++ if(!(cpus[csr_read(CSR_MHARTID)].in_enclave)) ++ return -1; ++ ++ if(platform_check_in_enclave_world() < 0) ++ return -1; ++ ++ return 0; ++} ++ ++static int check_enclave_authentication(struct enclave_t* enclave) ++{ ++ if(platform_check_enclave_authentication(enclave) < 0) ++ return -1; ++ ++ return 0; ++} ++ ++static void switch_to_enclave_ptbr(struct thread_state_t* thread, uintptr_t ptbr) ++{ ++ platform_switch_to_enclave_ptbr(thread, ptbr); ++} ++ ++static void switch_to_host_ptbr(struct thread_state_t* thread, uintptr_t ptbr) ++{ ++ platform_switch_to_host_ptbr(thread, ptbr); ++} ++ ++struct link_mem_t* init_mem_link(unsigned long mem_size, unsigned long slab_size) ++{ ++ struct link_mem_t* head; ++ ++ head = (struct link_mem_t*)mm_alloc(mem_size, NULL); ++ ++ if (head == NULL) ++ return NULL; ++ else ++ sbi_memset((void*)head, 0, mem_size); ++ ++ head->mem_size = mem_size; ++ head->slab_size = slab_size; ++ head->slab_num = (mem_size - sizeof(struct link_mem_t)) / slab_size; ++ void* align_addr = (char*)head + sizeof(struct link_mem_t); ++ head->addr = (char*)size_up_align((unsigned long)align_addr, slab_size); ++ head->next_link_mem = NULL; ++ ++ return head; ++} ++ ++struct link_mem_t* add_link_mem(struct link_mem_t** tail) ++{ ++ struct link_mem_t* new_link_mem; ++ ++ new_link_mem = (struct link_mem_t*)mm_alloc((*tail)->mem_size, NULL); ++ ++ if (new_link_mem == NULL) ++ return NULL; ++ else ++ sbi_memset((void*)new_link_mem, 0, (*tail)->mem_size); ++ ++ (*tail)->next_link_mem = new_link_mem; ++ new_link_mem->mem_size = (*tail)->mem_size; ++ new_link_mem->slab_num = (*tail)->slab_num; ++ new_link_mem->slab_size = (*tail)->slab_size; ++ void* align_addr = (char*)new_link_mem + sizeof(struct link_mem_t); ++ new_link_mem->addr = (char*)size_up_align((unsigned long)align_addr, (*tail)->slab_size); ++ new_link_mem->next_link_mem = NULL; ++ ++ return new_link_mem; ++} ++ ++int remove_link_mem(struct link_mem_t** head, struct link_mem_t* ptr, bool clear) ++{ ++ struct link_mem_t *cur_link_mem, *tmp_link_mem; ++ int retval =0; ++ ++ cur_link_mem = *head; ++ if (cur_link_mem == ptr) ++ { ++ *head = cur_link_mem->next_link_mem; ++ if (clear) ++ { ++ mm_free_clear(cur_link_mem, cur_link_mem->mem_size); ++ }else{ ++ mm_free(cur_link_mem, cur_link_mem->mem_size); ++ } ++ return 1; ++ } ++ ++ for (cur_link_mem = *head; cur_link_mem != NULL; cur_link_mem = cur_link_mem->next_link_mem) ++ { ++ if (cur_link_mem->next_link_mem == ptr) ++ { ++ tmp_link_mem = cur_link_mem->next_link_mem; ++ cur_link_mem->next_link_mem = cur_link_mem->next_link_mem->next_link_mem; ++ //FIXME ++ if (clear) ++ { ++ mm_free_clear(tmp_link_mem, tmp_link_mem->mem_size); ++ }else{ ++ mm_free(tmp_link_mem, tmp_link_mem->mem_size); ++ } ++ return retval; ++ } ++ } ++ ++ return retval; ++} ++ ++/* ++ * alloc an enclave struct now, which is zeroed ++ * Note: do not acquire metadata lock before the function! ++ * */ ++static struct enclave_t* alloc_enclave() ++{ ++ struct link_mem_t *cur, *next; ++ struct enclave_t* enclave = NULL; ++ int i, found, eid; ++ ++ acquire_big_metadata_lock(__func__); ++ ++ //enclave metadata list hasn't be initialized yet ++ if(enclave_metadata_head == NULL) ++ { ++ enclave_metadata_head = init_mem_link(ENCLAVE_METADATA_REGION_SIZE, sizeof(struct enclave_t)); ++ if(!enclave_metadata_head) ++ { ++ printm("[Penglai Monitor@%s] don't have enough mem\r\n", __func__); ++ goto alloc_eid_out; ++ } ++ enclave_metadata_tail = enclave_metadata_head; ++ } ++ ++ found = 0; ++ eid = 0; ++ for(cur = enclave_metadata_head; cur != NULL; cur = cur->next_link_mem) ++ { ++ for(i = 0; i < (cur->slab_num); i++) ++ { ++ enclave = (struct enclave_t*)(cur->addr) + i; ++ if(enclave->state == INVALID) ++ { ++ sbi_memset((void*)enclave, 0, sizeof(struct enclave_t)); ++ enclave->state = FRESH; ++ enclave->eid = eid; ++ found = 1; ++ break; ++ } ++ eid++; ++ } ++ if(found) ++ break; ++ } ++ ++ //don't have enough enclave metadata ++ if(!found) ++ { ++ next = add_link_mem(&enclave_metadata_tail); ++ if(next == NULL) ++ { ++ printm("[Penglai Monitor@%s] don't have enough mem\r\n", __func__); ++ enclave = NULL; ++ goto alloc_eid_out; ++ } ++ enclave = (struct enclave_t*)(next->addr); ++ sbi_memset((void*)enclave, 0, sizeof(struct enclave_t)); ++ enclave->state = FRESH; ++ enclave->eid = eid; ++ } ++ //add to eids_num for recycle ++ eids_num += 1; ++ ++alloc_eid_out: ++ release_big_metadata_lock(__func__); ++ return enclave; ++} ++ ++uintptr_t free_enclave_metadata() ++{ ++ int ret_val; ++ int eids_tmp; ++ struct link_mem_t *cur; ++ // struct enclave_t *enclave = NULL; ++ printm("[Penglai Monitor@%s] invoked\n", __func__); ++ ret_val = 0; ++ eids_tmp = eids_num; ++ for (cur = enclave_metadata_head; cur != NULL; ++ cur = cur->next_link_mem) { ++ struct enclave_t *check_enclave = NULL; ++ for (size_t i = 0; i < cur->slab_num; i++) { ++ check_enclave = (struct enclave_t *)(cur->addr) + i; ++ if (!check_enclave) { ++ printm("[Penglai Monitor@%s] don't have enclave_metadata in cur\r\n", ++ __func__); ++ ret_val = -1; ++ return ret_val; ++ }; ++ if (check_enclave->state == FRESH) { ++ break; ++ } ++ ++ if (check_enclave->state == INVALID) { ++ if (check_enclave->eid == (unsigned int)(-1)) { ++ eids_tmp--; ++ } ++ //all eids or eids in cur are invalid, free cur ++ if ((i == (cur->slab_num - 1)) || ++ eids_tmp == 0) { ++ struct link_mem_t *tmp = cur; ++ cur = cur->next_link_mem; ++ remove_link_mem(&enclave_metadata_head, ++ tmp, 1); ++ eids_num = eids_tmp; ++ break; ++ } else { ++ continue; ++ } ++ } else if (check_enclave->state != INVALID) { ++ printm("[Penglai Monitor@%s]enclave %ld is in use\n", ++ __func__, i); ++ break; ++ } ++ } ++ if (cur == NULL) { ++ break; ++ } ++ } ++ print_buddy_system(); ++ return 0; ++} ++ ++static int free_enclave(int eid) ++{ ++ struct link_mem_t *cur; ++ struct enclave_t *enclave = NULL; ++ int found, count, ret_val; ++ ++ acquire_big_metadata_lock(__func__); ++ ++ found = 0; ++ count = 0; ++ for(cur = enclave_metadata_head; cur != NULL; cur = cur->next_link_mem) ++ { ++ if(eid < (count + cur->slab_num)) ++ { ++ enclave = (struct enclave_t*)(cur->addr) + (eid - count); ++ sbi_memset((void*)enclave, 0, sizeof(struct enclave_t)); ++ enclave->state = INVALID; ++ enclave->eid = -1; ++ found = 1; ++ ret_val = 0; ++ break; ++ } ++ count += cur->slab_num; ++ } ++ ++ //haven't alloc this eid ++ if (!found) { ++ printm("[Penglai Monitor@%s] haven't alloc this eid %d\r\n", ++ __func__, eid); ++ ret_val = -1; ++ } ++ ++ release_big_metadata_lock(__func__); ++ ++ return ret_val; ++} ++ ++struct enclave_t* get_enclave(int eid) ++{ ++ struct link_mem_t *cur; ++ struct enclave_t *enclave; ++ int found, count; ++ ++ acquire_big_metadata_lock(__func__); ++ ++ found = 0; ++ count = 0; ++ for(cur = enclave_metadata_head; cur != NULL; cur = cur->next_link_mem) ++ { ++ if(eid < (count + cur->slab_num)) ++ { ++ enclave = (struct enclave_t*)(cur->addr) + (eid - count); ++ found = 1; ++ break; ++ } ++ ++ count += cur->slab_num; ++ } ++ ++ //haven't alloc this eid ++ if(!found) ++ { ++ printm("[Penglai Monitor@%s] haven't alloc this enclave\r\n", __func__); ++ enclave = NULL; ++ } ++ ++ release_big_metadata_lock(__func__); ++ return enclave; ++} ++ ++int swap_from_host_to_enclave(uintptr_t* host_regs, struct enclave_t* enclave) ++{ ++ printm("[Penglai Monitor@%s %d] swap_from_host_to_enclave\n", __func__, current_hartid()); ++ //grant encalve access to memory ++ if(grant_enclave_access(enclave) < 0) ++ return -1; ++ ++ //save host context ++ swap_prev_state(&(enclave->thread_context), host_regs); ++ ++ //different platforms have differnt ptbr switch methods ++ switch_to_enclave_ptbr(&(enclave->thread_context), enclave->thread_context.encl_ptbr); ++ ++ /* ++ * save host cache binding ++ * only workable when the hardware supports the feature ++ */ ++#if 0 ++ swap_prev_cache_binding(&enclave -> threads[0], read_csr(0x356)); ++#endif ++ ++ // disable interrupts ++ swap_prev_mie(&(enclave->thread_context), csr_read(CSR_MIE)); ++ ++ // clear pending interrupts ++ csr_read_clear(CSR_MIP, MIP_MTIP); ++ csr_read_clear(CSR_MIP, MIP_STIP); ++ csr_read_clear(CSR_MIP, MIP_SSIP); ++ csr_read_clear(CSR_MIP, MIP_SEIP); ++ ++ //disable interrupts/exceptions delegation ++ swap_prev_mideleg(&(enclave->thread_context), csr_read(CSR_MIDELEG)); ++ swap_prev_medeleg(&(enclave->thread_context), csr_read(CSR_MEDELEG)); ++ ++ // swap the mepc to transfer control to the enclave ++ // This will be overwriten by the entry-address in the case of run_enclave ++ //swap_prev_mepc(&(enclave->thread_context), csr_read(CSR_MEPC)); ++ swap_prev_mepc(&(enclave->thread_context), host_regs[32]); ++ host_regs[32] = csr_read(CSR_MEPC); //update the new value to host_regs ++ ++ //set return address to enclave ++ ++ //set mstatus to transfer control to u mode ++ uintptr_t mstatus = host_regs[33]; //In OpenSBI, we use regs to change mstatus ++ mstatus = INSERT_FIELD(mstatus, MSTATUS_MPP, PRV_U); ++ mstatus = INSERT_FIELD(mstatus, MSTATUS_FS, 0x3); // enable float ++ host_regs[33] = mstatus; ++ ++ //mark that cpu is in enclave world now ++ enter_enclave_world(enclave->eid); ++ //flush TLB ++ __asm__ __volatile__ ("sfence.vma" : : : "memory"); ++ ++ return 0; ++} ++ ++int swap_from_enclave_to_host(uintptr_t* regs, struct enclave_t* enclave) ++{ ++ printm("[Penglai Monitor@%s] swap_from_enclave_to_host\n", __func__); ++ //retrieve enclave access to memory ++ retrieve_enclave_access(enclave); ++ ++ //restore host context ++ swap_prev_state(&(enclave->thread_context), regs); ++ ++ //restore host's ptbr ++ switch_to_host_ptbr(&(enclave->thread_context), enclave->host_ptbr); ++ ++ //TODO: restore host cache binding ++ //swap_prev_cache_binding(&(enclave->thread_context), ); ++ ++ //restore interrupts ++ swap_prev_mie(&(enclave->thread_context), csr_read(CSR_MIE)); ++ ++ //restore interrupts/exceptions delegation ++ swap_prev_mideleg(&(enclave->thread_context), csr_read(CSR_MIDELEG)); ++ swap_prev_medeleg(&(enclave->thread_context), csr_read(CSR_MEDELEG)); ++ ++ //transfer control back to kernel ++ //swap_prev_mepc(&(enclave->thread_context), read_csr(mepc)); ++ //regs[32] = (uintptr_t)(enclave->thread_context.prev_mepc); //In OpenSBI, we use regs to change mepc ++ swap_prev_mepc(&(enclave->thread_context), regs[32]); ++ regs[32] = csr_read(CSR_MEPC); //update the new value to host_regs ++ ++ //restore mstatus ++#if 0 ++ uintptr_t mstatus = read_csr(mstatus); ++ mstatus = INSERT_FIELD(mstatus, MSTATUS_MPP, PRV_S); ++ write_csr(mstatus, mstatus); ++#else ++ uintptr_t mstatus = regs[33]; //In OpenSBI, we use regs to change mstatus ++ mstatus = INSERT_FIELD(mstatus, MSTATUS_MPP, PRV_S); ++ regs[33] = mstatus; ++#endif ++ ++ //mark that cpu is out of enclave world now ++ exit_enclave_world(); ++ ++ __asm__ __volatile__ ("sfence.vma" : : : "memory"); ++ ++ return 0; ++} ++ ++uintptr_t create_enclave(struct enclave_sbi_param_t create_args, bool retry) ++{ ++ struct enclave_t* enclave; ++ unsigned int eid; ++ uintptr_t retval = 0; ++ ++ enclave = alloc_enclave(); ++ if(!enclave) ++ { ++ printm("[Penglai Monitor@%s] enclave allocation is failed \r\n", __func__); ++ ++ if (retry) ++ { ++ printm("[Penglai Monitor@%s] retry failed, clear enclave \r\n", __func__); ++ sbi_memset((void*)(create_args.paddr), 0, create_args.size); ++ mm_free((void*)(create_args.paddr), create_args.size); ++ } ++ ++ return ENCLAVE_NO_MEMORY; ++ } ++ ++ // acquire_big_metadata_lock(__func__); ++ ++ eid = enclave->eid; ++ enclave->paddr = create_args.paddr; ++ enclave->size = create_args.size; ++ enclave->entry_point = create_args.entry_point; ++ enclave->untrusted_ptr = create_args.untrusted_ptr; ++ enclave->untrusted_ptr_paddr = create_args.untrusted_paddr; ++ enclave->untrusted_size = create_args.untrusted_size; ++ enclave->free_mem = create_args.free_mem; ++ enclave->ocall_func_id = create_args.ecall_arg0; ++ enclave->ocall_arg0 = create_args.ecall_arg1; ++ enclave->ocall_arg1 = create_args.ecall_arg2; ++ enclave->ocall_syscall_num = create_args.ecall_arg3; ++ enclave->kbuffer = create_args.kbuffer; ++ enclave->kbuffer_paddr = create_args.kbuffer_paddr; ++ enclave->kbuffer_size = create_args.kbuffer_size; ++ enclave->host_ptbr = csr_read(CSR_SATP); ++ enclave->thread_context.encl_ptbr = (create_args.paddr >> (RISCV_PGSHIFT) | SATP_MODE_CHOICE); ++ enclave->root_page_table = (unsigned long*)create_args.paddr; ++ enclave->state = FRESH; ++ ++ //Dump the PT here, for debug ++#if 0 ++ printm("[Penglai@%s], Dump PT for created enclave\n", __func__); ++ dump_pt(enclave->root_page_table, 1); ++#endif ++ ++ printm("[Penglai@%s] paddr:0x%lx, size:0x%lx, entry:0x%lx\n" ++ "untrusted ptr:0x%lx host_ptbr:0x%lx, pt:0x%ln\n" ++ "thread_context.encl_ptbr:0x%lx\n cur_satp:0x%lx\n", ++ __func__, enclave->paddr, enclave->size, enclave->entry_point, ++ enclave->untrusted_ptr, enclave->host_ptbr, enclave->root_page_table, ++ enclave->thread_context.encl_ptbr, csr_read(CSR_SATP)); ++ ++ // Calculate the enclave's measurement ++ hash_enclave(enclave, (void*)(enclave->hash), 0); ++ ++ // TODO: verify hash and whitelist check ++ ++ // Check page table mapping secure and not out of bound ++ //put it in run_enclave for debug ++ retval = check_enclave_pt(enclave); ++ if(retval != 0) ++ { ++ printm_err("M mode: create_enclave: check enclave page table failed, create failed\r\n"); ++ goto error_out; ++ } ++ ++ retval = copy_word_to_host((unsigned int*)create_args.eid_ptr, enclave->eid); ++ if(retval != 0) ++ { ++ printm_err("M mode: create_enclave: unknown error happended when copy word to host\r\n"); ++ goto error_out; ++ } ++ ++ printm("[Penglai Monitor@%s] return eid:%d\n", ++ __func__, enclave->eid); ++ ++ //spin_unlock(&enclave_metadata_lock); ++ // release_big_metadata_lock(__func__); ++ return 0; ++ ++/* ++ * If create failed for above reasons, secure memory and enclave struct ++ * allocated before will never be used. So we need to free these momery. ++ */ ++error_out: ++ sbi_memset((void*)(enclave->paddr), 0, enclave->size); ++ mm_free((void*)(enclave->paddr), enclave->size); ++ ++ //spin_unlock(&enclave_metadata_lock); ++ // release_big_metadata_lock(__func__); ++ ++ //free enclave struct ++ free_enclave(eid); //the enclave state will be set INVALID here ++ return ENCLAVE_ERROR; ++} ++ ++uintptr_t run_enclave(uintptr_t* regs, unsigned int eid) ++{ ++ struct enclave_t* enclave; ++ uintptr_t retval = 0; ++ ++ enclave = get_enclave(eid); ++ if (!enclave) ++ { ++ printm_err("[Penglai Monitor@%s] wrong enclave id\r\n", __func__); ++ return -1UL; ++ } ++#if 0 ++ printm("[Penglai@%s], check PT for run enclave\n", __func__); ++ // dump_pt(enclave->root_page_table, 1); ++ retval = check_enclave_pt(enclave); ++#endif ++ //spin_lock(&enclave_metadata_lock); ++ acquire_big_metadata_lock(__func__); ++ ++ if (enclave->state != FRESH) ++ { ++ printm_err("[Penglai Monitor@%s] enclave is not initialized or already used\r\n", __func__); ++ retval = -1UL; ++ goto run_enclave_out; ++ } ++ if (enclave->host_ptbr != csr_read(CSR_SATP)) ++ { ++ printm_err("[Penglai Monitor@%s] enclave doesn't belong to current host process\r\n", __func__); ++ retval = -1UL; ++ goto run_enclave_out; ++ } ++ ++ if (swap_from_host_to_enclave(regs, enclave) < 0) ++ { ++ printm("[Penglai Monitor@%s] enclave can not be run\r\n", __func__); ++ retval = -1UL; ++ goto run_enclave_out; ++ } ++ ++ //swap_prev_mepc(&(enclave->thread_context), regs[32]); ++ regs[32] = (uintptr_t)(enclave->entry_point); //In OpenSBI, we use regs to change mepc ++ ++ //TODO: enable timer interrupt ++ csr_read_set(CSR_MIE, MIP_MTIP); ++ ++ //set default stack ++ regs[2] = ENCLAVE_DEFAULT_STACK; ++ ++ //pass parameters ++ regs[11] = (uintptr_t)enclave->entry_point; ++ regs[12] = (uintptr_t)enclave->untrusted_ptr; ++ regs[13] = (uintptr_t)enclave->untrusted_size; ++ ++ enclave->state = RUNNING; ++ ++run_enclave_out: ++ //spin_unlock(&enclave_metadata_lock); ++ release_big_metadata_lock(__func__); ++ return retval; ++} ++ ++uintptr_t stop_enclave(uintptr_t* regs, unsigned int eid) ++{ ++ uintptr_t retval = 0; ++ struct enclave_t *enclave = get_enclave(eid); ++ if(!enclave) ++ { ++ printm_err("[Penglai Monitor@%s] wrong enclave id%d\r\n", __func__, eid); ++ return -1UL; ++ } ++ ++ //spin_lock(&enclave_metadata_lock); ++ acquire_big_metadata_lock(__func__); ++ ++ if(enclave->host_ptbr != csr_read(CSR_SATP)) ++ { ++ printm_err("[Penglai Monitor@%s] enclave doesn't belong to current host process\r\n", __func__); ++ retval = -1UL; ++ goto stop_enclave_out; ++ } ++ ++ if(enclave->state <= FRESH) ++ { ++ printm_err("[Penglai Monitor@%s] enclave%d hasn't begin running at all\r\n", __func__, eid); ++ retval = -1UL; ++ goto stop_enclave_out; ++ } ++ ++ if(enclave->state == STOPPED || enclave-> state == DESTROYED) ++ { ++ printm_err("[Penglai Monitor@%s] enclave%d already stopped/destroyed\r\n", __func__, eid); ++ retval = -1UL; ++ goto stop_enclave_out; ++ } ++ ++ /* The real-stop happen when the enclave traps into the monitor */ ++ enclave->state = STOPPED; ++ ++stop_enclave_out: ++ //spin_unlock(&enclave_metadata_lock); ++ release_big_metadata_lock(__func__); ++ return retval; ++} ++ ++uintptr_t destroy_enclave(uintptr_t* regs, unsigned int eid) ++{ ++ uintptr_t retval = 0; ++ struct enclave_t *enclave = get_enclave(eid); ++ if(!enclave) ++ { ++ printm_err("[Penglai Monitor@%s] wrong enclave id%d\r\n", __func__, eid); ++ return -1UL; ++ } ++ ++ //spin_lock(&enclave_metadata_lock); ++ acquire_big_metadata_lock(__func__); ++ ++ if (enclave->host_ptbr != csr_read(CSR_SATP)) ++ { ++ printm_err("[Penglai Monitor@%s] enclave doesn't belong to current host process" ++ "enclave->host_ptbr:0x%lx, csr_satp:0x%lx\r\n", __func__, enclave->host_ptbr, csr_read(CSR_SATP)); ++ retval = -1UL; ++ goto out; ++ } ++ ++ if (enclave->state < FRESH) ++ { ++ printm_err("[Penglai Monitor@%s] enclave%d hasn't created\r\n", __func__, eid); ++ retval = -1UL; ++ goto out; ++ } ++ ++ /* ++ * If the enclave is stopped or fresh, it will never goto the timer trap handler, ++ * we should destroy the enclave immediately ++ * */ ++ //if (enclave->state == STOPPED || enclave->state == FRESH) { ++ if (enclave->state == FRESH) { ++ sbi_memset((void*)(enclave->paddr), 0, enclave->size); ++ mm_free((void*)(enclave->paddr), enclave->size); ++ enclave->state = INVALID; ++ ++ release_big_metadata_lock(__func__); ++ ++ //free enclave struct ++ retval = free_enclave(eid); //the enclave state will be set INVALID here ++ return retval; ++ } ++ //FIXME: what if the enclave->state is RUNNABLE now? ++ ++ /* The real-destroy happen when the enclave traps into the monitor */ ++ enclave->state = DESTROYED; ++out: ++ release_big_metadata_lock(__func__); ++ return retval; ++} ++ ++uintptr_t resume_from_stop(uintptr_t* regs, unsigned int eid) ++{ ++ uintptr_t retval = 0; ++ struct enclave_t* enclave = get_enclave(eid); ++ ++ if (!enclave) ++ { ++ printm("[Penglai Monitor@%s] wrong enclave id%d\r\n", __func__, eid); ++ return -1UL; ++ } ++ ++ acquire_big_metadata_lock(__func__); ++ if(enclave->host_ptbr != csr_read(CSR_SATP)) ++ { ++ printm("[Penglai Monitor@%s] enclave doesn't belong to current host process\r\n", __func__); ++ retval = -1UL; ++ goto resume_from_stop_out; ++ } ++ ++ if(enclave->state != STOPPED) ++ { ++ printm("[Penglai Monitor@%s] enclave's state is not stopped\r\n", __func__); ++ retval = -1UL; ++ goto resume_from_stop_out; ++ } ++ ++ enclave->state = RUNNABLE; ++ printm("[Penglai Monitor@%s] encalve-%d turns to runnable now!\n", __func__, eid); ++ ++resume_from_stop_out: ++ release_big_metadata_lock(__func__); ++ return retval; ++} ++ ++uintptr_t resume_enclave(uintptr_t* regs, unsigned int eid) ++{ ++ uintptr_t retval = 0; ++ struct enclave_t* enclave = get_enclave(eid); ++ if(!enclave) ++ { ++ printm("[Penglai Monitor@%s] wrong enclave id%d\r\n", __func__, eid); ++ return -1UL; ++ } ++ ++ acquire_big_metadata_lock(__func__); ++ ++ if(enclave->host_ptbr != csr_read(CSR_SATP)) ++ { ++ printm("[Penglai Monitor@%s] enclave doesn't belong to current host process\r\n", __func__); ++ retval = -1UL; ++ goto resume_enclave_out; ++ } ++ ++ if(enclave->state == STOPPED) ++ { ++ retval = ENCLAVE_TIMER_IRQ; ++ goto resume_enclave_out; ++ } ++ ++ if (enclave->state == DESTROYED) { ++ sbi_memset((void*)(enclave->paddr), 0, enclave->size); ++ mm_free((void*)(enclave->paddr), enclave->size); ++ ++ spin_unlock(&enclave_metadata_lock); ++ ++ //free enclave struct ++ free_enclave(eid); //the enclave state will be set INVALID here ++ return ENCLAVE_SUCCESS; //this will break the infinite loop in the enclave-driver ++ } ++ ++ if(enclave->state != RUNNABLE) ++ { ++ printm("[Penglai Monitor@%s] enclave%d is not runnable\r\n", __func__, eid); ++ retval = -1UL; ++ goto resume_enclave_out; ++ } ++ ++ if(swap_from_host_to_enclave(regs, enclave) < 0) ++ { ++ printm("[Penglai Monitor@%s] enclave can not be run\r\n", __func__); ++ retval = -1UL; ++ goto resume_enclave_out; ++ } ++ ++ enclave->state = RUNNING; ++ ++ //regs[10] will be set to retval when mcall_trap return, so we have to ++ //set retval to be regs[10] here to succuessfully restore context ++ //TODO: retval should be set to indicate success or fail when resume from ocall ++ retval = regs[10]; ++ ++resume_enclave_out: ++ release_big_metadata_lock(__func__); ++ return retval; ++} ++ ++uintptr_t attest_enclave(uintptr_t eid, uintptr_t report_ptr, uintptr_t nonce) ++{ ++ struct enclave_t* enclave = NULL; ++ int attestable = 1; ++ struct report_t report; ++ enclave = get_enclave(eid); ++ acquire_big_metadata_lock(__func__); ++ ++ if(!attestable) ++ { ++ sbi_printf("M mode: attest_enclave: enclave%ld is not attestable\n", eid); ++ return -1UL; ++ } ++ ++ sbi_memcpy((void*)(report.dev_pub_key), (void*)DEV_PUB_KEY, PUBLIC_KEY_SIZE); ++ sbi_memcpy((void*)(report.sm.hash), (void*)SM_HASH, HASH_SIZE); ++ sbi_memcpy((void*)(report.sm.sm_pub_key), (void*)SM_PUB_KEY, PUBLIC_KEY_SIZE); ++ sbi_memcpy((void*)(report.sm.signature), (void*)SM_SIGNATURE, SIGNATURE_SIZE); ++ ++ update_enclave_hash((char *)(report.enclave.hash), (char *)enclave->hash, nonce); ++ sign_enclave((void*)(report.enclave.signature), (void*)(report.enclave.hash), HASH_SIZE); ++ report.enclave.nonce = nonce; ++ ++ copy_to_host((void*)report_ptr, (void*)(&report), sizeof(struct report_t)); ++ ++ release_big_metadata_lock(__func__); ++ return 0; ++} ++ ++uintptr_t exit_enclave(uintptr_t* regs, unsigned long retval) ++{ ++ int eid = get_enclave_id(); ++ struct enclave_t *enclave = NULL; ++ if(check_in_enclave_world() < 0) ++ { ++ printm_err("[Penglai Monitor@%s] cpu is not in enclave world now\r\n", __func__); ++ return -1; ++ } ++ printm("[Penglai Monitor@%s] retval of enclave is %lx\r\n", __func__, retval); ++ ++ enclave = get_enclave(eid); ++ ++ //spin_lock(&enclave_metadata_lock); ++ acquire_big_metadata_lock(__func__); ++ ++ if(!enclave || check_enclave_authentication(enclave)!=0 || enclave->state != RUNNING) ++ { ++ printm_err("[Penglai Monitor@%s] current enclave's eid is not %d\r\n", __func__, eid); ++ //spin_unlock(&enclave_metadata_lock); ++ release_big_metadata_lock(__func__); ++ return -1UL; ++ } ++ ++ swap_from_enclave_to_host(regs, enclave); ++ ++ printm("[Penglai Monitor@%s] untreasted mem:%lx ,val:%s \n\t kbuffer_addr:%lx val:%s \n", ++ __func__, enclave->untrusted_ptr, ++ (unsigned char *)(enclave->untrusted_ptr_paddr), enclave->kbuffer_paddr, ++ (unsigned char *)(enclave->kbuffer_paddr)); ++ //free enclave's memory ++ //TODO: support multiple memory region ++ sbi_memset((void*)(enclave->paddr), 0, enclave->size); ++ // mm_free((void*)(enclave->paddr), enclave->size); ++ // Optional: used to reclaim secmem immediately upon enclave exit ++ mm_free_clear((void*)(enclave->paddr), enclave->size); ++ release_big_metadata_lock(__func__); ++ ++ //free enclave struct ++ free_enclave(eid); ++ return 0; ++} ++ ++uintptr_t enclave_sys_write(uintptr_t* regs) ++{ ++ uintptr_t ret = 0; ++ int eid = get_enclave_id(); ++ struct enclave_t* enclave = NULL; ++ ++ if(check_in_enclave_world() < 0) ++ { ++ printm_err("[Penglai Monitor@%s] check enclave world is failed\n", __func__); ++ return -1; ++ } ++ ++ enclave = get_enclave(eid); ++ printm("[Penglai Monitor@%s] untreasted mem:%lx ,val:%s \n\t kbuffer_addr:%lx val:%s \n",__func__, enclave->untrusted_ptr_paddr, (unsigned char*)(enclave->untrusted_ptr_paddr), enclave->kbuffer_paddr, (unsigned char*)(enclave->kbuffer_paddr)); ++ ++ acquire_big_metadata_lock(__func__); ++ ++ if(!enclave || check_enclave_authentication(enclave)!=0 || enclave->state != RUNNING) ++ { ++ ret = -1UL; ++ printm_err("[Penglai Monitor@%s] check enclave authentication is failed\n", __func__); ++ goto out; ++ } ++ ++ uintptr_t ocall_func_id = OCALL_SYS_WRITE; ++ copy_to_host((uintptr_t*)enclave->ocall_func_id, &ocall_func_id, sizeof(uintptr_t)); ++ ++ swap_from_enclave_to_host(regs, enclave); ++ enclave->state = RUNNABLE; ++ ret = ENCLAVE_OCALL; ++out: ++ release_big_metadata_lock(__func__); ++ return ret; ++} ++ ++uintptr_t enclave_derive_seal_key(uintptr_t* regs, uintptr_t salt_va, uintptr_t salt_len, ++ uintptr_t key_buf_va, uintptr_t key_buf_len) ++{ ++ uintptr_t ret = 0; ++ int eid = get_enclave_id(); ++ struct enclave_t *enclave = NULL; ++ ++ pte_t *enclave_root_pt; ++ SM3_STATE hash_ctx; ++ unsigned char salt_local[HASH_SIZE]; ++ unsigned char hash[HASH_SIZE]; ++ ++ if(key_buf_len > HASH_SIZE || salt_len > HASH_SIZE) ++ { ++ printm("[Penglai Monitor@%s] Seal key length or Salt length can't bigger then SM3 Hash size(32)\n", __func__); ++ return -1; ++ } ++ ++ if(check_in_enclave_world() < 0) ++ { ++ printm_err("[Penglai Monitor@%s] check enclave world is failed\n", __func__); ++ return -1; ++ } ++ ++ enclave = get_enclave(eid); ++ ++ acquire_big_metadata_lock(__func__); ++ ++ if(!enclave || check_enclave_authentication(enclave)!=0 || enclave->state != RUNNING) ++ { ++ ret = -1UL; ++ printm_err("[Penglai Monitor@%s] check enclave authentication is failed\n", __func__); ++ goto out; ++ } ++ ++ enclave_root_pt = (pte_t*)(enclave->thread_context.encl_ptbr << RISCV_PGSHIFT); ++ ret = copy_from_enclave(enclave_root_pt, salt_local, (void *)salt_va, salt_len); ++ if(ret != 0) ++ { ++ ret = -1UL; ++ printm_err("[Penglai Monitor@%s] unknown error happended when copy from enclave\n", __func__); ++ goto out; ++ } ++ ++ SM3_init(&hash_ctx); ++ SM3_process(&hash_ctx, (unsigned char*)DEV_PRI_KEY, PRIVATE_KEY_SIZE); ++ SM3_process(&hash_ctx, enclave->hash, HASH_SIZE); ++ SM3_process(&hash_ctx, enclave->signer, HASH_SIZE); ++ SM3_process(&hash_ctx, salt_local, salt_len); ++ SM3_done(&hash_ctx, hash); ++ ++ ret = copy_to_enclave(enclave_root_pt, (void *)key_buf_va, hash, key_buf_len); ++ if(ret != 0){ ++ ret = -1UL; ++ printm_err("[Penglai Monitor@%s] unknown error happended when copy to enclave\n", __func__); ++ goto out; ++ } ++ ++out: ++ release_big_metadata_lock(__func__); ++ return ret; ++} ++ ++uintptr_t enclave_user_defined_ocall(uintptr_t* regs, uintptr_t ocall_buf_size) ++{ ++ uintptr_t ret = 0; ++ int eid = get_enclave_id(); ++ struct enclave_t* enclave = NULL; ++ if(check_in_enclave_world() < 0) ++ { ++ printm_err("[Penglai Monitor@%s] check enclave world is failed\n", __func__); ++ return -1; ++ } ++ ++ enclave = get_enclave(eid); ++ ++ acquire_big_metadata_lock(__func__); ++ ++ if(!enclave || check_enclave_authentication(enclave)!=0 || enclave->state != RUNNING) ++ { ++ ret = -1UL; ++ printm_err("[Penglai Monitor@%s] check enclave authentication is failed\n", __func__); ++ goto out; ++ } ++ ++ uintptr_t ocall_func_id = OCALL_USER_DEFINED; ++ copy_to_host((uintptr_t*)enclave->ocall_func_id, &ocall_func_id, sizeof(uintptr_t)); ++ copy_to_host((uintptr_t*)enclave->ocall_arg0, &ocall_buf_size, sizeof(uintptr_t)); ++ ++ swap_from_enclave_to_host(regs, enclave); ++ enclave->state = RUNNABLE; ++ ret = ENCLAVE_OCALL; ++out: ++ release_big_metadata_lock(__func__); ++ return ret; ++} ++ ++/* ++ * Timer handler for penglai enclaves ++ * In normal case, an enclave will pin a HART and run until it finished. ++ * The exception case is timer interrupt, which will trap into monitor to ++ * check current enclave states. ++ * ++ * If current enclave states is not Running or Runnable, it will be stoped/destroyed ++ * ++ * */ ++uintptr_t do_timer_irq(uintptr_t *regs, uintptr_t mcause, uintptr_t mepc) ++{ ++ uintptr_t retval = 0; ++ unsigned int eid = get_enclave_id(); ++ struct enclave_t *enclave = get_enclave(eid); ++ if (!enclave) ++ { ++ printm("[Penglai Monitor@%s] something is wrong with enclave%d\r\n", __func__, eid); ++ return -1UL; ++ } ++ ++ acquire_big_metadata_lock(__func__); ++ ++ /* ++ * An enclave trapping into monitor should not have other states. ++ * This is guaranteed by concurrency control for life cycle management。 ++ */ ++ if (enclave->state != RUNNING && enclave->state != DESTROYED && ++ enclave->state != STOPPED) { ++ printm_err("[Penglai Monitor@%s] Enclave(%d) state is wrong!\r\n", __func__, eid); ++ retval = -1; ++ } ++ ++ swap_from_enclave_to_host(regs, enclave); ++ ++ if (enclave->state == DESTROYED) { ++ sbi_memset((void*)(enclave->paddr), 0, enclave->size); ++ mm_free((void*)(enclave->paddr), enclave->size); ++ ++ release_big_metadata_lock(__func__); ++ ++ //free enclave struct ++ retval = free_enclave(eid); //the enclave state will be set INVALID here ++ ++ retval = ENCLAVE_SUCCESS; //this means we will not run any more ++ goto timer_irq_out; ++ }else if (enclave->state == RUNNING) { ++ enclave->state = RUNNABLE; ++ ++ retval = ENCLAVE_TIMER_IRQ; ++ }else { // The case for STOPPED ++ retval = ENCLAVE_TIMER_IRQ; ++ } ++ ++ release_big_metadata_lock(__func__); ++ ++timer_irq_out: ++ csr_read_clear(CSR_MIE, MIP_MTIP); ++ csr_read_set(CSR_MIP, MIP_STIP); ++ /*ret set timer now*/ ++ // sbi_timer_event_start(csr_read(CSR_TIME) + ENCLAVE_TIME_CREDITS); ++ return retval; ++} ++ ++uintptr_t resume_from_ocall(uintptr_t* regs, unsigned int eid) ++{ ++ uintptr_t retval = 0; ++ uintptr_t ocall_func_id = regs[12]; ++ struct enclave_t* enclave = NULL; ++ ++ enclave = get_enclave(eid); ++ if(!enclave || enclave->host_ptbr != csr_read(CSR_SATP)) ++ { ++ printm("M mode: %s wrong enclave id or enclave doesn't belong to current host process\n", __func__); ++ return -1UL; ++ } ++ ++ acquire_big_metadata_lock(__func__); ++ ++ switch(ocall_func_id) ++ { ++ case OCALL_SYS_WRITE: ++ retval = enclave->thread_context.prev_state.a0; ++ break; ++ case OCALL_USER_DEFINED: ++ retval = enclave->thread_context.prev_state.a0; ++ break; ++ default: ++ retval = 0; ++ break; ++ } ++ ++ release_big_metadata_lock(__func__); ++ ++ retval = resume_enclave(regs, eid); ++ return retval; ++} +diff --git a/lib/sbi/sm/gm/SM2_sv.c b/lib/sbi/sm/gm/SM2_sv.c +new file mode 100644 +index 0000000..9a23c20 +--- /dev/null ++++ b/lib/sbi/sm/gm/SM2_sv.c +@@ -0,0 +1,692 @@ ++/************************************************************************ ++ Copyright (c) IPADS@SJTU 2021. Modification to support Penglai (RISC-V TEE) ++ ++ This file contains GM/T SM2 standard implementation, provided by the Commercial ++ Cryptography Testing Center, see for more infomation. ++ ++ File name: SM2_sv.c ++ Version: SM2_sv_V1.0 ++ Date: Sep 27,2016 ++ Description: implementation of SM2 signature algorithm and verification algorithm ++ Function List: ++ 1.SM2_Init //initiate SM2 curve ++ 2.Test_Point //test if the given point is on SM2 curve ++ 3.Test_PubKey //test if the given public key is valid ++ 4.Test_Zero //test if the big x equals zero ++ 5.Test_n //test if the big x equals n ++ 6.Test_Range //test if the big x belong to the range[1,n-1] ++ 7.SM2_KeyGeneration //generate SM2 key pair ++ 8.SM2_Sign //SM2 signature algorithm ++ 9.SM2_Verify //SM2 verification ++ 10.SM2_SelfCheck() //SM2 self-check ++ 11.SM3_256() //this function can be found in SM3.c and SM3.h ++ ++ Additional Functions Added By PENGLAI Enclave: ++ 1.MIRACL_Init //init miracl system ++ 2.SM2_make_prikey //generate a SM2 private key ++ 3.SM2_make_pubkey //generate a SM2 public Key out of a private Key ++ 4.SM2_gen_random //generate a random number K lies in [1,n-1] ++ 5.SM2_compute_ZA //compute ZA out of a given pubkey ++**************************************************************************/ ++ ++#include "sm/gm/miracl/miracl.h" ++#include "sm/gm/SM2_sv.h" ++#include "sm/gm/SM3.h" ++ ++#include ++#include ++#include ++#include ++ ++#define MAX_MESSAGE_SIZE 1024 ++ ++const char SM2_p[32] = { ++ 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++const char SM2_a[32] = { ++ 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc}; ++ ++const char SM2_b[32] = { ++ 0x28, 0xe9, 0xfa, 0x9e, 0x9d, 0x9f, 0x5e, 0x34, 0x4d, 0x5a, 0x9e, 0x4b, 0xcf, 0x65, 0x09, 0xa7, ++ 0xf3, 0x97, 0x89, 0xf5, 0x15, 0xab, 0x8f, 0x92, 0xdd, 0xbc, 0xbd, 0x41, 0x4d, 0x94, 0x0e, 0x93}; ++ ++const char SM2_Gx[32] = { ++ 0x32, 0xc4, 0xae, 0x2c, 0x1f, 0x19, 0x81, 0x19, 0x5f, 0x99, 0x04, 0x46, 0x6a, 0x39, 0xc9, 0x94, ++ 0x8f, 0xe3, 0x0b, 0xbf, 0xf2, 0x66, 0x0b, 0xe1, 0x71, 0x5a, 0x45, 0x89, 0x33, 0x4c, 0x74, 0xc7}; ++ ++const char SM2_Gy[32] = { ++ 0xbc, 0x37, 0x36, 0xa2, 0xf4, 0xf6, 0x77, 0x9c, 0x59, 0xbd, 0xce, 0xe3, 0x6b, 0x69, 0x21, 0x53, ++ 0xd0, 0xa9, 0x87, 0x7c, 0xc6, 0x2a, 0x47, 0x40, 0x02, 0xdf, 0x32, 0xe5, 0x21, 0x39, 0xf0, 0xa0}; ++ ++const char SM2_n[32] = { ++ 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x72, 0x03, 0xdf, 0x6b, 0x21, 0xc6, 0x05, 0x2b, 0x53, 0xbb, 0xf4, 0x09, 0x39, 0xd5, 0x41, 0x23}; ++ ++big Gx, Gy, p, a, b, n; ++epoint *G, *nG; ++char g_mem[MR_BIG_RESERVE(6)]; ++char g_mem_point[MR_ECP_RESERVE(2)]; ++ ++static void MIRACL_Init() ++{ ++ unsigned long seed; ++ ++ seed = sbi_timer_value(); ++ printm("Initialize Penglai's random system with seed 0x%lx (sbi_timer_value)\n", seed); ++#ifdef PENGLAI_DEBUG ++ miracl *mip = mirsys(128, 16); ++ printm("MIRACL: pack: %d, nib: %d, big size: %ld, point size: %ld, workspace ptr: %lx\n", ++ mip->pack, mip->nib, mr_size(mip->nib-1), ++ mr_esize(mr_mip->nib-1), (unsigned long)mip->workspace); ++#else ++ mirsys(128, 16); ++#endif ++ irand((unsigned int)seed); ++} ++ ++/**************************************************************** ++ Function: SM2_Init ++ Description: Initiate SM2 curve, must called before ++ SM2_KeyGeneration,SM2_Sign,SM2_Verify. ++ Calls: MIRACL functions ++ Called By: SM2_SelfCheck ++ Input: null ++ Output: null ++ Return: 0: success; ++ 1: parameter initialization error; ++ 4: the given point G is not a point of order n ++ Others: ++****************************************************************/ ++int SM2_Init() ++{ ++ MIRACL_Init(); ++ printm("MIRACL initialized\n"); ++ sbi_memset(g_mem, 0, MR_BIG_RESERVE(6)); ++ Gx = mirvar_mem(g_mem, 0); ++ Gy = mirvar_mem(g_mem, 1); ++ p = mirvar_mem(g_mem, 2); ++ a = mirvar_mem(g_mem, 3); ++ b = mirvar_mem(g_mem, 4); ++ n = mirvar_mem(g_mem, 5); ++ ++ bytes_to_big(SM2_NUMWORD, SM2_Gx, Gx); ++ bytes_to_big(SM2_NUMWORD, SM2_Gy, Gy); ++ bytes_to_big(SM2_NUMWORD, SM2_p, p); ++ bytes_to_big(SM2_NUMWORD, SM2_a, a); ++ bytes_to_big(SM2_NUMWORD, SM2_b, b); ++ bytes_to_big(SM2_NUMWORD, SM2_n, n); ++ ++ ecurve_init(a, b, p, MR_PROJECTIVE); ++ ++ sbi_memset(g_mem_point, 0, MR_ECP_RESERVE(2)); ++ G = epoint_init_mem(g_mem_point, 0); ++ nG = epoint_init_mem(g_mem_point, 1); ++ ++ if (!epoint_set(Gx, Gy, 0, G)) //initialise point G ++ return ERR_ECURVE_INIT; ++ ecurve_mult(n, G, nG); ++ if (!point_at_infinity(nG)) //test if the order of the point is n ++ return ERR_ORDER; ++ ++ return 0; ++} ++ ++/**************************************************************** ++ Function: Test_Point ++ Description: test if the given point is on SM2 curve ++ Calls: ++ Called By: SM2_KeyGeneration ++ Input: point ++ Output: null ++ Return: 0: success ++ 3: not a valid point on curve ++ Others: ++****************************************************************/ ++int Test_Point(epoint *point) ++{ ++ big x, y, x_3, tmp; ++ char mem[MR_BIG_RESERVE(4)]; ++ sbi_memset(mem, 0, MR_BIG_RESERVE(4)); ++ x = mirvar_mem(mem, 0); ++ y = mirvar_mem(mem, 1); ++ x_3 = mirvar_mem(mem, 2); ++ tmp = mirvar_mem(mem, 3); ++ ++ //test if y^2=x^3+ax+b ++ epoint_get(point, x, y); ++ power(x, 3, p, x_3); //x_3=x^3 mod p ++ multiply(x, a, x); //x=a*x ++ divide(x, p, tmp); //x=a*x mod p , tmp=a*x/p ++ add(x_3, x, x); //x=x^3+ax ++ add(x, b, x); //x=x^3+ax+b ++ divide(x, p, tmp); //x=x^3+ax+b mod p ++ power(y, 2, p, y); //y=y^2 mod p ++ if (mr_compare(x, y) != 0) ++ return ERR_NOT_VALID_POINT; ++ ++ return 0; ++} ++ ++/**************************************************************** ++ Function: Test_PubKey ++ Description: test if the given public key is valid ++ Calls: ++ Called By: SM2_KeyGeneration ++ Input: pubKey //a point ++ Output: null ++ Return: 0: success ++ 2: a point at infinity ++ 5: X or Y coordinate is beyond Fq ++ 3: not a valid point on curve ++ 4: not a point of order n ++ Others: ++****************************************************************/ ++int Test_PubKey(epoint *pubKey) ++{ ++ big x, y; ++ epoint *nP; ++ char mem[MR_BIG_RESERVE(2)]; ++ char mem_point[MR_ECP_RESERVE(1)]; ++ ++ sbi_memset(mem, 0, MR_BIG_RESERVE(2)); ++ x = mirvar_mem(mem, 0); ++ y = mirvar_mem(mem, 1); ++ ++ sbi_memset(mem_point, 0, MR_ECP_RESERVE(1)); ++ nP = epoint_init_mem(mem_point, 0); ++ ++ //test if the pubKey is the point at infinity ++ if (point_at_infinity(pubKey)) // if pubKey is point at infinity, return error; ++ return ERR_INFINITY_POINT; ++ ++ //test if x

0)) ++ return 1; ++ return 0; ++} ++ ++/* ++ * the private key, a big number lies in[1,n-2] ++ */ ++static void SM2_make_prikey(unsigned char prikey[]) ++{ ++#ifdef PENGLAI_RANDOM_PRIKEY ++ big x, one, decr_n2; ++ char mem[MR_BIG_RESERVE(3)]; ++ ++ sbi_memset(mem, 0, MR_BIG_RESERVE(3)); ++ x = mirvar_mem(mem, 0); ++ one = mirvar_mem(mem, 1); ++ decr_n2 = mirvar_mem(mem, 2); ++ ++ convert(1, one); ++ decr(n, 2, decr_n2); ++ do{ ++ bigrand(n, x); // generate a big random number 0<=x 0)); ++ ++ big_to_bytes(SM2_NUMWORD, x, (char *)prikey, TRUE); ++#else ++ unsigned char dA[32] = { ++ 0x39, 0x45, 0x20, 0x8f, 0x7b, 0x21, 0x44, 0xb1, 0x3f, 0x36, 0xe3, 0x8a, 0xc6, 0xd3, 0x9f, 0x95, ++ 0x88, 0x93, 0x93, 0x69, 0x28, 0x60, 0xb5, 0x1a, 0x42, 0xfb, 0x81, 0xef, 0x4d, 0xf7, 0xc5, 0xb8}; ++ ++ sbi_memcpy(prikey, dA, 32); ++#endif ++} ++ ++/**************************************************************** ++ Function: SM2_make_pubkey ++ Description: calculate a pubKey out of a given priKey ++ Calls: ++ Called By: SM2_KeyGeneration() ++ Input: priKey // a big number lies in[1,n-2] ++ Output: pubKey // pubKey=[priKey]G ++ Return: 0: success ++ 2: a point at infinity ++ 5: X or Y coordinate is beyond Fq ++ 3: not a valid point on curve ++ 4: not a point of order n ++ Others: ++****************************************************************/ ++static int SM2_make_pubkey(unsigned char PriKey[], unsigned char Px[], unsigned char Py[]) ++{ ++ int i = 0; ++ big d, PAx, PAy; ++ epoint *PA; ++ char mem_point[MR_ECP_RESERVE(1)]; ++ char mem[MR_BIG_RESERVE(3)]; ++ ++ sbi_memset(mem_point, 0, MR_ECP_RESERVE(1)); ++ PA = epoint_init_mem(mem_point, 0); ++ ++ sbi_memset(mem, 0, MR_BIG_RESERVE(3)); ++ d = mirvar_mem(mem, 0); ++ PAx = mirvar_mem(mem, 1); ++ PAy = mirvar_mem(mem, 2); ++ ++ bytes_to_big(SM2_NUMWORD, (const char *)PriKey, d); ++ ++ ecurve_mult(d, G, PA); ++ epoint_get(PA, PAx, PAy); ++ ++ big_to_bytes(SM2_NUMWORD, PAx, (char *)Px, TRUE); ++ big_to_bytes(SM2_NUMWORD, PAy, (char *)Py, TRUE); ++ i = Test_PubKey(PA); ++ if (i) ++ return i; ++ return 0; ++} ++ ++/**************************************************************** ++ Function: SM2_KeyGeneration ++ Description: generate a priKey and calculate a pubKey out of it ++ Calls: SM2_make_pubkey() ++ Called By: SM2_SelfCheck() ++ Input: priKey // a big number lies in[1,n-2] ++ Output: pubKey // pubKey=[priKey]G ++ Return: 0: success ++ 2: a point at infinity ++ 5: X or Y coordinate is beyond Fq ++ 3: not a valid point on curve ++ 4: not a point of order n ++ Others: ++****************************************************************/ ++int SM2_KeyGeneration(unsigned char PriKey[], unsigned char Px[], unsigned char Py[]) ++{ ++ int i = 0; ++ ++ SM2_make_prikey(PriKey); ++ i = SM2_make_pubkey(PriKey, Px, Py); ++ if (i) ++ return i; ++ return 0; ++} ++ ++/* ++ * random, a random number K lies in [1,n-1] ++ */ ++static void SM2_gen_random(unsigned char rand[]) ++{ ++ big x, one, decr_n1; ++ char mem[MR_BIG_RESERVE(3)]; ++ ++ sbi_memset(mem, 0, MR_BIG_RESERVE(3)); ++ x = mirvar_mem(mem, 0); ++ one = mirvar_mem(mem, 1); ++ decr_n1 = mirvar_mem(mem, 2); ++ ++ convert(1, one); ++ decr(n, 1, decr_n1); ++ do{ ++ bigrand(n, x); // generate a big random number 0<=x 0)); ++ ++ big_to_bytes(SM2_NUMWORD, x, (char *)rand, TRUE); ++} ++ ++/**************************************************************** ++ Function: SM2_compute_ZA ++ Description: compute ZA out of a given pubkey ++ Calls: SM3_256() ++ Called By: SM2_Sign() SM2_Verify() ++ Input: pubKey // pubKey=[priKey]G ++ Output: ZA //ZA=Hash(ENTLA|| IDA|| a|| b|| Gx || Gy || xA|| yA) ++ Others: ++****************************************************************/ ++static void SM2_compute_ZA(unsigned char ZA[], unsigned char Px[], unsigned char Py[]) ++{ ++ unsigned char Msg[210]; ++ unsigned char IDA[16] = { ++ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, ++ 0x34, 0x35, 0x36, 0x37, 0x38}; //ASCII code of userA's identification ++ int IDA_len = 16; ++ unsigned char ENTLA[2] = {0x00, 0x80}; //the length of userA's identification,presentation in ASCII code ++ ++ // ENTLA|| IDA|| a|| b|| Gx || Gy || xA|| yA ++ sbi_memcpy(Msg, ENTLA, 2); ++ sbi_memcpy(Msg + 2, IDA, IDA_len); ++ sbi_memcpy(Msg + 2 + IDA_len, SM2_a, SM2_NUMWORD); ++ sbi_memcpy(Msg + 2 + IDA_len + SM2_NUMWORD, SM2_b, SM2_NUMWORD); ++ sbi_memcpy(Msg + 2 + IDA_len + SM2_NUMWORD * 2, SM2_Gx, SM2_NUMWORD); ++ sbi_memcpy(Msg + 2 + IDA_len + SM2_NUMWORD * 3, SM2_Gy, SM2_NUMWORD); ++ sbi_memcpy(Msg + 2 + IDA_len + SM2_NUMWORD * 4, Px, SM2_NUMWORD); ++ sbi_memcpy(Msg + 2 + IDA_len + SM2_NUMWORD * 5, Py, SM2_NUMWORD); ++ SM3_256(Msg, 210, ZA); ++} ++ ++/**************************************************************** ++ Function: SM2_Sign ++ Description: SM2 signature algorithm ++ Calls: SM2_Init(),Test_Zero(),Test_n(), SM3_256() ++ Called By: SM2_SelfCheck() ++ Input: message //the message to be signed ++ len //the length of message ++ d //the private key ++ Output: R,S //signature result ++ Return: 0: success ++ 1: parameter initialization error; ++ 4: the given point G is not a point of order n ++ 6: the signed r equals 0 or r+rand equals n ++ 7 the signed s equals 0 ++ Others: ++****************************************************************/ ++int SM2_Sign(unsigned char *message, int len, unsigned char d[], unsigned char R[], unsigned char S[]) ++{ ++ unsigned char rand[32]; ++ unsigned char Px[32], Py[32]; ++ unsigned char ZA[SM3_len / 8]; // ZA=Hash(ENTLA|| IDA|| a|| b|| Gx || Gy || xA|| yA) ++ unsigned char hash[SM3_len / 8]; ++ int M_len = len + SM3_len / 8; ++ unsigned char M[MAX_MESSAGE_SIZE + SM3_len / 8 + 1]; ++ char mem[MR_BIG_RESERVE(11)]; ++ char mem_point[MR_ECP_RESERVE(1)]; ++ ++ big dA, r, s, e, k, KGx, KGy; ++ big rem, rk, z1, z2; ++ epoint *KG; ++ ++ //initiate ++ sbi_memset(mem, 0, MR_BIG_RESERVE(11)); ++ dA = mirvar_mem(mem, 0); ++ e = mirvar_mem(mem, 1); ++ k = mirvar_mem(mem, 2); ++ KGx = mirvar_mem(mem, 3); ++ KGy = mirvar_mem(mem, 4); ++ r = mirvar_mem(mem, 5); ++ s = mirvar_mem(mem, 6); ++ rem = mirvar_mem(mem, 7); ++ rk = mirvar_mem(mem, 8); ++ z1 = mirvar_mem(mem, 9); ++ z2 = mirvar_mem(mem, 10); ++ ++ bytes_to_big(SM2_NUMWORD, (const char *)d, dA); //cinstr(dA,d); ++ ++ sbi_memset(mem_point, 0, MR_ECP_RESERVE(1)); ++ KG = epoint_init_mem(mem_point, 0); ++ ++ //step1,set M=ZA||M ++ sbi_memset(M, 0, MAX_MESSAGE_SIZE + SM3_len / 8 + 1); ++ SM2_make_pubkey(d, Px, Py); ++ SM2_compute_ZA(ZA, Px, Py); ++ sbi_memcpy(M, ZA, SM3_len / 8); ++ sbi_memcpy(M + SM3_len / 8, message, len); ++ ++ //step2,generate e=H(M) ++ sbi_memset(hash, 0, SM3_len / 8); ++ SM3_256(M, M_len, hash); ++ bytes_to_big(SM3_len / 8, (const char *)hash, e); ++ ++ //step3:generate k ++ SM2_gen_random(rand); ++ bytes_to_big(SM3_len / 8, (const char *)rand, k); ++ ++ //step4:calculate kG ++ ecurve_mult(k, G, KG); ++ ++ //step5:calculate r ++ epoint_get(KG, KGx, KGy); ++ add(e, KGx, r); ++ divide(r, n, rem); ++ ++ //judge r=0 or n+k=n? ++ add(r, k, rk); ++ if (Test_Zero(r) | Test_n(rk)) ++ return ERR_GENERATE_R; ++ ++ //step6:generate s ++ incr(dA, 1, z1); ++ xgcd(z1, n, z1, z1, z1); ++ multiply(r, dA, z2); ++ divide(z2, n, rem); ++ subtract(k, z2, z2); ++ add(z2, n, z2); ++ multiply(z1, z2, s); ++ divide(s, n, rem); ++ ++ //judge s=0? ++ if (Test_Zero(s)) ++ return ERR_GENERATE_S; ++ ++ big_to_bytes(SM2_NUMWORD, r, (char *)R, TRUE); ++ big_to_bytes(SM2_NUMWORD, s, (char *)S, TRUE); ++ ++ return 0; ++} ++ ++/**************************************************************** ++ Function: SM2_Verify ++ Description: SM2 verification algorithm ++ Calls: SM2_Init(),Test_Range(), Test_Zero(),SM3_256() ++ Called By: SM2_SelfCheck() ++ Input: message //the message to be signed ++ len //the length of message ++ Px,Py //the public key ++ R,S //signature result ++ Output: ++ Return: 0: success ++ 1: parameter initialization error; ++ 4: the given point G is not a point of order n ++ B: public key error ++ 8: the signed R out of range [1,n-1] ++ 9: the signed S out of range [1,n-1] ++ A: the intermediate data t equals 0 ++ C: verification fail ++ Others: ++****************************************************************/ ++int SM2_Verify(unsigned char *message, int len, unsigned char Px[], unsigned char Py[], unsigned char R[], unsigned char S[]) ++{ ++ unsigned char ZA[SM3_len / 8]; // ZA=Hash(ENTLA|| IDA|| a|| b|| Gx || Gy || xA|| yA) ++ unsigned char hash[SM3_len / 8]; ++ int M_len = len + SM3_len / 8; ++ unsigned char M[MAX_MESSAGE_SIZE + SM3_len / 8 + 1]; ++ char mem[MR_BIG_RESERVE(10)]; ++ char mem_point[MR_ECP_RESERVE(3)]; ++ ++ big PAx, PAy, r, s, e, t, rem, x1, y1; ++ big RR; ++ epoint *PA, *sG, *tPA; ++ ++ sbi_memset(mem, 0, MR_BIG_RESERVE(10)); ++ PAx = mirvar_mem(mem, 0); ++ PAy = mirvar_mem(mem, 1); ++ r = mirvar_mem(mem, 2); ++ s = mirvar_mem(mem, 3); ++ e = mirvar_mem(mem, 4); ++ t = mirvar_mem(mem, 5); ++ x1 = mirvar_mem(mem, 6); ++ y1 = mirvar_mem(mem, 7); ++ rem = mirvar_mem(mem, 8); ++ RR = mirvar_mem(mem, 9); ++ ++ sbi_memset(mem_point, 0, MR_ECP_RESERVE(3)); ++ PA = epoint_init_mem(mem_point, 0); ++ sG = epoint_init_mem(mem_point, 1); ++ tPA = epoint_init_mem(mem_point, 2); ++ ++ bytes_to_big(SM2_NUMWORD, (const char *)Px, PAx); ++ bytes_to_big(SM2_NUMWORD, (const char *)Py, PAy); ++ ++ bytes_to_big(SM2_NUMWORD, (const char *)R, r); ++ bytes_to_big(SM2_NUMWORD, (const char *)S, s); ++ ++ if (!epoint_set(PAx, PAy, 0, PA)) //initialise public key ++ return ERR_PUBKEY_INIT; ++ ++ //step1:test if r belong to [1,n-1] ++ if (Test_Range(r)) ++ return ERR_OUTRANGE_R; ++ ++ //step2:test if s belong to [1,n-1] ++ if (Test_Range(s)) ++ return ERR_OUTRANGE_S; ++ ++ //step3:generate M ++ SM2_compute_ZA(ZA, Px, Py); ++ sbi_memcpy(M, ZA, SM3_len / 8); ++ sbi_memcpy(M + SM3_len / 8, message, len); ++ ++ //step4:generate e=H(M) ++ SM3_256(M, M_len, hash); ++ bytes_to_big(SM3_len / 8, (const char*)hash, e); ++ ++ //step5:generate t ++ add(r, s, t); ++ divide(t, n, rem); ++ ++ if (Test_Zero(t)) ++ return ERR_GENERATE_T; ++ ++ //step6:generate(x1,y1) ++ ecurve_mult(s, G, sG); ++ ecurve_mult(t, PA, tPA); ++ ecurve_add(sG, tPA); ++ epoint_get(tPA, x1, y1); ++ ++ //step7:generate RR ++ add(e, x1, RR); ++ divide(RR, n, rem); ++ ++ if (mr_compare(RR, r) == 0) ++ return 0; ++ ++ return ERR_DATA_MEMCMP; ++} ++ ++/**************************************************************** ++ Function: SM2_SelfCheck ++ Description: SM2 self check ++ Calls: SM2_Init(), SM2_KeyGeneration,SM2_Sign, SM2_Verify,SM3_256() ++ Called By: ++ Input: ++ Output: ++ Return: 0: success ++ 1: paremeter initialization error ++ 2: a point at infinity ++ 5: X or Y coordinate is beyond Fq ++ 3: not a valid point on curve ++ 4: not a point of order n ++ B: public key error ++ 8: the signed R out of range [1,n-1] ++ 9: the signed S out of range [1,n-1] ++ A: the intermediate data t equals 0 ++ C: verification fail ++ Others: ++****************************************************************/ ++int SM2_SelfCheck() ++{ ++ unsigned long sp_ptr; ++ asm volatile("mv %0 ,sp" : "=r"(sp_ptr)); ++ printm(" - - - - SM2_SelfCheck , stack: %lx - - - - \n", sp_ptr); ++ ++ int temp; ++ unsigned char dA[32]; // the private key ++ unsigned char xA[32], yA[32]; // the public key ++ unsigned char r[32], s[32]; // Signature ++ ++ unsigned char *message = (unsigned char *)"message digest"; //the message to be signed ++ int len = sbi_strlen((const char *)message); //the length of message ++ ++ temp = SM2_Init(); ++ printm(" - - - - SM2_init finished ret %d - - - - \n", temp); ++ if (temp) ++ return temp; ++ ++ temp = SM2_KeyGeneration(dA, xA, yA); ++ printm(" - - - - KeyGeneration finished ret %d - - - - \n", temp); ++ if (temp) ++ return temp; ++ ++ temp = SM2_Sign(message, len, dA, r, s); ++ printm(" - - - - SM2_sign finished ret %d - - - - \n", temp); ++ if (temp) ++ return temp; ++ ++ temp = SM2_Verify(message, len, xA, yA, r, s); ++ printm(" - - - - SM2_Verify finished ret %d - - - - \n", temp); ++ if (temp) ++ return temp; ++ ++ return 0; ++} +diff --git a/lib/sbi/sm/gm/SM3.c b/lib/sbi/sm/gm/SM3.c +new file mode 100644 +index 0000000..bba534c +--- /dev/null ++++ b/lib/sbi/sm/gm/SM3.c +@@ -0,0 +1,399 @@ ++/************************************************************************ ++ Copyright (c) IPADS@SJTU 2021. Modification to support Penglai (RISC-V TEE) ++ ++ This file contains GM/T SM2 standard implementation, provided by the Commercial ++ Cryptography Testing Center, see for more infomation. ++ ++ File name: SM3.c ++ Version: SM3_V1.1 ++ Date: Sep 18,2016 ++ Description: to calculate a hash message from a given message ++ Function List: ++ 1.SM3_256 //calls SM3_init, SM3_process and SM3_done to calculate hash value ++ 2.SM3_init //init the SM3 state ++ 3.SM3_process //compress the the first len/64 blocks of the message ++ 4.SM3_done //compress the rest message and output the hash value ++ 5.SM3_compress //called by SM3_process and SM3_done, compress a single block of message ++ 6.BiToW //called by SM3_compress,to calculate W from Bi ++ 7.WToW1 //called by SM3_compress, calculate W' from W ++ 8.CF //called by SM3_compress, to calculate CF function. ++ 9.BigEndian //called by SM3_compress and SM3_done.GM/T 0004-2012 requires to use big-endian. ++ //if CPU uses little-endian, BigEndian function is a necessary call to change the ++ //little-endian format into big-endian format. ++ 10.SM3_SelfTest //test whether the SM3 calculation is correct by comparing the hash result with the standard data ++**************************************************************************/ ++ ++#include "sm/gm/SM3.h" ++ ++#include "sbi/sbi_string.h" ++ ++/**************************************************************** ++ Function: BiToW ++ Description: calculate W from Bi ++ Calls: ++ Called By: SM3_compress ++ Input: Bi[16] //a block of a message ++ Output: W[64] ++ Return: null ++ Others: ++****************************************************************/ ++void BiToW(unsigned int Bi[], unsigned int W[]) ++{ ++ int i; ++ unsigned int tmp; ++ ++ for (i = 0; i <= 15; i++) ++ W[i] = Bi[i]; ++ for (i = 16; i <= 67; i++) ++ { ++ tmp = W[i - 16] ^ W[i - 9] ^ SM3_rotl32(W[i - 3], 15); ++ W[i] = SM3_p1(tmp) ^ (SM3_rotl32(W[i - 13], 7)) ^ W[i - 6]; ++ } ++} ++ ++/***************************************************************** ++ Function: WToW1 ++ Description: calculate W1 from W ++ Calls: ++ Called By: SM3_compress ++ Input: W[64] ++ Output: W1[64] ++ Return: null ++ Others: ++*****************************************************************/ ++void WToW1(unsigned int W[], unsigned int W1[]) ++{ ++ int i; ++ for (i = 0; i <= 63; i++) ++ W1[i] = W[i] ^ W[i + 4]; ++} ++ ++/****************************************************************** ++ Function: CF ++ Description: calculate the CF compress function and update V ++ Calls: ++ Called By: SM3_compress ++ Input: W[64] ++ W1[64] ++ V[8] ++ Output: V[8] ++ Return: null ++ Others: ++********************************************************************/ ++void CF(unsigned int W[], unsigned int W1[], unsigned int V[]) ++{ ++ unsigned int SS1; ++ unsigned int SS2; ++ unsigned int TT1; ++ unsigned int TT2; ++ unsigned int A, B, C, D, E, F, G, H; ++ unsigned int T = SM3_T1; ++ unsigned int FF; ++ unsigned int GG; ++ int j; ++ ++ //reg init,set ABCDEFGH=V0 ++ A = V[0]; ++ B = V[1]; ++ C = V[2]; ++ D = V[3]; ++ E = V[4]; ++ F = V[5]; ++ G = V[6]; ++ H = V[7]; ++ ++ for (j = 0; j <= 63; j++) ++ { ++ //SS1 ++ if (j == 0) ++ T = SM3_T1; ++ else if (j == 16) ++ T = SM3_rotl32(SM3_T2, 16); ++ else ++ T = SM3_rotl32(T, 1); ++ SS1 = SM3_rotl32((SM3_rotl32(A, 12) + E + T), 7); ++ ++ //SS2 ++ SS2 = SS1 ^ SM3_rotl32(A, 12); ++ ++ //TT1 ++ if (j <= 15) ++ FF = SM3_ff0(A, B, C); ++ else ++ FF = SM3_ff1(A, B, C); ++ TT1 = FF + D + SS2 + *W1; ++ W1++; ++ ++ //TT2 ++ if (j <= 15) ++ GG = SM3_gg0(E, F, G); ++ else ++ GG = SM3_gg1(E, F, G); ++ TT2 = GG + H + SS1 + *W; ++ W++; ++ ++ //D ++ D = C; ++ ++ //C ++ C = SM3_rotl32(B, 9); ++ ++ //B ++ B = A; ++ ++ //A ++ A = TT1; ++ ++ //H ++ H = G; ++ //G ++ G = SM3_rotl32(F, 19); ++ ++ //F ++ F = E; ++ ++ //E ++ E = SM3_p0(TT2); ++ } ++ ++ //update V ++ V[0] = A ^ V[0]; ++ V[1] = B ^ V[1]; ++ V[2] = C ^ V[2]; ++ V[3] = D ^ V[3]; ++ V[4] = E ^ V[4]; ++ V[5] = F ^ V[5]; ++ V[6] = G ^ V[6]; ++ V[7] = H ^ V[7]; ++} ++ ++/****************************************************************************** ++ Function: BigEndian ++ Description: U32 endian converse.GM/T 0004-2012 requires to use big-endian. ++ if CPU uses little-endian, BigEndian function is a necessary ++ call to change the little-endian format into big-endian format. ++ Calls: ++ Called By: SM3_compress, SM3_done ++ Input: src[bytelen] ++ bytelen ++ Output: des[bytelen] ++ Return: null ++ Others: src and des could implies the same address ++*******************************************************************************/ ++void BigEndian(unsigned char src[], unsigned int bytelen, unsigned char des[]) ++{ ++ unsigned char tmp = 0; ++ unsigned int i = 0; ++ ++ for (i = 0; i < bytelen / 4; i++) ++ { ++ tmp = des[4 * i]; ++ des[4 * i] = src[4 * i + 3]; ++ src[4 * i + 3] = tmp; ++ ++ tmp = des[4 * i + 1]; ++ des[4 * i + 1] = src[4 * i + 2]; ++ des[4 * i + 2] = tmp; ++ } ++} ++ ++/****************************************************************************** ++ Function: SM3_init ++ Description: initiate SM3 state ++ Calls: ++ Called By: SM3_256 ++ Input: SM3_STATE *md ++ Output: SM3_STATE *md ++ Return: null ++ Others: ++*******************************************************************************/ ++void SM3_init(SM3_STATE *md) ++{ ++ md->curlen = md->length = 0; ++ md->state[0] = SM3_IVA; ++ md->state[1] = SM3_IVB; ++ md->state[2] = SM3_IVC; ++ md->state[3] = SM3_IVD; ++ md->state[4] = SM3_IVE; ++ md->state[5] = SM3_IVF; ++ md->state[6] = SM3_IVG; ++ md->state[7] = SM3_IVH; ++} ++ ++/****************************************************************************** ++ Function: SM3_compress ++ Description: compress a single block of message ++ Calls: BigEndian ++ BiToW ++ WToW1 ++ CF ++ Called By: SM3_256 ++ Input: SM3_STATE *md ++ Output: SM3_STATE *md ++ Return: null ++ Others: ++*******************************************************************************/ ++void SM3_compress(SM3_STATE *md) ++{ ++ unsigned int W[68]; ++ unsigned int W1[64]; ++ ++ //if CPU uses little-endian, BigEndian function is a necessary call ++ BigEndian(md->buf, 64, md->buf); ++ ++ BiToW((unsigned int *)md->buf, W); ++ WToW1(W, W1); ++ CF(W, W1, md->state); ++} ++ ++/****************************************************************************** ++ Function: SM3_process ++ Description: compress the first (len/64) blocks of message ++ Calls: SM3_compress ++ Called By: SM3_256 ++ Input: SM3_STATE *md ++ unsigned char buf[len] //the input message ++ int len //bytelen of message ++ Output: SM3_STATE *md ++ Return: null ++ Others: ++*******************************************************************************/ ++void SM3_process(SM3_STATE *md, unsigned char *buf, int len) ++{ ++ while (len--) ++ { ++ /* copy byte */ ++ md->buf[md->curlen] = *buf++; ++ md->curlen++; ++ ++ /* is 64 bytes full? */ ++ if (md->curlen == 64) ++ { ++ SM3_compress(md); ++ md->length += 512; ++ md->curlen = 0; ++ } ++ } ++} ++ ++/****************************************************************************** ++ Function: SM3_done ++ Description: compress the rest message that the SM3_process has left behind ++ Calls: SM3_compress ++ Called By: SM3_256 ++ Input: SM3_STATE *md ++ Output: unsigned char *hash ++ Return: null ++ Others: ++*******************************************************************************/ ++void SM3_done(SM3_STATE *md, unsigned char hash[]) ++{ ++ int i; ++ ++ /* increase the bit length of the message */ ++ md->length += md->curlen << 3; ++ ++ /* append the '1' bit */ ++ md->buf[md->curlen] = 0x80; ++ md->curlen++; ++ ++ /* if the length is currently above 56 bytes, appends zeros till ++ * it reaches 64 bytes, compress the current block, creat a new ++ * block by appending zeros and length,and then compress it */ ++ if (md->curlen > 56) ++ { ++ for (; md->curlen < 64;) ++ { ++ md->buf[md->curlen] = 0; ++ md->curlen++; ++ } ++ SM3_compress(md); ++ md->curlen = 0; ++ } ++ ++ /* if the length is less than 56 bytes, pad upto 56 bytes of zeroes */ ++ for (; md->curlen < 56;) ++ { ++ md->buf[md->curlen] = 0; ++ md->curlen++; ++ } ++ ++ /* since all messages are under 2^32 bits we mark the top bits zero */ ++ for (i = 56; i < 60; i++) ++ md->buf[i] = 0; ++ ++ /* append length */ ++ md->buf[63] = md->length & 0xff; ++ md->buf[62] = (md->length >> 8) & 0xff; ++ md->buf[61] = (md->length >> 16) & 0xff; ++ md->buf[60] = (md->length >> 24) & 0xff; ++ ++ SM3_compress(md); ++ ++ /* copy output */ ++ sbi_memcpy(hash, md->state, SM3_len / 8); ++ BigEndian(hash, SM3_len / 8, hash); //if CPU uses little-endian, BigEndian function is a necessary call ++} ++ ++/****************************************************************************** ++ Function: SM3_256 ++ Description: calculate a hash value from a given message ++ Calls: SM3_init ++ SM3_process ++ SM3_done ++ Called By: ++ Input: unsigned char buf[len] //the input message ++ int len //bytelen of the message ++ Output: unsigned char hash[32] ++ Return: null ++ Others: ++*******************************************************************************/ ++void SM3_256(unsigned char buf[], int len, unsigned char hash[]) ++{ ++ SM3_STATE md; ++ SM3_init(&md); ++ SM3_process(&md, buf, len); ++ SM3_done(&md, hash); ++} ++ ++/****************************************************************************** ++ Function: SM3_SelfTest ++ Description: test whether the SM3 calculation is correct by comparing ++ the hash result with the standard result ++ Calls: SM3_256 ++ Called By: ++ Input: null ++ Output: null ++ Return: 0 //the SM3 operation is correct ++ 1 //the sm3 operation is wrong ++ Others: ++*******************************************************************************/ ++int SM3_SelfTest() ++{ ++ unsigned int a = 1, b = 1; ++ unsigned char Msg1[3] = {0x61, 0x62, 0x63}; ++ int MsgLen1 = 3; ++ unsigned char MsgHash1[32] = {0}; ++ unsigned char StdHash1[32] = { ++ 0x66, 0xC7, 0xF0, 0xF4, 0x62, 0xEE, 0xED, 0xD9, 0xD1, 0xF2, 0xD4, 0x6B, 0xDC, 0x10, 0xE4, 0xE2, ++ 0x41, 0x67, 0xC4, 0x87, 0x5C, 0xF2, 0xF7, 0xA2, 0x29, 0x7D, 0xA0, 0x2B, 0x8F, 0x4B, 0xA8, 0xE0}; ++ unsigned char Msg2[64] = { ++ 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, ++ 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, ++ 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, ++ 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64}; ++ int MsgLen2 = 64; ++ unsigned char MsgHash2[32] = {0}; ++ unsigned char StdHash2[32] = { ++ 0xde, 0xbe, 0x9f, 0xf9, 0x22, 0x75, 0xb8, 0xa1, 0x38, 0x60, 0x48, 0x89, 0xc1, 0x8e, 0x5a, 0x4d, ++ 0x6f, 0xdb, 0x70, 0xe5, 0x38, 0x7e, 0x57, 0x65, 0x29, 0x3d, 0xcb, 0xa3, 0x9c, 0x0c, 0x57, 0x32}; ++ SM3_256(Msg1, MsgLen1, MsgHash1); ++ SM3_256(Msg2, MsgLen2, MsgHash2); ++ ++ a = sbi_memcmp(MsgHash1, StdHash1, SM3_len / 8); ++ b = sbi_memcmp(MsgHash2, StdHash2, SM3_len / 8); ++ ++ if ((a == 0) && (b == 0)) ++ return 0; ++ return 1; ++} +diff --git a/lib/sbi/sm/gm/miracl/mrarth0.c b/lib/sbi/sm/gm/miracl/mrarth0.c +new file mode 100644 +index 0000000..6938740 +--- /dev/null ++++ b/lib/sbi/sm/gm/miracl/mrarth0.c +@@ -0,0 +1,321 @@ ++ ++/*************************************************************************** ++ * ++Copyright 2013 CertiVox UK Ltd. * ++ * ++This file is part of CertiVox MIRACL Crypto SDK. * ++ * ++The CertiVox MIRACL Crypto SDK provides developers with an * ++extensive and efficient set of cryptographic functions. * ++For further information about its features and functionalities please * ++refer to http://www.certivox.com * ++ * ++* The CertiVox MIRACL Crypto SDK is free software: you can * ++ redistribute it and/or modify it under the terms of the * ++ GNU Affero General Public License as published by the * ++ Free Software Foundation, either version 3 of the License, * ++ or (at your option) any later version. * ++ * ++* The CertiVox MIRACL Crypto SDK is distributed in the hope * ++ that it will be useful, but WITHOUT ANY WARRANTY; without even the * ++ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * ++ See the GNU Affero General Public License for more details. * ++ * ++* You should have received a copy of the GNU Affero General Public * ++ License along with CertiVox MIRACL Crypto SDK. * ++ If not, see . * ++ * ++You can be released from the requirements of the license by purchasing * ++a commercial license. Buying such a license is mandatory as soon as you * ++develop commercial activities involving the CertiVox MIRACL Crypto SDK * ++without disclosing the source code of your own applications, or shipping * ++the CertiVox MIRACL Crypto SDK with a closed source product. * ++ * ++***************************************************************************/ ++/* ++ * MIRACL arithmetic routines 0 - Add and subtract routines ++ * mrarth0.c ++ * ++ */ ++ ++#include "sm/gm/miracl/miracl.h" ++ ++void mr_padd(_MIPD_ big x,big y,big z) ++{ /* add two big numbers, z=x+y where * ++ * x and y are positive */ ++ int i,lx,ly,lz,la; ++ mr_small carry,psum; ++ mr_small *gx,*gy,*gz; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ lx = (int)x->len; ++ ly = (int)y->len; ++ ++ if (ly>lx) ++ { ++ lz=ly; ++ la=lx; ++ if (x!=z) copy(y,z); ++ else la=ly; ++ } ++ else ++ { ++ lz=lx; ++ la=ly; ++ if (y!=z) copy(x,z); ++ else la=lx; ++ } ++ carry=0; ++ z->len=lz; ++ gx=x->w; gy=y->w; gz=z->w; ++ if (lznib || !mr_mip->check) z->len++; ++#ifndef MR_SIMPLE_BASE ++ if (mr_mip->base==0) ++ { ++#endif ++ for (i=0;igx[i]) carry=0; ++ else if (psum0;i++ ) ++ { /* add by columns to the length of larger number (if there is a carry) */ ++ psum=gx[i]+gy[i]+carry; ++ if (psum>gx[i]) carry=0; ++ else if (psumcheck && i>=mr_mip->nib) ++ { ++ mr_berror(_MIPP_ MR_ERR_OVERFLOW); ++ return; ++ } ++ gz[i]=carry; ++ } ++#ifndef MR_SIMPLE_BASE ++ } ++ else ++ { ++ for (i=0;i=mr_mip->base) ++ { /* set carry */ ++ carry=1; ++ psum-=mr_mip->base; ++ } ++ gz[i]=psum; ++ } ++ for (;i0;i++) ++ { ++ psum=gx[i]+gy[i]+carry; ++ carry=0; ++ if (psum>=mr_mip->base) ++ { /* set carry */ ++ carry=1; ++ psum-=mr_mip->base; ++ } ++ gz[i]=psum; ++ } ++ if (carry) ++ { /* carry left over - possible overflow */ ++ if (mr_mip->check && i>=mr_mip->nib) ++ { ++ mr_berror(_MIPP_ MR_ERR_OVERFLOW); ++ return; ++ } ++ gz[i]=carry; ++ } ++ } ++#endif ++ if (gz[z->len-1]==0) z->len--; ++ ++} ++ ++void mr_psub(_MIPD_ big x,big y,big z) ++{ /* subtract two big numbers z=x-y * ++ * where x and y are positive and x>y */ ++ int i,lx,ly; ++ mr_small borrow,pdiff; ++ mr_small *gx,*gy,*gz; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ lx = (int)x->len; ++ ly = (int)y->len; ++ if (ly>lx) ++ { ++ mr_berror(_MIPP_ MR_ERR_NEG_RESULT); ++ return; ++ } ++ if (y!=z) copy(x,z); ++ else ly=lx; ++ z->len=lx; ++ gx=x->w; gy=y->w; gz=z->w; ++ borrow=0; ++#ifndef MR_SIMPLE_BASE ++ if (mr_mip->base==0) ++ { ++#endif ++ for (i=0;i0;i++) ++ { /* subtract by columns */ ++ if (i>lx) ++ { ++ mr_berror(_MIPP_ MR_ERR_NEG_RESULT); ++ return; ++ } ++ pdiff=gx[i]-gy[i]-borrow; ++ if (pdiffgx[i]) borrow=1; ++ gz[i]=pdiff; ++ } ++#ifndef MR_SIMPLE_BASE ++ } ++ else for (i=0;i0;i++) ++ { /* subtract by columns */ ++ if (i>lx) ++ { ++ mr_berror(_MIPP_ MR_ERR_NEG_RESULT); ++ return; ++ } ++ pdiff=gy[i]+borrow; ++ borrow=0; ++ if (gx[i]>=pdiff) pdiff=gx[i]-pdiff; ++ else ++ { /* set borrow */ ++ pdiff=mr_mip->base+gx[i]-pdiff; ++ borrow=1; ++ } ++ gz[i]=pdiff; ++ } ++#endif ++ mr_lzero(z); ++} ++ ++static void mr_select(_MIPD_ big x,int d,big y,big z) ++{ /* perform required add or subtract operation */ ++ int sx,sy,sz,jf,xgty; ++#ifdef MR_FLASH ++ if (mr_notint(x) || mr_notint(y)) ++ { ++ mr_berror(_MIPP_ MR_ERR_INT_OP); ++ return; ++ } ++#endif ++ sx=exsign(x); ++ sy=exsign(y); ++ sz=0; ++ x->len&=MR_OBITS; /* force operands to be positive */ ++ y->len&=MR_OBITS; ++ xgty=mr_compare(x,y); ++ jf=(1+sx)+(1+d*sy)/2; ++ switch (jf) ++ { /* branch according to signs of operands */ ++ case 0: ++ if (xgty>=0) ++ mr_padd(_MIPP_ x,y,z); ++ else ++ mr_padd(_MIPP_ y,x,z); ++ sz=MINUS; ++ break; ++ case 1: ++ if (xgty<=0) ++ { ++ mr_psub(_MIPP_ y,x,z); ++ sz=PLUS; ++ } ++ else ++ { ++ mr_psub(_MIPP_ x,y,z); ++ sz=MINUS; ++ } ++ break; ++ case 2: ++ if (xgty>=0) ++ { ++ mr_psub(_MIPP_ x,y,z); ++ sz=PLUS; ++ } ++ else ++ { ++ mr_psub(_MIPP_ y,x,z); ++ sz=MINUS; ++ } ++ break; ++ case 3: ++ if (xgty>=0) ++ mr_padd(_MIPP_ x,y,z); ++ else ++ mr_padd(_MIPP_ y,x,z); ++ sz=PLUS; ++ break; ++ } ++ if (sz<0) z->len^=MR_MSBIT; /* set sign of result */ ++ if (x!=z && sx<0) x->len^=MR_MSBIT; /* restore signs to operands */ ++ if (y!=z && y!=x && sy<0) y->len^=MR_MSBIT; ++} ++ ++void add(_MIPD_ big x,big y,big z) ++{ /* add two signed big numbers together z=x+y */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(27) ++ ++ mr_select(_MIPP_ x,PLUS,y,z); ++ ++ MR_OUT ++} ++ ++void subtract(_MIPD_ big x,big y,big z) ++{ /* subtract two big signed numbers z=x-y */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(28) ++ ++ mr_select(_MIPP_ x,MINUS,y,z); ++ ++ MR_OUT ++} ++ ++void incr(_MIPD_ big x,int n,big z) ++{ /* add int to big number: z=x+n */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(7) ++ ++ convert(_MIPP_ n,mr_mip->w0); ++ mr_select(_MIPP_ x,PLUS,mr_mip->w0,z); ++ ++ MR_OUT ++} ++ ++void decr(_MIPD_ big x,int n,big z) ++{ /* subtract int from big number: z=x-n */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(8) ++ ++ convert(_MIPP_ n,mr_mip->w0); ++ mr_select(_MIPP_ x,MINUS,mr_mip->w0,z); ++ ++ MR_OUT ++} ++ +diff --git a/lib/sbi/sm/gm/miracl/mrarth1.c b/lib/sbi/sm/gm/miracl/mrarth1.c +new file mode 100644 +index 0000000..2817a24 +--- /dev/null ++++ b/lib/sbi/sm/gm/miracl/mrarth1.c +@@ -0,0 +1,1058 @@ ++ ++/*************************************************************************** ++ * ++Copyright 2013 CertiVox UK Ltd. * ++ * ++This file is part of CertiVox MIRACL Crypto SDK. * ++ * ++The CertiVox MIRACL Crypto SDK provides developers with an * ++extensive and efficient set of cryptographic functions. * ++For further information about its features and functionalities please * ++refer to http://www.certivox.com * ++ * ++* The CertiVox MIRACL Crypto SDK is free software: you can * ++ redistribute it and/or modify it under the terms of the * ++ GNU Affero General Public License as published by the * ++ Free Software Foundation, either version 3 of the License, * ++ or (at your option) any later version. * ++ * ++* The CertiVox MIRACL Crypto SDK is distributed in the hope * ++ that it will be useful, but WITHOUT ANY WARRANTY; without even the * ++ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * ++ See the GNU Affero General Public License for more details. * ++ * ++* You should have received a copy of the GNU Affero General Public * ++ License along with CertiVox MIRACL Crypto SDK. * ++ If not, see . * ++ * ++You can be released from the requirements of the license by purchasing * ++a commercial license. Buying such a license is mandatory as soon as you * ++develop commercial activities involving the CertiVox MIRACL Crypto SDK * ++without disclosing the source code of your own applications, or shipping * ++the CertiVox MIRACL Crypto SDK with a closed source product. * ++ * ++***************************************************************************/ ++ ++/* ++ * ++ * MIRACL arithmetic routines 1 - multiplying and dividing BIG NUMBERS by ++ * integer numbers. ++ * mrarth1.c ++ * ++ */ ++ ++#include "sm/gm/miracl/miracl.h" ++ ++#ifdef MR_FP ++#include ++#endif ++ ++#ifdef MR_WIN64 ++#include ++#endif ++ ++#ifdef MR_FP_ROUNDING ++#ifdef __GNUC__ ++#include ++#endif ++ ++/* Invert n and set FP rounding. ++ * Set to round up ++ * Calculate 1/n ++ * set to round down (towards zero) ++ * If rounding cannot be controlled, this function returns 0.0 */ ++ ++mr_large mr_invert(mr_small n) ++{ ++ mr_large inn; ++ int up= 0x1BFF; ++ ++#ifdef _MSC_VER ++ #ifdef MR_NOASM ++#define NO_EXTENDED ++ #endif ++#endif ++ ++#ifdef NO_EXTENDED ++ int down=0x1EFF; ++#else ++ int down=0x1FFF; ++#endif ++ ++#ifdef __TURBOC__ ++ asm ++ { ++ fldcw WORD PTR up ++ fld1 ++ fld QWORD PTR n; ++ fdiv ++ fstp TBYTE PTR inn; ++ fldcw WORD PTR down; ++ } ++ return inn; ++#endif ++#ifdef _MSC_VER ++ _asm ++ { ++ fldcw WORD PTR up ++ fld1 ++ fld QWORD PTR n; ++ fdiv ++ fstp QWORD PTR inn; ++ fldcw WORD PTR down; ++ } ++ return inn; ++#endif ++#ifdef __GNUC__ ++#ifdef i386 ++ __asm__ __volatile__ ( ++ "fldcw %2\n" ++ "fld1\n" ++ "fldl %1\n" ++ "fdivrp\n" ++ "fstpt %0\n" ++ "fldcw %3\n" ++ : "=m"(inn) ++ : "m"(n),"m"(up),"m"(down) ++ : "memory" ++ ); ++ return inn; ++#else ++ fpsetround(FP_RP); ++ inn=(mr_large)1.0/n; ++ fpsetround(FP_RZ); ++ return inn; ++#endif ++#endif ++ return 0.0L; ++} ++ ++#endif ++ ++void mr_pmul(_MIPD_ big x,mr_small sn,big z) ++{ ++ int m,xl; ++ mr_lentype sx; ++ mr_small carry; ++ ++#ifdef MR_ITANIUM ++ mr_small tm; ++#endif ++#ifdef MR_WIN64 ++ mr_small tm; ++#endif ++#ifdef MR_NOASM ++ union doubleword dble; ++#endif ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ if (x!=z) ++ { ++ zero(z); ++ if (sn==0) return; ++ } ++ else if (sn==0) ++ { ++ zero(z); ++ return; ++ } ++ m=0; ++ carry=0; ++ sx=x->len&MR_MSBIT; ++ xl=(int)(x->len&MR_OBITS); ++ ++#ifndef MR_SIMPLE_BASE ++ if (mr_mip->base==0) ++ { ++#endif ++#ifndef MR_NOFULLWIDTH ++/* inline 8086 assembly - substitutes for loop below */ ++#ifdef INLINE_ASM ++#if INLINE_ASM == 1 ++ ASM cld ++ ASM mov cx,xl ++ ASM or cx,cx ++ ASM je out1 ++#ifdef MR_LMM ++ ASM push ds ++ ASM push es ++ ASM les di,DWORD PTR zg ++ ASM lds si,DWORD PTR xg ++#else ++ ASM mov ax,ds ++ ASM mov es,ax ++ ASM mov di,zg ++ ASM mov si,xg ++#endif ++ ASM mov bx,sn ++ ASM push bp ++ ASM xor bp,bp ++ tcl1: ++ ASM lodsw ++ ASM mul bx ++ ASM add ax,bp ++ ASM adc dx,0 ++ ASM stosw ++ ASM mov bp,dx ++ ASM loop tcl1 ++ ++ ASM mov ax,bp ++ ASM pop bp ++#ifdef MR_LMM ++ ASM pop es ++ ASM pop ds ++#endif ++ ASM mov carry,ax ++ out1: ++#endif ++#if INLINE_ASM == 2 ++ ASM cld ++ ASM mov cx,xl ++ ASM or cx,cx ++ ASM je out1 ++#ifdef MR_LMM ++ ASM push ds ++ ASM push es ++ ASM les di,DWORD PTR zg ++ ASM lds si,DWORD PTR xg ++#else ++ ASM mov ax,ds ++ ASM mov es,ax ++ ASM mov di,zg ++ ASM mov si,xg ++#endif ++ ASM mov ebx,sn ++ ASM push ebp ++ ASM xor ebp,ebp ++ tcl1: ++ ASM lodsd ++ ASM mul ebx ++ ASM add eax,ebp ++ ASM adc edx,0 ++ ASM stosd ++ ASM mov ebp,edx ++ ASM loop tcl1 ++ ++ ASM mov eax,ebp ++ ASM pop ebp ++#ifdef MR_LMM ++ ASM pop es ++ ASM pop ds ++#endif ++ ASM mov carry,eax ++ out1: ++#endif ++#if INLINE_ASM == 3 ++ ASM mov ecx,xl ++ ASM or ecx,ecx ++ ASM je out1 ++ ASM mov ebx,sn ++ ASM mov edi,zg ++ ASM mov esi,xg ++ ASM push ebp ++ ASM xor ebp,ebp ++ tcl1: ++ ASM mov eax,[esi] ++ ASM add esi,4 ++ ASM mul ebx ++ ASM add eax,ebp ++ ASM adc edx,0 ++ ASM mov [edi],eax ++ ASM add edi,4 ++ ASM mov ebp,edx ++ ASM dec ecx ++ ASM jnz tcl1 ++ ++ ASM mov eax,ebp ++ ASM pop ebp ++ ASM mov carry,eax ++ out1: ++#endif ++#if INLINE_ASM == 4 ++ ++ ASM ( ++ "movl %4,%%ecx\n" ++ "orl %%ecx,%%ecx\n" ++ "je 1f\n" ++ "movl %3,%%ebx\n" ++ "movl %1,%%edi\n" ++ "movl %2,%%esi\n" ++ "pushl %%ebp\n" ++ "xorl %%ebp,%%ebp\n" ++ "0:\n" ++ "movl (%%esi),%%eax\n" ++ "addl $4,%%esi\n" ++ "mull %%ebx\n" ++ "addl %%ebp,%%eax\n" ++ "adcl $0,%%edx\n" ++ "movl %%eax,(%%edi)\n" ++ "addl $4,%%edi\n" ++ "movl %%edx,%%ebp\n" ++ "decl %%ecx\n" ++ "jnz 0b\n" ++ ++ "movl %%ebp,%%eax\n" ++ "popl %%ebp\n" ++ "movl %%eax,%0\n" ++ "1:" ++ :"=m"(carry) ++ :"m"(zg),"m"(xg),"m"(sn),"m"(xl) ++ :"eax","edi","esi","ebx","ecx","edx","memory" ++ ); ++ ++#endif ++#endif ++#ifndef INLINE_ASM ++ for (m=0;mw[m]*sn+carry; ++ carry=dble.h[MR_TOP]; ++ z->w[m]=dble.h[MR_BOT]; ++ } ++#else ++ carry=muldvd(x->w[m],sn,carry,&z->w[m]); ++#endif ++#endif ++ if (carry>0) ++ { ++ m=xl; ++ if (m>=mr_mip->nib && mr_mip->check) ++ { ++ mr_berror(_MIPP_ MR_ERR_OVERFLOW); ++ return; ++ } ++ z->w[m]=carry; ++ z->len=m+1; ++ } ++ else z->len=xl; ++#endif ++#ifndef MR_SIMPLE_BASE ++ } ++ else while (m0) ++ { /* multiply each digit of x by n */ ++ ++ if (m>mr_mip->nib && mr_mip->check) ++ { ++ mr_berror(_MIPP_ MR_ERR_OVERFLOW); ++ return; ++ } ++#ifdef MR_NOASM ++ dbled=(mr_large)x->w[m]*sn+carry; ++ #ifdef MR_FP_ROUNDING ++ carry=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); ++ #else ++ #ifndef MR_FP ++ if (mr_mip->base==mr_mip->base2) ++ carry=(mr_small)(dbled>>mr_mip->lg2b); ++ else ++ #endif ++ carry=(mr_small)MR_LROUND(dbled/mr_mip->base); ++ #endif ++ z->w[m]=(mr_small)(dbled-(mr_large)carry*mr_mip->base); ++#else ++ #ifdef MR_FP_ROUNDING ++ carry=imuldiv(x->w[m],sn,carry,mr_mip->base,mr_mip->inverse_base,&z->w[m]); ++ #else ++ carry=muldiv(x->w[m],sn,carry,mr_mip->base,&z->w[m]); ++ #endif ++#endif ++ ++ m++; ++ z->len=m; ++ } ++#endif ++ if (z->len!=0) z->len|=sx; ++} ++ ++void premult(_MIPD_ big x,int n,big z) ++{ /* premultiply a big number by an int z=x.n */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(9) ++ ++ ++#ifdef MR_FLASH ++ if (mr_notint(x)) ++ { ++ mr_berror(_MIPP_ MR_ERR_INT_OP); ++ MR_OUT ++ return; ++ } ++#endif ++ if (n==0) /* test for some special cases */ ++ { ++ zero(z); ++ MR_OUT ++ return; ++ } ++ if (n==1) ++ { ++ copy(x,z); ++ MR_OUT ++ return; ++ } ++ if (n<0) ++ { ++ n=(-n); ++ mr_pmul(_MIPP_ x,(mr_small)n,z); ++ if (z->len!=0) z->len^=MR_MSBIT; ++ } ++ else mr_pmul(_MIPP_ x,(mr_small)n,z); ++ MR_OUT ++} ++ ++#ifdef MR_FP_ROUNDING ++mr_small mr_sdiv(_MIPD_ big x,mr_small sn,mr_large isn,big z) ++#else ++mr_small mr_sdiv(_MIPD_ big x,mr_small sn,big z) ++#endif ++{ ++ int i,xl; ++ mr_small sr; ++#ifdef MR_NOASM ++ union doubleword dble; ++#endif ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ sr=0; ++ xl=(int)(x->len&MR_OBITS); ++ if (x!=z) zero(z); ++#ifndef MR_SIMPLE_BASE ++ if (mr_mip->base==0) ++ { ++#endif ++#ifndef MR_NOFULLWIDTH ++/* inline - substitutes for loop below */ ++#ifdef INLINE_ASM ++#if INLINE_ASM == 1 ++ ASM std ++ ASM mov cx,xl ++ ASM or cx,cx ++ ASM je out2 ++ ASM mov bx,cx ++ ASM shl bx,1 ++ ASM sub bx,2 ++#ifdef MR_LMM ++ ASM push ds ++ ASM push es ++ ASM les di,DWORD PTR zg ++ ASM lds si,DWORD PTR xg ++#else ++ ASM mov ax,ds ++ ASM mov es,ax ++ ASM mov di,zg ++ ASM mov si,xg ++#endif ++ ASM add si,bx ++ ASM add di,bx ++ ASM mov bx,sn ++ ASM push bp ++ ASM xor bp,bp ++ tcl2: ++ ASM mov dx,bp ++ ASM lodsw ++ ASM div bx ++ ASM mov bp,dx ++ ASM stosw ++ ASM loop tcl2 ++ ++ ASM mov ax,bp ++ ASM pop bp ++#ifdef MR_LMM ++ ASM pop es ++ ASM pop ds ++#endif ++ ASM mov sr,ax ++ out2: ++ ASM cld ++#endif ++#if INLINE_ASM == 2 ++ ASM std ++ ASM mov cx,xl ++ ASM or cx,cx ++ ASM je out2 ++ ASM mov bx,cx ++ ASM shl bx,2 ++ ASM sub bx,4 ++#ifdef MR_LMM ++ ASM push ds ++ ASM push es ++ ASM les di,DWORD PTR zg ++ ASM lds si,DWORD PTR xg ++#else ++ ASM mov ax,ds ++ ASM mov es,ax ++ ASM mov di, zg ++ ASM mov si, xg ++#endif ++ ASM add si,bx ++ ASM add di,bx ++ ASM mov ebx,sn ++ ASM push ebp ++ ASM xor ebp,ebp ++ tcl2: ++ ASM mov edx,ebp ++ ASM lodsd ++ ASM div ebx ++ ASM mov ebp,edx ++ ASM stosd ++ ASM loop tcl2 ++ ++ ASM mov eax,ebp ++ ASM pop ebp ++#ifdef MR_LMM ++ ASM pop es ++ ASM pop ds ++#endif ++ ASM mov sr,eax ++ out2: ++ ASM cld ++#endif ++#if INLINE_ASM == 3 ++ ASM mov ecx,xl ++ ASM or ecx,ecx ++ ASM je out2 ++ ASM mov ebx,ecx ++ ASM shl ebx,2 ++ ASM mov esi, xg ++ ASM add esi,ebx ++ ASM mov edi, zg ++ ASM add edi,ebx ++ ASM mov ebx,sn ++ ASM push ebp ++ ASM xor ebp,ebp ++ tcl2: ++ ASM sub esi,4 ++ ASM mov edx,ebp ++ ASM mov eax,[esi] ++ ASM div ebx ++ ASM sub edi,4 ++ ASM mov ebp,edx ++ ASM mov [edi],eax ++ ASM dec ecx ++ ASM jnz tcl2 ++ ++ ASM mov eax,ebp ++ ASM pop ebp ++ ASM mov sr,eax ++ out2: ++ ASM nop ++#endif ++#if INLINE_ASM == 4 ++ ++ ASM ( ++ "movl %4,%%ecx\n" ++ "orl %%ecx,%%ecx\n" ++ "je 3f\n" ++ "movl %%ecx,%%ebx\n" ++ "shll $2,%%ebx\n" ++ "movl %2,%%esi\n" ++ "addl %%ebx,%%esi\n" ++ "movl %1,%%edi\n" ++ "addl %%ebx,%%edi\n" ++ "movl %3,%%ebx\n" ++ "pushl %%ebp\n" ++ "xorl %%ebp,%%ebp\n" ++ "2:\n" ++ "subl $4,%%esi\n" ++ "movl %%ebp,%%edx\n" ++ "movl (%%esi),%%eax\n" ++ "divl %%ebx\n" ++ "subl $4,%%edi\n" ++ "movl %%edx,%%ebp\n" ++ "movl %%eax,(%%edi)\n" ++ "decl %%ecx\n" ++ "jnz 2b\n" ++ ++ "movl %%ebp,%%eax\n" ++ "popl %%ebp\n" ++ "movl %%eax,%0\n" ++ "3:" ++ "nop" ++ :"=m"(sr) ++ :"m"(zg),"m"(xg),"m"(sn),"m"(xl) ++ :"eax","edi","esi","ebx","ecx","edx","memory" ++ ); ++#endif ++#endif ++#ifndef INLINE_ASM ++ for (i=xl-1;i>=0;i--) ++ { ++#ifdef MR_NOASM ++ dble.h[MR_BOT]=x->w[i]; ++ dble.h[MR_TOP]=sr; ++ z->w[i]=(mr_small)(dble.d/sn); ++ sr=(mr_small)(dble.d-(mr_large)z->w[i]*sn); ++#else ++ z->w[i]=muldvm(sr,x->w[i],sn,&sr); ++#endif ++ } ++#endif ++#endif ++#ifndef MR_SIMPLE_BASE ++ } ++ else for (i=xl-1;i>=0;i--) ++ { /* divide each digit of x by n */ ++#ifdef MR_NOASM ++ dbled=(mr_large)sr*mr_mip->base+x->w[i]; ++#ifdef MR_FP_ROUNDING ++ z->w[i]=(mr_small)MR_LROUND(dbled*isn); ++#else ++ z->w[i]=(mr_small)MR_LROUND(dbled/sn); ++#endif ++ sr=(mr_small)(dbled-(mr_large)z->w[i]*sn); ++#else ++#ifdef MR_FP_ROUNDING ++ z->w[i]=imuldiv(sr,mr_mip->base,x->w[i],sn,isn,&sr); ++#else ++ z->w[i]=muldiv(sr,mr_mip->base,x->w[i],sn,&sr); ++#endif ++#endif ++ } ++#endif ++ z->len=x->len; ++ mr_lzero(z); ++ return sr; ++} ++ ++int subdiv(_MIPD_ big x,int n,big z) ++{ /* subdivide a big number by an int z=x/n * ++ * returns int remainder */ ++ mr_lentype sx; ++#ifdef MR_FP_ROUNDING ++ mr_large in; ++#endif ++ int r,i,msb; ++ mr_small lsb; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return 0; ++ ++ MR_IN(10) ++#ifdef MR_FLASH ++ if (mr_notint(x)) mr_berror(_MIPP_ MR_ERR_INT_OP); ++#endif ++ if (n==0) mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); ++ if (mr_mip->ERNUM) ++ { ++ MR_OUT ++ return 0; ++ } ++ ++ if (x->len==0) ++ { ++ zero(z); ++ MR_OUT ++ return 0; ++ } ++ if (n==1) /* special case */ ++ { ++ copy(x,z); ++ MR_OUT ++ return 0; ++ } ++ sx=(x->len&MR_MSBIT); ++ if (n==2 && mr_mip->base==0) ++ { /* fast division by 2 using shifting */ ++#ifndef MR_NOFULLWIDTH ++ ++/* I don't want this code upsetting the compiler ... */ ++/* mr_mip->base==0 can't happen with MR_NOFULLWIDTH */ ++ ++ copy(x,z); ++ msb=(int)(z->len&MR_OBITS)-1; ++ r=(int)z->w[0]&1; ++ for (i=0;;i++) ++ { ++ z->w[i]>>=1; ++ if (i==msb) ++ { ++ if (z->w[i]==0) mr_lzero(z); ++ break; ++ } ++ lsb=z->w[i+1]&1; ++ z->w[i]|=(lsb<<(MIRACL-1)); ++ } ++ ++ MR_OUT ++ if (sx==0) return r; ++ else return (-r); ++#endif ++ } ++ ++#ifdef MR_FP_ROUNDING ++ in=mr_invert(n); ++#endif ++ if (n<0) ++ { ++ n=(-n); ++#ifdef MR_FP_ROUNDING ++ r=(int)mr_sdiv(_MIPP_ x,(mr_small)n,in,z); ++#else ++ r=(int)mr_sdiv(_MIPP_ x,(mr_small)n,z); ++#endif ++ if (z->len!=0) z->len^=MR_MSBIT; ++ } ++#ifdef MR_FP_ROUNDING ++ else r=(int)mr_sdiv(_MIPP_ x,(mr_small)n,in,z); ++#else ++ else r=(int)mr_sdiv(_MIPP_ x,(mr_small)n,z); ++#endif ++ MR_OUT ++ if (sx==0) return r; ++ else return (-r); ++} ++ ++int remain(_MIPD_ big x,int n) ++{ /* return integer remainder when x divided by n */ ++ int r; ++ mr_lentype sx; ++#ifdef MR_FP ++ mr_small dres; ++#endif ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return FALSE; ++ ++ MR_IN(88); ++ ++ sx=(x->len&MR_MSBIT); ++ ++ if (n==2 && MR_REMAIN(mr_mip->base,2)==0) ++ { /* fast odd/even check if base is even */ ++ MR_OUT ++ if ((int)MR_REMAIN(x->w[0],2)==0) return 0; ++ else ++ { ++ if (sx==0) return 1; ++ else return (-1); ++ } ++ } ++ if (n==8 && MR_REMAIN(mr_mip->base,8)==0) ++ { /* fast check */ ++ MR_OUT ++ r=(int)MR_REMAIN(x->w[0],8); ++ if (sx!=0) r=-r; ++ return r; ++ } ++ ++ copy(x,mr_mip->w0); ++ r=subdiv(_MIPP_ mr_mip->w0,n,mr_mip->w0); ++ MR_OUT ++ return r; ++} ++ ++BOOL subdivisible(_MIPD_ big x,int n) ++{ ++ if (remain(_MIPP_ x,n)==0) return TRUE; ++ else return FALSE; ++} ++ ++int hamming(_MIPD_ big x) ++{ ++ int h; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return 0; ++ MR_IN(148); ++ h=0; ++ copy(x,mr_mip->w1); ++ absol(mr_mip->w1,mr_mip->w1); ++ while (size(mr_mip->w1)!=0) ++ h+=subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1); ++ ++ MR_OUT ++ return h; ++} ++ ++void bytes_to_big(_MIPD_ int len,const char *ptr,big x) ++{ /* convert len bytes into a big * ++ * The first byte is the Most significant */ ++ int i,j,m,n,r; ++ mr_small wrd; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ MR_IN(140); ++ ++ zero(x); ++ ++ if (len<=0) ++ { ++ MR_OUT ++ return; ++ } ++/* remove leading zeros.. */ ++ ++ while (*ptr==0) ++ { ++ ptr++; len--; ++ if (len==0) ++ { ++ MR_OUT ++ return; ++ } ++ } ++ ++#ifndef MR_SIMPLE_BASE ++ if (mr_mip->base==0) ++ { /* pack bytes directly into big */ ++#endif ++#ifndef MR_NOFULLWIDTH ++ m=MIRACL/8; ++ n=len/m; ++ ++ r=len%m; ++ wrd=(mr_small)0; ++ if (r!=0) ++ { ++ n++; ++ for (j=0;jlen=n; ++ if (n>mr_mip->nib && mr_mip->check) ++ { ++ mr_berror(_MIPP_ MR_ERR_OVERFLOW); ++ MR_OUT ++ return; ++ } ++ if (r!=0) ++ { ++ n--; ++ x->w[n]=wrd; ++ } ++ ++ for (i=n-1;i>=0;i--) ++ { ++ for (j=0;jw[i]=wrd; ++ } ++ mr_lzero(x); /* needed */ ++#endif ++#ifndef MR_SIMPLE_BASE ++ } ++ else ++ { ++ for (i=0;iERNUM) break; ++#if MIRACL==8 ++ mr_shift(_MIPP_ x,1,x); ++#else ++ premult(_MIPP_ x,256,x); ++#endif ++ ch=MR_TOBYTE(ptr[i]); ++ dig=ch; ++ incr(_MIPP_ x,(int)dig,x); ++ } ++ } ++#endif ++ MR_OUT ++} ++ ++int big_to_bytes(_MIPD_ int max,big x,char *ptr,BOOL justify) ++{ /* convert positive big into octet string */ ++ int i,j,r,m,n,len,start; ++ mr_small wrd; ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM || max<0) return 0; ++ ++ if (max==0 && justify) return 0; ++ if (size(x)==0) ++ { ++ if (justify) ++ { ++ for (i=0;ibase==0) ++ { ++#endif ++#ifndef MR_NOFULLWIDTH ++ m=MIRACL/8; ++ n=(int)(x->len&MR_OBITS); ++ n--; ++ len=n*m; ++ wrd=x->w[n]; /* most significant */ ++ r=0; ++ while (wrd!=(mr_small)0) { r++; wrd>>=8; len++;} ++ r%=m; ++ ++ if (max>0 && len>max) ++ { ++ mr_berror(_MIPP_ MR_ERR_TOO_BIG); ++ MR_OUT ++ return 0; ++ } ++ ++ if (justify) ++ { ++ start=max-len; ++ for (i=0;iw[n--]; ++ for (i=r-1;i>=0;i--) ++ { ++ ptr[start+i]=(char)(wrd&0xFF); ++ wrd>>=8; ++ } ++ } ++ ++ for (i=r;iw[n--]; ++ for (j=m-1;j>=0;j--) ++ { ++ ptr[start+i+j]=(char)(wrd&0xFF); ++ wrd>>=8; ++ } ++ } ++#endif ++#ifndef MR_SIMPLE_BASE ++ } ++ else ++ { ++ copy(x,mr_mip->w1); ++ for (len=0;;len++) ++ { ++ if (mr_mip->ERNUM) break; ++ ++ if (size(mr_mip->w1)==0) ++ { ++ if (justify) ++ { ++ if (len==max) break; ++ } ++ else break; ++ } ++ ++ if (max>0 && len>=max) ++ { ++ mr_berror(_MIPP_ MR_ERR_TOO_BIG); ++ MR_OUT ++ return 0; ++ } ++#if MIRACL==8 ++ ch=mr_mip->w1->w[0]; ++ mr_shift(_MIPP_ mr_mip->w1,-1,mr_mip->w1); ++#else ++ dig=(unsigned int)subdiv(_MIPP_ mr_mip->w1,256,mr_mip->w1); ++ ch=MR_TOBYTE(dig); ++#endif ++ for (i=len;i>0;i--) ptr[i]=ptr[i-1]; ++ ptr[0]=MR_TOBYTE(ch); ++ } ++ } ++#endif ++ MR_OUT ++ if (justify) return max; ++ else return len; ++} ++ ++#ifndef MR_NO_ECC_MULTIADD ++ ++/* Solinas's Joint Sparse Form */ ++ ++void mr_jsf(_MIPD_ big k0,big k1,big u0p,big u0m,big u1p,big u1m) ++{ ++ int j,u0,u1,d0,d1,l0,l1; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(191) ++ ++ d0=d1=0; ++ ++ convert(_MIPP_ 1,mr_mip->w1); ++ copy(k0,mr_mip->w2); ++ copy(k1,mr_mip->w3); ++ zero(u0p); zero(u0m); zero(u1p); zero(u1m); ++ ++ j=0; ++ while (!mr_mip->ERNUM) ++ { ++ if (size(mr_mip->w2)==0 && d0==0 && size(mr_mip->w3)==0 && d1==0) break; ++ l0=remain(_MIPP_ mr_mip->w2,8); ++ l0=(l0+d0)&0x7; ++ l1=remain(_MIPP_ mr_mip->w3,8); ++ l1=(l1+d1)&0x7; ++ ++ if (l0%2==0) u0=0; ++ else ++ { ++ u0=2-(l0%4); ++ if ((l0==3 || l0==5) && l1%4==2) u0=-u0; ++ } ++ if (l1%2==0) u1=0; ++ else ++ { ++ u1=2-(l1%4); ++ if ((l1==3 || l1==5) && l0%4==2) u1=-u1; ++ } ++#ifndef MR_ALWAYS_BINARY ++ if (mr_mip->base==mr_mip->base2) ++ { ++#endif ++ if (u0>0) mr_addbit(_MIPP_ u0p,j); ++ if (u0<0) mr_addbit(_MIPP_ u0m,j); ++ if (u1>0) mr_addbit(_MIPP_ u1p,j); ++ if (u1<0) mr_addbit(_MIPP_ u1m,j); ++ ++#ifndef MR_ALWAYS_BINARY ++ } ++ else ++ { ++ if (u0>0) add(_MIPP_ u0p,mr_mip->w1,u0p); ++ if (u0<0) add(_MIPP_ u0m,mr_mip->w1,u0m); ++ if (u1>0) add(_MIPP_ u1p,mr_mip->w1,u1p); ++ if (u1<0) add(_MIPP_ u1m,mr_mip->w1,u1m); ++ } ++#endif ++ ++ if (d0+d0==1+u0) d0=1-d0; ++ if (d1+d1==1+u1) d1=1-d1; ++ ++ subdiv(_MIPP_ mr_mip->w2,2,mr_mip->w2); ++ subdiv(_MIPP_ mr_mip->w3,2,mr_mip->w3); ++ ++#ifndef MR_ALWAYS_BINARY ++ if (mr_mip->base==mr_mip->base2) ++#endif ++ j++; ++#ifndef MR_ALWAYS_BINARY ++ else ++ premult(_MIPP_ mr_mip->w1,2,mr_mip->w1); ++#endif ++ } ++ MR_OUT ++ return; ++} ++ ++#endif +diff --git a/lib/sbi/sm/gm/miracl/mrarth2.c b/lib/sbi/sm/gm/miracl/mrarth2.c +new file mode 100644 +index 0000000..feaff96 +--- /dev/null ++++ b/lib/sbi/sm/gm/miracl/mrarth2.c +@@ -0,0 +1,1578 @@ ++ ++/*************************************************************************** ++ * ++Copyright 2013 CertiVox UK Ltd. * ++ * ++This file is part of CertiVox MIRACL Crypto SDK. * ++ * ++The CertiVox MIRACL Crypto SDK provides developers with an * ++extensive and efficient set of cryptographic functions. * ++For further information about its features and functionalities please * ++refer to http://www.certivox.com * ++ * ++* The CertiVox MIRACL Crypto SDK is free software: you can * ++ redistribute it and/or modify it under the terms of the * ++ GNU Affero General Public License as published by the * ++ Free Software Foundation, either version 3 of the License, * ++ or (at your option) any later version. * ++ * ++* The CertiVox MIRACL Crypto SDK is distributed in the hope * ++ that it will be useful, but WITHOUT ANY WARRANTY; without even the * ++ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * ++ See the GNU Affero General Public License for more details. * ++ * ++* You should have received a copy of the GNU Affero General Public * ++ License along with CertiVox MIRACL Crypto SDK. * ++ If not, see . * ++ * ++You can be released from the requirements of the license by purchasing * ++a commercial license. Buying such a license is mandatory as soon as you * ++develop commercial activities involving the CertiVox MIRACL Crypto SDK * ++without disclosing the source code of your own applications, or shipping * ++the CertiVox MIRACL Crypto SDK with a closed source product. * ++ * ++***************************************************************************/ ++/* ++ * MIRACL arithmetic routines 2 - multiplying and dividing BIG NUMBERS. ++ * mrarth2.c ++ * ++ */ ++ ++#include "sm/gm/miracl/miracl.h" ++ ++#ifdef MR_FP ++#include ++#endif ++ ++#ifdef MR_WIN64 ++#include ++#endif ++ ++ ++/* If a number has more than this number of digits, then squaring is faster */ ++ ++#define SQR_FASTER_THRESHOLD 5 ++ ++mr_small normalise(_MIPD_ big x,big y) ++{ /* normalise divisor */ ++ mr_small norm,r; ++#ifdef MR_FP ++ mr_small dres; ++#endif ++ int len; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ MR_IN(4) ++ ++ if (x!=y) copy(x,y); ++ len=(int)(y->len&MR_OBITS); ++#ifndef MR_SIMPLE_BASE ++ if (mr_mip->base==0) ++ { ++#endif ++#ifndef MR_NOFULLWIDTH ++ if ((r=y->w[len-1]+1)==0) norm=1; ++#ifdef MR_NOASM ++ else norm=(mr_small)(((mr_large)1 << MIRACL)/r); ++#else ++ else norm=muldvm((mr_small)1,(mr_small)0,r,&r); ++#endif ++ if (norm!=1) mr_pmul(_MIPP_ y,norm,y); ++#endif ++#ifndef MR_SIMPLE_BASE ++ } ++ else ++ { ++ norm=MR_DIV(mr_mip->base,(mr_small)(y->w[len-1]+1)); ++ if (norm!=1) mr_pmul(_MIPP_ y,norm,y); ++ } ++#endif ++ MR_OUT ++ return norm; ++} ++ ++void multiply(_MIPD_ big x,big y,big z) ++{ /* multiply two big numbers: z=x.y */ ++ int i,xl,yl,j,ti; ++ mr_small carry; ++ ++#ifdef MR_ITANIUM ++ mr_small tm; ++#endif ++#ifdef MR_WIN64 ++ mr_small tm,tr; ++#endif ++ mr_lentype sz; ++ big w0; ++#ifdef MR_NOASM ++ union doubleword dble; ++#endif ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ if (y->len==0 || x->len==0) ++ { ++ zero(z); ++ return; ++ } ++ if (x!=mr_mip->w5 && y!=mr_mip->w5 && z==mr_mip->w5) w0=mr_mip->w5; ++ else w0=mr_mip->w0; /* local pointer */ ++ ++ MR_IN(5) ++ ++#ifdef MR_FLASH ++ if (mr_notint(x) || mr_notint(y)) ++ { ++ mr_berror(_MIPP_ MR_ERR_INT_OP); ++ MR_OUT ++ return; ++ } ++#endif ++ sz=((x->len&MR_MSBIT)^(y->len&MR_MSBIT)); ++ xl=(int)(x->len&MR_OBITS); ++ yl=(int)(y->len&MR_OBITS); ++ zero(w0); ++ if (mr_mip->check && xl+yl>mr_mip->nib) ++ { ++ mr_berror(_MIPP_ MR_ERR_OVERFLOW); ++ MR_OUT ++ return; ++ } ++#ifndef MR_SIMPLE_BASE ++ if (mr_mip->base==0) ++ { ++#endif ++#ifndef MR_NOFULLWIDTH ++ if (x==y && xl>SQR_FASTER_THRESHOLD) ++ /* extra hassle make it not */ ++ /* worth it for small numbers */ ++ { /* fast squaring */ ++ for (i=0;iw[i]*x->w[j]+carry+w0->w[i+j]; ++ w0->w[i+j]=dble.h[MR_BOT]; ++ carry=dble.h[MR_TOP]; ++#else ++ muldvd2(x->w[i],x->w[j],&carry,&w0->w[i+j]); ++#endif ++ } ++ w0->w[xl+i]=carry; ++#endif ++ } ++#ifdef INLINE_ASM ++#if INLINE_ASM == 1 ++ ASM mov cx,xl ++ ASM shl cx,1 ++#ifdef MR_LMM ++ ASM push ds ++ ASM push es ++ ASM les bx,DWORD PTR w0g ++#else ++ ASM mov bx,w0g ++#endif ++ tcl5: ++#ifdef MR_LMM ++ ASM rcl WORD PTR es:[bx],1 ++#else ++ ASM rcl WORD PTR [bx],1 ++#endif ++ ASM inc bx ++ ASM inc bx ++ ASM loop tcl5 ++ ++ ASM cld ++ ASM mov cx,xl ++#ifdef MR_LMM ++ ASM les di,DWORD PTR w0g ++ ASM lds si,DWORD PTR xg ++#else ++ ASM mov di,w0g ++ ASM mov si,xg ++#endif ++ ++ ASM xor bx,bx ++ tcl7: ++ ASM lodsw ++ ASM mul ax ++ ASM add ax,bx ++ ASM adc dx,0 ++#ifdef MR_LMM ++ ASM add es:[di],ax ++#else ++ ASM add [di],ax ++#endif ++ ASM adc dx,0 ++ ASM xor bx,bx ++ ASM inc di ++ ASM inc di ++#ifdef MR_LMM ++ ASM add es:[di],dx ++#else ++ ASM add [di],dx ++#endif ++ ASM adc bx,0 ++ ASM inc di ++ ASM inc di ++ ASM loop tcl7 ++#ifdef MR_LMM ++ ASM pop es ++ ASM pop ds ++#endif ++#endif ++#if INLINE_ASM == 2 ++ ASM mov cx,xl ++ ASM shl cx,1 ++#ifdef MR_LMM ++ ASM push ds ++ ASM push es ++ ASM les bx,DWORD PTR w0g ++#else ++ ASM mov bx,w0g ++#endif ++ tcl5: ++#ifdef MR_LMM ++ ASM rcl DWORD PTR es:[bx],1 ++#else ++ ASM rcl DWORD PTR [bx],1 ++#endif ++ ASM inc bx ++ ASM inc bx ++ ASM inc bx ++ ASM inc bx ++ ASM loop tcl5 ++ ++ ASM cld ++ ASM mov cx,xl ++#ifdef MR_LMM ++ ASM les di,DWORD PTR w0g ++ ASM lds si,DWORD PTR xg ++#else ++ ASM mov di,w0g ++ ASM mov si,xg ++#endif ++ ASM xor ebx,ebx ++ tcl7: ++ ASM lodsd ++ ASM mul eax ++ ASM add eax,ebx ++ ASM adc edx,0 ++#ifdef MR_LMM ++ ASM add es:[di],eax ++#else ++ ASM add [di],eax ++#endif ++ ASM adc edx,0 ++ ASM xor ebx,ebx ++ ASM add di,4 ++#ifdef MR_LMM ++ ASM add es:[di],edx ++#else ++ ASM add [di],edx ++#endif ++ ASM adc ebx,0 ++ ASM add di,4 ++ ASM loop tcl7 ++#ifdef MR_LMM ++ ASM pop es ++ ASM pop ds ++#endif ++#endif ++#if INLINE_ASM == 3 ++ ASM mov ecx,xl ++ ASM shl ecx,1 ++ ASM mov edi,w0g ++ tcl5: ++ ASM rcl DWORD PTR [edi],1 ++ ASM inc edi ++ ASM inc edi ++ ASM inc edi ++ ASM inc edi ++ ASM loop tcl5 ++ ++ ASM mov ecx,xl ++ ASM mov esi,xg ++ ASM mov edi,w0g ++ ASM xor ebx,ebx ++ tcl7: ++ ASM mov eax,[esi] ++ ASM add esi,4 ++ ASM mul eax ++ ASM add eax,ebx ++ ASM adc edx,0 ++ ASM add [edi],eax ++ ASM adc edx,0 ++ ASM xor ebx,ebx ++ ASM add edi,4 ++ ASM add [edi],edx ++ ASM adc ebx,0 ++ ASM add edi,4 ++ ASM dec ecx ++ ASM jnz tcl7 ++#endif ++#if INLINE_ASM == 4 ++ ASM ( ++ "movl %0,%%ecx\n" ++ "shll $1,%%ecx\n" ++ "movl %1,%%edi\n" ++ "tcl5:\n" ++ "rcll $1,(%%edi)\n" ++ "incl %%edi\n" ++ "incl %%edi\n" ++ "incl %%edi\n" ++ "incl %%edi\n" ++ "loop tcl5\n" ++ ++ "movl %0,%%ecx\n" ++ "movl %2,%%esi\n" ++ "movl %1,%%edi\n" ++ "xorl %%ebx,%%ebx\n" ++ "tcl7:\n" ++ "movl (%%esi),%%eax\n" ++ "addl $4,%%esi\n" ++ "mull %%eax\n" ++ "addl %%ebx,%%eax\n" ++ "adcl $0,%%edx\n" ++ "addl %%eax,(%%edi)\n" ++ "adcl $0,%%edx\n" ++ "xorl %%ebx,%%ebx\n" ++ "addl $4,%%edi\n" ++ "addl %%edx,(%%edi)\n" ++ "adcl $0,%%ebx\n" ++ "addl $4,%%edi\n" ++ "decl %%ecx\n" ++ "jnz tcl7\n" ++ : ++ :"m"(xl),"m"(w0g),"m"(xg) ++ :"eax","edi","esi","ebx","ecx","edx","memory" ++ ); ++#endif ++#endif ++#ifndef INLINE_ASM ++ w0->len=xl+xl-1; ++ mr_padd(_MIPP_ w0,w0,w0); /* double it */ ++ carry=0; ++ for (i=0;iw[i]*x->w[i]+carry+w0->w[ti]; ++ w0->w[ti]=dble.h[MR_BOT]; ++ carry=dble.h[MR_TOP]; ++#else ++ muldvd2(x->w[i],x->w[i],&carry,&w0->w[ti]); ++#endif ++ w0->w[ti+1]+=carry; ++ if (w0->w[ti+1]w[i]*y->w[j]+carry+w0->w[i+j]; ++ w0->w[i+j]=dble.h[MR_BOT]; ++ carry=dble.h[MR_TOP]; ++#else ++ muldvd2(x->w[i],y->w[j],&carry,&w0->w[i+j]); ++#endif ++ } ++ w0->w[yl+i]=carry; ++#endif ++ } ++#endif ++#ifndef MR_SIMPLE_BASE ++ } ++ else ++ { ++ if (x==y && xl>SQR_FASTER_THRESHOLD) ++ { /* squaring can be done nearly twice as fast */ ++ for (i=0;iw[i]*x->w[j]+w0->w[i+j]+carry; ++ #ifdef MR_FP_ROUNDING ++ carry=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); ++ #else ++ #ifndef MR_FP ++ if (mr_mip->base==mr_mip->base2) ++ carry=(mr_small)(dbled>>mr_mip->lg2b); ++ else ++ #endif ++ carry=(mr_small)MR_LROUND(dbled/mr_mip->base); ++ #endif ++ w0->w[i+j]=(mr_small)(dbled-(mr_large)carry*mr_mip->base); ++#else ++ ++ #ifdef MR_FP_ROUNDING ++ carry=imuldiv(x->w[i],x->w[j],w0->w[i+j]+carry,mr_mip->base,mr_mip->inverse_base,&w0->w[i+j]); ++ #else ++ carry=muldiv(x->w[i],x->w[j],w0->w[i+j]+carry,mr_mip->base,&w0->w[i+j]); ++ #endif ++#endif ++ } ++ w0->w[xl+i]=carry; ++ } ++ w0->len=xl+xl-1; ++ mr_padd(_MIPP_ w0,w0,w0); /* double it */ ++ carry=0; ++ for (i=0;iw[i]*x->w[i]+w0->w[ti]+carry; ++#ifdef MR_FP_ROUNDING ++ carry=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); ++#else ++#ifndef MR_FP ++ if (mr_mip->base==mr_mip->base2) ++ carry=(mr_small)(dbled>>mr_mip->lg2b); ++ else ++#endif ++ carry=(mr_small)MR_LROUND(dbled/mr_mip->base); ++#endif ++ w0->w[ti]=(mr_small)(dbled-(mr_large)carry*mr_mip->base); ++#else ++ ++#ifdef MR_FP_ROUNDING ++ carry=imuldiv(x->w[i],x->w[i],w0->w[ti]+carry,mr_mip->base,mr_mip->inverse_base,&w0->w[ti]); ++#else ++ carry=muldiv(x->w[i],x->w[i],w0->w[ti]+carry,mr_mip->base,&w0->w[ti]); ++#endif ++ ++#endif ++ w0->w[ti+1]+=carry; ++ carry=0; ++ if (w0->w[ti+1]>=mr_mip->base) ++ { ++ carry=1; ++ w0->w[ti+1]-=mr_mip->base; ++ } ++ } ++ } ++ else for (i=0;iw[i]*y->w[j]+w0->w[i+j]+carry; ++ ++#ifdef MR_FP_ROUNDING ++ carry=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); ++#else ++#ifndef MR_FP ++ if (mr_mip->base==mr_mip->base2) ++ carry=(mr_small)(dbled>>mr_mip->lg2b); ++ else ++#endif ++ carry=(mr_small)MR_LROUND(dbled/mr_mip->base); ++#endif ++ w0->w[i+j]=(mr_small)(dbled-(mr_large)carry*mr_mip->base); ++#else ++ ++#ifdef MR_FP_ROUNDING ++ carry=imuldiv(x->w[i],y->w[j],w0->w[i+j]+carry,mr_mip->base,mr_mip->inverse_base,&w0->w[i+j]); ++#else ++ carry=muldiv(x->w[i],y->w[j],w0->w[i+j]+carry,mr_mip->base,&w0->w[i+j]); ++#endif ++ ++#endif ++ } ++ w0->w[yl+i]=carry; ++ } ++ } ++#endif ++ w0->len=(sz|(xl+yl)); /* set length and sign of result */ ++ ++ mr_lzero(w0); ++ copy(w0,z); ++ MR_OUT ++} ++ ++void divide(_MIPD_ big x,big y,big z) ++{ /* divide two big numbers z=x/y : x=x mod y * ++ * returns quotient only if divide(x,y,x) * ++ * returns remainder only if divide(x,y,y) */ ++ mr_small carry,attemp,ldy,sdy,ra,r,d,tst,psum; ++#ifdef MR_FP ++ mr_small dres; ++#endif ++ mr_lentype sx,sy,sz; ++ mr_small borrow,dig; ++ int i,k,m,x0,y0,w00; ++ big w0; ++ ++#ifdef MR_ITANIUM ++ mr_small tm; ++#endif ++#ifdef MR_WIN64 ++ mr_small tm; ++#endif ++#ifdef MR_NOASM ++ union doubleword dble; ++#endif ++ BOOL check; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ w0=mr_mip->w0; ++ ++ MR_IN(6) ++ ++ if (x==y) mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); ++#ifdef MR_FLASH ++ if (mr_notint(x) || mr_notint(y)) mr_berror(_MIPP_ MR_ERR_INT_OP); ++#endif ++ if (y->len==0) mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); ++ if (mr_mip->ERNUM) ++ { ++ MR_OUT ++ return; ++ } ++ sx=(x->len&MR_MSBIT); /* extract signs ... */ ++ sy=(y->len&MR_MSBIT); ++ sz=(sx^sy); ++ x->len&=MR_OBITS; /* ... and force operands to positive */ ++ y->len&=MR_OBITS; ++ x0=(int)x->len; ++ y0=(int)y->len; ++ copy(x,w0); ++ w00=(int)w0->len; ++ if (mr_mip->check && (w00-y0+1>mr_mip->nib)) ++ { ++ mr_berror(_MIPP_ MR_ERR_OVERFLOW); ++ MR_OUT ++ return; ++ } ++ d=0; ++ if (x0==y0) ++ { ++ if (x0==1) /* special case - x and y are both mr_smalls */ ++ { ++ d=MR_DIV(w0->w[0],y->w[0]); ++ w0->w[0]=MR_REMAIN(w0->w[0],y->w[0]); ++ mr_lzero(w0); ++ } ++ else if (MR_DIV(w0->w[x0-1],4)w[x0-1]) ++ while (mr_compare(w0,y)>=0) ++ { /* mr_small quotient - so do up to four subtracts instead */ ++ mr_psub(_MIPP_ w0,y,w0); ++ d++; ++ } ++ } ++ if (mr_compare(w0,y)<0) ++ { /* x less than y - so x becomes remainder */ ++ if (x!=z) /* testing parameters */ ++ { ++ copy(w0,x); ++ if (x->len!=0) x->len|=sx; ++ } ++ if (y!=z) ++ { ++ zero(z); ++ z->w[0]=d; ++ if (d>0) z->len=(sz|1); ++ } ++ y->len|=sy; ++ MR_OUT ++ return; ++ } ++ ++ if (y0==1) ++ { /* y is int - so use subdiv instead */ ++#ifdef MR_FP_ROUNDING ++ r=mr_sdiv(_MIPP_ w0,y->w[0],mr_invert(y->w[0]),w0); ++#else ++ r=mr_sdiv(_MIPP_ w0,y->w[0],w0); ++#endif ++ if (y!=z) ++ { ++ copy(w0,z); ++ z->len|=sz; ++ } ++ if (x!=z) ++ { ++ zero(x); ++ x->w[0]=r; ++ if (r>0) x->len=(sx|1); ++ } ++ y->len|=sy; ++ MR_OUT ++ return; ++ } ++ if (y!=z) zero(z); ++ d=normalise(_MIPP_ y,y); ++ check=mr_mip->check; ++ mr_mip->check=OFF; ++#ifndef MR_SIMPLE_BASE ++ if (mr_mip->base==0) ++ { ++#endif ++#ifndef MR_NOFULLWIDTH ++ if (d!=1) mr_pmul(_MIPP_ w0,d,w0); ++ ldy=y->w[y0-1]; ++ sdy=y->w[y0-2]; ++ for (k=w00-1;k>=y0-1;k--) ++ { /* long division */ ++#ifdef INLINE_ASM ++#if INLINE_ASM == 1 ++#ifdef MR_LMM ++ ASM push ds ++ ASM lds bx,DWORD PTR w0g ++#else ++ ASM mov bx,w0g ++#endif ++ ASM mov si,k ++ ASM shl si,1 ++ ASM add bx,si ++ ASM mov dx,[bx+2] ++ ASM mov ax,[bx] ++ ASM cmp dx,ldy ++ ASM jne tcl8 ++ ASM mov di,0xffff ++ ASM mov si,ax ++ ASM add si,ldy ++ ASM jc tcl12 ++ ASM jmp tcl10 ++ tcl8: ++ ASM div WORD PTR ldy ++ ASM mov di,ax ++ ASM mov si,dx ++ tcl10: ++ ASM mov ax,sdy ++ ASM mul di ++ ASM cmp dx,si ++ ASM jb tcl12 ++ ASM jne tcl11 ++ ASM cmp ax,[bx-2] ++ ASM jbe tcl12 ++ tcl11: ++ ASM dec di ++ ASM add si,ldy ++ ASM jnc tcl10 ++ tcl12: ++ ASM mov attemp,di ++#ifdef MR_LMM ++ ASM pop ds ++#endif ++#endif ++/* NOTE push and pop of esi/edi should not be necessary - Borland C bug * ++ * These pushes are needed here even if register variables are disabled */ ++#if INLINE_ASM == 2 ++ ASM push esi ++ ASM push edi ++#ifdef MR_LMM ++ ASM push ds ++ ASM lds bx,DWORD PTR w0g ++#else ++ ASM mov bx,w0g ++#endif ++ ASM mov si,k ++ ASM shl si,2 ++ ASM add bx,si ++ ASM mov edx,[bx+4] ++ ASM mov eax,[bx] ++ ASM cmp edx,ldy ++ ASM jne tcl8 ++ ASM mov edi,0xffffffff ++ ASM mov esi,eax ++ ASM add esi,ldy ++ ASM jc tcl12 ++ ASM jmp tcl10 ++ tcl8: ++ ASM div DWORD PTR ldy ++ ASM mov edi,eax ++ ASM mov esi,edx ++ tcl10: ++ ASM mov eax,sdy ++ ASM mul edi ++ ASM cmp edx,esi ++ ASM jb tcl12 ++ ASM jne tcl11 ++ ASM cmp eax,[bx-4] ++ ASM jbe tcl12 ++ tcl11: ++ ASM dec edi ++ ASM add esi,ldy ++ ASM jnc tcl10 ++ tcl12: ++ ASM mov attemp,edi ++#ifdef MR_LMM ++ ASM pop ds ++#endif ++ ASM pop edi ++ ASM pop esi ++#endif ++#if INLINE_ASM == 3 ++ ASM push esi ++ ASM push edi ++ ASM mov ebx,w0g ++ ASM mov esi,k ++ ASM shl esi,2 ++ ASM add ebx,esi ++ ASM mov edx,[ebx+4] ++ ASM mov eax,[ebx] ++ ASM cmp edx,ldy ++ ASM jne tcl8 ++ ASM mov edi,0xffffffff ++ ASM mov esi,eax ++ ASM add esi,ldy ++ ASM jc tcl12 ++ ASM jmp tcl10 ++ tcl8: ++ ASM div DWORD PTR ldy ++ ASM mov edi,eax ++ ASM mov esi,edx ++ tcl10: ++ ASM mov eax,sdy ++ ASM mul edi ++ ASM cmp edx,esi ++ ASM jb tcl12 ++ ASM jne tcl11 ++ ASM cmp eax,[ebx-4] ++ ASM jbe tcl12 ++ tcl11: ++ ASM dec edi ++ ASM add esi,ldy ++ ASM jnc tcl10 ++ tcl12: ++ ASM mov attemp,edi ++ ASM pop edi ++ ASM pop esi ++#endif ++#if INLINE_ASM == 4 ++ ASM ( ++ "movl %1,%%ebx\n" ++ "movl %2,%%esi\n" ++ "shll $2,%%esi\n" ++ "addl %%esi,%%ebx\n" ++ "movl 4(%%ebx),%%edx\n" ++ "movl (%%ebx),%%eax\n" ++ "cmpl %3,%%edx\n" ++ "jne tcl8\n" ++ "movl $0xffffffff,%%edi\n" ++ "movl %%eax,%%esi\n" ++ "addl %3,%%esi\n" ++ "jc tcl12\n" ++ "jmp tcl10\n" ++ "tcl8:\n" ++ "divl %3\n" ++ "movl %%eax,%%edi\n" ++ "movl %%edx,%%esi\n" ++ "tcl10:\n" ++ "movl %4,%%eax\n" ++ "mull %%edi\n" ++ "cmpl %%esi,%%edx\n" ++ "jb tcl12\n" ++ "jne tcl11\n" ++ "cmpl -4(%%ebx),%%eax\n" ++ "jbe tcl12\n" ++ "tcl11:\n" ++ "decl %%edi\n" ++ "addl %3,%%esi\n" ++ "jnc tcl10\n" ++ "tcl12:\n" ++ "movl %%edi,%0\n" ++ :"=m"(attemp) ++ :"m"(w0g),"m"(k),"m"(ldy),"m"(sdy) ++ :"eax","edi","esi","ebx","ecx","edx","memory" ++ ); ++#endif ++#endif ++#ifndef INLINE_ASM ++ carry=0; ++ if (w0->w[k+1]==ldy) /* guess next quotient digit */ ++ { ++ attemp=(mr_small)(-1); ++ ra=ldy+w0->w[k]; ++ if (raw[k]; ++ dble.h[MR_TOP]=w0->w[k+1]; ++ attemp=(mr_small)(dble.d/ldy); ++ ra=(mr_small)(dble.d-(mr_large)attemp*ldy); ++ } ++#else ++ else attemp=muldvm(w0->w[k+1],w0->w[k],ldy,&ra); ++#endif ++ while (carry==0) ++ { ++#ifdef MR_NOASM ++ dble.d=(mr_large)attemp*sdy; ++ r=dble.h[MR_BOT]; ++ tst=dble.h[MR_TOP]; ++#else ++ tst=muldvd(sdy,attemp,(mr_small)0,&r); ++#endif ++ if (tst< ra || (tst==ra && r<=w0->w[k-1])) break; ++ attemp--; /* refine guess */ ++ ra+=ldy; ++ if (ra0) ++ { /* do partial subtraction */ ++ borrow=0; ++ /* inline - substitutes for loop below */ ++#ifdef INLINE_ASM ++#if INLINE_ASM == 1 ++ ASM cld ++ ASM mov cx,y0 ++ ASM mov si,m ++ ASM shl si,1 ++ ASM mov di,attemp ++#ifdef MR_LMM ++ ASM push ds ++ ASM push es ++ ASM les bx,DWORD PTR w0g ++ ASM add bx,si ++ ASM sub bx,2 ++ ASM lds si,DWORD PTR yg ++#else ++ ASM mov bx,w0g ++ ASM add bx,si ++ ASM sub bx,2 ++ ASM mov si,yg ++#endif ++ ASM push bp ++ ASM xor bp,bp ++ ++ tcl3: ++ ASM lodsw ++ ASM mul di ++ ASM add ax,bp ++ ASM adc dx,0 ++ ASM inc bx ++ ASM inc bx ++#ifdef MR_LMM ++ ASM sub es:[bx],ax ++#else ++ ASM sub [bx],ax ++#endif ++ ASM adc dx,0 ++ ASM mov bp,dx ++ ASM loop tcl3 ++ ++ ASM mov ax,bp ++ ASM pop bp ++#ifdef MR_LMM ++ ASM pop es ++ ASM pop ds ++#endif ++ ASM mov borrow,ax ++#endif ++/* NOTE push and pop of esi/edi should not be necessary - Borland C bug * ++ * These pushes are needed here even if register variables are disabled */ ++#if INLINE_ASM == 2 ++ ASM push esi ++ ASM push edi ++ ASM cld ++ ASM mov cx,y0 ++ ASM mov si,m ++ ASM shl si,2 ++ ASM mov edi,attemp ++#ifdef MR_LMM ++ ASM push ds ++ ASM push es ++ ASM les bx,DWORD PTR w0g ++ ASM add bx,si ++ ASM sub bx,4 ++ ASM lds si,DWORD PTR yg ++#else ++ ASM mov bx,w0g ++ ASM add bx,si ++ ASM sub bx,4 ++ ASM mov si,yg ++#endif ++ ASM push ebp ++ ASM xor ebp,ebp ++ ++ tcl3: ++ ASM lodsd ++ ASM mul edi ++ ASM add eax,ebp ++ ASM adc edx,0 ++ ASM add bx,4 ++#ifdef MR_LMM ++ ASM sub es:[bx],eax ++#else ++ ASM sub [bx],eax ++#endif ++ ASM adc edx,0 ++ ASM mov ebp,edx ++ ASM loop tcl3 ++ ++ ASM mov eax,ebp ++ ASM pop ebp ++#ifdef MR_LMM ++ ASM pop es ++ ASM pop ds ++#endif ++ ASM mov borrow,eax ++ ASM pop edi ++ ASM pop esi ++#endif ++#if INLINE_ASM == 3 ++ ASM push esi ++ ASM push edi ++ ASM mov ecx,y0 ++ ASM mov esi,m ++ ASM shl esi,2 ++ ASM mov edi,attemp ++ ASM mov ebx,w0g ++ ASM add ebx,esi ++ ASM mov esi,yg ++ ASM sub ebx,esi ++ ASM sub ebx,4 ++ ASM push ebp ++ ASM xor ebp,ebp ++ ++ tcl3: ++ ASM mov eax,[esi] ++ ASM add esi,4 ++ ASM mul edi ++ ASM add eax,ebp ++ ASM mov ebp,[esi+ebx] ++ ASM adc edx,0 ++ ASM sub ebp,eax ++ ASM adc edx,0 ++ ASM mov [esi+ebx],ebp ++ ASM dec ecx ++ ASM mov ebp,edx ++ ASM jnz tcl3 ++ ++ ASM mov eax,ebp ++ ASM pop ebp ++ ASM mov borrow,eax ++ ASM pop edi ++ ASM pop esi ++#endif ++#if INLINE_ASM == 4 ++ ASM ( ++ "movl %1,%%ecx\n" ++ "movl %2,%%esi\n" ++ "shll $2,%%esi\n" ++ "movl %3,%%edi\n" ++ "movl %4,%%ebx\n" ++ "addl %%esi,%%ebx\n" ++ "movl %5,%%esi\n" ++ "subl %%esi,%%ebx\n" ++ "subl $4,%%ebx\n" ++ "pushl %%ebp\n" ++ "xorl %%ebp,%%ebp\n" ++ "tcl3:\n" ++ "movl (%%esi),%%eax\n" ++ "addl $4,%%esi\n" ++ "mull %%edi\n" ++ "addl %%ebp,%%eax\n" ++ "movl (%%esi,%%ebx),%%ebp\n" ++ "adcl $0,%%edx\n" ++ "subl %%eax,%%ebp\n" ++ "adcl $0,%%edx\n" ++ "movl %%ebp,(%%esi,%%ebx)\n" ++ "decl %%ecx\n" ++ "movl %%edx,%%ebp\n" ++ "jnz tcl3\n" ++ ++ "movl %%ebp,%%eax\n" ++ "popl %%ebp\n" ++ "movl %%eax,%0\n" ++ ++ :"=m"(borrow) ++ :"m"(y0),"m"(m),"m"(attemp),"m"(w0g),"m"(yg) ++ :"eax","edi","esi","ebx","ecx","edx","memory" ++ ); ++#endif ++#endif ++#ifndef INLINE_ASM ++ for (i=0;iw[i]+borrow; ++ dig=dble.h[MR_BOT]; ++ borrow=dble.h[MR_TOP]; ++#else ++ borrow=muldvd(attemp,y->w[i],borrow,&dig); ++#endif ++ if (w0->w[m+i]w[m+i]-=dig; ++ } ++#endif ++ ++ if (w0->w[k+1]w[k+1]=0; ++ carry=0; ++ for (i=0;iw[m+i]+y->w[i]+carry; ++ if (psum>y->w[i]) carry=0; ++ if (psumw[i]) carry=1; ++ w0->w[m+i]=psum; ++ } ++ attemp--; /* ... and adjust guess */ ++ } ++ else w0->w[k+1]-=borrow; ++ } ++ if (k==w00-1 && attemp==0) w00--; ++ else if (y!=z) z->w[m]=attemp; ++ } ++#endif ++#ifndef MR_SIMPLE_BASE ++ } ++ else ++ { /* have to do it the hard way */ ++ if (d!=1) mr_pmul(_MIPP_ w0,d,w0); ++ ldy=y->w[y0-1]; ++ sdy=y->w[y0-2]; ++ ++ for (k=w00-1;k>=y0-1;k--) ++ { /* long division */ ++ ++ ++ if (w0->w[k+1]==ldy) /* guess next quotient digit */ ++ { ++ attemp=mr_mip->base-1; ++ ra=ldy+w0->w[k]; ++ } ++#ifdef MR_NOASM ++ else ++ { ++ dbled=(mr_large)w0->w[k+1]*mr_mip->base+w0->w[k]; ++ attemp=(mr_small)MR_LROUND(dbled/ldy); ++ ra=(mr_small)(dbled-(mr_large)attemp*ldy); ++ } ++#else ++ else attemp=muldiv(w0->w[k+1],mr_mip->base,w0->w[k],ldy,&ra); ++#endif ++ while (rabase) ++ { ++#ifdef MR_NOASM ++ dbled=(mr_large)sdy*attemp; ++#ifdef MR_FP_ROUNDING ++ tst=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); ++#else ++#ifndef MR_FP ++ if (mr_mip->base==mr_mip->base2) ++ tst=(mr_small)(dbled>>mr_mip->lg2b); ++ else ++#endif ++ tst=(mr_small)MR_LROUND(dbled/mr_mip->base); ++#endif ++ r=(mr_small)(dbled-(mr_large)tst*mr_mip->base); ++#else ++#ifdef MR_FP_ROUNDING ++ tst=imuldiv(sdy,attemp,(mr_small)0,mr_mip->base,mr_mip->inverse_base,&r); ++#else ++ tst=muldiv(sdy,attemp,(mr_small)0,mr_mip->base,&r); ++#endif ++#endif ++ if (tst< ra || (tst==ra && r<=w0->w[k-1])) break; ++ attemp--; /* refine guess */ ++ ra+=ldy; ++ } ++ m=k-y0+1; ++ if (attemp>0) ++ { /* do partial subtraction */ ++ borrow=0; ++ for (i=0;iw[i]+borrow; ++#ifdef MR_FP_ROUNDING ++ borrow=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); ++#else ++#ifndef MR_FP ++ if (mr_mip->base==mr_mip->base2) ++ borrow=(mr_small)(dbled>>mr_mip->lg2b); ++ else ++#endif ++ borrow=(mr_small)MR_LROUND(dbled/mr_mip->base); ++#endif ++ dig=(mr_small)(dbled-(mr_large)borrow*mr_mip->base); ++#else ++#ifdef MR_FP_ROUNDING ++ borrow=imuldiv(attemp,y->w[i],borrow,mr_mip->base,mr_mip->inverse_base,&dig); ++#else ++ borrow=muldiv(attemp,y->w[i],borrow,mr_mip->base,&dig); ++#endif ++#endif ++ if (w0->w[m+i]w[m+i]+=(mr_mip->base-dig); ++ } ++ else w0->w[m+i]-=dig; ++ } ++ if (w0->w[k+1]w[k+1]=0; ++ carry=0; ++ for (i=0;iw[m+i]+y->w[i]+carry; ++ carry=0; ++ if (psum>=mr_mip->base) ++ { ++ carry=1; ++ psum-=mr_mip->base; ++ } ++ w0->w[m+i]=psum; ++ } ++ attemp--; /* ... and adjust guess */ ++ } ++ else ++ w0->w[k+1]-=borrow; ++ } ++ if (k==w00-1 && attemp==0) w00--; ++ else if (y!=z) z->w[m]=attemp; ++ } ++ } ++#endif ++ if (y!=z) z->len=((w00-y0+1)|sz); /* set sign and length of result */ ++ ++ w0->len=y0; ++ ++ mr_lzero(y); ++ mr_lzero(z); ++ ++ if (x!=z) ++ { ++ mr_lzero(w0); ++#ifdef MR_FP_ROUNDING ++ if (d!=1) mr_sdiv(_MIPP_ w0,d,mr_invert(d),x); ++#else ++ if (d!=1) mr_sdiv(_MIPP_ w0,d,x); ++#endif ++ else copy(w0,x); ++ if (x->len!=0) x->len|=sx; ++ } ++#ifdef MR_FP_ROUNDING ++ if (d!=1) mr_sdiv(_MIPP_ y,d,mr_invert(d),y); ++#else ++ if (d!=1) mr_sdiv(_MIPP_ y,d,y); ++#endif ++ y->len|=sy; ++ mr_mip->check=check; ++ ++ MR_OUT ++} ++ ++BOOL divisible(_MIPD_ big x,big y) ++{ /* returns y|x, that is TRUE if y divides x exactly */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return FALSE; ++ ++ MR_IN(87) ++ ++ copy (x,mr_mip->w0); ++ divide(_MIPP_ mr_mip->w0,y,y); ++ ++ MR_OUT ++ if (size(mr_mip->w0)==0) return TRUE; ++ else return FALSE; ++} ++ ++void mad(_MIPD_ big x,big y,big z,big w,big q,big r) ++{ /* Multiply, Add and Divide; q=(x*y+z)/w remainder r * ++ * returns remainder only if w=q, quotient only if q=r * ++ * add done only if x, y and z are distinct. */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ BOOL check; ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(24) ++ if (w==r) ++ { ++ mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); ++ MR_OUT ++ return; ++ } ++ check=mr_mip->check; ++ mr_mip->check=OFF; /* turn off some error checks */ ++ ++ multiply(_MIPP_ x,y,mr_mip->w0); ++ if (x!=z && y!=z) add(_MIPP_ mr_mip->w0,z,mr_mip->w0); ++ ++ divide(_MIPP_ mr_mip->w0,w,q); ++ if (q!=r) copy(mr_mip->w0,r); ++ mr_mip->check=check; ++ MR_OUT ++} ++ +diff --git a/lib/sbi/sm/gm/miracl/mrarth3.c b/lib/sbi/sm/gm/miracl/mrarth3.c +new file mode 100644 +index 0000000..e51268e +--- /dev/null ++++ b/lib/sbi/sm/gm/miracl/mrarth3.c +@@ -0,0 +1,231 @@ ++ ++/*************************************************************************** ++ * ++Copyright 2013 CertiVox UK Ltd. * ++ * ++This file is part of CertiVox MIRACL Crypto SDK. * ++ * ++The CertiVox MIRACL Crypto SDK provides developers with an * ++extensive and efficient set of cryptographic functions. * ++For further information about its features and functionalities please * ++refer to http://www.certivox.com * ++ * ++* The CertiVox MIRACL Crypto SDK is free software: you can * ++ redistribute it and/or modify it under the terms of the * ++ GNU Affero General Public License as published by the * ++ Free Software Foundation, either version 3 of the License, * ++ or (at your option) any later version. * ++ * ++* The CertiVox MIRACL Crypto SDK is distributed in the hope * ++ that it will be useful, but WITHOUT ANY WARRANTY; without even the * ++ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * ++ See the GNU Affero General Public License for more details. * ++ * ++* You should have received a copy of the GNU Affero General Public * ++ License along with CertiVox MIRACL Crypto SDK. * ++ If not, see . * ++ * ++You can be released from the requirements of the license by purchasing * ++a commercial license. Buying such a license is mandatory as soon as you * ++develop commercial activities involving the CertiVox MIRACL Crypto SDK * ++without disclosing the source code of your own applications, or shipping * ++the CertiVox MIRACL Crypto SDK with a closed source product. * ++ * ++***************************************************************************/ ++/* ++ * MIRACL arithmetic routines 3 - simple powers and roots ++ * mrarth3.c ++ */ ++ ++#include "sm/gm/miracl/miracl.h" ++#include ++ ++void expint(_MIPD_ int b,int n,big x) ++{ /* sets x=b^n */ ++ unsigned int bit,un; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ convert(_MIPP_ 1,x); ++ if (n==0) return; ++ ++ MR_IN(50) ++ ++ if (n<0) ++ { ++ mr_berror(_MIPP_ MR_ERR_NEG_POWER); ++ MR_OUT ++ return; ++ } ++ if (b==2) expb2(_MIPP_ n,x); ++ else ++ { ++ bit=1; ++ un=(unsigned int)n; ++ while (un>=bit) bit<<=1; ++ bit>>=1; ++ while (bit>0) ++ { /* ltr method */ ++ multiply(_MIPP_ x,x,x); ++ if ((bit&un)!=0) premult(_MIPP_ x,b,x); ++ bit>>=1; ++ } ++ } ++ MR_OUT ++} ++ ++void power(_MIPD_ big x,long n,big z,big w) ++{ /* raise big number to int power w=x^n * ++ * (mod z if z and w distinct) */ ++ mr_small norm; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ copy(x,mr_mip->w5); ++ zero(w); ++ if(mr_mip->ERNUM || size(mr_mip->w5)==0) return; ++ convert(_MIPP_ 1,w); ++ if (n==0L) return; ++ ++ MR_IN(17) ++ ++ if (n<0L) ++ { ++ mr_berror(_MIPP_ MR_ERR_NEG_POWER); ++ MR_OUT ++ return; ++ } ++ ++ if (w==z) forever ++ { /* "Russian peasant" exponentiation */ ++ if (n%2!=0L) ++ multiply(_MIPP_ w,mr_mip->w5,w); ++ n/=2L; ++ if (mr_mip->ERNUM || n==0L) break; ++ multiply(_MIPP_ mr_mip->w5,mr_mip->w5,mr_mip->w5); ++ } ++ else ++ { ++ norm=normalise(_MIPP_ z,z); ++ divide(_MIPP_ mr_mip->w5,z,z); ++ forever ++ { ++ if (mr_mip->user!=NULL) (*mr_mip->user)(); ++ ++ if (n%2!=0L) mad(_MIPP_ w,mr_mip->w5,mr_mip->w5,z,z,w); ++ n/=2L; ++ if (mr_mip->ERNUM || n==0L) break; ++ mad(_MIPP_ mr_mip->w5,mr_mip->w5,mr_mip->w5,z,z,mr_mip->w5); ++ } ++ if (norm!=1) ++ { ++#ifdef MR_FP_ROUNDING ++ mr_sdiv(_MIPP_ z,norm,mr_invert(norm),z); ++#else ++ mr_sdiv(_MIPP_ z,norm,z); ++#endif ++ divide(_MIPP_ w,z,z); ++ } ++ } ++ ++ MR_OUT ++} ++ ++BOOL nroot(_MIPD_ big x,int n,big w) ++{ /* extract lower approximation to nth root * ++ * w=x^(1/n) returns TRUE for exact root * ++ * uses Newtons method */ ++ int sx,dif,s,p,d,lg2,lgx,rem; ++ BOOL full; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return FALSE; ++ if (size(x)==0 || n==1) ++ { ++ copy(x,w); ++ return TRUE; ++ } ++ ++ MR_IN(16) ++ ++ if (n<1) mr_berror(_MIPP_ MR_ERR_BAD_ROOT); ++ sx=exsign(x); ++ if (n%2==0 && sx==MINUS) mr_berror(_MIPP_ MR_ERR_NEG_ROOT); ++ if (mr_mip->ERNUM) ++ { ++ MR_OUT ++ return FALSE; ++ } ++ insign(PLUS,x); ++ lgx=logb2(_MIPP_ x); ++ if (n>=lgx) ++ { /* root must be 1 */ ++ insign(sx,x); ++ convert(_MIPP_ sx,w); ++ MR_OUT ++ if (lgx==1) return TRUE; ++ else return FALSE; ++ } ++ expb2(_MIPP_ 1+(lgx-1)/n,mr_mip->w2); /* guess root as 2^(log2(x)/n) */ ++ s=(-(((int)x->len-1)/n)*n); ++ mr_shift(_MIPP_ mr_mip->w2,s/n,mr_mip->w2); ++ lg2=logb2(_MIPP_ mr_mip->w2)-1; ++ full=FALSE; ++ if (s==0) full=TRUE; ++ d=0; ++ p=1; ++ while (!mr_mip->ERNUM) ++ { /* Newtons method */ ++ copy(mr_mip->w2,mr_mip->w3); ++ mr_shift(_MIPP_ x,s,mr_mip->w4); ++ mr_mip->check=OFF; ++ power(_MIPP_ mr_mip->w2,n-1,mr_mip->w6,mr_mip->w6); ++ mr_mip->check=ON; ++ divide(_MIPP_ mr_mip->w4,mr_mip->w6,mr_mip->w2); ++ rem=size(mr_mip->w4); ++ subtract(_MIPP_ mr_mip->w2,mr_mip->w3,mr_mip->w2); ++ dif=size(mr_mip->w2); ++ subdiv(_MIPP_ mr_mip->w2,n,mr_mip->w2); ++ add(_MIPP_ mr_mip->w2,mr_mip->w3,mr_mip->w2); ++ p*=2; ++ if(plg2b) continue; ++ if (full && mr_abs(dif)w2,1,mr_mip->w2); ++ mr_mip->check=OFF; ++ power(_MIPP_ mr_mip->w2,n,mr_mip->w6,mr_mip->w6); ++ mr_mip->check=ON; ++ dif=mr_compare(x,mr_mip->w6); ++ } ++ copy(mr_mip->w2,w); ++ insign(sx,w); ++ insign(sx,x); ++ MR_OUT ++ if (rem==0 && dif==0) return TRUE; ++ else return FALSE; ++ } ++ else ++ { /* adjust precision */ ++ d*=2; ++ if (d==0) d=1; ++ s+=d*n; ++ if (s>=0) ++ { ++ d-=s/n; ++ s=0; ++ full=TRUE; ++ } ++ mr_shift(_MIPP_ mr_mip->w2,d,mr_mip->w2); ++ } ++ p/=2; ++ } ++ MR_OUT ++ return FALSE; ++} ++ +diff --git a/lib/sbi/sm/gm/miracl/mrbits.c b/lib/sbi/sm/gm/miracl/mrbits.c +new file mode 100644 +index 0000000..b3b1182 +--- /dev/null ++++ b/lib/sbi/sm/gm/miracl/mrbits.c +@@ -0,0 +1,244 @@ ++ ++/*************************************************************************** ++ * ++Copyright 2013 CertiVox UK Ltd. * ++ * ++This file is part of CertiVox MIRACL Crypto SDK. * ++ * ++The CertiVox MIRACL Crypto SDK provides developers with an * ++extensive and efficient set of cryptographic functions. * ++For further information about its features and functionalities please * ++refer to http://www.certivox.com * ++ * ++* The CertiVox MIRACL Crypto SDK is free software: you can * ++ redistribute it and/or modify it under the terms of the * ++ GNU Affero General Public License as published by the * ++ Free Software Foundation, either version 3 of the License, * ++ or (at your option) any later version. * ++ * ++* The CertiVox MIRACL Crypto SDK is distributed in the hope * ++ that it will be useful, but WITHOUT ANY WARRANTY; without even the * ++ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * ++ See the GNU Affero General Public License for more details. * ++ * ++* You should have received a copy of the GNU Affero General Public * ++ License along with CertiVox MIRACL Crypto SDK. * ++ If not, see . * ++ * ++You can be released from the requirements of the license by purchasing * ++a commercial license. Buying such a license is mandatory as soon as you * ++develop commercial activities involving the CertiVox MIRACL Crypto SDK * ++without disclosing the source code of your own applications, or shipping * ++the CertiVox MIRACL Crypto SDK with a closed source product. * ++ * ++***************************************************************************/ ++/* ++ * MIRACL bit manipulation routines ++ * mrbits.c ++ */ ++ ++#include "sm/gm/miracl/miracl.h" ++ ++#ifdef MR_FP ++#include ++#endif ++ ++int logb2(_MIPD_ big x) ++{ /* returns number of bits in x */ ++ int xl,lg2; ++ mr_small top; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM || size(x)==0) return 0; ++ ++ MR_IN(49) ++ ++ ++#ifndef MR_ALWAYS_BINARY ++ if (mr_mip->base==mr_mip->base2) ++ { ++#endif ++ xl=(int)(x->len&MR_OBITS); ++ lg2=mr_mip->lg2b*(xl-1); ++ top=x->w[xl-1]; ++ while (top>=1) ++ { ++ lg2++; ++ top/=2; ++ } ++ ++#ifndef MR_ALWAYS_BINARY ++ } ++ else ++ { ++ copy(x,mr_mip->w0); ++ insign(PLUS,mr_mip->w0); ++ lg2=0; ++ while (mr_mip->w0->len>1) ++ { ++#ifdef MR_FP_ROUNDING ++ mr_sdiv(_MIPP_ mr_mip->w0,mr_mip->base2,mr_invert(mr_mip->base2),mr_mip->w0); ++#else ++ mr_sdiv(_MIPP_ mr_mip->w0,mr_mip->base2,mr_mip->w0); ++#endif ++ lg2+=mr_mip->lg2b; ++ } ++ ++ while (mr_mip->w0->w[0]>=1) ++ { ++ lg2++; ++ mr_mip->w0->w[0]/=2; ++ } ++ } ++#endif ++ MR_OUT ++ return lg2; ++} ++ ++void sftbit(_MIPD_ big x,int n,big z) ++{ /* shift x by n bits */ ++ int m; ++ mr_small sm; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ copy(x,z); ++ if (n==0) return; ++ ++ MR_IN(47) ++ ++ m=mr_abs(n); ++ sm=mr_shiftbits((mr_small)1,m%mr_mip->lg2b); ++ if (n>0) ++ { /* shift left */ ++ ++#ifndef MR_ALWAYS_BINARY ++ if (mr_mip->base==mr_mip->base2) ++ { ++#endif ++ mr_shift(_MIPP_ z,n/mr_mip->lg2b,z); ++ mr_pmul(_MIPP_ z,sm,z); ++#ifndef MR_ALWAYS_BINARY ++ } ++ else ++ { ++ expb2(_MIPP_ m,mr_mip->w1); ++ multiply(_MIPP_ z,mr_mip->w1,z); ++ } ++#endif ++ } ++ else ++ { /* shift right */ ++ ++#ifndef MR_ALWAYS_BINARY ++ if (mr_mip->base==mr_mip->base2) ++ { ++#endif ++ mr_shift(_MIPP_ z,n/mr_mip->lg2b,z); ++#ifdef MR_FP_ROUNDING ++ mr_sdiv(_MIPP_ z,sm,mr_invert(sm),z); ++#else ++ mr_sdiv(_MIPP_ z,sm,z); ++#endif ++ ++#ifndef MR_ALWAYS_BINARY ++ } ++ else ++ { ++ expb2(_MIPP_ m,mr_mip->w1); ++ divide(_MIPP_ z,mr_mip->w1,z); ++ } ++#endif ++ } ++ MR_OUT ++} ++ ++void expb2(_MIPD_ int n,big x) ++{ /* sets x=2^n */ ++ int r,p; ++#ifndef MR_ALWAYS_BINARY ++ int i; ++#endif ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ convert(_MIPP_ 1,x); ++ if (n==0) return; ++ ++ MR_IN(149) ++ ++ if (n<0) ++ { ++ mr_berror(_MIPP_ MR_ERR_NEG_POWER); ++ MR_OUT ++ return; ++ } ++ r=n/mr_mip->lg2b; ++ p=n%mr_mip->lg2b; ++ ++#ifndef MR_ALWAYS_BINARY ++ if (mr_mip->base==mr_mip->base2) ++ { ++#endif ++ mr_shift(_MIPP_ x,r,x); ++ x->w[x->len-1]=mr_shiftbits(x->w[x->len-1],p); ++#ifndef MR_ALWAYS_BINARY ++ } ++ else ++ { ++ for (i=1;i<=r;i++) ++ mr_pmul(_MIPP_ x,mr_mip->base2,x); ++ mr_pmul(_MIPP_ x,mr_shiftbits((mr_small)1,p),x); ++ } ++#endif ++ MR_OUT ++} ++ ++#ifndef MR_NO_RAND ++ ++void bigbits(_MIPD_ int n,big x) ++{ /* sets x as random < 2^n */ ++ mr_small r; ++ mr_lentype wlen; ++#ifdef MR_FP ++ mr_small dres; ++#endif ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ zero(x); ++ if (mr_mip->ERNUM || n<=0) return; ++ ++ MR_IN(150) ++ ++ expb2(_MIPP_ n,mr_mip->w1); ++ wlen=mr_mip->w1->len; ++ do ++ { ++ r=brand(_MIPPO_ ); ++ if (mr_mip->base==0) x->w[x->len++]=r; ++ else x->w[x->len++]=MR_REMAIN(r,mr_mip->base); ++ } while (x->lenbase==mr_mip->base2) ++ { ++#endif ++ ++ x->w[wlen-1]=MR_REMAIN(x->w[wlen-1],mr_mip->w1->w[wlen-1]); ++ mr_lzero(x); ++ ++#ifndef MR_ALWAYS_BINARY ++ } ++ else ++ { ++ divide(_MIPP_ x,mr_mip->w1,mr_mip->w1); ++ } ++#endif ++ ++ MR_OUT ++} ++ ++#endif +diff --git a/lib/sbi/sm/gm/miracl/mrcore.c b/lib/sbi/sm/gm/miracl/mrcore.c +new file mode 100644 +index 0000000..ea99c16 +--- /dev/null ++++ b/lib/sbi/sm/gm/miracl/mrcore.c +@@ -0,0 +1,2290 @@ ++ ++/*************************************************************************** ++ * ++Copyright 2013 CertiVox UK Ltd. * ++ * ++This file is part of CertiVox MIRACL Crypto SDK. * ++ * ++The CertiVox MIRACL Crypto SDK provides developers with an * ++extensive and efficient set of cryptographic functions. * ++For further information about its features and functionalities please * ++refer to http://www.certivox.com * ++ * ++* The CertiVox MIRACL Crypto SDK is free software: you can * ++ redistribute it and/or modify it under the terms of the * ++ GNU Affero General Public License as published by the * ++ Free Software Foundation, either version 3 of the License, * ++ or (at your option) any later version. * ++ * ++* The CertiVox MIRACL Crypto SDK is distributed in the hope * ++ that it will be useful, but WITHOUT ANY WARRANTY; without even the * ++ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * ++ See the GNU Affero General Public License for more details. * ++ * ++* You should have received a copy of the GNU Affero General Public * ++ License along with CertiVox MIRACL Crypto SDK. * ++ If not, see . * ++ * ++You can be released from the requirements of the license by purchasing * ++a commercial license. Buying such a license is mandatory as soon as you * ++develop commercial activities involving the CertiVox MIRACL Crypto SDK * ++without disclosing the source code of your own applications, or shipping * ++the CertiVox MIRACL Crypto SDK with a closed source product. * ++ * ++***************************************************************************/ ++/* ++ * ++ * MIRACL Core module - contains initialisation code and general purpose ++ * utilities ++ * mrcore.c ++ * ++ * Space can be saved by removing unneeded functions (mr_and ?) ++ * ++ */ ++ ++#include "sm/gm/miracl/miracl.h" ++#include "sbi/sbi_string.h" ++ ++#ifdef MR_FP ++#include ++#endif ++ ++/*** Multi-Threaded Support ***/ ++ ++#ifndef MR_GENERIC_MT ++ ++ #ifdef MR_OPENMP_MT ++ #include ++ ++#define MR_MIP_EXISTS ++ ++ miracl *mr_mip; ++ #pragma omp threadprivate(mr_mip) ++ ++ miracl *get_mip() ++ { ++ return mr_mip; ++ } ++ ++ void mr_init_threading() ++ { ++ } ++ ++ void mr_end_threading() ++ { ++ } ++ ++ #endif ++ ++ #ifdef MR_WINDOWS_MT ++ #include ++ DWORD mr_key; ++ ++ miracl *get_mip() ++ { ++ return (miracl *)TlsGetValue(mr_key); ++ } ++ ++ void mr_init_threading() ++ { ++ mr_key=TlsAlloc(); ++ } ++ ++ void mr_end_threading() ++ { ++ TlsFree(mr_key); ++ } ++ ++ #endif ++ ++ #ifdef MR_UNIX_MT ++ #include ++ pthread_key_t mr_key; ++ ++ miracl *get_mip() ++ { ++ return (miracl *)pthread_getspecific(mr_key); ++ } ++ ++ void mr_init_threading() ++ { ++ pthread_key_create(&mr_key,(void(*)(void *))NULL); ++ } ++ ++ void mr_end_threading() ++ { ++ pthread_key_delete(mr_key); ++ } ++ #endif ++ ++ #ifndef MR_WINDOWS_MT ++ #ifndef MR_UNIX_MT ++ #ifndef MR_OPENMP_MT ++ #ifdef MR_STATIC ++ miracl mip; ++ miracl *mr_mip=&mip; ++ #else ++ miracl *mr_mip=NULL; /* MIRACL's one and only global variable */ ++ #endif ++#define MR_MIP_EXISTS ++ miracl *get_mip() ++ { ++ return (miracl *)mr_mip; ++ } ++ #endif ++ #endif ++ #endif ++ ++#ifdef MR_MIP_EXISTS ++ void set_mip(miracl *mip) ++ { ++ mr_mip=mip; ++ } ++#endif ++ ++#endif ++ ++/* See Advanced Windows by Jeffrey Richter, Chapter 12 for methods for ++ creating different instances of this global for each executing thread ++ when using Windows '95/NT ++*/ ++ ++#ifdef MR_STATIC ++ ++#if MIRACL==8 ++ ++static const int mr_small_primes[]= ++{2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103, ++107,109,113,127,0}; ++ ++#else ++ ++static const int mr_small_primes[]= ++{2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103, ++107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211, ++223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331, ++337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449, ++457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587, ++593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709, ++719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853, ++857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991, ++997,0}; ++ ++#endif ++ ++#endif ++ ++#ifndef MR_STRIPPED_DOWN ++#ifndef MR_NO_STANDARD_IO ++ ++static char *names[] = ++{(char *)"your program",(char *)"innum",(char *)"otnum",(char *)"jack",(char *)"normalise", ++(char *)"multiply",(char *)"divide",(char *)"incr",(char *)"decr",(char *)"premult", ++(char *)"subdiv",(char *)"fdsize",(char *)"egcd",(char *)"cbase", ++(char *)"cinnum",(char *)"cotnum",(char *)"nroot",(char *)"power", ++(char *)"powmod",(char *)"bigdig",(char *)"bigrand",(char *)"nxprime",(char *)"isprime", ++(char *)"mirvar",(char *)"mad",(char *)"multi_inverse",(char *)"putdig", ++(char *)"add",(char *)"subtract",(char *)"mirsys",(char *)"xgcd", ++(char *)"fpack",(char *)"dconv",(char *)"mr_shift",(char *)"mround",(char *)"fmul", ++(char *)"fdiv",(char *)"fadd",(char *)"fsub",(char *)"fcomp",(char *)"fconv", ++(char *)"frecip",(char *)"fpmul",(char *)"fincr",(char *)"",(char *)"ftrunc", ++(char *)"frand",(char *)"sftbit",(char *)"build",(char *)"logb2",(char *)"expint", ++(char *)"fpower",(char *)"froot",(char *)"fpi",(char *)"fexp",(char *)"flog",(char *)"fpowf", ++(char *)"ftan",(char *)"fatan",(char *)"fsin",(char *)"fasin",(char *)"fcos",(char *)"facos", ++(char *)"ftanh",(char *)"fatanh",(char *)"fsinh",(char *)"fasinh",(char *)"fcosh", ++(char *)"facosh",(char *)"flop",(char *)"gprime",(char *)"powltr",(char *)"fft_mult", ++(char *)"crt_init",(char *)"crt",(char *)"otstr",(char *)"instr",(char *)"cotstr",(char *)"cinstr",(char *)"powmod2", ++(char *)"prepare_monty",(char *)"nres",(char *)"redc",(char *)"nres_modmult",(char *)"nres_powmod", ++(char *)"nres_moddiv",(char *)"nres_powltr",(char *)"divisible",(char *)"remain", ++(char *)"fmodulo",(char *)"nres_modadd",(char *)"nres_modsub",(char *)"nres_negate", ++(char *)"ecurve_init",(char *)"ecurve_add",(char *)"ecurve_mult", ++(char *)"epoint_init",(char *)"epoint_set",(char *)"epoint_get",(char *)"nres_powmod2", ++(char *)"nres_sqroot",(char *)"sqroot",(char *)"nres_premult",(char *)"ecurve_mult2", ++(char *)"ecurve_sub",(char *)"trial_division",(char *)"nxsafeprime",(char *)"nres_lucas",(char *)"lucas", ++(char *)"brick_init",(char *)"pow_brick",(char *)"set_user_function", ++(char *)"nres_powmodn",(char *)"powmodn",(char *)"ecurve_multn", ++(char *)"ebrick_init",(char *)"mul_brick",(char *)"epoint_norm",(char *)"nres_multi_inverse",(char *)"", ++(char *)"nres_dotprod",(char *)"epoint_negate",(char *)"ecurve_multi_add", ++(char *)"ecurve2_init",(char *)"",(char *)"epoint2_set",(char *)"epoint2_norm",(char *)"epoint2_get", ++(char *)"epoint2_comp",(char *)"ecurve2_add",(char *)"epoint2_negate",(char *)"ecurve2_sub", ++(char *)"ecurve2_multi_add",(char *)"ecurve2_mult",(char *)"ecurve2_multn",(char *)"ecurve2_mult2", ++(char *)"ebrick2_init",(char *)"mul2_brick",(char *)"prepare_basis",(char *)"strong_bigrand", ++(char *)"bytes_to_big",(char *)"big_to_bytes",(char *)"set_io_buffer_size", ++(char *)"epoint_getxyz",(char *)"epoint_double_add",(char *)"nres_double_inverse", ++(char *)"double_inverse",(char *)"epoint_x",(char *)"hamming",(char *)"expb2",(char *)"bigbits", ++(char *)"nres_lazy",(char *)"zzn2_imul",(char *)"nres_double_modadd",(char *)"nres_double_modsub", ++/*155*/(char *)"",(char *)"zzn2_from_int",(char *)"zzn2_negate",(char *)"zzn2_conj",(char *)"zzn2_add", ++(char *)"zzn2_sub",(char *)"zzn2_smul",(char *)"zzn2_mul",(char *)"zzn2_inv",(char *)"zzn2_timesi",(char *)"zzn2_powl", ++(char *)"zzn2_from_bigs",(char *)"zzn2_from_big",(char *)"zzn2_from_ints", ++(char *)"zzn2_sadd",(char *)"zzn2_ssub",(char *)"zzn2_times_irp",(char *)"zzn2_div2", ++(char *)"zzn3_from_int",(char *)"zzn3_from_ints",(char *)"zzn3_from_bigs", ++(char *)"zzn3_from_big",(char *)"zzn3_negate",(char *)"zzn3_powq",(char *)"zzn3_init", ++(char *)"zzn3_add",(char *)"zzn3_sadd",(char *)"zzn3_sub",(char *)"zzn3_ssub",(char *)"zzn3_smul", ++(char *)"zzn3_imul",(char *)"zzn3_mul",(char *)"zzn3_inv",(char *)"zzn3_div2",(char *)"zzn3_timesi", ++(char *)"epoint_multi_norm",(char *)"mr_jsf",(char *)"epoint2_multi_norm", ++(char *)"ecn2_compare",(char *)"ecn2_norm",(char *)"ecn2_set",(char *)"zzn2_txx", ++(char *)"zzn2_txd",(char *)"nres_div2",(char *)"nres_div3",(char *)"zzn2_div3", ++(char *)"ecn2_setx",(char *)"ecn2_rhs",(char *)"zzn2_qr",(char *)"zzn2_sqrt",(char *)"ecn2_add",(char *)"ecn2_mul2_jsf",(char *)"ecn2_mul", ++(char *)"nres_div5",(char *)"zzn2_div5",(char *)"zzn2_sqr",(char *)"ecn2_add_sub",(char *)"ecn2_psi",(char *)"invmodp", ++(char *)"zzn2_multi_inverse",(char *)"ecn2_multi_norm",(char *)"ecn2_precomp",(char *)"ecn2_mul4_gls_v", ++(char *)"ecn2_mul2",(char *)"ecn2_precomp_gls",(char *)"ecn2_mul2_gls", ++(char *)"ecn2_brick_init",(char *)"ecn2_mul_brick_gls",(char *)"ecn2_multn",(char *)"zzn3_timesi2", ++(char *)"nres_complex",(char *)"zzn4_from_int",(char *)"zzn4_negate",(char *)"zzn4_conj",(char *)"zzn4_add",(char *)"zzn4_sadd",(char *)"zzn4_sub",(char *)"zzn4_ssub",(char *)"zzn4_smul",(char *)"zzn4_sqr", ++(char *)"zzn4_mul",(char *)"zzn4_inv",(char *)"zzn4_div2",(char *)"zzn4_powq",(char *)"zzn4_tx",(char *)"zzn4_imul",(char *)"zzn4_lmul",(char *)"zzn4_from_big", ++(char *)"ecn2_mult4"}; ++ ++/* 0 - 243 (244 in all) */ ++ ++#endif ++#endif ++ ++#ifdef MR_NOASM ++ ++/* C only versions of muldiv/muldvd/muldvd2/muldvm */ ++/* Note that mr_large should be twice the size of mr_small */ ++ ++mr_small muldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_small *rp) ++{ ++ mr_small q; ++ mr_large p=(mr_large)a*b+c; ++ q=(mr_small)(MR_LROUND(p/m)); ++ *rp=(mr_small)(p-(mr_large)q*m); ++ return q; ++} ++ ++#ifdef MR_FP_ROUNDING ++ ++mr_small imuldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_large im,mr_small *rp) ++{ ++ mr_small q; ++ mr_large ldres,p=(mr_large)a*b+c; ++ q=(mr_small)MR_LROUND(p*im); ++ *rp=(mr_small)(p-(mr_large)q*m); ++ return q; ++} ++ ++#endif ++ ++#ifndef MR_NOFULLWIDTH ++ ++mr_small muldvm(mr_small a,mr_small c,mr_small m,mr_small *rp) ++{ ++ mr_small q; ++ union doubleword dble; ++ dble.h[MR_BOT]=c; ++ dble.h[MR_TOP]=a; ++ ++ q=(mr_small)(dble.d/m); ++ *rp=(mr_small)(dble.d-(mr_large)q*m); ++ return q; ++} ++ ++mr_small muldvd(mr_small a,mr_small b,mr_small c,mr_small *rp) ++{ ++ union doubleword dble; ++ dble.d=(mr_large)a*b+c; ++ ++ *rp=dble.h[MR_BOT]; ++ return dble.h[MR_TOP]; ++} ++ ++void muldvd2(mr_small a,mr_small b,mr_small *c,mr_small *rp) ++{ ++ union doubleword dble; ++ dble.d=(mr_large)a*b+*c+*rp; ++ *rp=dble.h[MR_BOT]; ++ *c=dble.h[MR_TOP]; ++} ++ ++#endif ++#endif ++ ++#ifdef MR_NOFULLWIDTH ++ ++/* no FULLWIDTH working, so supply dummies */ ++ ++/* ++ ++mr_small muldvd(mr_small a,mr_small b,mr_small c,mr_small *rp) ++{ ++ return (mr_small)0; ++} ++ ++mr_small muldvm(mr_small a,mr_small c,mr_small m,mr_small *rp) ++{ ++ return (mr_small)0; ++} ++ ++void muldvd2(mr_small a,mr_small b,mr_small *c,mr_small *rp) ++{ ++} ++ ++*/ ++ ++#endif ++ ++#ifndef MR_NO_STANDARD_IO ++ ++static void mputs(char *s) ++{ /* output a string */ ++ int i=0; ++ while (s[i]!=0) fputc((int)s[i++],stdout); ++} ++#endif ++ ++void mr_berror(_MIPD_ int nerr) ++{ /* Big number error routine */ ++#ifndef MR_STRIPPED_DOWN ++int i; ++#endif ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++if (mr_mip->ERCON) ++{ ++ mr_mip->ERNUM=nerr; ++ return; ++} ++#ifndef MR_NO_STANDARD_IO ++ ++#ifndef MR_STRIPPED_DOWN ++mputs((char *)"\nMIRACL error from routine "); ++if (mr_mip->depthtrace[mr_mip->depth]]); ++else mputs((char *)"???"); ++fputc('\n',stdout); ++ ++for (i=mr_mip->depth-1;i>=0;i--) ++{ ++ mputs((char *)" called from "); ++ if (itrace[i]]); ++ else mputs((char *)"???"); ++ fputc('\n',stdout); ++} ++ ++switch (nerr) ++{ ++case 1 : ++mputs((char *)"Number base too big for representation\n"); ++break; ++case 2 : ++mputs((char *)"Division by zero attempted\n"); ++break; ++case 3 : ++mputs((char *)"Overflow - Number too big\n"); ++break; ++case 4 : ++mputs((char *)"Internal result is negative\n"); ++break; ++case 5 : ++mputs((char *)"Input format error\n"); ++break; ++case 6 : ++mputs((char *)"Illegal number base\n"); ++break; ++case 7 : ++mputs((char *)"Illegal parameter usage\n"); ++break; ++case 8 : ++mputs((char *)"Out of space\n"); ++break; ++case 9 : ++mputs((char *)"Even root of a negative number\n"); ++break; ++case 10: ++mputs((char *)"Raising integer to negative power\n"); ++break; ++case 11: ++mputs((char *)"Attempt to take illegal root\n"); ++break; ++case 12: ++mputs((char *)"Integer operation attempted on Flash number\n"); ++break; ++case 13: ++mputs((char *)"Flash overflow\n"); ++break; ++case 14: ++mputs((char *)"Numbers too big\n"); ++break; ++case 15: ++mputs((char *)"Log of a non-positive number\n"); ++break; ++case 16: ++mputs((char *)"Flash to double conversion failure\n"); ++break; ++case 17: ++mputs((char *)"I/O buffer overflow\n"); ++break; ++case 18: ++mputs((char *)"MIRACL not initialised - no call to mirsys()\n"); ++break; ++case 19: ++mputs((char *)"Illegal modulus \n"); ++break; ++case 20: ++mputs((char *)"No modulus defined\n"); ++break; ++case 21: ++mputs((char *)"Exponent too big\n"); ++break; ++case 22: ++mputs((char *)"Unsupported Feature - check mirdef.h\n"); ++break; ++case 23: ++mputs((char *)"Specified double length type isn't double length\n"); ++break; ++case 24: ++mputs((char *)"Specified basis is NOT irreducible\n"); ++break; ++case 25: ++mputs((char *)"Unable to control Floating-point rounding\n"); ++break; ++case 26: ++mputs((char *)"Base must be binary (MR_ALWAYS_BINARY defined in mirdef.h ?)\n"); ++break; ++case 27: ++mputs((char *)"No irreducible basis defined\n"); ++break; ++case 28: ++mputs((char *)"Composite modulus\n"); ++break; ++case 29: ++mputs((char *)"Input/output error when reading from RNG device node\n"); ++break; ++default: ++mputs((char *)"Undefined error\n"); ++break; ++} ++exit(0); ++#else ++mputs((char *)"MIRACL error\n"); ++exit(0); ++#endif ++ ++#endif ++} ++ ++#ifndef MR_STRIPPED_DOWN ++ ++void mr_track(_MIPDO_ ) ++{ /* track course of program execution * ++ * through the MIRACL routines */ ++ ++#ifndef MR_NO_STANDARD_IO ++ ++ int i; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ for (i=0;idepth;i++) fputc('-',stdout); ++ fputc('>',stdout); ++ mputs(names[mr_mip->trace[mr_mip->depth]]); ++ fputc('\n',stdout); ++#endif ++} ++ ++#endif ++ ++#ifndef MR_NO_RAND ++ ++mr_small brand(_MIPDO_ ) ++{ /* Marsaglia & Zaman random number generator */ ++ int i,k; ++ mr_unsign32 pdiff,t; ++ mr_small r; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->lg2b>32) ++ { /* underlying type is > 32 bits. Assume <= 64 bits */ ++ mr_mip->rndptr+=2; ++ if (mr_mip->rndptrira[mr_mip->rndptr]; ++ r=mr_shiftbits(r,mr_mip->lg2b-32); ++ r+=(mr_small)mr_mip->ira[mr_mip->rndptr+1]; ++ return r; ++ } ++ } ++ else ++ { ++ mr_mip->rndptr++; ++ if (mr_mip->rndptrira[mr_mip->rndptr]; ++ } ++ mr_mip->rndptr=0; ++ for (i=0,k=NK-NJ;iira[k]; ++ pdiff=t - mr_mip->ira[i] - mr_mip->borrow; ++ if (pdiffborrow=0; ++ if (pdiff>t) mr_mip->borrow=1; ++ mr_mip->ira[i]=pdiff; ++ } ++ if (mr_mip->lg2b>32) ++ { /* double up */ ++ r=(mr_small)mr_mip->ira[0]; ++ r=mr_shiftbits(r,mr_mip->lg2b-32); ++ r+=(mr_small)mr_mip->ira[1]; ++ return r; ++ } ++ else return (mr_small)(mr_mip->ira[0]); ++} ++ ++void irand(_MIPD_ mr_unsign32 seed) ++{ /* initialise random number system */ ++ int i,in; ++ mr_unsign32 t,m=1L; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ mr_mip->borrow=0L; ++ mr_mip->rndptr=0; ++ mr_mip->ira[0]=seed; ++ for (i=1;iira[in]=m; ++ t=m; ++ m=seed-m; ++ seed=t; ++ } ++ for (i=0;i<1000;i++) brand(_MIPPO_ ); /* "warm-up" & stir the generator */ ++} ++ ++#endif ++ ++mr_small mr_shiftbits(mr_small x,int n) ++{ ++#ifdef MR_FP ++ int i; ++ mr_small dres; ++ if (n==0) return x; ++ if (n>0) ++ { ++ for (i=0;i0) x<<=n; ++ else x>>=(-n); ++ return x; ++#endif ++ ++} ++ ++mr_small mr_setbase(_MIPD_ mr_small nb) ++{ /* set base. Pack as many digits as * ++ * possible into each computer word */ ++ mr_small temp; ++#ifdef MR_FP ++ mr_small dres; ++#endif ++#ifndef MR_NOFULLWIDTH ++ BOOL fits; ++ int bits; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ fits=FALSE; ++ bits=MIRACL; ++ while (bits>1) ++ { ++ bits/=2; ++ temp=((mr_small)1<apbase=nb; ++ mr_mip->pack=MIRACL/bits; ++ mr_mip->base=0; ++ return 0; ++ } ++#endif ++ mr_mip->apbase=nb; ++ mr_mip->pack=1; ++ mr_mip->base=nb; ++#ifdef MR_SIMPLE_BASE ++ return 0; ++#else ++ if (mr_mip->base==0) return 0; ++ temp=MR_DIV(MAXBASE,nb); ++ while (temp>=nb) ++ { ++ temp=MR_DIV(temp,nb); ++ mr_mip->base*=nb; ++ mr_mip->pack++; ++ } ++#ifdef MR_FP_ROUNDING ++ mr_mip->inverse_base=mr_invert(mr_mip->base); ++ return mr_mip->inverse_base; ++#else ++ return 0; ++#endif ++#endif ++} ++ ++#ifdef MR_FLASH ++ ++BOOL fit(big x,big y,int f) ++{ /* returns TRUE if x/y would fit flash format of length f */ ++ int n,d; ++ n=(int)(x->len&(MR_OBITS)); ++ d=(int)(y->len&(MR_OBITS)); ++ if (n==1 && x->w[0]==1) n=0; ++ if (d==1 && y->w[0]==1) d=0; ++ if (n+d<=f) return TRUE; ++ return FALSE; ++} ++ ++#endif ++ ++int mr_lent(flash x) ++{ /* return length of big or flash in words */ ++ mr_lentype lx; ++ lx=(x->len&(MR_OBITS)); ++#ifdef MR_FLASH ++ return (int)((lx&(MR_MSK))+((lx>>(MR_BTS))&(MR_MSK))); ++#else ++ return (int)lx; ++#endif ++} ++ ++void zero(flash x) ++{ /* set big/flash number to zero */ ++ int i,n; ++ mr_small *g; ++ if (x==NULL) return; ++#ifdef MR_FLASH ++ n=mr_lent(x); ++#else ++ n=(x->len&MR_OBITS); ++#endif ++ g=x->w; ++ ++ for (i=0;ilen=0; ++} ++ ++void uconvert(_MIPD_ unsigned int n ,big x) ++{ /* convert unsigned integer n to big number format */ ++ int m; ++#ifdef MR_FP ++ mr_small dres; ++#endif ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ zero(x); ++ if (n==0) return; ++ ++ m=0; ++#ifndef MR_SIMPLE_BASE ++ if (mr_mip->base==0) ++ { ++#endif ++#ifndef MR_NOFULLWIDTH ++#if MR_IBITS > MIRACL ++ while (n>0) ++ { ++ x->w[m++]=(mr_small)(n%((mr_small)1<<(MIRACL))); ++ n/=((mr_small)1<<(MIRACL)); ++ } ++#else ++ x->w[m++]=(mr_small)n; ++#endif ++#endif ++#ifndef MR_SIMPLE_BASE ++ } ++ else while (n>0) ++ { ++ x->w[m++]=MR_REMAIN((mr_small)n,mr_mip->base); ++ n=(unsigned int)((mr_small)n/mr_mip->base); ++ } ++#endif ++ x->len=m; ++} ++ ++void tconvert(_MIPD_ mr_utype n,big x) ++{ ++ mr_lentype s; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (n==0) {zero(x); return;} ++ s=0; ++ if (n<0) ++ { ++ s=MR_MSBIT; ++ n=(-n); ++ } ++ x->w[0]=n; ++ x->len=1; ++ x->len|=s; ++} ++ ++void convert(_MIPD_ int n ,big x) ++{ /* convert signed integer n to big number format */ ++ mr_lentype s; ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (n==0) {zero(x); return;} ++ s=0; ++ if (n<0) ++ { ++ s=MR_MSBIT; ++ n=(-n); ++ } ++ uconvert(_MIPP_ (unsigned int)n,x); ++ x->len|=s; ++} ++ ++#ifndef MR_STATIC ++#ifdef mr_dltype ++ ++void dlconv(_MIPD_ mr_dltype n,big x) ++{ /* convert double length integer to big number format - rarely needed */ ++ int m; ++ mr_lentype s; ++#ifdef MR_FP ++ mr_small dres; ++#endif ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ zero(x); ++ if (n==0) return; ++ s=0; ++ if (n<0) ++ { ++ s=MR_MSBIT; ++ n=(-n); ++ } ++ m=0; ++#ifndef MR_SIMPLE_BASE ++ if (mr_mip->base==0) ++ { ++#endif ++#ifndef MR_NOFULLWIDTH ++ while (n>0) ++ { ++ x->w[m++]=(mr_small)(n%((mr_dltype)1<<(MIRACL))); ++ n/=((mr_dltype)1<<(MIRACL)); ++ } ++#endif ++#ifndef MR_SIMPLE_BASE ++ } ++ else while (n>0) ++ { ++ x->w[m++]=(mr_small)MR_REMAIN(n,mr_mip->base); ++ n/=mr_mip->base; ++ } ++#endif ++ x->len=(m|s); ++} ++ ++#endif ++ ++void ulgconv(_MIPD_ unsigned long n,big x) ++{ /* convert unsigned long integer to big number format - rarely needed */ ++ int m; ++#ifdef MR_FP ++ mr_small dres; ++#endif ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ zero(x); ++ if (n==0) return; ++ ++ m=0; ++#ifndef MR_SIMPLE_BASE ++ if (mr_mip->base==0) ++ { ++#endif ++#ifndef MR_NOFULLWIDTH ++#if MR_LBITS > MIRACL ++ while (n>0) ++ { ++ x->w[m++]=(mr_small)(n%(1L<<(MIRACL))); ++ n/=(1L<<(MIRACL)); ++ } ++#else ++ x->w[m++]=(mr_small)n; ++#endif ++#endif ++#ifndef MR_SIMPLE_BASE ++ } ++ else while (n>0) ++ { ++ x->w[m++]=MR_REMAIN(n,mr_mip->base); ++ n=(unsigned long)((mr_small)n/mr_mip->base); ++ } ++#endif ++ x->len=m; ++} ++ ++void lgconv(_MIPD_ long n,big x) ++{ /* convert signed long integer to big number format - rarely needed */ ++ mr_lentype s; ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (n==0) {zero(x); return;} ++ s=0; ++ if (n<0) ++ { ++ s=MR_MSBIT; ++ n=(-n); ++ } ++ ulgconv(_MIPP_ (unsigned long)n,x); ++ ++ x->len|=s; ++} ++ ++flash mirvar(_MIPD_ int iv) ++{ /* initialize big/flash number */ ++ flash x; ++ int align; ++ char *ptr; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ if (mr_mip->ERNUM) return NULL; ++ MR_IN(23); ++ ++ if (!(mr_mip->active)) ++ { ++ mr_berror(_MIPP_ MR_ERR_NO_MIRSYS); ++ MR_OUT ++ return NULL; ++ } ++ ++/* OK, now I control alignment.... */ ++ ++/* Allocate space for big, the length, the pointer, and the array */ ++/* Do it all in one memory allocation - this is quicker */ ++/* Ensure that the array has correct alignment */ ++ ++ x=(big)mr_alloc(_MIPP_ mr_size(mr_mip->nib-1),1); ++ if (x==NULL) ++ { ++ MR_OUT ++ return x; ++ } ++ ++ ptr=(char *)&x->w; ++ align=(unsigned long)(ptr+sizeof(mr_small *))%sizeof(mr_small); ++ ++ x->w=(mr_small *)(ptr+sizeof(mr_small *)+sizeof(mr_small)-align); ++ ++ if (iv!=0) convert(_MIPP_ iv,x); ++ MR_OUT ++ return x; ++} ++ ++#endif ++ ++flash mirvar_mem_variable(char *mem,int index,int sz) ++{ ++ flash x; ++ int align; ++ char *ptr; ++ int offset,r; ++ ++/* alignment */ ++ offset=0; ++ r=(unsigned long)mem%MR_SL; ++ if (r>0) offset=MR_SL-r; ++ ++ x=(big)&mem[offset+mr_size(sz)*index]; ++ ptr=(char *)&x->w; ++ align=(unsigned long)(ptr+sizeof(mr_small *))%sizeof(mr_small); ++ x->w=(mr_small *)(ptr+sizeof(mr_small *)+sizeof(mr_small)-align); ++ ++ return x; ++} ++ ++flash mirvar_mem(_MIPD_ char *mem,int index) ++{ /* initialize big/flash number from pre-allocated memory */ ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ if (mr_mip->ERNUM) return NULL; ++ ++ return mirvar_mem_variable(mem,index,mr_mip->nib-1); ++ ++} ++ ++void set_user_function(_MIPD_ BOOL (*user)(void)) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(111) ++ ++ if (!(mr_mip->active)) ++ { ++ mr_berror(_MIPP_ MR_ERR_NO_MIRSYS); ++ MR_OUT ++ return; ++ } ++ ++ mr_mip->user=user; ++ ++ MR_OUT ++} ++ ++#ifndef MR_STATIC ++ ++#ifndef MR_SIMPLE_IO ++ ++void set_io_buffer_size(_MIPD_ int len) ++{ ++ int i; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (len<0) return; ++ MR_IN(142) ++ for (i=0;iIOBSIZ;i++) mr_mip->IOBUFF[i]=0; ++ mr_free(mr_mip->IOBUFF); ++ if (len==0) ++ { ++ MR_OUT ++ return; ++ } ++ mr_mip->IOBSIZ=len; ++ mr_mip->IOBUFF=(char *)mr_alloc(_MIPP_ len+1,1); ++ mr_mip->IOBUFF[0]='\0'; ++ MR_OUT ++} ++#endif ++ ++#endif ++ ++/* Initialise a big from ROM given its fixed length */ ++ ++BOOL init_big_from_rom(big x,int len,const mr_small *rom,int romsize,int *romptr) ++{ ++ int i; ++ zero(x); ++ x->len=len; ++ for (i=0;i=romsize) return FALSE; ++#ifdef MR_AVR ++ x->w[i]=pgm_read_byte_near(&rom[*romptr]); ++#else ++ x->w[i]=rom[*romptr]; ++#endif ++ (*romptr)++; ++ } ++ ++ mr_lzero(x); ++ return TRUE; ++} ++ ++/* Initialise an elliptic curve point from ROM */ ++ ++BOOL init_point_from_rom(epoint *P,int len,const mr_small *rom,int romsize,int *romptr) ++{ ++ if (!init_big_from_rom(P->X,len,rom,romsize,romptr)) return FALSE; ++ if (!init_big_from_rom(P->Y,len,rom,romsize,romptr)) return FALSE; ++ P->marker=MR_EPOINT_NORMALIZED; ++ return TRUE; ++} ++ ++#ifdef MR_GENERIC_AND_STATIC ++miracl *mirsys(miracl *mr_mip,int nd,mr_small nb) ++#else ++miracl *mirsys(int nd,mr_small nb) ++#endif ++{ /* Initialize MIRACL system to * ++ * use numbers to base nb, and * ++ * nd digits or (-nd) bytes long */ ++ ++/* In these cases mr_mip is passed as the first parameter */ ++ ++#ifdef MR_GENERIC_AND_STATIC ++ return mirsys_basic(mr_mip,nd,nb); ++#endif ++ ++#ifdef MR_GENERIC_MT ++#ifndef MR_STATIC ++ miracl *mr_mip=mr_first_alloc(); ++ return mirsys_basic(mr_mip,nd,nb); ++#endif ++#endif ++/* In these cases mr_mip is a "global" pointer and the mip itself is allocated from the heap. ++ In fact mr_mip (and mip) may be thread specific if some multi-threading scheme is implemented */ ++#ifndef MR_STATIC ++ #ifdef MR_WINDOWS_MT ++ miracl *mr_mip=mr_first_alloc(); ++ TlsSetValue(mr_key,mr_mip); ++ #endif ++ ++ #ifdef MR_UNIX_MT ++ miracl *mr_mip=mr_first_alloc(); ++ pthread_setspecific(mr_key,mr_mip); ++ #endif ++ ++ #ifdef MR_OPENMP_MT ++ mr_mip=mr_first_alloc(); ++ #endif ++ ++ #ifndef MR_WINDOWS_MT ++ #ifndef MR_UNIX_MT ++ #ifndef MR_OPENMP_MT ++ mr_mip=mr_first_alloc(); ++ #endif ++ #endif ++ #endif ++#endif ++ ++#ifndef MR_GENERIC_MT ++ mr_mip=get_mip(); ++#endif ++ return mirsys_basic(mr_mip,nd,nb); ++} ++ ++miracl *mirsys_basic(miracl *mr_mip,int nd,mr_small nb) ++{ ++#ifndef MR_NO_RAND ++ int i; ++#endif ++ ++ mr_small b,nw; ++#ifdef MR_FP ++ mr_small dres; ++#endif ++ ++ if (mr_mip==NULL) return NULL; ++ ++#ifndef MR_STRIPPED_DOWN ++ mr_mip->depth=0; ++ mr_mip->trace[0]=0; ++ mr_mip->depth++; ++ mr_mip->trace[mr_mip->depth]=29; ++#endif ++ /* digest hardware configuration */ ++ ++#ifdef MR_NO_STANDARD_IO ++ mr_mip->ERCON=TRUE; ++#else ++ mr_mip->ERCON=FALSE; ++#endif ++#ifndef MR_STATIC ++ mr_mip->logN=0; ++ mr_mip->degree=0; ++ mr_mip->chin.NP=0; ++#endif ++ ++ ++ mr_mip->user=NULL; ++ mr_mip->same=FALSE; ++ mr_mip->first_one=FALSE; ++ mr_mip->debug=FALSE; ++ mr_mip->AA=0; ++#ifndef MR_AFFINE_ONLY ++ mr_mip->coord=MR_NOTSET; ++#endif ++ ++#ifdef MR_NOFULLWIDTH ++ if (nb==0) ++ { ++ mr_berror(_MIPP_ MR_ERR_BAD_BASE); ++ MR_OUT ++ return mr_mip; ++ } ++#endif ++ ++#ifndef MR_FP ++#ifdef mr_dltype ++#ifndef MR_NOFULLWIDTH ++ if (sizeof(mr_dltype)<2*sizeof(mr_utype)) ++ { /* double length type, isn't */ ++ mr_berror(_MIPP_ MR_ERR_NOT_DOUBLE_LEN); ++ MR_OUT ++ return mr_mip; ++ } ++#endif ++#endif ++#endif ++ ++ if (nb==1 || nb>MAXBASE) ++ { ++ mr_berror(_MIPP_ MR_ERR_BAD_BASE); ++ MR_OUT ++ return mr_mip; ++ } ++ ++#ifdef MR_FP_ROUNDING ++ if (mr_setbase(_MIPP_ nb)==0) ++ { /* unable in fact to control FP rounding */ ++ mr_berror(_MIPP_ MR_ERR_NO_ROUNDING); ++ MR_OUT ++ return mr_mip; ++ } ++#else ++ mr_setbase(_MIPP_ nb); ++#endif ++ ++ b=mr_mip->base; ++ ++#ifdef MR_SIMPLE_BASE ++ if (b!=0) ++ { ++ mr_berror(_MIPP_ MR_ERR_BAD_BASE); ++ MR_OUT ++ return mr_mip; ++ } ++#endif ++ ++ mr_mip->lg2b=0; ++ mr_mip->base2=1; ++#ifndef MR_SIMPLE_BASE ++ if (b==0) ++ { ++#endif ++ mr_mip->lg2b=MIRACL; ++ mr_mip->base2=0; ++#ifndef MR_SIMPLE_BASE ++ } ++ else while (b>1) ++ { ++ b=MR_DIV(b,2); ++ mr_mip->lg2b++; ++ mr_mip->base2*=2; ++ } ++#endif ++ ++#ifdef MR_ALWAYS_BINARY ++ if (mr_mip->base!=mr_mip->base2) ++ { ++ mr_berror(_MIPP_ MR_ERR_NOT_BINARY); ++ MR_OUT ++ return mr_mip; ++ } ++#endif ++ ++/* calculate total space for bigs */ ++/* ++ ++ big -> |int len|small *ptr| alignment space | size in words +1| alignment up to multiple of 4 | ++ ++ ++*/ ++ if (nd>0) nw=MR_ROUNDUP(nd,mr_mip->pack); ++ else nw=MR_ROUNDUP(8*(-nd),mr_mip->lg2b); ++ ++ if (nw<1) nw=1; ++ mr_mip->nib=(int)(nw+1); /* add one extra word for small overflows */ ++ ++#ifdef MR_STATIC ++ if (nw>MR_STATIC) ++ { ++ mr_berror(_MIPP_ MR_ERR_TOO_BIG); ++ MR_OUT ++ return mr_mip; ++ } ++#endif ++ ++ /* mr_mip->nib=(int)(nw+1); add one extra word for small overflows */ ++ ++#ifdef MR_FLASH ++ mr_mip->workprec=mr_mip->nib; ++ mr_mip->stprec=mr_mip->nib; ++ while (mr_mip->stprec>2 && mr_mip->stprec>MR_FLASH/mr_mip->lg2b) ++ mr_mip->stprec=(mr_mip->stprec+1)/2; ++ if (mr_mip->stprec<2) mr_mip->stprec=2; ++ ++#endif ++ ++#ifndef MR_DOUBLE_BIG ++ mr_mip->check=ON; ++#else ++ mr_mip->check=OFF; ++#endif ++ ++#ifndef MR_SIMPLE_BASE ++#ifndef MR_SIMPLE_IO ++ mr_mip->IOBASE=10; /* defaults */ ++#endif ++#endif ++ mr_mip->ERNUM=0; ++ ++ mr_mip->NTRY=6; ++ mr_mip->MONTY=ON; ++#ifdef MR_FLASH ++ mr_mip->EXACT=TRUE; ++ mr_mip->RPOINT=OFF; ++#endif ++#ifndef MR_STRIPPED_DOWN ++ mr_mip->TRACER=OFF; ++#endif ++ ++#ifndef MR_SIMPLE_IO ++ mr_mip->INPLEN=0; ++ mr_mip->IOBSIZ=MR_DEFAULT_BUFFER_SIZE; ++#endif ++ ++#ifdef MR_STATIC ++ mr_mip->PRIMES=mr_small_primes; ++#else ++ mr_mip->PRIMES=NULL; ++#ifndef MR_SIMPLE_IO ++ mr_mip->IOBUFF=(char *)mr_alloc(_MIPP_ MR_DEFAULT_BUFFER_SIZE+1,1); ++#endif ++#endif ++#ifndef MR_SIMPLE_IO ++ mr_mip->IOBUFF[0]='\0'; ++#endif ++ mr_mip->qnr=0; ++ mr_mip->cnr=0; ++ mr_mip->TWIST=0; ++ mr_mip->pmod8=0; ++ mr_mip->pmod9=0; ++ ++/* quick start for rng. irand(.) should be called first before serious use.. */ ++ ++#ifndef MR_NO_RAND ++ mr_mip->ira[0]=0x55555555; ++ mr_mip->ira[1]=0x12345678; ++ ++ for (i=2;iira[i]=mr_mip->ira[i-1]+mr_mip->ira[i-2]+0x1379BDF1; ++ mr_mip->rndptr=NK; ++ mr_mip->borrow=0; ++#endif ++ ++ mr_mip->nib=2*mr_mip->nib+1; ++#ifdef MR_FLASH ++ if (mr_mip->nib!=(mr_mip->nib&(MR_MSK))) ++#else ++ if (mr_mip->nib!=(int)(mr_mip->nib&(MR_OBITS))) ++#endif ++ { ++ mr_berror(_MIPP_ MR_ERR_TOO_BIG); ++ mr_mip->nib=(mr_mip->nib-1)/2; ++ MR_OUT ++ return mr_mip; ++ } ++#ifndef MR_STATIC ++ mr_mip->workspace=(char *)memalloc(_MIPP_ MR_SPACES); /* grab workspace */ ++#else ++ sbi_memset(mr_mip->workspace,0,MR_BIG_RESERVE(MR_SPACES)); ++#endif ++ ++ mr_mip->M=0; ++ mr_mip->fin=FALSE; ++ mr_mip->fout=FALSE; ++ mr_mip->active=ON; ++ ++ mr_mip->nib=(mr_mip->nib-1)/2; ++ ++/* allocate memory for workspace variables */ ++ ++#ifndef MR_DOUBLE_BIG ++ ++ mr_mip->w0=mirvar_mem(_MIPP_ mr_mip->workspace,0); /* double length */ ++ mr_mip->w1=mirvar_mem(_MIPP_ mr_mip->workspace,2); ++ mr_mip->w2=mirvar_mem(_MIPP_ mr_mip->workspace,3); ++ mr_mip->w3=mirvar_mem(_MIPP_ mr_mip->workspace,4); ++ mr_mip->w4=mirvar_mem(_MIPP_ mr_mip->workspace,5); ++ mr_mip->w5=mirvar_mem(_MIPP_ mr_mip->workspace,6); /* double length */ ++ mr_mip->w6=mirvar_mem(_MIPP_ mr_mip->workspace,8); /* double length */ ++ mr_mip->w7=mirvar_mem(_MIPP_ mr_mip->workspace,10); /* double length */ ++ mr_mip->w8=mirvar_mem(_MIPP_ mr_mip->workspace,12); ++ mr_mip->w9=mirvar_mem(_MIPP_ mr_mip->workspace,13); ++ mr_mip->w10=mirvar_mem(_MIPP_ mr_mip->workspace,14); ++ mr_mip->w11=mirvar_mem(_MIPP_ mr_mip->workspace,15); ++ mr_mip->w12=mirvar_mem(_MIPP_ mr_mip->workspace,16); ++ mr_mip->w13=mirvar_mem(_MIPP_ mr_mip->workspace,17); ++ mr_mip->w14=mirvar_mem(_MIPP_ mr_mip->workspace,18); ++ mr_mip->w15=mirvar_mem(_MIPP_ mr_mip->workspace,19); ++ mr_mip->sru=mirvar_mem(_MIPP_ mr_mip->workspace,20); ++ mr_mip->modulus=mirvar_mem(_MIPP_ mr_mip->workspace,21); ++ mr_mip->pR=mirvar_mem(_MIPP_ mr_mip->workspace,22); /* double length */ ++ mr_mip->A=mirvar_mem(_MIPP_ mr_mip->workspace,24); ++ mr_mip->B=mirvar_mem(_MIPP_ mr_mip->workspace,25); ++ mr_mip->one=mirvar_mem(_MIPP_ mr_mip->workspace,26); ++#ifdef MR_KCM ++ mr_mip->big_ndash=mirvar_mem(_MIPP_ mr_mip->workspace,27); ++ mr_mip->ws=mirvar_mem(_MIPP_ mr_mip->workspace,28); ++ mr_mip->wt=mirvar_mem(_MIPP_ mr_mip->workspace,29); /* double length */ ++#endif ++#ifdef MR_FLASH ++#ifdef MR_KCM ++ mr_mip->pi=mirvar_mem(_MIPP_ mr_mip->workspace,31); ++#else ++ mr_mip->pi=mirvar_mem(_MIPP_ mr_mip->workspace,27); ++#endif ++#endif ++ ++#else ++/* w0-w7 are double normal length */ ++ mr_mip->w0=mirvar_mem(_MIPP_ mr_mip->workspace,0); /* quad length */ ++ mr_mip->w1=mirvar_mem(_MIPP_ mr_mip->workspace,4); /* double length */ ++ mr_mip->w2=mirvar_mem(_MIPP_ mr_mip->workspace,6); ++ mr_mip->w3=mirvar_mem(_MIPP_ mr_mip->workspace,8); ++ mr_mip->w4=mirvar_mem(_MIPP_ mr_mip->workspace,10); ++ mr_mip->w5=mirvar_mem(_MIPP_ mr_mip->workspace,12); /* quad length */ ++ mr_mip->w6=mirvar_mem(_MIPP_ mr_mip->workspace,16); /* quad length */ ++ mr_mip->w7=mirvar_mem(_MIPP_ mr_mip->workspace,20); /* quad length */ ++ mr_mip->w8=mirvar_mem(_MIPP_ mr_mip->workspace,24); ++ ++ mr_mip->w9=mirvar_mem(_MIPP_ mr_mip->workspace,25); ++ mr_mip->w10=mirvar_mem(_MIPP_ mr_mip->workspace,26); ++ mr_mip->w11=mirvar_mem(_MIPP_ mr_mip->workspace,27); ++ mr_mip->w12=mirvar_mem(_MIPP_ mr_mip->workspace,28); ++ mr_mip->w13=mirvar_mem(_MIPP_ mr_mip->workspace,29); ++ mr_mip->w14=mirvar_mem(_MIPP_ mr_mip->workspace,30); ++ mr_mip->w15=mirvar_mem(_MIPP_ mr_mip->workspace,31); ++ mr_mip->sru=mirvar_mem(_MIPP_ mr_mip->workspace,32); ++ mr_mip->modulus=mirvar_mem(_MIPP_ mr_mip->workspace,33); ++ mr_mip->pR=mirvar_mem(_MIPP_ mr_mip->workspace,34); /* double length */ ++ mr_mip->A=mirvar_mem(_MIPP_ mr_mip->workspace,36); ++ mr_mip->B=mirvar_mem(_MIPP_ mr_mip->workspace,37); ++ mr_mip->one=mirvar_mem(_MIPP_ mr_mip->workspace,38); ++#ifdef MR_KCM ++ mr_mip->big_ndash=mirvar_mem(_MIPP_ mr_mip->workspace,39); ++ mr_mip->ws=mirvar_mem(_MIPP_ mr_mip->workspace,40); ++ mr_mip->wt=mirvar_mem(_MIPP_ mr_mip->workspace,41); /* double length */ ++#endif ++#ifdef MR_FLASH ++#ifdef MR_KCM ++ mr_mip->pi=mirvar_mem(_MIPP_ mr_mip->workspace,43); ++#else ++ mr_mip->pi=mirvar_mem(_MIPP_ mr_mip->workspace,39); ++#endif ++#endif ++ ++#endif ++ MR_OUT ++ return mr_mip; ++} ++ ++#ifndef MR_STATIC ++ ++/* allocate space for a number of bigs from the heap */ ++ ++void *memalloc(_MIPD_ int num) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ return mr_alloc(_MIPP_ mr_big_reserve(num,mr_mip->nib-1),1); ++} ++ ++#endif ++ ++void memkill(_MIPD_ char *mem,int len) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mem==NULL) return; ++ sbi_memset(mem,0,mr_big_reserve(len,mr_mip->nib-1)); ++#ifndef MR_STATIC ++ mr_free(mem); ++#endif ++} ++ ++#ifndef MR_STATIC ++ ++void mirkill(big x) ++{ /* kill a big/flash variable, that is set it to zero ++ and free its memory */ ++ if (x==NULL) return; ++ zero(x); ++ mr_free(x); ++} ++ ++#endif ++ ++void mirexit(_MIPDO_ ) ++{ /* clean up after miracl */ ++ ++ int i; ++#ifdef MR_WINDOWS_MT ++ miracl *mr_mip=get_mip(); ++#endif ++#ifdef MR_UNIX_MT ++ miracl *mr_mip=get_mip(); ++#endif ++#ifdef MR_OPENMP_MT ++ miracl *mr_mip=get_mip(); ++#endif ++ mr_mip->ERCON=FALSE; ++ mr_mip->active=OFF; ++ memkill(_MIPP_ mr_mip->workspace,MR_SPACES); ++#ifndef MR_NO_RAND ++ for (i=0;iira[i]=0L; ++#endif ++#ifndef MR_STATIC ++#ifndef MR_SIMPLE_IO ++ set_io_buffer_size(_MIPP_ 0); ++#endif ++ if (mr_mip->PRIMES!=NULL) mr_free(mr_mip->PRIMES); ++#else ++#ifndef MR_SIMPLE_IO ++ for (i=0;iIOBUFF[i]=0; ++#endif ++#endif ++ ++#ifndef MR_STATIC ++ mr_free(mr_mip); ++#ifdef MR_WINDOWS_MT ++ TlsSetValue(mr_key, NULL); /* Thank you Thales */ ++#endif ++#endif ++ ++#ifndef MR_GENERIC_MT ++#ifndef MR_WINDOWS_MT ++#ifndef MR_UNIX_MT ++#ifndef MR_STATIC ++ mr_mip=NULL; ++#endif ++#endif ++#endif ++#endif ++ ++#ifdef MR_OPENMP_MT ++ mr_mip=NULL; ++#endif ++ ++} ++ ++int exsign(flash x) ++{ /* extract sign of big/flash number */ ++ if ((x->len&(MR_MSBIT))==0) return PLUS; ++ else return MINUS; ++} ++ ++void insign(int s,flash x) ++{ /* assert sign of big/flash number */ ++ if (x->len==0) return; ++ if (s<0) x->len|=MR_MSBIT; ++ else x->len&=MR_OBITS; ++} ++ ++void mr_lzero(big x) ++{ /* strip leading zeros from big number */ ++ mr_lentype s; ++ int m; ++ s=(x->len&(MR_MSBIT)); ++ m=(int)(x->len&(MR_OBITS)); ++ while (m>0 && x->w[m-1]==0) ++ m--; ++ x->len=m; ++ if (m>0) x->len|=s; ++} ++ ++#ifndef MR_SIMPLE_IO ++ ++int getdig(_MIPD_ big x,int i) ++{ /* extract a packed digit */ ++ int k; ++ mr_small n; ++#ifdef MR_FP ++ mr_small dres; ++#endif ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ i--; ++ n=x->w[i/mr_mip->pack]; ++ ++ if (mr_mip->pack==1) return (int)n; ++ k=i%mr_mip->pack; ++ for (i=1;i<=k;i++) ++ n=MR_DIV(n,mr_mip->apbase); ++ return (int)MR_REMAIN(n,mr_mip->apbase); ++} ++ ++int numdig(_MIPD_ big x) ++{ /* returns number of digits in x */ ++ int nd; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ if (x->len==0) return 0; ++ ++ nd=(int)(x->len&(MR_OBITS))*mr_mip->pack; ++ while (getdig(_MIPP_ x,nd)==0) ++ nd--; ++ return nd; ++} ++ ++void putdig(_MIPD_ int n,big x,int i) ++{ /* insert a digit into a packed word */ ++ int j,k,lx; ++ mr_small m,p; ++ mr_lentype s; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(26) ++ ++ s=(x->len&(MR_MSBIT)); ++ lx=(int)(x->len&(MR_OBITS)); ++ m=getdig(_MIPP_ x,i); ++ p=n; ++ i--; ++ j=i/mr_mip->pack; ++ k=i%mr_mip->pack; ++ for (i=1;i<=k;i++) ++ { ++ m*=mr_mip->apbase; ++ p*=mr_mip->apbase; ++ } ++ if (j>=mr_mip->nib && (mr_mip->check || j>=2*mr_mip->nib)) ++ { ++ mr_berror(_MIPP_ MR_ERR_OVERFLOW); ++ MR_OUT ++ return; ++ } ++ ++ x->w[j]=(x->w[j]-m)+p; ++ if (j>=lx) x->len=((j+1)|s); ++ mr_lzero(x); ++ MR_OUT ++} ++ ++#endif ++ ++#ifndef MR_FP ++ ++void mr_and(big x,big y,big z) ++{ /* z= bitwise logical AND of x and y */ ++ int i,nx,ny,nz,nr; ++ if (x==y) ++ { ++ copy(x,z); ++ return; ++ } ++ ++#ifdef MR_FLASH ++ nx=mr_lent(x); ++ ny=mr_lent(y); ++ nz=mr_lent(z); ++#else ++ ny=(y->len&(MR_OBITS)); ++ nx=(x->len&(MR_OBITS)); ++ nz=(z->len&(MR_OBITS)); ++#endif ++ if (nyw[i]=x->w[i]&y->w[i]; ++ for (i=nr;iw[i]=0; ++ z->len=nr; ++ mr_lzero(z); ++} ++ ++void mr_xor(big x,big y,big z) ++{ ++ int i,nx,ny,nz,nr; ++ if (x==y) ++ { ++ copy(x,z); ++ return; ++ } ++ ++#ifdef MR_FLASH ++ nx=mr_lent(x); ++ ny=mr_lent(y); ++ nz=mr_lent(z); ++#else ++ ny=(y->len&(MR_OBITS)); ++ nx=(x->len&(MR_OBITS)); ++ nz=(z->len&(MR_OBITS)); ++#endif ++ if (nyw[i]=x->w[i]^y->w[i]; ++ for (i=nr;iw[i]=0; ++ z->len=nr; ++ mr_lzero(z); ++} ++ ++#endif ++ ++void copy(flash x,flash y) ++{ /* copy x to y: y=x */ ++ int i,nx,ny; ++ mr_small *gx,*gy; ++ if (x==y || y==NULL) return; ++ ++ if (x==NULL) ++ { ++ zero(y); ++ return; ++ } ++ ++#ifdef MR_FLASH ++ ny=mr_lent(y); ++ nx=mr_lent(x); ++#else ++ ny=(y->len&(MR_OBITS)); ++ nx=(x->len&(MR_OBITS)); ++#endif ++ ++ gx=x->w; ++ gy=y->w; ++ ++ for (i=nx;ilen=x->len; ++ ++} ++ ++void negify(flash x,flash y) ++{ /* negate a big/flash variable: y=-x */ ++ copy(x,y); ++ if (y->len!=0) y->len^=MR_MSBIT; ++} ++ ++void absol(flash x,flash y) ++{ /* y=abs(x) */ ++ copy(x,y); ++ y->len&=MR_OBITS; ++} ++ ++BOOL mr_notint(flash x) ++{ /* returns TRUE if x is Flash */ ++#ifdef MR_FLASH ++ if ((((x->len&(MR_OBITS))>>(MR_BTS))&(MR_MSK))!=0) return TRUE; ++#endif ++ return FALSE; ++} ++ ++void mr_shift(_MIPD_ big x,int n,big w) ++{ /* set w=x.(mr_base^n) by shifting */ ++ mr_lentype s; ++ int i,bl; ++ mr_small *gw=w->w; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ copy(x,w); ++ if (w->len==0 || n==0) return; ++ MR_IN(33) ++ ++ if (mr_notint(w)) mr_berror(_MIPP_ MR_ERR_INT_OP); ++ s=(w->len&(MR_MSBIT)); ++ bl=(int)(w->len&(MR_OBITS))+n; ++ if (bl<=0) ++ { ++ zero(w); ++ MR_OUT ++ return; ++ } ++ if (bl>mr_mip->nib && mr_mip->check) mr_berror(_MIPP_ MR_ERR_OVERFLOW); ++ if (mr_mip->ERNUM) ++ { ++ MR_OUT ++ return; ++ } ++ if (n>0) ++ { ++ for (i=bl-1;i>=n;i--) ++ gw[i]=gw[i-n]; ++ for (i=0;ilen=(bl|s); ++ MR_OUT ++} ++ ++int size(big x) ++{ /* get size of big number; convert to * ++ * integer - if possible */ ++ int n,m; ++ mr_lentype s; ++ if (x==NULL) return 0; ++ s=(x->len&MR_MSBIT); ++ m=(int)(x->len&MR_OBITS); ++ if (m==0) return 0; ++ if (m==1 && x->w[0]<(mr_small)MR_TOOBIG) n=(int)x->w[0]; ++ else n=MR_TOOBIG; ++ if (s==MR_MSBIT) return (-n); ++ return n; ++} ++ ++int mr_compare(big x,big y) ++{ /* compare x and y: =1 if x>y =-1 if xlen&MR_MSBIT); ++ sy=(y->len&MR_MSBIT); ++ if (sx==0) sig=PLUS; ++ else sig=MINUS; ++ if (sx!=sy) return sig; ++ m=(int)(x->len&MR_OBITS); ++ n=(int)(y->len&MR_OBITS); ++ if (m>n) return sig; ++ if (m0) ++ { /* check digit by digit */ ++ m--; ++ if (x->w[m]>y->w[m]) return sig; ++ if (x->w[m]w[m]) return -sig; ++ } ++ return 0; ++} ++ ++#ifdef MR_FLASH ++ ++void fpack(_MIPD_ big n,big d,flash x) ++{ /* create floating-slash number x=n/d from * ++ * big integer numerator and denominator */ ++ mr_lentype s; ++ int i,ld,ln; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(31) ++ ++ ld=(int)(d->len&MR_OBITS); ++ if (ld==0) mr_berror(_MIPP_ MR_ERR_FLASH_OVERFLOW); ++ if (ld==1 && d->w[0]==1) ld=0; ++ if (x==d) mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); ++ if (mr_notint(n) || mr_notint(d)) mr_berror(_MIPP_ MR_ERR_INT_OP); ++ s=(n->len&MR_MSBIT); ++ ln=(int)(n->len&MR_OBITS); ++ if (ln==1 && n->w[0]==1) ln=0; ++ if ((ld+ln>mr_mip->nib) && (mr_mip->check || ld+ln>2*mr_mip->nib)) ++ mr_berror(_MIPP_ MR_ERR_FLASH_OVERFLOW); ++ if (mr_mip->ERNUM) ++ { ++ MR_OUT ++ return; ++ } ++ copy(n,x); ++ if (n->len==0) ++ { ++ MR_OUT ++ return; ++ } ++ s^=(d->len&MR_MSBIT); ++ if (ld==0) ++ { ++ if (x->len!=0) x->len|=s; ++ MR_OUT ++ return; ++ } ++ for (i=0;iw[ln+i]=d->w[i]; ++ x->len=(s|(ln+((mr_lentype)ld<ERNUM) return; ++ if (mr_notint(x)) ++ { ++ s=(x->len&MR_MSBIT); ++ ly=(x->len&MR_OBITS); ++ ln=(int)(ly&MR_MSK); ++ if (ln==0) ++ { ++ if(s==MR_MSBIT) convert(_MIPP_ (-1),y); ++ else convert(_MIPP_ 1,y); ++ return; ++ } ++ ld=(int)((ly>>MR_BTS)&MR_MSK); ++ if (x!=y) ++ { ++ for (i=0;iw[i]=x->w[i]; ++ for (i=ln;iw[i]=0; ++ } ++ else for (i=0;iw[ln+i]=0; ++ y->len=(ln|s); ++ } ++ else copy(x,y); ++} ++ ++void denom(_MIPD_ flash x,big y) ++{ /* extract denominator of x */ ++ int i,ln,ld; ++ mr_lentype ly; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ if (!mr_notint(x)) ++ { ++ convert(_MIPP_ 1,y); ++ return; ++ } ++ ly=(x->len&MR_OBITS); ++ ln=(int)(ly&MR_MSK); ++ ld=(int)((ly>>MR_BTS)&MR_MSK); ++ for (i=0;iw[i]=x->w[ln+i]; ++ if (x==y) for (i=0;iw[ld+i]=0; ++ else for (i=ld;iw[i]=0; ++ y->len=ld; ++} ++ ++#endif ++ ++unsigned int igcd(unsigned int x,unsigned int y) ++{ /* integer GCD, returns GCD of x and y */ ++ unsigned int r; ++ if (y==0) return x; ++ while ((r=x%y)!=0) ++ x=y,y=r; ++ return y; ++} ++ ++unsigned long lgcd(unsigned long x,unsigned long y) ++{ /* long GCD, returns GCD of x and y */ ++ unsigned long r; ++ if (y==0) return x; ++ while ((r=x%y)!=0) ++ x=y,y=r; ++ return y; ++} ++ ++unsigned int isqrt(unsigned int num,unsigned int guess) ++{ /* square root of an integer */ ++ unsigned int sqr; ++ unsigned int oldguess=guess; ++ if (num==0) return 0; ++ if (num<4) return 1; ++ ++ for (;;) ++ { /* Newtons iteration */ ++ /* sqr=guess+(((num/guess)-guess)/2); */ ++ sqr=((num/guess)+guess)/2; ++ if (sqr==guess || sqr==oldguess) ++ { ++ if (sqr*sqr>num) sqr--; ++ return sqr; ++ } ++ oldguess=guess; ++ guess=sqr; ++ } ++} ++ ++unsigned long mr_lsqrt(unsigned long num,unsigned long guess) ++{ /* square root of a long */ ++ unsigned long sqr; ++ unsigned long oldguess=guess; ++ if (num==0) return 0; ++ if (num<4) return 1; ++ ++ for (;;) ++ { /* Newtons iteration */ ++ /* sqr=guess+(((num/guess)-guess)/2); */ ++ sqr=((num/guess)+guess)/2; ++ if (sqr==guess || sqr==oldguess) ++ { ++ if (sqr*sqr>num) sqr--; ++ return sqr; ++ } ++ oldguess=guess; ++ guess=sqr; ++ } ++} ++ ++mr_small sgcd(mr_small x,mr_small y) ++{ /* integer GCD, returns GCD of x and y */ ++ mr_small r; ++#ifdef MR_FP ++ mr_small dres; ++#endif ++ if (y==(mr_small)0) return x; ++ while ((r=MR_REMAIN(x,y))!=(mr_small)0) ++ x=y,y=r; ++ return y; ++} ++ ++/* routines to support sliding-windows exponentiation * ++ * in various contexts */ ++ ++int mr_testbit(_MIPD_ big x,int n) ++{ /* return value of n-th bit of big */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++#ifdef MR_FP ++ mr_small m,a,dres; ++ m=mr_shiftbits((mr_small)1,n%mr_mip->lg2b); ++ ++ a=x->w[n/mr_mip->lg2b]; ++ ++ a=MR_DIV(a,m); ++ ++ if ((MR_DIV(a,2.0)*2.0) != a) return 1; ++#else ++ if ((x->w[n/mr_mip->lg2b] & ((mr_small)1<<(n%mr_mip->lg2b))) >0) return 1; ++#endif ++ return 0; ++} ++ ++void mr_addbit(_MIPD_ big x,int n) ++{ /* add 2^n to positive x - where you know that bit is zero. Use with care! */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ mr_lentype m=n/mr_mip->lg2b; ++ x->w[m]+=mr_shiftbits((mr_small)1,n%mr_mip->lg2b); ++ if (x->lenlen=m+1; ++} ++ ++int recode(_MIPD_ big e,int t,int w,int i) ++{ /* recode exponent for Comb method */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ int j,r; ++ r=0; ++ for (j=w-1;j>=0;j--) ++ { ++ r<<=1; ++ r|=mr_testbit(_MIPP_ e,i+j*t); ++ } ++ return r; ++} ++ ++int mr_window(_MIPD_ big x,int i,int *nbs,int * nzs,int window_size) ++{ /* returns sliding window value, max. of 5 bits, * ++ * (Note from version 5.23 this can be changed by * ++ * setting parameter window_size. This can be * ++ * a useful space-saver) starting at i-th bit of big x. * ++ * nbs is number of bits processed, nzs is the number of * ++ * additional trailing zeros detected. Returns valid bit * ++ * pattern 1x..x1 with no two adjacent 0's. So 10101 * ++ * will return 21 with nbs=5, nzs=0. 11001 will return 3,* ++ * with nbs=2, nzs=2, having stopped after the first 11..*/ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ int j,r,w; ++ w=window_size; ++ ++/* check for leading 0 bit */ ++ ++ *nbs=1; ++ *nzs=0; ++ if (!mr_testbit(_MIPP_ x,i)) return 0; ++ ++/* adjust window size if not enough bits left */ ++ ++ if (i-w+1<0) w=i+1; ++ ++ r=1; ++ for (j=i-1;j>i-w;j--) ++ { /* accumulate bits. Abort if two 0's in a row */ ++ (*nbs)++; ++ r*=2; ++ if (mr_testbit(_MIPP_ x,j)) r+=1; ++ if (r%4==0) ++ { /* oops - too many zeros - shorten window */ ++ r/=4; ++ *nbs-=2; ++ *nzs=2; ++ break; ++ } ++ } ++ if (r%2==0) ++ { /* remove trailing 0 */ ++ r/=2; ++ *nzs=1; ++ (*nbs)--; ++ } ++ return r; ++} ++ ++int mr_window2(_MIPD_ big x,big y,int i,int *nbs,int *nzs) ++{ /* two bit window for double exponentiation */ ++ int r,w; ++ BOOL a,b,c,d; ++ w=2; ++ *nbs=1; ++ *nzs=0; ++ ++/* check for two leading 0's */ ++ a=mr_testbit(_MIPP_ x,i); b=mr_testbit(_MIPP_ y,i); ++ ++ if (!a && !b) return 0; ++ if (i<1) w=1; ++ ++ if (a) ++ { ++ if (b) r=3; ++ else r=2; ++ } ++ else r=1; ++ if (w==1) return r; ++ ++ c=mr_testbit(_MIPP_ x,i-1); d=mr_testbit(_MIPP_ y,i-1); ++ ++ if (!c && !d) ++ { ++ *nzs=1; ++ return r; ++ } ++ ++ *nbs=2; ++ r*=4; ++ if (c) ++ { ++ if (d) r+=3; ++ else r+=2; ++ } ++ else r+=1; ++ return r; ++} ++ ++int mr_naf_window(_MIPD_ big x,big x3,int i,int *nbs,int *nzs,int store) ++{ /* returns sliding window value, using fractional windows * ++ * where "store" precomputed values are precalulated and * ++ * stored. Scanning starts at the i-th bit of x. nbs is * ++ * the number of bits processed. nzs is number of * ++ * additional trailing zeros detected. x and x3 (which is * ++ * 3*x) are combined to produce the NAF (non-adjacent * ++ * form). So if x=11011(27) and x3 is 1010001, the LSB is * ++ * ignored and the value 100T0T (32-4-1=27) processed, * ++ * where T is -1. Note x.P = (3x-x)/2.P. This value will * ++ * return +7, with nbs=4 and nzs=1, having stopped after * ++ * the first 4 bits. If it goes too far, it must backtrack * ++ * Note in an NAF non-zero elements are never side by side, * ++ * so 10T10T won't happen. NOTE: return value n zero or * ++ * odd, -21 <= n <= +21 */ ++ ++ int nb,j,r,abs_r,biggest; ++ ++ /* get first bit */ ++ nb=mr_testbit(_MIPP_ x3,i)-mr_testbit(_MIPP_ x,i); ++ ++ *nbs=1; ++ *nzs=0; ++ if (nb==0) return 0; ++ if (i==0) return nb; ++ ++ biggest=2*store-1; ++ ++ if (nb>0) r=1; ++ else r=(-1); ++ ++ for (j=i-1;j>0;j--) ++ { ++ (*nbs)++; ++ r*=2; ++ nb=mr_testbit(_MIPP_ x3,j)-mr_testbit(_MIPP_ x,j); ++ if (nb>0) r+=1; ++ if (nb<0) r-=1; ++ abs_r = r > 0 ? r : -r; ++ if (abs_r>biggest) break; ++ } ++ ++ if (r%2!=0 && j!=0) ++ { /* backtrack */ ++ if (nb>0) r=(r-1)/2; ++ if (nb<0) r=(r+1)/2; ++ (*nbs)--; ++ } ++ ++ while (r%2==0) ++ { /* remove trailing zeros */ ++ r/=2; ++ (*nzs)++; ++ (*nbs)--; ++ } ++ return r; ++} ++ ++/* Some general purpose elliptic curve stuff */ ++ ++BOOL point_at_infinity(epoint *p) ++{ ++ if (p==NULL) return FALSE; ++ if (p->marker==MR_EPOINT_INFINITY) return TRUE; ++ return FALSE; ++} ++ ++#ifndef MR_STATIC ++ ++epoint* epoint_init(_MIPDO_ ) ++{ /* initialise epoint to general point at infinity. */ ++ epoint *p; ++ char *ptr; ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return NULL; ++ ++ MR_IN(96) ++ ++/* Create space for whole structure in one heap access */ ++ ++ p=(epoint *)mr_alloc(_MIPP_ mr_esize(mr_mip->nib-1),1); ++ ++ ptr=(char *)p+sizeof(epoint); ++ p->X=mirvar_mem(_MIPP_ ptr,0); ++ p->Y=mirvar_mem(_MIPP_ ptr,1); ++#ifndef MR_AFFINE_ONLY ++ p->Z=mirvar_mem(_MIPP_ ptr,2); ++#endif ++ p->marker=MR_EPOINT_INFINITY; ++ ++ MR_OUT ++ ++ return p; ++} ++ ++#endif ++ ++epoint* epoint_init_mem_variable(_MIPD_ char *mem,int index,int sz) ++{ ++ epoint *p; ++ char *ptr; ++ int offset,r; ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ offset=0; ++ r=(unsigned long)mem%MR_SL; ++ if (r>0) offset=MR_SL-r; ++ ++#ifndef MR_AFFINE_ONLY ++ if (mr_mip->coord==MR_AFFINE) ++ p=(epoint *)&mem[offset+index*mr_esize_a(sz)]; ++ else ++#endif ++ p=(epoint *)&mem[offset+index*mr_esize(sz)]; ++ ptr=(char *)p+sizeof(epoint); ++ p->X=mirvar_mem_variable(ptr,0,sz); ++ p->Y=mirvar_mem_variable(ptr,1,sz); ++#ifndef MR_AFFINE_ONLY ++ if (mr_mip->coord!=MR_AFFINE) p->Z=mirvar_mem_variable(ptr,2,sz); ++#endif ++ p->marker=MR_EPOINT_INFINITY; ++ return p; ++} ++ ++epoint* epoint_init_mem(_MIPD_ char *mem,int index) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return NULL; ++ ++ return epoint_init_mem_variable(_MIPP_ mem,index,mr_mip->nib-1); ++} ++ ++#ifndef MR_STATIC ++ ++/* allocate space for a number of epoints from the heap */ ++ ++void *ecp_memalloc(_MIPD_ int num) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++#ifndef MR_AFFINE_ONLY ++ if (mr_mip->coord==MR_AFFINE) ++ return mr_alloc(_MIPP_ mr_ecp_reserve_a(num,mr_mip->nib-1),1); ++ else ++#endif ++ return mr_alloc(_MIPP_ mr_ecp_reserve(num,mr_mip->nib-1),1); ++} ++ ++#endif ++ ++void ecp_memkill(_MIPD_ char *mem,int num) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ if (mem==NULL) return; ++ ++#ifndef MR_AFFINE_ONLY ++ if (mr_mip->coord==MR_AFFINE) ++ sbi_memset(mem,0,mr_ecp_reserve_a(num,mr_mip->nib-1)); ++ else ++#endif ++ sbi_memset(mem,0,mr_ecp_reserve(num,mr_mip->nib-1)); ++ ++ ++#ifndef MR_STATIC ++ mr_free(mem); ++#endif ++} ++ ++#ifndef MR_STATIC ++ ++void epoint_free(epoint *p) ++{ /* clean up point */ ++ ++ if (p==NULL) return; ++ zero(p->X); ++ zero(p->Y); ++#ifndef MR_AFFINE_ONLY ++ if (p->marker==MR_EPOINT_GENERAL) zero(p->Z); ++#endif ++ mr_free(p); ++} ++ ++#endif +diff --git a/lib/sbi/sm/gm/miracl/mrcurve.c b/lib/sbi/sm/gm/miracl/mrcurve.c +new file mode 100644 +index 0000000..2f689eb +--- /dev/null ++++ b/lib/sbi/sm/gm/miracl/mrcurve.c +@@ -0,0 +1,2501 @@ ++ ++/*************************************************************************** ++ * ++Copyright 2013 CertiVox UK Ltd * ++ * ++This file is part of CertiVox MIRACL Crypto SDK. * ++ * ++The CertiVox MIRACL Crypto SDK provides developers with an * ++extensive and efficient set of cryptographic functions. * ++For further information about its features and functionalities please * ++refer to http://www.certivox.com * ++ * ++* The CertiVox MIRACL Crypto SDK is free software: you can * ++ redistribute it and/or modify it under the terms of the * ++ GNU Affero General Public License as published by the * ++ Free Software Foundation, either version 3 of the License, * ++ or (at your option) any later version. * ++ * ++* The CertiVox MIRACL Crypto SDK is distributed in the hope * ++ that it will be useful, but WITHOUT ANY WARRANTY; without even the * ++ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * ++ See the GNU Affero General Public License for more details. * ++ * ++* You should have received a copy of the GNU Affero General Public * ++ License along with CertiVox MIRACL Crypto SDK. * ++ If not, see . * ++ * ++You can be released from the requirements of the license by purchasing * ++a commercial license. Buying such a license is mandatory as soon as you * ++develop commercial activities involving the CertiVox MIRACL Crypto SDK * ++without disclosing the source code of your own applications, or shipping * ++the CertiVox MIRACL Crypto SDK with a closed source product. * ++ * ++***************************************************************************/ ++/* ++ * MIRACL elliptic curve routines ++ * mrcurve.c ++ * ++ * Assumes Weierstrass equation y^2 = x^3 + Ax + B ++ * See IEEE P1363 Draft Standard ++ * ++ * (See below for Edwards coordinates implementation) ++ * ++ * Uses Montgomery's representation internally ++ * ++ * Works particularly well with fixed length Comba multiplier ++ * e.g. #define MR_COMBA 5 for 5x32 = 160 bit modulus ++ * on 32-bit computer ++ * ++ */ ++ ++#include "sm/gm/miracl/miracl.h" ++ ++#ifdef MR_STATIC ++#include "sbi/sbi_string.h" ++#endif ++ ++#ifndef MR_EDWARDS ++ ++static void epoint_getrhs(_MIPD_ big x,big y) ++{ /* x and y must be different */ ++ ++ /* find x^3+Ax+B */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ nres_modmult(_MIPP_ x,x,y); ++ ++ nres_modmult(_MIPP_ y,x,y); ++ if (mr_abs(mr_mip->Asize)==MR_TOOBIG) ++ nres_modmult(_MIPP_ x,mr_mip->A,mr_mip->w1); ++ else ++ nres_premult(_MIPP_ x,mr_mip->Asize,mr_mip->w1); ++ nres_modadd(_MIPP_ y,mr_mip->w1,y); ++ if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) ++ nres_modadd(_MIPP_ y,mr_mip->B,y); ++ else ++ { ++ convert(_MIPP_ mr_mip->Bsize,mr_mip->w1); ++ nres(_MIPP_ mr_mip->w1,mr_mip->w1); ++ nres_modadd(_MIPP_ y,mr_mip->w1,y); ++ } ++} ++ ++#ifndef MR_NOSUPPORT_COMPRESSION ++ ++BOOL epoint_x(_MIPD_ big x) ++{ /* test if x is associated with a point on the * ++ * currently active curve */ ++ int j; ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return FALSE; ++ ++ MR_IN(147) ++ ++ if (x==NULL) return FALSE; ++ ++ nres(_MIPP_ x,mr_mip->w2); ++ epoint_getrhs(_MIPP_ mr_mip->w2,mr_mip->w3); ++ ++ if (size(mr_mip->w3)==0) ++ { ++ MR_OUT ++ return TRUE; ++ } ++ ++ redc(_MIPP_ mr_mip->w3,mr_mip->w4); ++ j=jack(_MIPP_ mr_mip->w4,mr_mip->modulus); ++ ++ MR_OUT ++ if (j==1) return TRUE; ++ return FALSE; ++} ++ ++#endif ++ ++BOOL epoint_set(_MIPD_ big x,big y,int cb,epoint *p) ++{ /* initialise a point on active ecurve * ++ * if x or y == NULL, set to point at infinity * ++ * if x==y, a y co-ordinate is calculated - if * ++ * possible - and cb suggests LSB 0/1 of y * ++ * (which "decompresses" y). Otherwise, check * ++ * validity of given (x,y) point, ignoring cb. * ++ * Returns TRUE for valid point, otherwise FALSE. */ ++ ++ BOOL valid; ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return FALSE; ++ ++ MR_IN(97) ++ ++ if (x==NULL || y==NULL) ++ { ++ copy(mr_mip->one,p->X); ++ copy(mr_mip->one,p->Y); ++ p->marker=MR_EPOINT_INFINITY; ++ MR_OUT ++ return TRUE; ++ } ++ ++/* find x^3+Ax+B */ ++ ++ nres(_MIPP_ x,p->X); ++ ++ epoint_getrhs(_MIPP_ p->X,mr_mip->w3); ++ ++ valid=FALSE; ++ ++ if (x!=y) ++ { /* compare with y^2 */ ++ nres(_MIPP_ y,p->Y); ++ nres_modmult(_MIPP_ p->Y,p->Y,mr_mip->w1); ++ ++ if (mr_compare(mr_mip->w1,mr_mip->w3)==0) valid=TRUE; ++ } ++ else ++ { /* no y supplied - calculate one. Find square root */ ++#ifndef MR_NOSUPPORT_COMPRESSION ++ ++ valid=nres_sqroot(_MIPP_ mr_mip->w3,p->Y); ++ /* check LSB - have we got the right root? */ ++ redc(_MIPP_ p->Y,mr_mip->w1); ++ if (remain(_MIPP_ mr_mip->w1,2)!=cb) ++ mr_psub(_MIPP_ mr_mip->modulus,p->Y,p->Y); ++ ++#else ++ mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); ++ MR_OUT ++ return FALSE; ++#endif ++ } ++ if (valid) ++ { ++ p->marker=MR_EPOINT_NORMALIZED; ++ MR_OUT ++ return TRUE; ++ } ++ ++ MR_OUT ++ return FALSE; ++} ++ ++#ifndef MR_STATIC ++ ++void epoint_getxyz(_MIPD_ epoint *p,big x,big y,big z) ++{ /* get (x,y,z) coordinates */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ MR_IN(143) ++ convert(_MIPP_ 1,mr_mip->w1); ++ if (p->marker==MR_EPOINT_INFINITY) ++ { ++#ifndef MR_AFFINE_ONLY ++ if (mr_mip->coord==MR_AFFINE) ++ { /* (0,1) or (0,0) = O */ ++#endif ++ if (x!=NULL) zero(x); ++ if (mr_mip->Bsize==0) ++ { ++ if (y!=NULL) copy(mr_mip->w1,y); ++ } ++ else ++ { ++ if (y!=NULL) zero(y); ++ } ++#ifndef MR_AFFINE_ONLY ++ } ++ if (mr_mip->coord==MR_PROJECTIVE) ++ { /* (1,1,0) = O */ ++ if (x!=NULL) copy(mr_mip->w1,x); ++ if (y!=NULL) copy(mr_mip->w1,y); ++ } ++#endif ++ if (z!=NULL) zero(z); ++ MR_OUT ++ return; ++ } ++ if (x!=NULL) redc(_MIPP_ p->X,x); ++ if (y!=NULL) redc(_MIPP_ p->Y,y); ++#ifndef MR_AFFINE_ONLY ++ if (mr_mip->coord==MR_AFFINE) ++ { ++#endif ++ if (z!=NULL) zero(z); ++#ifndef MR_AFFINE_ONLY ++ } ++ ++ if (mr_mip->coord==MR_PROJECTIVE) ++ { ++ if (z!=NULL) ++ { ++ if (p->marker!=MR_EPOINT_GENERAL) copy(mr_mip->w1,z); ++ else redc(_MIPP_ p->Z,z); ++ } ++ } ++#endif ++ MR_OUT ++ return; ++} ++ ++#endif ++ ++int epoint_get(_MIPD_ epoint* p,big x,big y) ++{ /* Get point co-ordinates in affine, normal form * ++ * (converted from projective, Montgomery form) * ++ * if x==y, supplies x only. Return value is Least * ++ * Significant Bit of y (useful for point compression) */ ++ ++ int lsb; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ if (p->marker==MR_EPOINT_INFINITY) ++ { ++ zero(x); ++ zero(y); ++ return 0; ++ } ++ if (mr_mip->ERNUM) return 0; ++ ++ MR_IN(98) ++ ++ if (!epoint_norm(_MIPP_ p)) ++ { /* not possible ! */ ++ MR_OUT ++ return (-1); ++ } ++ ++ redc(_MIPP_ p->X,x); ++ redc(_MIPP_ p->Y,mr_mip->w1); ++ ++ if (x!=y) copy(mr_mip->w1,y); ++ lsb=remain(_MIPP_ mr_mip->w1,2); ++ MR_OUT ++ return lsb; ++} ++ ++BOOL epoint_norm(_MIPD_ epoint *p) ++{ /* normalise a point */ ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++#ifndef MR_AFFINE_ONLY ++ ++ if (mr_mip->coord==MR_AFFINE) return TRUE; ++ if (p->marker!=MR_EPOINT_GENERAL) return TRUE; ++ ++ if (mr_mip->ERNUM) return FALSE; ++ ++ MR_IN(117) ++ ++ copy(mr_mip->one,mr_mip->w8); ++ ++ if (nres_moddiv(_MIPP_ mr_mip->w8,p->Z,mr_mip->w8)>1) /* 1/Z */ ++ { ++ epoint_set(_MIPP_ NULL,NULL,0,p); ++ mr_berror(_MIPP_ MR_ERR_COMPOSITE_MODULUS); ++ MR_OUT ++ return FALSE; ++ } ++ ++ nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w1);/* 1/ZZ */ ++ nres_modmult(_MIPP_ p->X,mr_mip->w1,p->X); /* X/ZZ */ ++ nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w8,mr_mip->w1);/* 1/ZZZ */ ++ nres_modmult(_MIPP_ p->Y,mr_mip->w1,p->Y); /* Y/ZZZ */ ++ ++ copy(mr_mip->one,p->Z); ++ ++ p->marker=MR_EPOINT_NORMALIZED; ++ MR_OUT ++ ++#endif ++ ++ return TRUE; ++} ++ ++BOOL epoint_multi_norm(_MIPD_ int m,big *work,epoint **p) ++{ /* Normalise an array of points of length mcoord==MR_AFFINE) return TRUE; ++ if (mr_mip->ERNUM) return FALSE; ++ if (m>MR_MAX_M_T_S) return FALSE; ++ ++ MR_IN(190) ++ ++ for (i=0;imarker==MR_EPOINT_NORMALIZED) w[i]=mr_mip->one; ++ else w[i]=p[i]->Z; ++ if (p[i]->marker==MR_EPOINT_INFINITY) {inf=TRUE; break;} /* whoops, one of them is point at infinity */ ++ } ++ ++ if (inf) ++ { ++ for (i=0;ione,p[i]->Z); ++ p[i]->marker=MR_EPOINT_NORMALIZED; ++ nres_modmult(_MIPP_ work[i],work[i],mr_mip->w1); ++ nres_modmult(_MIPP_ p[i]->X,mr_mip->w1,p[i]->X); /* X/ZZ */ ++ nres_modmult(_MIPP_ mr_mip->w1,work[i],mr_mip->w1); ++ nres_modmult(_MIPP_ p[i]->Y,mr_mip->w1,p[i]->Y); /* Y/ZZZ */ ++ } ++ MR_OUT ++#endif ++ return TRUE; ++} ++ ++/* adds b+=a, d+=c, and slopes in s1 and s2 */ ++ ++#ifndef MR_NO_ECC_MULTIADD ++#ifndef MR_STATIC ++ ++void ecurve_double_add(_MIPD_ epoint *a,epoint*b,epoint *c,epoint *d,big *s1,big *s2) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(144); ++ ++#ifndef MR_AFFINE_ONLY ++ ++ if (mr_mip->coord==MR_AFFINE) ++ { ++#endif ++ if (a->marker==MR_EPOINT_INFINITY || size(a->Y)==0) ++ { ++ *s1=NULL; ++ ecurve_add(_MIPP_ c,d); ++ *s2=mr_mip->w8; ++ MR_OUT ++ return; ++ } ++ if (b->marker==MR_EPOINT_INFINITY || size(b->Y)==0) ++ { ++ *s1=NULL; ++ epoint_copy(a,b); ++ ecurve_add(_MIPP_ c,d); ++ *s2=mr_mip->w8; ++ MR_OUT ++ return; ++ } ++ if (c->marker==MR_EPOINT_INFINITY || size(c->Y)==0) ++ { ++ ecurve_add(_MIPP_ a,b); ++ *s1=mr_mip->w8; ++ *s2=NULL; ++ MR_OUT ++ return; ++ } ++ if (d->marker==MR_EPOINT_INFINITY || size(d->Y)==0) ++ { ++ epoint_copy(c,d); ++ ecurve_add(_MIPP_ a,b); ++ *s1=mr_mip->w8; ++ *s2=NULL; ++ MR_OUT ++ return; ++ } ++ ++ if (a==b || (mr_compare(a->X,b->X)==0 && mr_compare(a->Y,b->Y)==0)) ++ { ++ nres_modmult(_MIPP_ a->X,a->X,mr_mip->w8); ++ nres_premult(_MIPP_ mr_mip->w8,3,mr_mip->w8); /* 3x^2 */ ++ if (mr_abs(mr_mip->Asize)==MR_TOOBIG) ++ nres_modadd(_MIPP_ mr_mip->w8,mr_mip->A,mr_mip->w8); ++ else ++ { ++ convert(_MIPP_ mr_mip->Asize,mr_mip->w2); ++ nres(_MIPP_ mr_mip->w2,mr_mip->w2); ++ nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w2,mr_mip->w8); ++ } ++ nres_premult(_MIPP_ a->Y,2,mr_mip->w10); ++ } ++ else ++ { ++ if (mr_compare(a->X,b->X)==0) ++ { ++ epoint_set(_MIPP_ NULL,NULL,0,b); ++ *s1=NULL; ++ ecurve_add(_MIPP_ c,d); ++ *s2=mr_mip->w8; ++ MR_OUT ++ return; ++ } ++ nres_modsub(_MIPP_ a->Y,b->Y,mr_mip->w8); ++ nres_modsub(_MIPP_ a->X,b->X,mr_mip->w10); ++ } ++ ++ if (c==d || (mr_compare(c->X,d->X)==0 && mr_compare(c->Y,d->Y)==0)) ++ { ++ nres_modmult(_MIPP_ c->X,c->X,mr_mip->w9); ++ nres_premult(_MIPP_ mr_mip->w9,3,mr_mip->w9); /* 3x^2 */ ++ if (mr_abs(mr_mip->Asize)==MR_TOOBIG) ++ nres_modadd(_MIPP_ mr_mip->w9,mr_mip->A,mr_mip->w9); ++ else ++ { ++ convert(_MIPP_ mr_mip->Asize,mr_mip->w2); ++ nres(_MIPP_ mr_mip->w2,mr_mip->w2); ++ nres_modadd(_MIPP_ mr_mip->w9,mr_mip->w2,mr_mip->w9); ++ } ++ nres_premult(_MIPP_ c->Y,2,mr_mip->w11); ++ } ++ else ++ { ++ if (mr_compare(c->X,d->X)==0) ++ { ++ epoint_set(_MIPP_ NULL,NULL,0,d); ++ *s2=NULL; ++ ecurve_add(_MIPP_ a,b); ++ *s1=mr_mip->w8; ++ MR_OUT ++ return; ++ } ++ nres_modsub(_MIPP_ c->Y,d->Y,mr_mip->w9); ++ nres_modsub(_MIPP_ c->X,d->X,mr_mip->w11); ++ } ++ ++ nres_double_inverse(_MIPP_ mr_mip->w10,mr_mip->w10,mr_mip->w11,mr_mip->w11); ++ nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w10,mr_mip->w8); ++ nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); ++ ++ nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w2); /* m^2 */ ++ nres_modsub(_MIPP_ mr_mip->w2,a->X,mr_mip->w1); ++ nres_modsub(_MIPP_ mr_mip->w1,b->X,mr_mip->w1); ++ ++ nres_modsub(_MIPP_ b->X,mr_mip->w1,mr_mip->w2); ++ nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w8,mr_mip->w2); ++ nres_modsub(_MIPP_ mr_mip->w2,b->Y,b->Y); ++ copy(mr_mip->w1,b->X); ++ b->marker=MR_EPOINT_GENERAL; ++ ++ nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w9,mr_mip->w2); /* m^2 */ ++ nres_modsub(_MIPP_ mr_mip->w2,c->X,mr_mip->w1); ++ nres_modsub(_MIPP_ mr_mip->w1,d->X,mr_mip->w1); ++ ++ nres_modsub(_MIPP_ d->X,mr_mip->w1,mr_mip->w2); ++ nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w9,mr_mip->w2); ++ nres_modsub(_MIPP_ mr_mip->w2,d->Y,d->Y); ++ copy(mr_mip->w1,d->X); ++ d->marker=MR_EPOINT_GENERAL; ++ ++ *s1=mr_mip->w8; ++ *s2=mr_mip->w9; ++#ifndef MR_AFFINE_ONLY ++ } ++ else ++ { /* no speed-up */ ++ ecurve_add(_MIPP_ a,b); ++ copy(mr_mip->w8,mr_mip->w9); ++ *s1=mr_mip->w9; ++ ecurve_add(_MIPP_ c,d); ++ *s2=mr_mip->w8; ++ } ++#endif ++ MR_OUT ++} ++ ++void ecurve_multi_add(_MIPD_ int m,epoint **x,epoint**w) ++{ /* adds m points together simultaneously, w[i]+=x[i] */ ++ int i,*flag; ++ big *A,*B,*C; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(122) ++#ifndef MR_AFFINE_ONLY ++ if (mr_mip->coord==MR_AFFINE) ++ { /* this can be done faster */ ++#endif ++ A=(big *)mr_alloc(_MIPP_ m,sizeof(big)); ++ B=(big *)mr_alloc(_MIPP_ m,sizeof(big)); ++ C=(big *)mr_alloc(_MIPP_ m,sizeof(big)); ++ flag=(int *)mr_alloc(_MIPP_ m,sizeof(int)); ++ ++ copy(mr_mip->one,mr_mip->w3); ++ ++ for (i=0;iX,w[i]->X)==0 && mr_compare(x[i]->Y,w[i]->Y)==0) ++ { /* doubling */ ++ if (x[i]->marker==MR_EPOINT_INFINITY || size(x[i]->Y)==0) ++ { ++ flag[i]=1; /* result is infinity */ ++ copy(mr_mip->w3,B[i]); ++ continue; ++ } ++ nres_modmult(_MIPP_ x[i]->X,x[i]->X,A[i]); ++ nres_premult(_MIPP_ A[i],3,A[i]); /* 3*x^2 */ ++ if (mr_abs(mr_mip->Asize) == MR_TOOBIG) ++ nres_modadd(_MIPP_ A[i],mr_mip->A,A[i]); ++ else ++ { ++ convert(_MIPP_ mr_mip->Asize,mr_mip->w2); ++ nres(_MIPP_ mr_mip->w2,mr_mip->w2); ++ nres_modadd(_MIPP_ A[i],mr_mip->w2,A[i]); ++ } /* 3*x^2+A */ ++ nres_premult(_MIPP_ x[i]->Y,2,B[i]); ++ } ++ else ++ { ++ if (x[i]->marker==MR_EPOINT_INFINITY) ++ { ++ flag[i]=2; /* w[i] unchanged */ ++ copy(mr_mip->w3,B[i]); ++ continue; ++ } ++ if (w[i]->marker==MR_EPOINT_INFINITY) ++ { ++ flag[i]=3; /* w[i] = x[i] */ ++ copy(mr_mip->w3,B[i]); ++ continue; ++ } ++ nres_modsub(_MIPP_ x[i]->X,w[i]->X,B[i]); ++ if (size(B[i])==0) ++ { /* point at infinity */ ++ flag[i]=1; /* result is infinity */ ++ copy(mr_mip->w3,B[i]); ++ continue; ++ } ++ nres_modsub(_MIPP_ x[i]->Y,w[i]->Y,A[i]); ++ } ++ } ++ nres_multi_inverse(_MIPP_ m,B,C); /* only one inversion needed */ ++ for (i=0;iw8); ++ ++ nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w2); /* m^2 */ ++ nres_modsub(_MIPP_ mr_mip->w2,x[i]->X,mr_mip->w1); ++ nres_modsub(_MIPP_ mr_mip->w1,w[i]->X,mr_mip->w1); ++ ++ nres_modsub(_MIPP_ w[i]->X,mr_mip->w1,mr_mip->w2); ++ nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w8,mr_mip->w2); ++ nres_modsub(_MIPP_ mr_mip->w2,w[i]->Y,w[i]->Y); ++ copy(mr_mip->w1,w[i]->X); ++ w[i]->marker=MR_EPOINT_NORMALIZED; ++ ++ mr_free(C[i]); ++ mr_free(B[i]); ++ mr_free(A[i]); ++ } ++ mr_free(flag); ++ mr_free(C); mr_free(B); mr_free(A); ++#ifndef MR_AFFINE_ONLY ++ } ++ else ++ { /* no speed-up */ ++ for (i=0;iERNUM) return; ++ ++ if (p->marker==MR_EPOINT_INFINITY) ++ { /* 2 times infinity == infinity ! */ ++ return; ++ } ++ ++#ifndef MR_AFFINE_ONLY ++ if (mr_mip->coord==MR_AFFINE) ++ { /* 2 sqrs, 1 mul, 1 div */ ++#endif ++ if (size(p->Y)==0) ++ { /* set to point at infinity */ ++ epoint_set(_MIPP_ NULL,NULL,0,p); ++ return; ++ } ++ ++ nres_modmult(_MIPP_ p->X,p->X,mr_mip->w8); /* w8=x^2 */ ++ nres_premult(_MIPP_ mr_mip->w8,3,mr_mip->w8); /* w8=3*x^2 */ ++ if (mr_abs(mr_mip->Asize) == MR_TOOBIG) ++ nres_modadd(_MIPP_ mr_mip->w8,mr_mip->A,mr_mip->w8); ++ else ++ { ++ convert(_MIPP_ mr_mip->Asize,mr_mip->w2); ++ nres(_MIPP_ mr_mip->w2,mr_mip->w2); ++ nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w2,mr_mip->w8); ++ } /* w8=3*x^2+A */ ++ nres_premult(_MIPP_ p->Y,2,mr_mip->w6); /* w6=2y */ ++ if (nres_moddiv(_MIPP_ mr_mip->w8,mr_mip->w6,mr_mip->w8)>1) ++ { ++ epoint_set(_MIPP_ NULL,NULL,0,p); ++ mr_berror(_MIPP_ MR_ERR_COMPOSITE_MODULUS); ++ return; ++ } ++ ++/* w8 is slope m on exit */ ++ ++ nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w2); /* w2=m^2 */ ++ nres_premult(_MIPP_ p->X,2,mr_mip->w1); ++ nres_modsub(_MIPP_ mr_mip->w2,mr_mip->w1,mr_mip->w1); /* w1=m^2-2x */ ++ ++ nres_modsub(_MIPP_ p->X,mr_mip->w1,mr_mip->w2); ++ nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w8,mr_mip->w2); ++ nres_modsub(_MIPP_ mr_mip->w2,p->Y,p->Y); ++ copy(mr_mip->w1,p->X); ++ ++ return; ++#ifndef MR_AFFINE_ONLY ++ } ++ ++ if (size(p->Y)==0) ++ { /* set to point at infinity */ ++ epoint_set(_MIPP_ NULL,NULL,0,p); ++ return; ++ } ++ ++ convert(_MIPP_ 1,mr_mip->w1); ++ if (mr_abs(mr_mip->Asize) < MR_TOOBIG) ++ { ++ if (mr_mip->Asize!=0) ++ { ++ if (p->marker==MR_EPOINT_NORMALIZED) ++ nres(_MIPP_ mr_mip->w1,mr_mip->w6); ++ else nres_modmult(_MIPP_ p->Z,p->Z,mr_mip->w6); ++ } ++ if (mr_mip->Asize==(-3)) ++ { /* a is -3. Goody. 4 sqrs, 4 muls */ ++ nres_modsub(_MIPP_ p->X,mr_mip->w6,mr_mip->w3); ++ nres_modadd(_MIPP_ p->X,mr_mip->w6,mr_mip->w8); ++ nres_modmult(_MIPP_ mr_mip->w3,mr_mip->w8,mr_mip->w3); ++ nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w3,mr_mip->w8); ++ nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w3,mr_mip->w8); ++ } ++ else ++ { /* a is small */ ++ if (mr_mip->Asize!=0) ++ { /* a is non zero! */ ++ nres_modmult(_MIPP_ mr_mip->w6,mr_mip->w6,mr_mip->w3); ++ nres_premult(_MIPP_ mr_mip->w3,mr_mip->Asize,mr_mip->w3); ++ } ++ nres_modmult(_MIPP_ p->X,p->X,mr_mip->w1); ++ nres_modadd(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w8); ++ nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w1,mr_mip->w8); ++ if (mr_mip->Asize!=0) nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w3,mr_mip->w8); ++ } ++ } ++ else ++ { /* a is not special */ ++ if (p->marker==MR_EPOINT_NORMALIZED) nres(_MIPP_ mr_mip->w1,mr_mip->w6); ++ else nres_modmult(_MIPP_ p->Z,p->Z,mr_mip->w6); ++ nres_modmult(_MIPP_ mr_mip->w6,mr_mip->w6,mr_mip->w3); ++ nres_modmult(_MIPP_ mr_mip->w3,mr_mip->A,mr_mip->w3); ++ nres_modmult(_MIPP_ p->X,p->X,mr_mip->w1); ++ nres_modadd(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w8); ++ nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w1,mr_mip->w8); ++ nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w3,mr_mip->w8); ++ } ++ ++/* w8 contains numerator of slope 3x^2+A.z^4 * ++ * denominator is now placed in Z */ ++ nres_modmult(_MIPP_ p->Y,p->Y,mr_mip->w2); ++ nres_modmult(_MIPP_ p->X,mr_mip->w2,mr_mip->w3); ++ nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w3,mr_mip->w3); ++ nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w3,mr_mip->w3); ++ nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,p->X); ++ nres_modsub(_MIPP_ p->X,mr_mip->w3,p->X); ++ nres_modsub(_MIPP_ p->X,mr_mip->w3,p->X); ++ if (p->marker==MR_EPOINT_NORMALIZED) ++ copy(p->Y,p->Z); ++ else nres_modmult(_MIPP_ p->Z,p->Y,p->Z); ++ nres_modadd(_MIPP_ p->Z,p->Z,p->Z); ++ ++ nres_modadd(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w7); ++ nres_modmult(_MIPP_ mr_mip->w7,mr_mip->w7,mr_mip->w2); ++ nres_modadd(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w2); ++ nres_modsub(_MIPP_ mr_mip->w3,p->X,mr_mip->w3); ++ nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w3,p->Y); ++ nres_modsub(_MIPP_ p->Y,mr_mip->w2,p->Y); ++ ++/* alternative method ++ nres_modadd(_MIPP_ p->Y,p->Y,mr_mip->w2); ++ ++ if (p->marker==MR_EPOINT_NORMALIZED) ++ copy(mr_mip->w2,p->Z); ++ ++ else nres_modmult(_MIPP_ mr_mip->w2,p->Z,p->Z); ++ ++ nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w2); ++ nres_modmult(_MIPP_ p->X,mr_mip->w2,mr_mip->w3); ++ nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w3,p->X); ++ nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w1); ++ nres_modsub(_MIPP_ mr_mip->w1,p->X,p->X); ++ nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w2); ++ ++ if (remain(_MIPP_ mr_mip->w2,2)!=0) ++ mr_padd(_MIPP_ mr_mip->w2,mr_mip->modulus,mr_mip->w2); ++ subdiv(_MIPP_ mr_mip->w2,2,mr_mip->w2); ++ ++ nres_modsub(_MIPP_ mr_mip->w3,p->X,mr_mip->w3); ++ nres_modmult(_MIPP_ mr_mip->w3,mr_mip->w8,mr_mip->w3); ++ nres_modsub(_MIPP_ mr_mip->w3,mr_mip->w2,p->Y); ++*/ ++ ++/* ++ ++Observe that when finished w8 contains the line slope, w7 has 2y^2 and w6 has z^2 ++This is useful for calculating line functions in pairings ++ ++*/ ++ ++ p->marker=MR_EPOINT_GENERAL; ++ return; ++#endif ++} ++ ++static BOOL ecurve_padd(_MIPD_ epoint *p,epoint *pa) ++{ /* primitive add two epoints on the active ecurve - pa+=p; * ++ * note that if p is normalized, its Z coordinate isn't used */ ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++#ifndef MR_AFFINE_ONLY ++ if (mr_mip->coord==MR_AFFINE) ++ { /* 1 sqr, 1 mul, 1 div */ ++#endif ++ nres_modsub(_MIPP_ p->Y,pa->Y,mr_mip->w8); ++ nres_modsub(_MIPP_ p->X,pa->X,mr_mip->w6); ++ if (size(mr_mip->w6)==0) ++ { /* divide by 0 */ ++ if (size(mr_mip->w8)==0) ++ { /* should have doubled ! */ ++ return FALSE; ++ } ++ else ++ { /* point at infinity */ ++ epoint_set(_MIPP_ NULL,NULL,0,pa); ++ return TRUE; ++ } ++ } ++ if (nres_moddiv(_MIPP_ mr_mip->w8,mr_mip->w6,mr_mip->w8)>1) ++ { ++ epoint_set(_MIPP_ NULL,NULL,0,pa); ++ mr_berror(_MIPP_ MR_ERR_COMPOSITE_MODULUS); ++ return TRUE; ++ } ++ ++ nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w2); /* w2=m^2 */ ++ nres_modsub(_MIPP_ mr_mip->w2,p->X,mr_mip->w1); /* w1=m^2-x1-x2 */ ++ nres_modsub(_MIPP_ mr_mip->w1,pa->X,mr_mip->w1); ++ ++ ++ nres_modsub(_MIPP_ pa->X,mr_mip->w1,mr_mip->w2); ++ nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w8,mr_mip->w2); ++ nres_modsub(_MIPP_ mr_mip->w2,pa->Y,pa->Y); ++ copy(mr_mip->w1,pa->X); ++ ++ pa->marker=MR_EPOINT_NORMALIZED; ++ return TRUE; ++#ifndef MR_AFFINE_ONLY ++ } ++ ++ if (p->marker!=MR_EPOINT_NORMALIZED) ++ { ++ nres_modmult(_MIPP_ p->Z,p->Z,mr_mip->w6); ++ nres_modmult(_MIPP_ pa->X,mr_mip->w6,mr_mip->w1); ++ nres_modmult(_MIPP_ mr_mip->w6,p->Z,mr_mip->w6); ++ nres_modmult(_MIPP_ pa->Y,mr_mip->w6,mr_mip->w8); ++ } ++ else ++ { ++ copy(pa->X,mr_mip->w1); ++ copy(pa->Y,mr_mip->w8); ++ } ++ if (pa->marker==MR_EPOINT_NORMALIZED) ++ copy(mr_mip->one,mr_mip->w6); ++ else nres_modmult(_MIPP_ pa->Z,pa->Z,mr_mip->w6); ++ ++ nres_modmult(_MIPP_ p->X,mr_mip->w6,mr_mip->w4); ++ if (pa->marker!=MR_EPOINT_NORMALIZED) ++ nres_modmult(_MIPP_ mr_mip->w6,pa->Z,mr_mip->w6); ++ nres_modmult(_MIPP_ p->Y,mr_mip->w6,mr_mip->w5); ++ nres_modsub(_MIPP_ mr_mip->w1,mr_mip->w4,mr_mip->w1); ++ nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w5,mr_mip->w8); ++ ++/* w8 contains the numerator of the slope */ ++ ++ if (size(mr_mip->w1)==0) ++ { ++ if (size(mr_mip->w8)==0) ++ { /* should have doubled ! */ ++ return FALSE; ++ } ++ else ++ { /* point at infinity */ ++ epoint_set(_MIPP_ NULL,NULL,0,pa); ++ return TRUE; ++ } ++ } ++ nres_modadd(_MIPP_ mr_mip->w4,mr_mip->w4,mr_mip->w6); ++ nres_modadd(_MIPP_ mr_mip->w1,mr_mip->w6,mr_mip->w4); ++ nres_modadd(_MIPP_ mr_mip->w5,mr_mip->w5,mr_mip->w6); ++ nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w6,mr_mip->w5); ++ ++ if (p->marker!=MR_EPOINT_NORMALIZED) ++ { ++ if (pa->marker!=MR_EPOINT_NORMALIZED) ++ nres_modmult(_MIPP_ pa->Z,p->Z,mr_mip->w3); ++ else ++ copy(p->Z,mr_mip->w3); ++ nres_modmult(_MIPP_ mr_mip->w3,mr_mip->w1,pa->Z); ++ } ++ else ++ { ++ if (pa->marker!=MR_EPOINT_NORMALIZED) ++ nres_modmult(_MIPP_ pa->Z,mr_mip->w1,pa->Z); ++ else ++ copy(mr_mip->w1,pa->Z); ++ } ++ nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w6); ++ nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w6,mr_mip->w1); ++ nres_modmult(_MIPP_ mr_mip->w6,mr_mip->w4,mr_mip->w6); ++ nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w4); ++ ++ nres_modsub(_MIPP_ mr_mip->w4,mr_mip->w6,pa->X); ++ nres_modsub(_MIPP_ mr_mip->w6,pa->X,mr_mip->w6); ++ nres_modsub(_MIPP_ mr_mip->w6,pa->X,mr_mip->w6); ++ nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w6,mr_mip->w2); ++ nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w5,mr_mip->w1); ++ nres_modsub(_MIPP_ mr_mip->w2,mr_mip->w1,mr_mip->w5); ++ ++/* divide by 2 */ ++ ++ nres_div2(_MIPP_ mr_mip->w5,pa->Y); ++ ++ pa->marker=MR_EPOINT_GENERAL; ++ return TRUE; ++#endif ++} ++ ++void epoint_copy(epoint *a,epoint *b) ++{ ++ if (a==b || b==NULL) return; ++ ++ copy(a->X,b->X); ++ copy(a->Y,b->Y); ++#ifndef MR_AFFINE_ONLY ++ if (a->marker==MR_EPOINT_GENERAL) copy(a->Z,b->Z); ++#endif ++ b->marker=a->marker; ++ return; ++} ++ ++BOOL epoint_comp(_MIPD_ epoint *a,epoint *b) ++{ ++ BOOL result; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return FALSE; ++ if (a==b) return TRUE; ++ if (a->marker==MR_EPOINT_INFINITY) ++ { ++ if (b->marker==MR_EPOINT_INFINITY) return TRUE; ++ else return FALSE; ++ } ++ if (b->marker==MR_EPOINT_INFINITY) ++ return FALSE; ++ ++#ifndef MR_AFFINE_ONLY ++ if (mr_mip->coord==MR_AFFINE) ++ { ++#endif ++ if (mr_compare(a->X,b->X)==0 && mr_compare(a->Y,b->Y)==0) result=TRUE; ++ else result=FALSE; ++ return result; ++#ifndef MR_AFFINE_ONLY ++ } ++ ++ if (mr_mip->coord==MR_PROJECTIVE) ++ { ++ MR_IN(105) ++ if (a->marker!=MR_EPOINT_GENERAL) ++ copy(mr_mip->one,mr_mip->w1); ++ else copy(a->Z,mr_mip->w1); ++ ++ if (b->marker!=MR_EPOINT_GENERAL) ++ copy(mr_mip->one,mr_mip->w2); ++ else copy(b->Z,mr_mip->w2); ++ ++ nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w3); /* Za*Za */ ++ nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w4); /* Zb*Zb */ ++ ++ nres_modmult(_MIPP_ a->X,mr_mip->w4,mr_mip->w5); /* Xa*Zb*Zb */ ++ nres_modmult(_MIPP_ b->X,mr_mip->w3,mr_mip->w6); /* Xb*Za*Za */ ++ ++ if (mr_compare(mr_mip->w5,mr_mip->w6)!=0) result=FALSE; ++ else ++ { ++ nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w3,mr_mip->w3); ++ nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w4,mr_mip->w4); ++ ++ nres_modmult(_MIPP_ a->Y,mr_mip->w4,mr_mip->w5); ++ nres_modmult(_MIPP_ b->Y,mr_mip->w3,mr_mip->w6); ++ ++ if (mr_compare(mr_mip->w5,mr_mip->w6)!=0) result=FALSE; ++ else result=TRUE; ++ } ++ MR_OUT ++ return result; ++ } ++ return FALSE; ++#endif ++} ++ ++int ecurve_add(_MIPD_ epoint *p,epoint *pa) ++{ /* pa=pa+p; */ ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return MR_OVER; ++ ++ MR_IN(94) ++ ++ if (p==pa) ++ { ++ ecurve_double(_MIPP_ pa); ++ MR_OUT ++ if (pa->marker==MR_EPOINT_INFINITY) return MR_OVER; ++ return MR_DOUBLE; ++ } ++ if (pa->marker==MR_EPOINT_INFINITY) ++ { ++ epoint_copy(p,pa); ++ MR_OUT ++ return MR_ADD; ++ } ++ if (p->marker==MR_EPOINT_INFINITY) ++ { ++ MR_OUT ++ return MR_ADD; ++ } ++ ++ if (!ecurve_padd(_MIPP_ p,pa)) ++ { ++ ecurve_double(_MIPP_ pa); ++ MR_OUT ++ return MR_DOUBLE; ++ } ++ MR_OUT ++ if (pa->marker==MR_EPOINT_INFINITY) return MR_OVER; ++ return MR_ADD; ++} ++ ++void epoint_negate(_MIPD_ epoint *p) ++{ /* negate a point */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ if (p->marker==MR_EPOINT_INFINITY) return; ++ ++ MR_IN(121) ++ if (size(p->Y)!=0) mr_psub(_MIPP_ mr_mip->modulus,p->Y,p->Y); ++ MR_OUT ++} ++ ++int ecurve_sub(_MIPD_ epoint *p,epoint *pa) ++{ ++ int r; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return MR_OVER; ++ ++ MR_IN(104) ++ ++ if (p==pa) ++ { ++ epoint_set(_MIPP_ NULL,NULL,0,pa); ++ MR_OUT ++ return MR_OVER; ++ } ++ if (p->marker==MR_EPOINT_INFINITY) ++ { ++ MR_OUT ++ return MR_ADD; ++ } ++ ++ epoint_negate(_MIPP_ p); ++ r=ecurve_add(_MIPP_ p,pa); ++ epoint_negate(_MIPP_ p); ++ ++ MR_OUT ++ return r; ++} ++ ++int ecurve_mult(_MIPD_ big e,epoint *pa,epoint *pt) ++{ /* pt=e*pa; */ ++ int i,j,n,nb,nbs,nzs,nadds; ++ epoint *table[MR_ECC_STORE_N]; ++#ifndef MR_AFFINE_ONLY ++ big work[MR_ECC_STORE_N]; ++#endif ++ ++#ifdef MR_STATIC ++ char mem[MR_ECP_RESERVE(MR_ECC_STORE_N)]; ++#ifndef MR_AFFINE_ONLY ++ char mem1[MR_BIG_RESERVE(MR_ECC_STORE_N)]; ++#endif ++#else ++ char *mem; ++#ifndef MR_AFFINE_ONLY ++ char *mem1; ++#endif ++#endif ++ ++#ifndef MR_ALWAYS_BINARY ++ epoint *p; ++ int ce,ch; ++#endif ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return 0; ++ ++ MR_IN(95) ++ if (size(e)==0) ++ { /* multiplied by 0 */ ++ epoint_set(_MIPP_ NULL,NULL,0,pt); ++ MR_OUT ++ return 0; ++ } ++ copy(e,mr_mip->w9); ++/* epoint_norm(_MIPP_ pa); */ ++ epoint_copy(pa,pt); ++ ++ if (size(mr_mip->w9)<0) ++ { /* pt = -pt */ ++ negify(mr_mip->w9,mr_mip->w9); ++ epoint_negate(_MIPP_ pt); ++ } ++ ++ if (size(mr_mip->w9)==1) ++ { ++ MR_OUT ++ return 0; ++ } ++ ++ premult(_MIPP_ mr_mip->w9,3,mr_mip->w10); /* h=3*e */ ++ ++#ifndef MR_STATIC ++#ifndef MR_ALWAYS_BINARY ++ if (mr_mip->base==mr_mip->base2) ++ { ++#endif ++#endif ++ ++#ifdef MR_STATIC ++ sbi_memset(mem,0,MR_ECP_RESERVE(MR_ECC_STORE_N)); ++#ifndef MR_AFFINE_ONLY ++ sbi_memset(mem1,0,MR_BIG_RESERVE(MR_ECC_STORE_N)); ++#endif ++#else ++ mem=(char *)ecp_memalloc(_MIPP_ MR_ECC_STORE_N); ++#ifndef MR_AFFINE_ONLY ++ mem1=(char *)memalloc(_MIPP_ MR_ECC_STORE_N); ++#endif ++#endif ++ ++ for (i=0;i<=MR_ECC_STORE_N-1;i++) ++ { ++ table[i]=epoint_init_mem(_MIPP_ mem,i); ++#ifndef MR_AFFINE_ONLY ++ work[i]=mirvar_mem(_MIPP_ mem1,i); ++#endif ++ } ++ epoint_copy(pt,table[0]); ++ epoint_copy(table[0],table[MR_ECC_STORE_N-1]); ++ ecurve_double(_MIPP_ table[MR_ECC_STORE_N-1]); ++ /* epoint_norm(_MIPP_ table[MR_ECC_STORE_N-1]); */ ++ for (i=1;iw10); ++ nadds=0; ++ epoint_set(_MIPP_ NULL,NULL,0,pt); ++ ++ for (i=nb-1;i>=1;) ++ { /* add/subtract */ ++ if (mr_mip->user!=NULL) (*mr_mip->user)(); ++ n=mr_naf_window(_MIPP_ mr_mip->w9,mr_mip->w10,i,&nbs,&nzs,MR_ECC_STORE_N); ++ for (j=0;j0) {ecurve_add(_MIPP_ table[n/2],pt); nadds++;} ++ if (n<0) {ecurve_sub(_MIPP_ table[(-n)/2],pt); nadds++;} ++ i-=nbs; ++ if (nzs) ++ { ++ for (j=0;jw10)-1,mr_mip->w11); ++ mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); ++ subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); ++ while (size(mr_mip->w11) > 1) ++ { /* add/subtract method */ ++ if (mr_mip->user!=NULL) (*mr_mip->user)(); ++ ++ ecurve_double(_MIPP_ pt); ++ ce=mr_compare(mr_mip->w9,mr_mip->w11); /* e(i)=1? */ ++ ch=mr_compare(mr_mip->w10,mr_mip->w11); /* h(i)=1? */ ++ if (ch>=0) ++ { /* h(i)=1 */ ++ if (ce<0) {ecurve_add(_MIPP_ p,pt); nadds++;} ++ mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); ++ } ++ if (ce>=0) ++ { /* e(i)=1 */ ++ if (ch<0) {ecurve_sub(_MIPP_ p,pt); nadds++;} ++ mr_psub(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); ++ } ++ subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); ++ } ++ ecp_memkill(_MIPP_ mem,1); ++ } ++#endif ++#endif ++ MR_OUT ++ return nadds; ++} ++ ++#ifndef MR_NO_ECC_MULTIADD ++#ifndef MR_STATIC ++ ++void ecurve_multn(_MIPD_ int n,big *y,epoint **x,epoint *w) ++{ /* pt=e[o]*p[0]+e[1]*p[1]+ .... e[n-1]*p[n-1] */ ++ int i,j,k,m,nb,ea; ++ epoint **G; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(114) ++ ++ m=1< nb) nb=k; ++ ++ epoint_set(_MIPP_ NULL,NULL,0,w); /* w=0 */ ++ ++#ifndef MR_ALWAYS_BINARY ++ if (mr_mip->base==mr_mip->base2) ++ { ++#endif ++ for (i=nb-1;i>=0;i--) ++ { ++ if (mr_mip->user!=NULL) (*mr_mip->user)(); ++ ea=0; ++ k=1; ++ for (j=0;jERNUM) return FALSE; ++ ++ if (P->marker==MR_EPOINT_GENERAL || Q->marker==MR_EPOINT_GENERAL) ++ { ++ mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); ++ MR_OUT ++ return FALSE; ++ } ++ ++ if (mr_compare(P->X,Q->X)==0) ++ { /* P=Q or P=-Q - shouldn't happen */ ++ epoint_copy(P,PP); ++ ecurve_add(_MIPP_ Q,PP); ++ epoint_copy(P,PM); ++ ecurve_sub(_MIPP_ Q,PM); ++ ++ MR_OUT ++ return TRUE; ++ } ++ ++ t1= mr_mip->w10; ++ t2= mr_mip->w11; ++ lam = mr_mip->w13; ++ ++ copy(P->X,t2); ++ nres_modsub(_MIPP_ t2,Q->X,t2); ++ ++ redc(_MIPP_ t2,t2); ++ invmodp(_MIPP_ t2,mr_mip->modulus,t2); ++ nres(_MIPP_ t2,t2); ++ ++ nres_modadd(_MIPP_ P->X,Q->X,PP->X); ++ copy(PP->X,PM->X); ++ ++ copy(P->Y,t1); ++ nres_modsub(_MIPP_ t1,Q->Y,t1); ++ copy(t1,lam); ++ nres_modmult(_MIPP_ lam,t2,lam); ++ copy(lam,t1); ++ nres_modmult(_MIPP_ t1,t1,t1); ++ nres_modsub(_MIPP_ t1,PP->X,PP->X); ++ copy(Q->X,PP->Y); ++ nres_modsub(_MIPP_ PP->Y,PP->X,PP->Y); ++ nres_modmult(_MIPP_ PP->Y,lam,PP->Y); ++ nres_modsub(_MIPP_ PP->Y,Q->Y,PP->Y); ++ ++ copy(P->Y,t1); ++ nres_modadd(_MIPP_ t1,Q->Y,t1); ++ copy(t1,lam); ++ nres_modmult(_MIPP_ lam,t2,lam); ++ copy(lam,t1); ++ nres_modmult(_MIPP_ t1,t1,t1); ++ nres_modsub(_MIPP_ t1,PM->X,PM->X); ++ copy(Q->X,PM->Y); ++ nres_modsub(_MIPP_ PM->Y,PM->X,PM->Y); ++ nres_modmult(_MIPP_ PM->Y,lam,PM->Y); ++ nres_modadd(_MIPP_ PM->Y,Q->Y,PM->Y); ++ ++ PP->marker=MR_EPOINT_NORMALIZED; ++ PM->marker=MR_EPOINT_NORMALIZED; ++ ++ return TRUE; ++} ++ ++void ecurve_mult2(_MIPD_ big e,epoint *p,big ea,epoint *pa,epoint *pt) ++{ /* pt=e*p+ea*pa; */ ++ int e1,h1,e2,h2,bb; ++ epoint *p1,*p2,*ps[2]; ++#ifdef MR_STATIC ++ char mem[MR_ECP_RESERVE(4)]; ++#else ++ char *mem; ++#endif ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(103) ++ ++ if (size(e)==0) ++ { ++ ecurve_mult(_MIPP_ ea,pa,pt); ++ MR_OUT ++ return; ++ } ++#ifdef MR_STATIC ++ sbi_memset(mem,0,MR_ECP_RESERVE(4)); ++#else ++ mem=(char *)ecp_memalloc(_MIPP_ 4); ++#endif ++ p2=epoint_init_mem(_MIPP_ mem,0); ++ p1=epoint_init_mem(_MIPP_ mem,1); ++ ps[0]=epoint_init_mem(_MIPP_ mem,2); ++ ps[1]=epoint_init_mem(_MIPP_ mem,3); ++ ++ epoint_norm(_MIPP_ pa); ++ epoint_copy(pa,p2); ++ copy(ea,mr_mip->w9); ++ if (size(mr_mip->w9)<0) ++ { /* p2 = -p2 */ ++ negify(mr_mip->w9,mr_mip->w9); ++ epoint_negate(_MIPP_ p2); ++ } ++ ++ epoint_norm(_MIPP_ p); ++ epoint_copy(p,p1); ++ copy(e,mr_mip->w12); ++ if (size(mr_mip->w12)<0) ++ { /* p1= -p1 */ ++ negify(mr_mip->w12,mr_mip->w12); ++ epoint_negate(_MIPP_ p1); ++ } ++ ++ ++ epoint_set(_MIPP_ NULL,NULL,0,pt); /* pt=0 */ ++ ecurve_add_sub(_MIPP_ p1,p2,ps[0],ps[1]); /* only one inversion! ps[0]=p1+p2, ps[1]=p1-p2 */ ++ ++ mr_jsf(_MIPP_ mr_mip->w9,mr_mip->w12,mr_mip->w10,mr_mip->w9,mr_mip->w13,mr_mip->w12); ++ ++/* To use a simple NAF instead, substitute this for the JSF ++ premult(_MIPP_ mr_mip->w9,3,mr_mip->w10); 3*ea ++ premult(_MIPP_ mr_mip->w12,3,mr_mip->w13); 3*e ++*/ ++ ++#ifndef MR_ALWAYS_BINARY ++ if (mr_mip->base==mr_mip->base2) ++ { ++#endif ++ if (mr_compare(mr_mip->w10,mr_mip->w13)>=0) bb=logb2(_MIPP_ mr_mip->w10)-1; ++ else bb=logb2(_MIPP_ mr_mip->w13)-1; ++ ++ while (bb>=0) /* for the simple NAF, this should be 1 */ ++ { ++ if (mr_mip->user!=NULL) (*mr_mip->user)(); ++ ecurve_double(_MIPP_ pt); ++ ++ e1=h1=e2=h2=0; ++ if (mr_testbit(_MIPP_ mr_mip->w9,bb)) e2=1; ++ if (mr_testbit(_MIPP_ mr_mip->w10,bb)) h2=1; ++ if (mr_testbit(_MIPP_ mr_mip->w12,bb)) e1=1; ++ if (mr_testbit(_MIPP_ mr_mip->w13,bb)) h1=1; ++ ++ if (e1!=h1) ++ { ++ if (e2==h2) ++ { ++ if (h1==1) ecurve_add(_MIPP_ p1,pt); ++ else ecurve_sub(_MIPP_ p1,pt); ++ } ++ else ++ { ++ if (h1==1) ++ { ++ if (h2==1) ecurve_add(_MIPP_ ps[0],pt); ++ else ecurve_add(_MIPP_ ps[1],pt); ++ } ++ else ++ { ++ if (h2==1) ecurve_sub(_MIPP_ ps[1],pt); ++ else ecurve_sub(_MIPP_ ps[0],pt); ++ } ++ } ++ } ++ else if (e2!=h2) ++ { ++ if (h2==1) ecurve_add(_MIPP_ p2,pt); ++ else ecurve_sub(_MIPP_ p2,pt); ++ } ++ bb-=1; ++ } ++#ifndef MR_ALWAYS_BINARY ++ } ++ else ++ { ++ if (mr_compare(mr_mip->w10,mr_mip->w13)>=0) ++ expb2(_MIPP_ logb2(_MIPP_ mr_mip->w10)-1,mr_mip->w11); ++ else expb2(_MIPP_ logb2(_MIPP_ mr_mip->w13)-1,mr_mip->w11); ++ ++ while (size(mr_mip->w11) > 0) /* for the NAF, this should be 1 */ ++ { /* add/subtract method */ ++ if (mr_mip->user!=NULL) (*mr_mip->user)(); ++ ++ ecurve_double(_MIPP_ pt); ++ ++ e1=h1=e2=h2=0; ++ if (mr_compare(mr_mip->w9,mr_mip->w11)>=0) ++ { /* e1(i)=1? */ ++ e2=1; ++ mr_psub(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); ++ } ++ if (mr_compare(mr_mip->w10,mr_mip->w11)>=0) ++ { /* h1(i)=1? */ ++ h2=1; ++ mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); ++ } ++ if (mr_compare(mr_mip->w12,mr_mip->w11)>=0) ++ { /* e2(i)=1? */ ++ e1=1; ++ mr_psub(_MIPP_ mr_mip->w12,mr_mip->w11,mr_mip->w12); ++ } ++ if (mr_compare(mr_mip->w13,mr_mip->w11)>=0) ++ { /* h2(i)=1? */ ++ h1=1; ++ mr_psub(_MIPP_ mr_mip->w13,mr_mip->w11,mr_mip->w13); ++ } ++ ++ if (e1!=h1) ++ { ++ if (e2==h2) ++ { ++ if (h1==1) ecurve_add(_MIPP_ p1,pt); ++ else ecurve_sub(_MIPP_ p1,pt); ++ } ++ else ++ { ++ if (h1==1) ++ { ++ if (h2==1) ecurve_add(_MIPP_ ps[0],pt); ++ else ecurve_add(_MIPP_ ps[1],pt); ++ } ++ else ++ { ++ if (h2==1) ecurve_sub(_MIPP_ ps[1],pt); ++ else ecurve_sub(_MIPP_ ps[0],pt); ++ } ++ } ++ } ++ else if (e2!=h2) ++ { ++ if (h2==1) ecurve_add(_MIPP_ p2,pt); ++ else ecurve_sub(_MIPP_ p2,pt); ++ } ++ ++ subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); ++ } ++ } ++#endif ++ ecp_memkill(_MIPP_ mem,4); ++ MR_OUT ++} ++ ++#endif ++ ++#else ++ ++/* Twisted Inverted Edwards curves ++ ++ * Assumes Twisted Inverted Edward's equation x^2+Ay^2 = x^2.y^2 + B ++ * Assumes points are not of order 2 or 4 ++*/ ++ ++static void epoint_getrhs(_MIPD_ big x,big y) ++{ ++ /* find RHS=(x^2-B)/(x^2-A) */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ nres_modmult(_MIPP_ x,x,mr_mip->w6); ++ nres_modsub(_MIPP_ mr_mip->w6,mr_mip->B,y); ++ nres_modsub(_MIPP_ mr_mip->w6,mr_mip->A,mr_mip->w6); ++ ++ nres_moddiv(_MIPP_ y,mr_mip->w6,y); ++} ++ ++#ifndef MR_NOSUPPORT_COMPRESSION ++ ++BOOL epoint_x(_MIPD_ big x) ++{ /* test if x is associated with a point on the * ++ * currently active curve */ ++ int j; ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return FALSE; ++ ++ MR_IN(147) ++ ++ if (x==NULL) return FALSE; ++ ++ nres(_MIPP_ x,mr_mip->w2); ++ epoint_getrhs(_MIPP_ mr_mip->w2,mr_mip->w7); ++ ++ if (size(mr_mip->w7)==0) ++ { ++ MR_OUT ++ return TRUE; ++ } ++ ++ redc(_MIPP_ mr_mip->w7,mr_mip->w4); ++ j=jack(_MIPP_ mr_mip->w4,mr_mip->modulus); ++ ++ MR_OUT ++ if (j==1) return TRUE; ++ return FALSE; ++} ++ ++#endif ++ ++BOOL epoint_set(_MIPD_ big x,big y,int cb,epoint *p) ++{ /* initialise a point on active ecurve * ++ * if x or y == NULL, set to point at infinity * ++ * if x==y, a y co-ordinate is calculated - if * ++ * possible - and cb suggests LSB 0/1 of y * ++ * (which "decompresses" y). Otherwise, check * ++ * validity of given (x,y) point, ignoring cb. * ++ * Returns TRUE for valid point, otherwise FALSE. */ ++ ++ BOOL valid; ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return FALSE; ++ ++ MR_IN(97) ++ ++ if (x==NULL || y==NULL) ++ { ++ copy(mr_mip->one,p->X); ++ zero(p->Y); ++ p->marker=MR_EPOINT_INFINITY; ++ MR_OUT ++ return TRUE; ++ } ++ ++ valid=FALSE; ++ nres(_MIPP_ x,p->X); ++ if (x!=y) ++ { /* Check directly that x^2+Ay^2 == x^2.y^2+B */ ++ nres(_MIPP_ y,p->Y); ++ nres_modmult(_MIPP_ p->X,p->X,mr_mip->w1); ++ nres_modmult(_MIPP_ p->Y,p->Y,mr_mip->w2); ++ nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w3); ++ nres_modadd(_MIPP_ mr_mip->w3,mr_mip->B,mr_mip->w3); ++ ++ ++ if (mr_abs(mr_mip->Asize)==MR_TOOBIG) ++ nres_modmult(_MIPP_ mr_mip->w2,mr_mip->A,mr_mip->w2); ++ else ++ nres_premult(_MIPP_ mr_mip->w2,mr_mip->Asize,mr_mip->w2); ++ nres_modadd(_MIPP_ mr_mip->w2,mr_mip->w1,mr_mip->w2); ++ if (mr_compare(mr_mip->w2,mr_mip->w3)==0) valid=TRUE; ++ } ++ else ++ { /* find RHS */ ++ epoint_getrhs(_MIPP_ p->X,mr_mip->w7); ++ /* no y supplied - calculate one. Find square root */ ++#ifndef MR_NOSUPPORT_COMPRESSION ++ valid=nres_sqroot(_MIPP_ mr_mip->w7,p->Y); ++ /* check LSB - have we got the right root? */ ++ redc(_MIPP_ p->Y,mr_mip->w1); ++ if (remain(_MIPP_ mr_mip->w1,2)!=cb) ++ mr_psub(_MIPP_ mr_mip->modulus,p->Y,p->Y); ++ ++#else ++ mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); ++ MR_OUT ++ return FALSE; ++#endif ++ } ++ if (valid) ++ { ++ p->marker=MR_EPOINT_NORMALIZED; ++ MR_OUT ++ return TRUE; ++ } ++ ++ MR_OUT ++ return FALSE; ++} ++ ++#ifndef MR_STATIC ++ ++void epoint_getxyz(_MIPD_ epoint *p,big x,big y,big z) ++{ /* get (x,y,z) coordinates */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ MR_IN(143) ++ convert(_MIPP_ 1,mr_mip->w1); ++ if (p->marker==MR_EPOINT_INFINITY) ++ { ++ if (x!=NULL) copy(mr_mip->w1,x); ++ if (y!=NULL) zero(y); ++ if (z!=NULL) zero(z); ++ MR_OUT ++ return; ++ } ++ if (x!=NULL) redc(_MIPP_ p->X,x); ++ if (y!=NULL) redc(_MIPP_ p->Y,y); ++ if (z!=NULL) redc(_MIPP_ p->Z,z); ++ ++ MR_OUT ++ return; ++} ++ ++#endif ++ ++int epoint_get(_MIPD_ epoint* p,big x,big y) ++{ /* Get point co-ordinates in affine, normal form * ++ * (converted from projective, Montgomery form) * ++ * if x==y, supplies x only. Return value is Least * ++ * Significant Bit of y (useful for point compression) */ ++ ++ int lsb; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ if (p->marker==MR_EPOINT_INFINITY) ++ { ++ zero(y); ++ convert(_MIPP_ 1,x); ++ return 0; ++ } ++ if (mr_mip->ERNUM) return 0; ++ ++ MR_IN(98) ++ ++ if (!epoint_norm(_MIPP_ p)) ++ { /* not possible ! */ ++ MR_OUT ++ return (-1); ++ } ++ ++ redc(_MIPP_ p->X,x); ++ redc(_MIPP_ p->Y,mr_mip->w1); ++ ++ if (x!=y) copy(mr_mip->w1,y); ++ lsb=remain(_MIPP_ mr_mip->w1,2); ++ MR_OUT ++ return lsb; ++} ++ ++BOOL epoint_norm(_MIPD_ epoint *p) ++{ /* normalise a point */ ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ if (p->marker!=MR_EPOINT_GENERAL) return TRUE; ++ ++ if (mr_mip->ERNUM) return FALSE; ++ ++ MR_IN(117) ++ ++ copy(mr_mip->one,mr_mip->w8); ++ ++ if (nres_moddiv(_MIPP_ mr_mip->w8,p->Z,mr_mip->w8)>1) /* 1/Z */ ++ { ++ epoint_set(_MIPP_ NULL,NULL,0,p); ++ mr_berror(_MIPP_ MR_ERR_COMPOSITE_MODULUS); ++ MR_OUT ++ return FALSE; ++ } ++ ++ nres_modmult(_MIPP_ p->X,mr_mip->w8,p->X); /* X/Z */ ++ nres_modmult(_MIPP_ p->Y,mr_mip->w8,p->Y); /* Y/Z */ ++ ++ copy(mr_mip->one,p->Z); ++ ++ p->marker=MR_EPOINT_NORMALIZED; ++ MR_OUT ++ ++ return TRUE; ++} ++ ++void ecurve_double(_MIPD_ epoint *p) ++{ /* double epoint on active ecurve */ ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ if (p->marker==MR_EPOINT_INFINITY) ++ { /* 2 times infinity == infinity ! */ ++ return; ++ } ++ nres_modadd(_MIPP_ p->X,p->Y,mr_mip->w1); ++ ++ nres_modmult(_MIPP_ p->X,p->X,p->X); /* A=X1^2 */ ++ nres_modmult(_MIPP_ p->Y,p->Y,p->Y); /* B=Y1^2 */ ++ nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w1); /* (X+Y)^2 */ ++ nres_modsub(_MIPP_ mr_mip->w1,p->X,mr_mip->w1); ++ nres_modsub(_MIPP_ mr_mip->w1,p->Y,mr_mip->w1); /* E=(X+Y)^2-A-B */ ++ ++ if (mr_abs(mr_mip->Asize)==MR_TOOBIG) /* U = aB */ ++ nres_modmult(_MIPP_ p->Y,mr_mip->A,p->Y); ++ else ++ nres_premult(_MIPP_ p->Y,mr_mip->Asize,p->Y); ++ ++ if (p->marker!=MR_EPOINT_NORMALIZED) ++ nres_modmult(_MIPP_ p->Z,p->Z,p->Z); ++ else ++ copy(mr_mip->one,p->Z); ++ ++ nres_modadd(_MIPP_ p->Z,p->Z,p->Z); ++ if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) /* 2dZ^2 */ ++ nres_modmult(_MIPP_ p->Z,mr_mip->B,p->Z); ++ else ++ nres_premult(_MIPP_ p->Z,mr_mip->Bsize,p->Z); ++ ++ nres_modadd(_MIPP_ p->X,p->Y,mr_mip->w2); /* C=A+U */ ++ nres_modsub(_MIPP_ p->X,p->Y,mr_mip->w3); /* D=A-U */ ++ ++ nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w3,p->X); /* X=C.D */ ++ ++ nres_modsub(_MIPP_ mr_mip->w2,p->Z,mr_mip->w2); /* C-2dZ^2 */ ++ nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w1,p->Y); /* Y=E.(C-2dZ^2) */ ++ nres_modmult(_MIPP_ mr_mip->w3,mr_mip->w1,p->Z); /* Z=D.E */ ++ ++ p->marker=MR_EPOINT_GENERAL; ++ return; ++} ++ ++static BOOL ecurve_padd(_MIPD_ epoint *p,epoint *pa) ++{ /* primitive add two epoints on the active ecurve - pa+=p; * ++ * note that if p is normalized, its Z coordinate isn't used */ ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ if (p->marker==MR_EPOINT_INFINITY) return TRUE; ++ if (pa->marker==MR_EPOINT_INFINITY) ++ { ++ epoint_copy(p,pa); ++ return TRUE; ++ } ++ ++ nres_modadd(_MIPP_ p->X,p->Y,mr_mip->w1); ++ nres_modadd(_MIPP_ pa->X,pa->Y,mr_mip->w2); ++ nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w1); /* I=(X1+Y1)(X2+Y2) */ ++ if (p->marker!=MR_EPOINT_NORMALIZED) ++ { ++ if (pa->marker==MR_EPOINT_NORMALIZED) ++ copy(p->Z,pa->Z); ++ else nres_modmult(_MIPP_ p->Z,pa->Z,pa->Z); /* z = A = Z1*Z2 */ ++ } ++ else ++ { ++ if (pa->marker==MR_EPOINT_NORMALIZED) copy(mr_mip->one,pa->Z); ++ } ++ ++ nres_modmult(_MIPP_ pa->Z,pa->Z,mr_mip->w2); /* w2 = B = dA^2 */ ++ if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) ++ nres_modmult(_MIPP_ mr_mip->w2,mr_mip->B,mr_mip->w2); ++ else ++ nres_premult(_MIPP_ mr_mip->w2,mr_mip->Bsize,mr_mip->w2); ++ nres_modmult(_MIPP_ p->X,pa->X,pa->X); /* x = C = X1*X2 */ ++ nres_modmult(_MIPP_ p->Y,pa->Y,pa->Y); /* y = D = Y1*Y2 */ ++ nres_modmult(_MIPP_ pa->X,pa->Y,mr_mip->w3); /* w3 = E = C*D */ ++ ++ nres_modsub(_MIPP_ mr_mip->w1,pa->X,mr_mip->w1); ++ nres_modsub(_MIPP_ mr_mip->w1,pa->Y,mr_mip->w1); /* I=(X1+Y1)(X2+Y2)-C-D =X1*Y2+Y1*X2 */ ++ ++ if (mr_abs(mr_mip->Asize)==MR_TOOBIG) /* */ ++ nres_modmult(_MIPP_ pa->Y,mr_mip->A,pa->Y); ++ else ++ nres_premult(_MIPP_ pa->Y,mr_mip->Asize,pa->Y); ++ nres_modsub(_MIPP_ pa->X,pa->Y,pa->X); /* X = H = C-aD */ ++ ++ nres_modmult(_MIPP_ pa->Z,pa->X,pa->Z); ++ nres_modmult(_MIPP_ pa->Z,mr_mip->w1,pa->Z); ++ ++ nres_modsub(_MIPP_ mr_mip->w3,mr_mip->w2,pa->Y); ++ nres_modmult(_MIPP_ pa->Y,mr_mip->w1,pa->Y); ++ ++ nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w2,mr_mip->w3); ++ nres_modmult(_MIPP_ pa->X,mr_mip->w3,pa->X); ++ ++ if (size(pa->Z)==0) ++ { ++ copy(mr_mip->one,pa->X); ++ zero(pa->Y); ++ pa->marker=MR_EPOINT_INFINITY; ++ } ++ else pa->marker=MR_EPOINT_GENERAL; ++ ++ return TRUE; ++} ++ ++void epoint_copy(epoint *a,epoint *b) ++{ ++ if (a==b || b==NULL) return; ++ ++ copy(a->X,b->X); ++ copy(a->Y,b->Y); ++ copy(a->Z,b->Z); ++ ++ b->marker=a->marker; ++ return; ++} ++ ++BOOL epoint_comp(_MIPD_ epoint *a,epoint *b) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return FALSE; ++ if (a==b) return TRUE; ++ if (a->marker==MR_EPOINT_INFINITY) ++ { ++ if (b->marker==MR_EPOINT_INFINITY) return TRUE; ++ else return FALSE; ++ } ++ if (b->marker==MR_EPOINT_INFINITY) ++ return FALSE; ++ ++ MR_IN(105) ++ copy(a->Z,mr_mip->w1); ++ copy(b->Z,mr_mip->w2); ++ ++ nres_modmult(_MIPP_ a->X,b->Z,mr_mip->w1); ++ nres_modmult(_MIPP_ b->X,a->Z,mr_mip->w2); ++ ++ if (mr_compare(mr_mip->w1,mr_mip->w2)!=0) ++ { ++ MR_OUT ++ return FALSE; ++ } ++ ++ nres_modmult(_MIPP_ a->Y,b->Z,mr_mip->w1); ++ nres_modmult(_MIPP_ b->Y,a->Z,mr_mip->w2); ++ ++ if (mr_compare(mr_mip->w1,mr_mip->w2)!=0) ++ { ++ MR_OUT ++ return FALSE; ++ } ++ MR_OUT ++ return TRUE; ++ ++} ++ ++int ecurve_add(_MIPD_ epoint *p,epoint *pa) ++{ /* pa=pa+p; */ ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return MR_OVER; ++ ++ MR_IN(94) ++ ++ if (p==pa) ++ { ++ ecurve_double(_MIPP_ pa); ++ MR_OUT ++ if (pa->marker==MR_EPOINT_INFINITY) return MR_OVER; ++ return MR_DOUBLE; ++ } ++ if (pa->marker==MR_EPOINT_INFINITY) ++ { ++ epoint_copy(p,pa); ++ MR_OUT ++ return MR_ADD; ++ } ++ if (p->marker==MR_EPOINT_INFINITY) ++ { ++ MR_OUT ++ return MR_ADD; ++ } ++ ++ if (!ecurve_padd(_MIPP_ p,pa)) ++ { ++ ecurve_double(_MIPP_ pa); ++ MR_OUT ++ return MR_DOUBLE; ++ } ++ MR_OUT ++ if (pa->marker==MR_EPOINT_INFINITY) return MR_OVER; ++ return MR_ADD; ++} ++ ++void epoint_negate(_MIPD_ epoint *p) ++{ /* negate a point */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ if (p->marker==MR_EPOINT_INFINITY) return; ++ ++ MR_IN(121) ++ if (size(p->X)!=0) mr_psub(_MIPP_ mr_mip->modulus,p->X,p->X); ++ MR_OUT ++} ++ ++int ecurve_sub(_MIPD_ epoint *p,epoint *pa) ++{ ++ int r; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return MR_OVER; ++ ++ MR_IN(104) ++ ++ if (p==pa) ++ { ++ epoint_set(_MIPP_ NULL,NULL,0,pa); ++ MR_OUT ++ return MR_OVER; ++ } ++ if (p->marker==MR_EPOINT_INFINITY) ++ { ++ MR_OUT ++ return MR_ADD; ++ } ++ ++ epoint_negate(_MIPP_ p); ++ r=ecurve_add(_MIPP_ p,pa); ++ epoint_negate(_MIPP_ p); ++ ++ MR_OUT ++ return r; ++} ++ ++int ecurve_mult(_MIPD_ big e,epoint *pa,epoint *pt) ++{ /* pt=e*pa; */ ++ int i,j,n,nb,nbs,nzs,nadds; ++ epoint *table[MR_ECC_STORE_N]; ++ ++#ifdef MR_STATIC ++ char mem[MR_ECP_RESERVE(MR_ECC_STORE_N)]; ++#else ++ char *mem; ++#endif ++ ++#ifndef MR_ALWAYS_BINARY ++ epoint *p; ++ int ce,ch; ++#endif ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return 0; ++ ++ MR_IN(95) ++ if (size(e)==0) ++ { /* multiplied by 0 */ ++ epoint_set(_MIPP_ NULL,NULL,0,pt); ++ MR_OUT ++ return 0; ++ } ++ copy(e,mr_mip->w9); ++ epoint_copy(pa,pt); ++ ++ if (size(mr_mip->w9)<0) ++ { /* pt = -pt */ ++ negify(mr_mip->w9,mr_mip->w9); ++ epoint_negate(_MIPP_ pt); ++ } ++ ++ if (size(mr_mip->w9)==1) ++ { ++ MR_OUT ++ return 0; ++ } ++ ++ premult(_MIPP_ mr_mip->w9,3,mr_mip->w10); /* h=3*e */ ++ ++#ifndef MR_STATIC ++#ifndef MR_ALWAYS_BINARY ++ if (mr_mip->base==mr_mip->base2) ++ { ++#endif ++#endif ++ ++#ifdef MR_STATIC ++ sbi_memset(mem,0,MR_ECP_RESERVE(MR_ECC_STORE_N)); ++#else ++ mem=(char *)ecp_memalloc(_MIPP_ MR_ECC_STORE_N); ++#endif ++ ++ for (i=0;i<=MR_ECC_STORE_N-1;i++) ++ table[i]=epoint_init_mem(_MIPP_ mem,i); ++ ++ epoint_copy(pt,table[0]); ++ epoint_copy(table[0],table[MR_ECC_STORE_N-1]); ++ ecurve_double(_MIPP_ table[MR_ECC_STORE_N-1]); ++ ++ for (i=1;iw10); ++ nadds=0; ++ epoint_set(_MIPP_ NULL,NULL,0,pt); ++ for (i=nb-1;i>=1;) ++ { /* add/subtract */ ++ if (mr_mip->user!=NULL) (*mr_mip->user)(); ++ n=mr_naf_window(_MIPP_ mr_mip->w9,mr_mip->w10,i,&nbs,&nzs,MR_ECC_STORE_N); ++ for (j=0;j0) {ecurve_add(_MIPP_ table[n/2],pt); nadds++;} ++ if (n<0) {ecurve_sub(_MIPP_ table[(-n)/2],pt); nadds++;} ++ i-=nbs; ++ if (nzs) ++ { ++ for (j=0;jw10)-1,mr_mip->w11); ++ mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); ++ subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); ++ while (size(mr_mip->w11) > 1) ++ { /* add/subtract method */ ++ if (mr_mip->user!=NULL) (*mr_mip->user)(); ++ ++ ecurve_double(_MIPP_ pt); ++ ce=mr_compare(mr_mip->w9,mr_mip->w11); /* e(i)=1? */ ++ ch=mr_compare(mr_mip->w10,mr_mip->w11); /* h(i)=1? */ ++ if (ch>=0) ++ { /* h(i)=1 */ ++ if (ce<0) {ecurve_add(_MIPP_ p,pt); nadds++;} ++ mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); ++ } ++ if (ce>=0) ++ { /* e(i)=1 */ ++ if (ch<0) {ecurve_sub(_MIPP_ p,pt); nadds++;} ++ mr_psub(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); ++ } ++ subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); ++ } ++ ecp_memkill(_MIPP_ mem,1); ++ } ++#endif ++#endif ++ MR_OUT ++ return nadds; ++} ++ ++#ifndef MR_NO_ECC_MULTIADD ++#ifndef MR_STATIC ++ ++void ecurve_multn(_MIPD_ int n,big *y,epoint **x,epoint *w) ++{ /* pt=e[0]*p[0]+e[1]*p[1]+ .... e[n-1]*p[n-1] */ ++ int i,j,k,m,nb,ea; ++ epoint **G; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(114) ++ ++ m=1< nb) nb=k; ++ ++ epoint_set(_MIPP_ NULL,NULL,0,w); /* w=0 */ ++ ++#ifndef MR_ALWAYS_BINARY ++ if (mr_mip->base==mr_mip->base2) ++ { ++#endif ++ for (i=nb-1;i>=0;i--) ++ { ++ if (mr_mip->user!=NULL) (*mr_mip->user)(); ++ ea=0; ++ k=1; ++ for (j=0;jmarker==MR_EPOINT_NORMALIZED) ++ { ++ if (Q->marker==MR_EPOINT_NORMALIZED) ++ copy(mr_mip->one,mr_mip->w1); ++ else copy(Q->Z,mr_mip->w1); ++ } ++ else ++ { ++ if (Q->marker==MR_EPOINT_NORMALIZED) ++ copy(P->Z,mr_mip->w1); ++ else nres_modmult(_MIPP_ P->Z,Q->Z,mr_mip->w1); /* w1 = A = Z1*Z2 */ ++ } ++ nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w2); /* w2 = B = dA^2 */ ++ if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) ++ nres_modmult(_MIPP_ mr_mip->w2,mr_mip->B,mr_mip->w2); ++ else ++ nres_premult(_MIPP_ mr_mip->w2,mr_mip->Bsize,mr_mip->w2); ++ nres_modmult(_MIPP_ P->X,Q->X,mr_mip->w3); /* w3 = C = X1*X2 */ ++ nres_modmult(_MIPP_ P->Y,Q->Y,mr_mip->w4); /* w4 = D = Y1*Y2 */ ++ nres_modmult(_MIPP_ mr_mip->w3,mr_mip->w4,mr_mip->w5); /* w5 = E = C*D */ ++ nres_modmult(_MIPP_ P->X,Q->Y,mr_mip->w7); /* w7 = F = X1.Y2 */ ++ nres_modmult(_MIPP_ Q->X,P->Y,mr_mip->w8); /* w8 = G = X2.Y1 */ ++ ++ if (mr_abs(mr_mip->Asize)==MR_TOOBIG) /* w4 = aD */ ++ nres_modmult(_MIPP_ mr_mip->w4,mr_mip->A,mr_mip->w4); ++ else ++ nres_premult(_MIPP_ mr_mip->w4,mr_mip->Asize,mr_mip->w4); ++ ++/* P+Q */ ++ ++ nres_modsub(_MIPP_ mr_mip->w3,mr_mip->w4,mr_mip->w6); /* w6 = H = C-aD */ ++ nres_modadd(_MIPP_ mr_mip->w7,mr_mip->w8,PP->Z); /* X1*Y2+X2*Y1 */ ++ nres_modadd(_MIPP_ mr_mip->w5,mr_mip->w2,PP->X); ++ nres_modmult(_MIPP_ PP->X,mr_mip->w6,PP->X); ++ nres_modsub(_MIPP_ mr_mip->w5,mr_mip->w2,PP->Y); ++ nres_modmult(_MIPP_ PP->Y,PP->Z,PP->Y); ++ nres_modmult(_MIPP_ PP->Z,mr_mip->w6,PP->Z); ++ nres_modmult(_MIPP_ PP->Z,mr_mip->w1,PP->Z); ++ ++ if (size(PP->Z)==0) ++ { ++ copy(mr_mip->one,PP->X); ++ zero(PP->Y); ++ PP->marker=MR_EPOINT_INFINITY; ++ } ++ else PP->marker=MR_EPOINT_GENERAL; ++ ++/* P-Q */ ++ ++ nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w4,mr_mip->w6); /* w6 = C+aD */ ++ nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w7,PM->Z); /* X2*Y1-X1*Y2 */ ++ nres_modsub(_MIPP_ mr_mip->w5,mr_mip->w2,PM->X); ++ nres_modmult(_MIPP_ PM->X,mr_mip->w6,PM->X); ++ nres_modadd(_MIPP_ mr_mip->w5,mr_mip->w2,PM->Y); ++ nres_modmult(_MIPP_ PM->Y,PM->Z,PM->Y); ++ nres_modmult(_MIPP_ PM->Z,mr_mip->w6,PM->Z); ++ nres_modmult(_MIPP_ PM->Z,mr_mip->w1,PM->Z); ++ ++ if (size(PM->Z)==0) ++ { ++ copy(mr_mip->one,PM->X); ++ zero(PM->Y); ++ PM->marker=MR_EPOINT_INFINITY; ++ } ++ else PM->marker=MR_EPOINT_GENERAL; ++ ++ return TRUE; ++} ++ ++void ecurve_mult2(_MIPD_ big e,epoint *p,big ea,epoint *pa,epoint *pt) ++{ /* pt=e*p+ea*pa; */ ++ int e1,h1,e2,h2,bb; ++ epoint *p1,*p2,*ps[2]; ++#ifdef MR_STATIC ++ char mem[MR_ECP_RESERVE(4)]; ++#else ++ char *mem; ++#endif ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(103) ++ ++ if (size(e)==0) ++ { ++ ecurve_mult(_MIPP_ ea,pa,pt); ++ MR_OUT ++ return; ++ } ++#ifdef MR_STATIC ++ sbi_memset(mem,0,MR_ECP_RESERVE(4)); ++#else ++ mem=(char *)ecp_memalloc(_MIPP_ 4); ++#endif ++ p2=epoint_init_mem(_MIPP_ mem,0); ++ p1=epoint_init_mem(_MIPP_ mem,1); ++ ps[0]=epoint_init_mem(_MIPP_ mem,2); ++ ps[1]=epoint_init_mem(_MIPP_ mem,3); ++ ++ epoint_copy(pa,p2); ++ copy(ea,mr_mip->w9); ++ if (size(mr_mip->w9)<0) ++ { /* p2 = -p2 */ ++ negify(mr_mip->w9,mr_mip->w9); ++ epoint_negate(_MIPP_ p2); ++ } ++ ++ epoint_copy(p,p1); ++ copy(e,mr_mip->w12); ++ if (size(mr_mip->w12)<0) ++ { /* p1= -p1 */ ++ negify(mr_mip->w12,mr_mip->w12); ++ epoint_negate(_MIPP_ p1); ++ } ++ ++ epoint_set(_MIPP_ NULL,NULL,0,pt); /* pt=0 */ ++ ecurve_add_sub(_MIPP_ p1,p2,ps[0],ps[1]); /* ps[0]=p1+p2, ps[1]=p1-p2 */ ++ ++ mr_jsf(_MIPP_ mr_mip->w9,mr_mip->w12,mr_mip->w10,mr_mip->w9,mr_mip->w13,mr_mip->w12); ++ ++/* To use a simple NAF instead, substitute this for the JSF ++ premult(_MIPP_ mr_mip->w9,3,mr_mip->w10); 3*ea ++ premult(_MIPP_ mr_mip->w12,3,mr_mip->w13); 3*e ++*/ ++ ++#ifndef MR_ALWAYS_BINARY ++ if (mr_mip->base==mr_mip->base2) ++ { ++#endif ++ if (mr_compare(mr_mip->w10,mr_mip->w13)>=0) bb=logb2(_MIPP_ mr_mip->w10)-1; ++ else bb=logb2(_MIPP_ mr_mip->w13)-1; ++ ++ while (bb>=0) /* for the simple NAF, this should be 1 */ ++ { ++ if (mr_mip->user!=NULL) (*mr_mip->user)(); ++ ecurve_double(_MIPP_ pt); ++ ++ e1=h1=e2=h2=0; ++ if (mr_testbit(_MIPP_ mr_mip->w9,bb)) e2=1; ++ if (mr_testbit(_MIPP_ mr_mip->w10,bb)) h2=1; ++ if (mr_testbit(_MIPP_ mr_mip->w12,bb)) e1=1; ++ if (mr_testbit(_MIPP_ mr_mip->w13,bb)) h1=1; ++ ++ if (e1!=h1) ++ { ++ if (e2==h2) ++ { ++ if (h1==1) ecurve_add(_MIPP_ p1,pt); ++ else ecurve_sub(_MIPP_ p1,pt); ++ } ++ else ++ { ++ if (h1==1) ++ { ++ if (h2==1) ecurve_add(_MIPP_ ps[0],pt); ++ else ecurve_add(_MIPP_ ps[1],pt); ++ } ++ else ++ { ++ if (h2==1) ecurve_sub(_MIPP_ ps[1],pt); ++ else ecurve_sub(_MIPP_ ps[0],pt); ++ } ++ } ++ } ++ else if (e2!=h2) ++ { ++ if (h2==1) ecurve_add(_MIPP_ p2,pt); ++ else ecurve_sub(_MIPP_ p2,pt); ++ } ++ bb-=1; ++ } ++#ifndef MR_ALWAYS_BINARY ++ } ++ else ++ { ++ if (mr_compare(mr_mip->w10,mr_mip->w13)>=0) ++ expb2(_MIPP_ logb2(_MIPP_ mr_mip->w10)-1,mr_mip->w11); ++ else expb2(_MIPP_ logb2(_MIPP_ mr_mip->w13)-1,mr_mip->w11); ++ ++ while (size(mr_mip->w11) > 0) /* for the NAF, this should be 1 */ ++ { /* add/subtract method */ ++ if (mr_mip->user!=NULL) (*mr_mip->user)(); ++ ++ ecurve_double(_MIPP_ pt); ++ ++ e1=h1=e2=h2=0; ++ if (mr_compare(mr_mip->w9,mr_mip->w11)>=0) ++ { /* e1(i)=1? */ ++ e2=1; ++ mr_psub(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); ++ } ++ if (mr_compare(mr_mip->w10,mr_mip->w11)>=0) ++ { /* h1(i)=1? */ ++ h2=1; ++ mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); ++ } ++ if (mr_compare(mr_mip->w12,mr_mip->w11)>=0) ++ { /* e2(i)=1? */ ++ e1=1; ++ mr_psub(_MIPP_ mr_mip->w12,mr_mip->w11,mr_mip->w12); ++ } ++ if (mr_compare(mr_mip->w13,mr_mip->w11)>=0) ++ { /* h2(i)=1? */ ++ h1=1; ++ mr_psub(_MIPP_ mr_mip->w13,mr_mip->w11,mr_mip->w13); ++ } ++ ++ if (e1!=h1) ++ { ++ if (e2==h2) ++ { ++ if (h1==1) ecurve_add(_MIPP_ p1,pt); ++ else ecurve_sub(_MIPP_ p1,pt); ++ } ++ else ++ { ++ if (h1==1) ++ { ++ if (h2==1) ecurve_add(_MIPP_ ps[0],pt); ++ else ecurve_add(_MIPP_ ps[1],pt); ++ } ++ else ++ { ++ if (h2==1) ecurve_sub(_MIPP_ ps[1],pt); ++ else ecurve_sub(_MIPP_ ps[0],pt); ++ } ++ } ++ } ++ else if (e2!=h2) ++ { ++ if (h2==1) ecurve_add(_MIPP_ p2,pt); ++ else ecurve_sub(_MIPP_ p2,pt); ++ } ++ ++ subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); ++ } ++ } ++#endif ++ ecp_memkill(_MIPP_ mem,4); ++ MR_OUT ++} ++ ++#endif ++ ++#endif +diff --git a/lib/sbi/sm/gm/miracl/mrjack.c b/lib/sbi/sm/gm/miracl/mrjack.c +new file mode 100644 +index 0000000..3e6048e +--- /dev/null ++++ b/lib/sbi/sm/gm/miracl/mrjack.c +@@ -0,0 +1,342 @@ ++ ++/*************************************************************************** ++ * ++Copyright 2013 CertiVox UK Ltd. * ++ * ++This file is part of CertiVox MIRACL Crypto SDK. * ++ * ++The CertiVox MIRACL Crypto SDK provides developers with an * ++extensive and efficient set of cryptographic functions. * ++For further information about its features and functionalities please * ++refer to http://www.certivox.com * ++ * ++* The CertiVox MIRACL Crypto SDK is free software: you can * ++ redistribute it and/or modify it under the terms of the * ++ GNU Affero General Public License as published by the * ++ Free Software Foundation, either version 3 of the License, * ++ or (at your option) any later version. * ++ * ++* The CertiVox MIRACL Crypto SDK is distributed in the hope * ++ that it will be useful, but WITHOUT ANY WARRANTY; without even the * ++ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * ++ See the GNU Affero General Public License for more details. * ++ * ++* You should have received a copy of the GNU Affero General Public * ++ License along with CertiVox MIRACL Crypto SDK. * ++ If not, see . * ++ * ++You can be released from the requirements of the license by purchasing * ++a commercial license. Buying such a license is mandatory as soon as you * ++develop commercial activities involving the CertiVox MIRACL Crypto SDK * ++without disclosing the source code of your own applications, or shipping * ++the CertiVox MIRACL Crypto SDK with a closed source product. * ++ * ++***************************************************************************/ ++/* ++ * MIRACL Jacobi symbol routine ++ * mrjack.c ++ * ++ * See "A binary algorithm for the Jacobi symbol" ++ * Shallit and Sorenson ++ */ ++ ++#include "sm/gm/miracl/miracl.h" ++ ++int jack(_MIPD_ big a,big n) ++{ /* find jacobi symbol (a/n), for positive odd n */ ++ big w; ++ int nm8,onm8,t; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM || size(a)==0 || size(n) <1) return 0; ++ MR_IN(3) ++ ++ t=1; ++ copy(n,mr_mip->w2); ++ nm8=remain(_MIPP_ mr_mip->w2,8); ++ if (nm8%2==0) ++ { ++ MR_OUT ++ return 0; ++ } ++ ++ if (size(a)<0) ++ { ++ if (nm8%4==3) t=-1; ++ negify(a,mr_mip->w1); ++ } ++ else copy(a,mr_mip->w1); ++ ++ while (size(mr_mip->w1)!=0) ++ { ++ while (remain(_MIPP_ mr_mip->w1,2)==0) ++ { ++ subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1); ++ if (nm8==3 || nm8==5) t=-t; ++ } ++ if (mr_compare(mr_mip->w1,mr_mip->w2)<0) ++ { ++ onm8=nm8; ++ w=mr_mip->w1; mr_mip->w1=mr_mip->w2; mr_mip->w2=w; ++ nm8=remain(_MIPP_ mr_mip->w2,8); ++ if (onm8%4==3 && nm8%4==3) t=-t; ++ } ++ mr_psub(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w1); ++ subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1); ++ ++ if (nm8==3 || nm8==5) t=-t; ++ } ++ ++ MR_OUT ++ if (size(mr_mip->w2)==1) return t; ++ return 0; ++} ++ ++/* ++ * See "Efficient Algorithms for Computing the Jacobi Symbol" ++ * Eikenberry & Sorenson ++ * ++ * Its turns out this is slower than the binary method above for reasonable sizes ++ * of parameters (and takes up a lot more space!) ++ ++ ++#ifdef MR_FP ++#include ++#endif ++ ++ ++static void rfind(mr_small u,mr_small v,mr_small k,mr_small sk,mr_utype *a,mr_utype *b) ++{ ++ mr_utype x2,y2,r; ++ mr_small w,q,x1,y1,sr; ++#ifdef MR_FP ++ mr_small dres; ++#endif ++ ++ w=invers(v,k); ++ w=smul(u,w,k); ++ ++ x1=k; x2=0; ++ y1=w; y2=1; ++ ++// NOTE: x1 and y1 are always +ve. x2 and y2 are always small ++ ++ while (y1>=sk) ++ { ++#ifndef MR_NOFULLWIDTH ++ if (x1==0) q=muldvm((mr_small)1,(mr_small)0,y1,&sr); ++ else ++#endif ++ q=MR_DIV(x1,y1); ++ r= x1-q*y1; x1=y1; y1=r; ++ sr=x2-q*y2; x2=y2; y2=sr; ++ } ++ if (y2>=0) { *a=y2; *b=0-y1; } ++ else { *a=-y2; *b=y1; } ++} ++ ++int jack(_MIPD_ big U,big V) ++{ // find jacobi symbol for U wrt V. Only defined for ++ // positive V, V odd. Otherwise returns 0 ++ int i,e,r,m,t,v8,u4; ++ mr_utype a,b; ++ mr_small u,v,d,g,k,sk,s; ++#ifdef MR_FP ++ mr_small dres; ++#endif ++ big w; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++#ifdef MR_FP_ROUNDING ++ mr_large ik,id; ++#endif ++ if (mr_mip->ERNUM || size(U)==0 || size(V) <1) return 0; ++ copy(U,mr_mip->w1); ++ copy(V,mr_mip->w2); ++ a=0; ++ MR_IN(3) ++ ++ if (remain(_MIPP_ mr_mip->w2,2)==0) ++ { // V is even ++ MR_OUT ++ return 0; ++ } ++ ++ if (mr_mip->base!=0) ++ { ++ k=1; ++ for (m=1;;m++) ++ { ++ k*=2; ++ if (k==MAXBASE) break; ++ } ++ if (m%2==1) {m--; k=MR_DIV(k,2);} ++#ifdef MR_FP_ROUNDING ++ ik=mr_invert(k); ++#endif ++ } ++ else ++ { ++ m=MIRACL; ++ k=0; ++ } ++ r=m/2; ++ sk=1; ++ for (i=0;iw2,8); ++ ++ while (!mr_mip->ERNUM && size(mr_mip->w1)!=0) ++ { ++ if (size(mr_mip->w1)<0) ++ { ++ negify(mr_mip->w1,mr_mip->w1); ++ if (v8%4==3) t=-t; ++ } ++ ++ do { // oddify ++ ++#ifndef MR_ALWAYS_BINARY ++ if (mr_mip->base==mr_mip->base2) ++ { ++#endif ++ if (mr_mip->base==k) u=mr_mip->w1->w[0]; ++ else u=MR_REMAIN(mr_mip->w1->w[0],k); ++#ifndef MR_ALWAYS_BINARY ++ } ++ ++#ifdef MR_FP_ROUNDING ++ else u=mr_sdiv(_MIPP_ mr_mip->w1,k,ik,mr_mip->w3); ++#else ++ else u=mr_sdiv(_MIPP_ mr_mip->w1,k,mr_mip->w3); ++#endif ++ ++#endif ++ if (u==0) {s=k; e=0;} ++ else ++ { ++ s=1; e=0; ++ while (MR_REMAIN(u,2)==0) {s*=2; e++; u=MR_DIV(u,2);} ++ } ++ if (s==mr_mip->base) mr_shift(_MIPP_ mr_mip->w1,-1,mr_mip->w1); ++#ifdef MR_FP_ROUNDING ++ else if (s>1) ++ { ++ mr_sdiv(_MIPP_ mr_mip->w1,s,mr_invert(s),mr_mip->w1); ++ } ++#else ++ else if (s>1) mr_sdiv(_MIPP_ mr_mip->w1,s,mr_mip->w1); ++#endif ++ } while (u==0); ++ if (e%2!=0 && (v8==3 || v8==5)) t=-t; ++ if (mr_compare(mr_mip->w1,mr_mip->w2)<0) ++ { ++ if (mr_mip->base==mr_mip->base2) u4=(int)MR_REMAIN(mr_mip->w1->w[0],4); ++ else u4=remain(_MIPP_ mr_mip->w1,4); ++ if (v8%4==3 && u4==3) t=-t; ++ w=mr_mip->w1; mr_mip->w1=mr_mip->w2; mr_mip->w2=w; ++ } ++ ++#ifndef MR_ALWAYS_BINARY ++ if (mr_mip->base==mr_mip->base2) ++ { ++#endif ++ if (k==mr_mip->base) ++ { ++ u=mr_mip->w1->w[0]; ++ v=mr_mip->w2->w[0]; ++ } ++ else ++ { ++ u=MR_REMAIN(mr_mip->w1->w[0],k); ++ v=MR_REMAIN(mr_mip->w2->w[0],k); ++ } ++#ifndef MR_ALWAYS_BINARY ++ } ++ else ++ { ++#ifdef MR_FP_ROUNDING ++ u=mr_sdiv(_MIPP_ mr_mip->w1,k,ik,mr_mip->w3); ++ v=mr_sdiv(_MIPP_ mr_mip->w2,k,ik,mr_mip->w3); ++#else ++ u=mr_sdiv(_MIPP_ mr_mip->w1,k,mr_mip->w3); ++ v=mr_sdiv(_MIPP_ mr_mip->w2,k,mr_mip->w3); ++#endif ++ } ++#endif ++ rfind(u,v,k,sk,&a,&b); ++ if (a>1) ++ { ++#ifdef MR_FP_ROUNDING ++ d=mr_sdiv(_MIPP_ mr_mip->w2,a,mr_invert(a),mr_mip->w3); ++#else ++ d=mr_sdiv(_MIPP_ mr_mip->w2,a,mr_mip->w3); ++#endif ++ d=sgcd(d,a); ++ a=MR_DIV(a,d); ++ } ++ else d=1; ++ ++ if (d>1) ++ { ++#ifdef MR_FP_ROUNDING ++ id=mr_invert(d); ++ mr_sdiv(_MIPP_ mr_mip->w2,d,id,mr_mip->w2); ++ u=mr_sdiv(_MIPP_ mr_mip->w1,d,id,mr_mip->w3); ++#else ++ mr_sdiv(_MIPP_ mr_mip->w2,d,mr_mip->w2); ++ u=mr_sdiv(_MIPP_ mr_mip->w1,d,mr_mip->w3); ++#endif ++ } ++ else u=0; ++ ++ g=a; ++ if (mr_mip->base==mr_mip->base2) v8=(int)MR_REMAIN(mr_mip->w2->w[0],8); ++ else v8=remain(_MIPP_ mr_mip->w2,8); ++ while (MR_REMAIN(g,2)==0) ++ { ++ g=MR_DIV(g,2); ++ if (v8==3 || v8==5) t=-t; ++ } ++ if (MR_REMAIN(g,4)==3 && v8%4==3) t=-t; ++#ifdef MR_FP_ROUNDING ++ v=mr_sdiv(_MIPP_ mr_mip->w2,g,mr_invert(g),mr_mip->w3); ++#else ++ v=mr_sdiv(_MIPP_ mr_mip->w2,g,mr_mip->w3); ++#endif ++ t*=jac(v,g)*jac(u,d); ++ if (t==0) ++ { ++ MR_OUT ++ return 0; ++ } ++ ++// printf("a= %I64d b=%I64d %d\n",a,b,(int)b); ++ ++ if (a>1) mr_pmul(_MIPP_ mr_mip->w1,a,mr_mip->w1); ++ if (b>=0) ++ mr_pmul(_MIPP_ mr_mip->w2,b,mr_mip->w3); ++ else ++ { ++ b=-b; ++ mr_pmul(_MIPP_ mr_mip->w2,b,mr_mip->w3); ++ negify(mr_mip->w3,mr_mip->w3); ++ } ++ // premult(_MIPP_ mr_mip->w2,(int)b,mr_mip->w3); <- nasty bug - potential loss of precision in b ++ add(_MIPP_ mr_mip->w1,mr_mip->w3,mr_mip->w1); ++ if (k==mr_mip->base) mr_shift(_MIPP_ mr_mip->w1,-1,mr_mip->w1); ++#ifdef MR_FP_ROUNDING ++ else mr_sdiv(_MIPP_ mr_mip->w1,k,ik,mr_mip->w1); ++#else ++ else mr_sdiv(_MIPP_ mr_mip->w1,k,mr_mip->w1); ++#endif ++ } ++ MR_OUT ++ if (size(mr_mip->w2)==1) return t; ++ return 0; ++} ++ ++*/ +diff --git a/lib/sbi/sm/gm/miracl/mrlucas.c b/lib/sbi/sm/gm/miracl/mrlucas.c +new file mode 100644 +index 0000000..3bf9913 +--- /dev/null ++++ b/lib/sbi/sm/gm/miracl/mrlucas.c +@@ -0,0 +1,157 @@ ++ ++/*************************************************************************** ++ * ++Copyright 2013 CertiVox UK Ltd. * ++ * ++This file is part of CertiVox MIRACL Crypto SDK. * ++ * ++The CertiVox MIRACL Crypto SDK provides developers with an * ++extensive and efficient set of cryptographic functions. * ++For further information about its features and functionalities please * ++refer to http://www.certivox.com * ++ * ++* The CertiVox MIRACL Crypto SDK is free software: you can * ++ redistribute it and/or modify it under the terms of the * ++ GNU Affero General Public License as published by the * ++ Free Software Foundation, either version 3 of the License, * ++ or (at your option) any later version. * ++ * ++* The CertiVox MIRACL Crypto SDK is distributed in the hope * ++ that it will be useful, but WITHOUT ANY WARRANTY; without even the * ++ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * ++ See the GNU Affero General Public License for more details. * ++ * ++* You should have received a copy of the GNU Affero General Public * ++ License along with CertiVox MIRACL Crypto SDK. * ++ If not, see . * ++ * ++You can be released from the requirements of the license by purchasing * ++a commercial license. Buying such a license is mandatory as soon as you * ++develop commercial activities involving the CertiVox MIRACL Crypto SDK * ++without disclosing the source code of your own applications, or shipping * ++the CertiVox MIRACL Crypto SDK with a closed source product. * ++ * ++***************************************************************************/ ++/* ++ * MIRACL methods for evaluating lucas V function ++ * mrlucas.c (Postl's algorithm) ++ */ ++ ++#include "sm/gm/miracl/miracl.h" ++#include ++ ++void nres_lucas(_MIPD_ big p,big r,big vp,big v) ++{ ++ int i,nb; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(107) ++ ++ if (size(r)==0) ++ { ++ zero(vp); ++ convert(_MIPP_ 2,v); ++ nres(_MIPP_ v,v); ++ MR_OUT ++ return; ++ } ++ if (size(r)==1 || size(r)==(-1)) ++ { /* note - sign of r doesn't matter */ ++ convert(_MIPP_ 2,vp); ++ nres(_MIPP_ vp,vp); ++ copy(p,v); ++ MR_OUT ++ return; ++ } ++ ++ copy(p,mr_mip->w3); ++ ++ convert(_MIPP_ 2,mr_mip->w4); ++ nres(_MIPP_ mr_mip->w4,mr_mip->w4); /* w4=2 */ ++ ++ copy(mr_mip->w4,mr_mip->w8); ++ copy(mr_mip->w3,mr_mip->w9); ++ ++ copy(r,mr_mip->w1); ++ insign(PLUS,mr_mip->w1); ++ decr(_MIPP_ mr_mip->w1,1,mr_mip->w1); ++ ++#ifndef MR_ALWAYS_BINARY ++ if (mr_mip->base==mr_mip->base2) ++ { ++#endif ++ nb=logb2(_MIPP_ mr_mip->w1); ++ for (i=nb-1;i>=0;i--) ++ { ++ if (mr_mip->user!=NULL) (*mr_mip->user)(); ++ ++ if (mr_testbit(_MIPP_ mr_mip->w1,i)) ++ { ++ nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w9,mr_mip->w8); ++ nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w3,mr_mip->w8); ++ nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w9,mr_mip->w9); ++ nres_modsub(_MIPP_ mr_mip->w9,mr_mip->w4,mr_mip->w9); ++ ++ } ++ else ++ { ++ nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w8,mr_mip->w9); ++ nres_modsub(_MIPP_ mr_mip->w9,mr_mip->w3,mr_mip->w9); ++ nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w8); ++ nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w4,mr_mip->w8); ++ } ++ } ++ ++#ifndef MR_ALWAYS_BINARY ++ } ++ else ++ { ++ expb2(_MIPP_ logb2(_MIPP_ mr_mip->w1)-1,mr_mip->w2); ++ ++ while (!mr_mip->ERNUM && size(mr_mip->w2)!=0) ++ { /* use binary method */ ++ if (mr_compare(mr_mip->w1,mr_mip->w2)>=0) ++ { /* vp=v*vp-p, v=v*v-2 */ ++ nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w9,mr_mip->w8); ++ nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w3,mr_mip->w8); ++ nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w9,mr_mip->w9); ++ nres_modsub(_MIPP_ mr_mip->w9,mr_mip->w4,mr_mip->w9); ++ subtract(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w1); ++ } ++ else ++ { /* v=v*vp-p, vp=vp*vp-2 */ ++ nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w8,mr_mip->w9); ++ nres_modsub(_MIPP_ mr_mip->w9,mr_mip->w3,mr_mip->w9); ++ nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w8); ++ nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w4,mr_mip->w8); ++ } ++ subdiv(_MIPP_ mr_mip->w2,2,mr_mip->w2); ++ } ++ } ++#endif ++ ++ copy(mr_mip->w9,v); ++ if (v!=vp) copy(mr_mip->w8,vp); ++ MR_OUT ++ ++} ++ ++void lucas(_MIPD_ big p,big r,big n,big vp,big v) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(108) ++ prepare_monty(_MIPP_ n); ++ nres(_MIPP_ p,mr_mip->w3); ++ nres_lucas(_MIPP_ mr_mip->w3,r,mr_mip->w8,mr_mip->w9); ++ redc(_MIPP_ mr_mip->w9,v); ++ if (v!=vp) redc(_MIPP_ mr_mip->w8,vp); ++ MR_OUT ++} ++ +diff --git a/lib/sbi/sm/gm/miracl/mrmonty.c b/lib/sbi/sm/gm/miracl/mrmonty.c +new file mode 100644 +index 0000000..095719e +--- /dev/null ++++ b/lib/sbi/sm/gm/miracl/mrmonty.c +@@ -0,0 +1,1411 @@ ++ ++/*************************************************************************** ++ * ++Copyright 2013 CertiVox UK Ltd. * ++ * ++This file is part of CertiVox MIRACL Crypto SDK. * ++ * ++The CertiVox MIRACL Crypto SDK provides developers with an * ++extensive and efficient set of cryptographic functions. * ++For further information about its features and functionalities please * ++refer to http://www.certivox.com * ++ * ++* The CertiVox MIRACL Crypto SDK is free software: you can * ++ redistribute it and/or modify it under the terms of the * ++ GNU Affero General Public License as published by the * ++ Free Software Foundation, either version 3 of the License, * ++ or (at your option) any later version. * ++ * ++* The CertiVox MIRACL Crypto SDK is distributed in the hope * ++ that it will be useful, but WITHOUT ANY WARRANTY; without even the * ++ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * ++ See the GNU Affero General Public License for more details. * ++ * ++* You should have received a copy of the GNU Affero General Public * ++ License along with CertiVox MIRACL Crypto SDK. * ++ If not, see . * ++ * ++You can be released from the requirements of the license by purchasing * ++a commercial license. Buying such a license is mandatory as soon as you * ++develop commercial activities involving the CertiVox MIRACL Crypto SDK * ++without disclosing the source code of your own applications, or shipping * ++the CertiVox MIRACL Crypto SDK with a closed source product. * ++ * ++***************************************************************************/ ++/* ++ * MIRACL Montgomery's method for modular arithmetic without division. ++ * mrmonty.c ++ * ++ * Programs to implement Montgomery's method ++ * See "Modular Multiplication Without Trial Division", Math. Comp. ++ * Vol 44, Number 170, April 1985, Pages 519-521 ++ * NOTE - there is an important correction to this paper mentioned as a ++ * footnote in "Speeding the Pollard and Elliptic Curve Methods", ++ * Math. Comput., Vol. 48, January 1987, 243-264 ++ * ++ * The advantage of this approach is that no division required in order ++ * to compute a modular reduction - useful if division is slow ++ * e.g. on a SPARC processor, or a DSP. ++ * ++ * The disadvantage is that numbers must first be converted to an internal ++ * "n-residue" form. ++ * ++ */ ++ ++#include "sm/gm/miracl/miracl.h" ++#include ++ ++#ifdef MR_FP ++#include ++#endif ++ ++#ifdef MR_WIN64 ++#include ++#endif ++ ++#ifdef MR_COUNT_OPS ++extern int fpc,fpa; ++#endif ++ ++#ifdef MR_CELL ++extern void mod256(_MIPD_ big,big); ++#endif ++ ++void kill_monty(_MIPDO_ ) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ zero(mr_mip->modulus); ++#ifdef MR_KCM ++ zero(mr_mip->big_ndash); ++#endif ++} ++ ++mr_small prepare_monty(_MIPD_ big n) ++{ /* prepare Montgomery modulus */ ++#ifdef MR_KCM ++ int nl; ++#endif ++#ifdef MR_PENTIUM ++ mr_small ndash; ++ mr_small base; ++ mr_small magic=13835058055282163712.0; ++ int control=0x1FFF; ++#endif ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return (mr_small)0; ++/* Is it set-up already? */ ++ if (size(mr_mip->modulus)!=0) ++ if (mr_compare(n,mr_mip->modulus)==0) return mr_mip->ndash; ++ ++ MR_IN(80) ++ ++ if (size(n)<=2) ++ { ++ mr_berror(_MIPP_ MR_ERR_BAD_MODULUS); ++ MR_OUT ++ return (mr_small)0; ++ } ++ ++ zero(mr_mip->w6); ++ zero(mr_mip->w15); ++ ++/* set a small negative QNR (on the assumption that n is prime!) */ ++/* These defaults can be over-ridden */ ++ ++/* Did you know that for p=2 mod 3, -3 is a QNR? */ ++ ++ mr_mip->pmod8=remain(_MIPP_ n,8); ++ ++ switch (mr_mip->pmod8) ++ { ++ case 0: ++ case 1: ++ case 2: ++ case 4: ++ case 6: ++ mr_mip->qnr=0; /* none defined */ ++ break; ++ case 3: ++ mr_mip->qnr=-1; ++ break; ++ case 5: ++ mr_mip->qnr=-2; ++ break; ++ case 7: ++ mr_mip->qnr=-1; ++ break; ++ } ++ mr_mip->pmod9=remain(_MIPP_ n,9); ++ ++ mr_mip->NO_CARRY=FALSE; ++ if (n->w[n->len-1]>>M4 < 5) mr_mip->NO_CARRY=TRUE; ++ ++#ifdef MR_PENTIUM ++ ++mr_mip->ACTIVE=FALSE; ++if (mr_mip->base!=0) ++ if (MR_PENTIUM==n->len) mr_mip->ACTIVE=TRUE; ++ if (MR_PENTIUM<0) ++ { ++ if (n->len<=(-MR_PENTIUM)) mr_mip->ACTIVE=TRUE; ++ if (logb2(_MIPP_ n)%mr_mip->lg2b==0) mr_mip->ACTIVE=FALSE; ++ } ++#endif ++ ++#ifdef MR_DISABLE_MONTGOMERY ++ mr_mip->MONTY=OFF; ++#else ++ mr_mip->MONTY=ON; ++#endif ++ ++#ifdef MR_COMBA ++ mr_mip->ACTIVE=FALSE; ++ ++ if (MR_COMBA==n->len && mr_mip->base==mr_mip->base2) ++ { ++ mr_mip->ACTIVE=TRUE; ++#ifdef MR_SPECIAL ++ mr_mip->MONTY=OFF; /* "special" modulus reduction */ ++ ++#endif /* implemented in mrcomba.c */ ++ } ++ ++#endif ++ convert(_MIPP_ 1,mr_mip->one); ++ if (!mr_mip->MONTY) ++ { /* Montgomery arithmetic is turned off */ ++ copy(n,mr_mip->modulus); ++ mr_mip->ndash=0; ++ MR_OUT ++ return (mr_small)0; ++ } ++ ++#ifdef MR_KCM ++ ++/* test for base==0 & n->len=MR_KCM.2^x */ ++ ++ mr_mip->ACTIVE=FALSE; ++ if (mr_mip->base==0) ++ { ++ nl=(int)n->len; ++ while (nl>=MR_KCM) ++ { ++ if (nl==MR_KCM) ++ { ++ mr_mip->ACTIVE=TRUE; ++ break; ++ } ++ if (nl%2!=0) break; ++ nl/=2; ++ } ++ } ++ if (mr_mip->ACTIVE) ++ { ++ mr_mip->w6->len=n->len+1; ++ mr_mip->w6->w[n->len]=1; ++ if (invmodp(_MIPP_ n,mr_mip->w6,mr_mip->w14)!=1) ++ { /* problems */ ++ mr_berror(_MIPP_ MR_ERR_BAD_MODULUS); ++ MR_OUT ++ return (mr_small)0; ++ } ++ } ++ else ++ { ++#endif ++ mr_mip->w6->len=2; ++ mr_mip->w6->w[0]=0; ++ mr_mip->w6->w[1]=1; /* w6 = base */ ++ mr_mip->w15->len=1; ++ mr_mip->w15->w[0]=n->w[0]; /* w15 = n mod base */ ++ if (invmodp(_MIPP_ mr_mip->w15,mr_mip->w6,mr_mip->w14)!=1) ++ { /* problems */ ++ mr_berror(_MIPP_ MR_ERR_BAD_MODULUS); ++ MR_OUT ++ return (mr_small)0; ++ } ++#ifdef MR_KCM ++ } ++ copy(mr_mip->w14,mr_mip->big_ndash); ++#endif ++ ++ mr_mip->ndash=mr_mip->base-mr_mip->w14->w[0]; /* = N' mod b */ ++ copy(n,mr_mip->modulus); ++ mr_mip->check=OFF; ++ mr_shift(_MIPP_ mr_mip->modulus,(int)mr_mip->modulus->len,mr_mip->pR); ++ mr_mip->check=ON; ++#ifdef MR_PENTIUM ++/* prime the FP stack */ ++ if (mr_mip->ACTIVE) ++ { ++ ndash=mr_mip->ndash; ++ base=mr_mip->base; ++ magic *=base; ++ ASM ++ { ++ finit ++ fldcw WORD PTR control ++ fld QWORD PTR ndash ++ fld1 ++ fld QWORD PTR base ++ fdiv ++ fld QWORD PTR magic ++ } ++ } ++#endif ++ nres(_MIPP_ mr_mip->one,mr_mip->one); ++ MR_OUT ++ ++ return mr_mip->ndash; ++} ++ ++void nres(_MIPD_ big x,big y) ++{ /* convert x to n-residue format */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(81) ++ ++ if (size(mr_mip->modulus)==0) ++ { ++ mr_berror(_MIPP_ MR_ERR_NO_MODULUS); ++ MR_OUT ++ return; ++ } ++ copy(x,y); ++ divide(_MIPP_ y,mr_mip->modulus,mr_mip->modulus); ++ if (size(y)<0) add(_MIPP_ y,mr_mip->modulus,y); ++ if (!mr_mip->MONTY) ++ { ++ MR_OUT ++ return; ++ } ++ mr_mip->check=OFF; ++ ++ mr_shift(_MIPP_ y,(int)mr_mip->modulus->len,mr_mip->w0); ++ divide(_MIPP_ mr_mip->w0,mr_mip->modulus,mr_mip->modulus); ++ mr_mip->check=ON; ++ copy(mr_mip->w0,y); ++ ++ MR_OUT ++} ++ ++void redc(_MIPD_ big x,big y) ++{ /* Montgomery's REDC function p. 520 */ ++ /* also used to convert n-residues back to normal form */ ++ mr_small carry,delay_carry,m,ndash; ++ ++#ifdef MR_ITANIUM ++ mr_small tm; ++#endif ++#ifdef MR_WIN64 ++ mr_small tm,tr; ++#endif ++ int i,j,rn,rn2; ++ big w0,modulus; ++#ifdef MR_NOASM ++ union doubleword dble; ++#endif ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(82) ++ ++ w0=mr_mip->w0; /* get these into local variables (for inline assembly) */ ++ modulus=mr_mip->modulus; ++ ndash=mr_mip->ndash; ++ ++ copy(x,w0); ++ if (!mr_mip->MONTY) ++ { ++/*#ifdef MR_CELL ++ mod256(_MIPP_ w0,w0); ++#else */ ++ divide(_MIPP_ w0,modulus,modulus); ++/* #endif */ ++ copy(w0,y); ++ MR_OUT ++ return; ++ } ++ delay_carry=0; ++ rn=(int)modulus->len; ++ rn2=rn+rn; ++#ifndef MR_SIMPLE_BASE ++ if (mr_mip->base==0) ++ { ++#endif ++#ifndef MR_NOFULLWIDTH ++ for (i=0;iw[i],ndash,0,&m); Note that after this time */ ++ m=ndash*w0->w[i]; ++ carry=0; /* around the loop, w0[i]=0 */ ++ ++ for (j=0;jw[j]+carry+w0->w[i+j]; ++ w0->w[i+j]=dble.h[MR_BOT]; ++ carry=dble.h[MR_TOP]; ++#else ++ muldvd2(m,modulus->w[j],&carry,&w0->w[i+j]); ++#endif ++ } ++ w0->w[rn+i]+=delay_carry; ++ if (w0->w[rn+i]w[rn+i]+=carry; ++ if (w0->w[rn+i]w[i],ndash,0,mr_mip->base,mr_mip->inverse_base,&m); ++#else ++ muldiv(w0->w[i],ndash,0,mr_mip->base,&m); ++#endif ++ carry=0; ++ for (j=0;jw[j]+carry+w0->w[i+j]; ++#ifdef MR_FP_ROUNDING ++ carry=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); ++#else ++#ifndef MR_FP ++ if (mr_mip->base==mr_mip->base2) ++ carry=(mr_small)(dbled>>mr_mip->lg2b); ++ else ++#endif ++ carry=(mr_small)MR_LROUND(dbled/mr_mip->base); ++#endif ++ w0->w[i+j]=(mr_small)(dbled-(mr_large)carry*mr_mip->base); ++#else ++#ifdef MR_FP_ROUNDING ++ carry=imuldiv(modulus->w[j],m,w0->w[i+j]+carry,mr_mip->base,mr_mip->inverse_base,&w0->w[i+j]); ++#else ++ carry=muldiv(modulus->w[j],m,w0->w[i+j]+carry,mr_mip->base,&w0->w[i+j]); ++#endif ++#endif ++ } ++ w0->w[rn+i]+=(delay_carry+carry); ++ delay_carry=0; ++ if (w0->w[rn+i]>=mr_mip->base) ++ { ++ w0->w[rn+i]-=mr_mip->base; ++ delay_carry=1; ++ } ++ } ++#endif ++ w0->w[rn2]=delay_carry; ++ w0->len=rn2+1; ++ mr_shift(_MIPP_ w0,(-rn),w0); ++ mr_lzero(w0); ++ ++ if (mr_compare(w0,modulus)>=0) mr_psub(_MIPP_ w0,modulus,w0); ++ copy(w0,y); ++ MR_OUT ++} ++ ++/* "Complex" method for ZZn2 squaring */ ++ ++void nres_complex(_MIPD_ big a,big b,big r,big i) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ MR_IN(225) ++ ++ if (mr_mip->NO_CARRY && mr_mip->qnr==-1) ++ { /* if modulus is small enough we can ignore carries, and use simple addition and subtraction */ ++ /* recall that Montgomery reduction can cope as long as product is less than pR */ ++#ifdef MR_COMBA ++#ifdef MR_COUNT_OPS ++fpa+=3; ++#endif ++ if (mr_mip->ACTIVE) ++ { ++ comba_add(a,b,mr_mip->w1); ++ comba_add(a,mr_mip->modulus,mr_mip->w2); /* a-b is p+a-b */ ++ comba_sub(mr_mip->w2,b,mr_mip->w2); ++ comba_add(a,a,r); ++ } ++ else ++ { ++#endif ++ mr_padd(_MIPP_ a,b,mr_mip->w1); ++ mr_padd(_MIPP_ a,mr_mip->modulus,mr_mip->w2); ++ mr_psub(_MIPP_ mr_mip->w2,b,mr_mip->w2); ++ mr_padd(_MIPP_ a,a,r); ++#ifdef MR_COMBA ++ } ++#endif ++ nres_modmult(_MIPP_ r,b,i); ++ nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w2,r); ++ } ++ else ++ { ++ nres_modadd(_MIPP_ a,b,mr_mip->w1); ++ nres_modsub(_MIPP_ a,b,mr_mip->w2); ++ ++ if (mr_mip->qnr==-2) ++ nres_modsub(_MIPP_ mr_mip->w2,b,mr_mip->w2); ++ ++ nres_modmult(_MIPP_ a,b,i); ++ nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w2,r); ++ ++ if (mr_mip->qnr==-2) ++ nres_modadd(_MIPP_ r,i,r); ++ ++ nres_modadd(_MIPP_ i,i,i); ++ } ++ MR_OUT ++} ++ ++#ifndef MR_NO_LAZY_REDUCTION ++ ++/* ++ ++Lazy reduction technique for zzn2 multiplication - competitive if Reduction is more ++expensive that Multiplication. This is true for pairing-based crypto. Note that ++Lazy reduction can also be used with Karatsuba! Uses w1, w2, w5, and w6. ++ ++Reduction poly is X^2-D=0 ++ ++(a0+a1.X).(b0+b1.X) = (a0.b0 + D.a1.b1) + (a1.b0+a0.b1).X ++ ++Karatsuba ++ ++ (a0.b0+D.a1.b1) + ((a0+a1)(b0+b1) - a0.b0 - a1.b1).X ++*/ ++ ++void nres_lazy(_MIPD_ big a0,big a1,big b0,big b1,big r,big i) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ mr_mip->check=OFF; ++#ifdef MR_COUNT_OPS ++fpc+=3; ++fpa+=5; ++if (mr_mip->qnr==-2) fpa++; ++#endif ++ ++#ifdef MR_COMBA ++ if (mr_mip->ACTIVE) ++ { ++ comba_mult(a0,b0,mr_mip->w0); ++ comba_mult(a1,b1,mr_mip->w5); ++ } ++ else ++ { ++#endif ++#ifdef MR_KCM ++ if (mr_mip->ACTIVE) ++ { ++ kcm_mul(_MIPP_ a1,b1,mr_mip->w5); /* this destroys w0! */ ++ kcm_mul(_MIPP_ a0,b0,mr_mip->w0); ++ } ++ else ++ { ++#endif ++ MR_IN(151) ++ multiply(_MIPP_ a0,b0,mr_mip->w0); ++ multiply(_MIPP_ a1,b1,mr_mip->w5); ++#ifdef MR_COMBA ++ } ++#endif ++#ifdef MR_KCM ++ } ++#endif ++ ++ if (mr_mip->NO_CARRY && mr_mip->qnr==-1) ++ { /* if modulus is small enough we can ignore carries, and use simple addition and subtraction */ ++#ifdef MR_COMBA ++#ifdef MR_COUNT_OPS ++fpa+=2; ++#endif ++ if (mr_mip->ACTIVE) ++ { ++ comba_double_add(mr_mip->w0,mr_mip->w5,mr_mip->w6); ++ comba_add(a0,a1,mr_mip->w1); ++ comba_add(b0,b1,mr_mip->w2); ++ } ++ else ++ { ++#endif ++ mr_padd(_MIPP_ mr_mip->w0,mr_mip->w5,mr_mip->w6); ++ mr_padd(_MIPP_ a0,a1,mr_mip->w1); ++ mr_padd(_MIPP_ b0,b1,mr_mip->w2); ++#ifdef MR_COMBA ++ } ++#endif ++ } ++ else ++ { ++ nres_double_modadd(_MIPP_ mr_mip->w0,mr_mip->w5,mr_mip->w6); /* w6 = a0.b0+a1.b1 */ ++ if (mr_mip->qnr==-2) ++ nres_double_modadd(_MIPP_ mr_mip->w5,mr_mip->w5,mr_mip->w5); ++ nres_modadd(_MIPP_ a0,a1,mr_mip->w1); ++ nres_modadd(_MIPP_ b0,b1,mr_mip->w2); ++ } ++ nres_double_modsub(_MIPP_ mr_mip->w0,mr_mip->w5,mr_mip->w0); /* r = a0.b0+D.a1.b1 */ ++ ++#ifdef MR_COMBA ++ if (mr_mip->ACTIVE) ++ { ++ comba_redc(_MIPP_ mr_mip->w0,r); ++ comba_mult(mr_mip->w1,mr_mip->w2,mr_mip->w0); ++ } ++ else ++ { ++#endif ++#ifdef MR_KCM ++ if (mr_mip->ACTIVE) ++ { ++ kcm_redc(_MIPP_ mr_mip->w0,r); ++ kcm_mul(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w0); ++ } ++ else ++ { ++#endif ++ redc(_MIPP_ mr_mip->w0,r); ++ multiply(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w0); /* w0=(a0+a1)*(b0+b1) */ ++#ifdef MR_COMBA ++ } ++#endif ++#ifdef MR_KCM ++ } ++#endif ++ ++ if (mr_mip->NO_CARRY && mr_mip->qnr==-1) ++ { ++#ifdef MR_COMBA ++ if (mr_mip->ACTIVE) ++ comba_double_sub(mr_mip->w0,mr_mip->w6,mr_mip->w0); ++ else ++#endif ++ mr_psub(_MIPP_ mr_mip->w0,mr_mip->w6,mr_mip->w0); ++ } ++ else ++ nres_double_modsub(_MIPP_ mr_mip->w0,mr_mip->w6,mr_mip->w0); /* (a0+a1)*(b0+b1) - w6 */ ++ ++#ifdef MR_COMBA ++ if (mr_mip->ACTIVE) ++ { ++ comba_redc(_MIPP_ mr_mip->w0,i); ++ } ++ else ++ { ++#endif ++#ifdef MR_KCM ++ if (mr_mip->ACTIVE) ++ { ++ kcm_redc(_MIPP_ mr_mip->w0,i); ++ } ++ else ++ { ++#endif ++ redc(_MIPP_ mr_mip->w0,i); ++ MR_OUT ++#ifdef MR_COMBA ++ } ++#endif ++#ifdef MR_KCM ++ } ++#endif ++ ++ mr_mip->check=ON; ++ ++} ++ ++#endif ++ ++#ifndef MR_STATIC ++ ++void nres_dotprod(_MIPD_ int n,big *x,big *y,big w) ++{ ++ int i; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ if (mr_mip->ERNUM) return; ++ MR_IN(120) ++ mr_mip->check=OFF; ++ zero(mr_mip->w7); ++ for (i=0;iw0); ++ mr_padd(_MIPP_ mr_mip->w7,mr_mip->w0,mr_mip->w7); ++ } ++ copy(mr_mip->pR,mr_mip->w6); ++ /* w6 = p.R */ ++ divide(_MIPP_ mr_mip->w7,mr_mip->w6,mr_mip->w6); ++ redc(_MIPP_ mr_mip->w7,w); ++ ++ mr_mip->check=ON; ++ MR_OUT ++} ++ ++#endif ++ ++void nres_negate(_MIPD_ big x, big w) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (size(x)==0) ++ { ++ zero(w); ++ return; ++ } ++#ifdef MR_COMBA ++ if (mr_mip->ACTIVE) ++ { ++ comba_negate(_MIPP_ x,w); ++ return; ++ } ++ else ++ { ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(92) ++ mr_psub(_MIPP_ mr_mip->modulus,x,w); ++ MR_OUT ++ ++#ifdef MR_COMBA ++ } ++#endif ++ ++} ++ ++void nres_div2(_MIPD_ big x,big w) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ MR_IN(198) ++ copy(x,mr_mip->w1); ++ if (remain(_MIPP_ mr_mip->w1,2)!=0) ++ add(_MIPP_ mr_mip->w1,mr_mip->modulus,mr_mip->w1); ++ subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1); ++ copy(mr_mip->w1,w); ++ ++ MR_OUT ++} ++ ++void nres_div3(_MIPD_ big x,big w) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ MR_IN(199) ++ copy(x,mr_mip->w1); ++ while (remain(_MIPP_ mr_mip->w1,3)!=0) ++ add(_MIPP_ mr_mip->w1,mr_mip->modulus,mr_mip->w1); ++ subdiv(_MIPP_ mr_mip->w1,3,mr_mip->w1); ++ copy(mr_mip->w1,w); ++ ++ MR_OUT ++} ++ ++void nres_div5(_MIPD_ big x,big w) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ MR_IN(208) ++ copy(x,mr_mip->w1); ++ while (remain(_MIPP_ mr_mip->w1,5)!=0) ++ add(_MIPP_ mr_mip->w1,mr_mip->modulus,mr_mip->w1); ++ subdiv(_MIPP_ mr_mip->w1,5,mr_mip->w1); ++ copy(mr_mip->w1,w); ++ ++ MR_OUT ++} ++ ++/* mod pR addition and subtraction */ ++#ifndef MR_NO_LAZY_REDUCTION ++ ++void nres_double_modadd(_MIPD_ big x,big y,big w) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++#ifdef MR_COMBA ++ ++ if (mr_mip->ACTIVE) ++ { ++ comba_double_modadd(_MIPP_ x,y,w); ++ return; ++ } ++ else ++ { ++#endif ++ ++ if (mr_mip->ERNUM) return; ++ MR_IN(153) ++ ++ mr_padd(_MIPP_ x,y,w); ++ if (mr_compare(w,mr_mip->pR)>=0) ++ mr_psub(_MIPP_ w,mr_mip->pR,w); ++ ++ MR_OUT ++#ifdef MR_COMBA ++ } ++#endif ++} ++ ++void nres_double_modsub(_MIPD_ big x,big y,big w) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++#ifdef MR_COMBA ++ ++ if (mr_mip->ACTIVE) ++ { ++ comba_double_modsub(_MIPP_ x,y,w); ++ return; ++ } ++ else ++ { ++#endif ++ ++ if (mr_mip->ERNUM) return; ++ MR_IN(154) ++ ++ if (mr_compare(x,y)>=0) ++ mr_psub(_MIPP_ x,y,w); ++ else ++ { ++ mr_psub(_MIPP_ y,x,w); ++ mr_psub(_MIPP_ mr_mip->pR,w,w); ++ } ++ ++ MR_OUT ++#ifdef MR_COMBA ++ } ++#endif ++} ++ ++#endif ++ ++void nres_modadd(_MIPD_ big x,big y,big w) ++{ /* modular addition */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++#ifdef MR_COUNT_OPS ++fpa++; ++#endif ++#ifdef MR_COMBA ++ ++ if (mr_mip->ACTIVE) ++ { ++ comba_modadd(_MIPP_ x,y,w); ++ return; ++ } ++ else ++ { ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(90) ++ mr_padd(_MIPP_ x,y,w); ++ if (mr_compare(w,mr_mip->modulus)>=0) mr_psub(_MIPP_ w,mr_mip->modulus,w); ++ ++ MR_OUT ++#ifdef MR_COMBA ++ } ++#endif ++} ++ ++void nres_modsub(_MIPD_ big x,big y,big w) ++{ /* modular subtraction */ ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++#ifdef MR_COUNT_OPS ++fpa++; ++#endif ++#ifdef MR_COMBA ++ if (mr_mip->ACTIVE) ++ { ++ comba_modsub(_MIPP_ x,y,w); ++ return; ++ } ++ else ++ { ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(91) ++ ++ if (mr_compare(x,y)>=0) ++ mr_psub(_MIPP_ x,y,w); ++ else ++ { ++ mr_psub(_MIPP_ y,x,w); ++ mr_psub(_MIPP_ mr_mip->modulus,w,w); ++ } ++ ++ MR_OUT ++#ifdef MR_COMBA ++ } ++#endif ++ ++} ++ ++int nres_moddiv(_MIPD_ big x,big y,big w) ++{ /* Modular division using n-residues w=x/y mod n */ ++ int gcd; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return 0; ++ ++ MR_IN(85) ++ ++ if (x==y) ++ { /* Illegal parameter usage */ ++ mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); ++ MR_OUT ++ ++ return 0; ++ } ++ redc(_MIPP_ y,mr_mip->w6); ++ gcd=invmodp(_MIPP_ mr_mip->w6,mr_mip->modulus,mr_mip->w6); ++ ++ if (gcd!=1) zero(w); /* fails silently and returns 0 */ ++ else ++ { ++ nres(_MIPP_ mr_mip->w6,mr_mip->w6); ++ nres_modmult(_MIPP_ x,mr_mip->w6,w); ++ /* mad(_MIPP_ x,mr_mip->w6,x,mr_mip->modulus,mr_mip->modulus,w); */ ++ } ++ MR_OUT ++ return gcd; ++} ++ ++void nres_premult(_MIPD_ big x,int k,big w) ++{ /* multiply n-residue by small ordinary integer */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ int sign=0; ++ if (k==0) ++ { ++ zero(w); ++ return; ++ } ++ if (k<0) ++ { ++ k=-k; ++ sign=1; ++ } ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(102) ++ ++ if (k<=6) ++ { ++ switch (k) ++ { ++ case 1: copy(x,w); ++ break; ++ case 2: nres_modadd(_MIPP_ x,x,w); ++ break; ++ case 3: ++ nres_modadd(_MIPP_ x,x,mr_mip->w0); ++ nres_modadd(_MIPP_ x,mr_mip->w0,w); ++ break; ++ case 4: ++ nres_modadd(_MIPP_ x,x,w); ++ nres_modadd(_MIPP_ w,w,w); ++ break; ++ case 5: ++ nres_modadd(_MIPP_ x,x,mr_mip->w0); ++ nres_modadd(_MIPP_ mr_mip->w0,mr_mip->w0,mr_mip->w0); ++ nres_modadd(_MIPP_ x,mr_mip->w0,w); ++ break; ++ case 6: ++ nres_modadd(_MIPP_ x,x,w); ++ nres_modadd(_MIPP_ w,w,mr_mip->w0); ++ nres_modadd(_MIPP_ w,mr_mip->w0,w); ++ break; ++ } ++ if (sign==1) nres_negate(_MIPP_ w,w); ++ MR_OUT ++ return; ++ } ++ ++ mr_pmul(_MIPP_ x,(mr_small)k,mr_mip->w0); ++#ifdef MR_COMBA ++#ifdef MR_SPECIAL ++ comba_redc(_MIPP_ mr_mip->w0,w); ++#else ++ divide(_MIPP_ mr_mip->w0,mr_mip->modulus,mr_mip->modulus); ++ copy(mr_mip->w0,w); ++#endif ++#else ++ divide(_MIPP_ mr_mip->w0,mr_mip->modulus,mr_mip->modulus); ++ copy(mr_mip->w0,w); ++#endif ++ ++ if (sign==1) nres_negate(_MIPP_ w,w); ++ ++ MR_OUT ++} ++ ++void nres_modmult(_MIPD_ big x,big y,big w) ++{ /* Modular multiplication using n-residues w=x*y mod n */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if ((x==NULL || x->len==0) && x==w) return; ++ if ((y==NULL || y->len==0) && y==w) return; ++ if (y==NULL || x==NULL || x->len==0 || y->len==0) ++ { ++ zero(w); ++ return; ++ } ++#ifdef MR_COUNT_OPS ++fpc++; ++#endif ++#ifdef MR_COMBA ++ if (mr_mip->ACTIVE) ++ { ++ if (x==y) comba_square(x,mr_mip->w0); ++ else comba_mult(x,y,mr_mip->w0); ++ comba_redc(_MIPP_ mr_mip->w0,w); ++ } ++ else ++ { ++#endif ++#ifdef MR_KCM ++ if (mr_mip->ACTIVE) ++ { ++ if (x==y) kcm_sqr(_MIPP_ x,mr_mip->w0); ++ else kcm_mul(_MIPP_ x,y,mr_mip->w0); ++ kcm_redc(_MIPP_ mr_mip->w0,w); ++ } ++ else ++ { ++#endif ++#ifdef MR_PENTIUM ++ if (mr_mip->ACTIVE) ++ { ++ if (x==y) fastmodsquare(_MIPP_ x,w); ++ else fastmodmult(_MIPP_ x,y,w); ++ } ++ else ++ { ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(83) ++ ++ mr_mip->check=OFF; ++ multiply(_MIPP_ x,y,mr_mip->w0); ++ redc(_MIPP_ mr_mip->w0,w); ++ mr_mip->check=ON; ++ MR_OUT ++#ifdef MR_COMBA ++} ++#endif ++#ifdef MR_KCM ++} ++#endif ++#ifdef MR_PENTIUM ++} ++#endif ++ ++} ++ ++/* Montgomery's trick for finding multiple * ++ * simultaneous modular inverses * ++ * Based on the observation that * ++ * 1/x = yz*(1/xyz) * ++ * 1/y = xz*(1/xyz) * ++ * 1/z = xy*(1/xyz) * ++ * Why are all of Peter Montgomery's clever * ++ * algorithms always described as "tricks" ??*/ ++ ++BOOL nres_double_inverse(_MIPD_ big x,big y,big w,big z) ++{ /* find y=1/x mod n and z=1/w mod n */ ++ /* 1/x = w/xw, and 1/w = x/xw */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ MR_IN(145) ++ ++ nres_modmult(_MIPP_ x,w,mr_mip->w6); /* xw */ ++ ++ if (size(mr_mip->w6)==0) ++ { ++ mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); ++ MR_OUT ++ return FALSE; ++ } ++ redc(_MIPP_ mr_mip->w6,mr_mip->w6); ++ redc(_MIPP_ mr_mip->w6,mr_mip->w6); ++ invmodp(_MIPP_ mr_mip->w6,mr_mip->modulus,mr_mip->w6); ++ ++ nres_modmult(_MIPP_ w,mr_mip->w6,mr_mip->w5); ++ nres_modmult(_MIPP_ x,mr_mip->w6,z); ++ copy(mr_mip->w5,y); ++ ++ MR_OUT ++ return TRUE; ++} ++ ++BOOL nres_multi_inverse(_MIPD_ int m,big *x,big *w) ++{ /* find w[i]=1/x[i] mod n, for i=0 to m-1 * ++ * x and w MUST be distinct */ ++ int i; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (m==0) return TRUE; ++ if (m<0) return FALSE; ++ MR_IN(118) ++ ++ if (x==w) ++ { ++ mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); ++ MR_OUT ++ return FALSE; ++ } ++ ++ if (m==1) ++ { ++ copy(mr_mip->one,w[0]); ++ nres_moddiv(_MIPP_ w[0],x[0],w[0]); ++ MR_OUT ++ return TRUE; ++ } ++ ++ convert(_MIPP_ 1,w[0]); ++ copy(x[0],w[1]); ++ for (i=2;iw6); /* y=x[0]*x[1]*x[2]....x[m-1] */ ++ if (size(mr_mip->w6)==0) ++ { ++ mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); ++ MR_OUT ++ return FALSE; ++ } ++ ++ redc(_MIPP_ mr_mip->w6,mr_mip->w6); ++ redc(_MIPP_ mr_mip->w6,mr_mip->w6); ++ ++ invmodp(_MIPP_ mr_mip->w6,mr_mip->modulus,mr_mip->w6); ++ ++/* Now y=1/y */ ++ ++ copy(x[m-1],mr_mip->w5); ++ nres_modmult(_MIPP_ w[m-1],mr_mip->w6,w[m-1]); ++ ++ for (i=m-2;;i--) ++ { ++ if (i==0) ++ { ++ nres_modmult(_MIPP_ mr_mip->w5,mr_mip->w6,w[0]); ++ break; ++ } ++ nres_modmult(_MIPP_ w[i],mr_mip->w5,w[i]); ++ nres_modmult(_MIPP_ w[i],mr_mip->w6,w[i]); ++ nres_modmult(_MIPP_ mr_mip->w5,x[i],mr_mip->w5); ++ } ++ ++ MR_OUT ++ return TRUE; ++} ++ ++/* initialise elliptic curve */ ++ ++void ecurve_init(_MIPD_ big a,big b,big p,int type) ++{ /* Initialize the active ecurve * ++ * Asize indicate size of A * ++ * Bsize indicate size of B */ ++ int as; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(93) ++ ++#ifndef MR_NO_SS ++ mr_mip->SS=FALSE; /* no special support for super-singular curves */ ++#endif ++ ++ prepare_monty(_MIPP_ p); ++ ++ mr_mip->Asize=size(a); ++ if (mr_abs(mr_mip->Asize)==MR_TOOBIG) ++ { ++ if (mr_mip->Asize>=0) ++ { /* big positive number - check it isn't minus something small */ ++ copy(a,mr_mip->w1); ++ divide(_MIPP_ mr_mip->w1,p,p); ++ subtract(_MIPP_ p,mr_mip->w1,mr_mip->w1); ++ as=size(mr_mip->w1); ++ if (asAsize=-as; ++ } ++ } ++ nres(_MIPP_ a,mr_mip->A); ++ ++ mr_mip->Bsize=size(b); ++ if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) ++ { ++ if (mr_mip->Bsize>=0) ++ { /* big positive number - check it isn't minus something small */ ++ copy(b,mr_mip->w1); ++ divide(_MIPP_ mr_mip->w1,p,p); ++ subtract(_MIPP_ p,mr_mip->w1,mr_mip->w1); ++ as=size(mr_mip->w1); ++ if (asBsize=-as; ++ } ++ } ++ ++ nres(_MIPP_ b,mr_mip->B); ++#ifdef MR_EDWARDS ++ mr_mip->coord=MR_PROJECTIVE; /* only type supported for Edwards curves */ ++#else ++#ifndef MR_AFFINE_ONLY ++ if (type==MR_BEST) mr_mip->coord=MR_PROJECTIVE; ++ else mr_mip->coord=type; ++#else ++ if (type==MR_PROJECTIVE) ++ mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); ++#endif ++#endif ++ MR_OUT ++ return; ++} +diff --git a/lib/sbi/sm/gm/miracl/mrrand.c b/lib/sbi/sm/gm/miracl/mrrand.c +new file mode 100644 +index 0000000..31ca796 +--- /dev/null ++++ b/lib/sbi/sm/gm/miracl/mrrand.c +@@ -0,0 +1,110 @@ ++ ++/*************************************************************************** ++ * ++Copyright 2013 CertiVox UK Ltd. * ++ * ++This file is part of CertiVox MIRACL Crypto SDK. * ++ * ++The CertiVox MIRACL Crypto SDK provides developers with an * ++extensive and efficient set of cryptographic functions. * ++For further information about its features and functionalities please * ++refer to http://www.certivox.com * ++ * ++* The CertiVox MIRACL Crypto SDK is free software: you can * ++ redistribute it and/or modify it under the terms of the * ++ GNU Affero General Public License as published by the * ++ Free Software Foundation, either version 3 of the License, * ++ or (at your option) any later version. * ++ * ++* The CertiVox MIRACL Crypto SDK is distributed in the hope * ++ that it will be useful, but WITHOUT ANY WARRANTY; without even the * ++ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * ++ See the GNU Affero General Public License for more details. * ++ * ++* You should have received a copy of the GNU Affero General Public * ++ License along with CertiVox MIRACL Crypto SDK. * ++ If not, see . * ++ * ++You can be released from the requirements of the license by purchasing * ++a commercial license. Buying such a license is mandatory as soon as you * ++develop commercial activities involving the CertiVox MIRACL Crypto SDK * ++without disclosing the source code of your own applications, or shipping * ++the CertiVox MIRACL Crypto SDK with a closed source product. * ++ * ++***************************************************************************/ ++/* ++ * MIRACL random number routines ++ * mrrand.c ++ */ ++ ++#include "sm/gm/miracl/miracl.h" ++ ++#ifdef MR_FP ++#include ++#endif ++ ++#ifndef MR_NO_RAND ++ ++void bigrand(_MIPD_ big w,big x) ++{ /* generate a big random number 0<=xERNUM) return; ++ ++ MR_IN(20) ++ ++ /* decr(_MIPP_ w,2,w); */ ++ m=0; ++ zero(mr_mip->w0); ++ ++ do ++ { /* create big rand piece by piece */ ++ m++; ++ mr_mip->w0->len=m; ++ r=brand(_MIPPO_ ); ++ if (mr_mip->base==0) mr_mip->w0->w[m-1]=r; ++ else mr_mip->w0->w[m-1]=MR_REMAIN(r,mr_mip->base); ++ } while (mr_compare(mr_mip->w0,w)<0); ++ mr_lzero(mr_mip->w0); ++ divide(_MIPP_ mr_mip->w0,w,w); ++ ++ copy(mr_mip->w0,x); ++ /* incr(_MIPP_ x,2,x); ++ if (w!=x) incr(_MIPP_ w,2,w); */ ++ MR_OUT ++} ++ ++void bigdig(_MIPD_ int n,int b,big x) ++{ /* generate random number n digits long * ++ * to "printable" base b */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return; ++ ++ MR_IN(19) ++ ++ if (b<2 || b>256) ++ { ++ mr_berror(_MIPP_ MR_ERR_BASE_TOO_BIG); ++ MR_OUT ++ return; ++ } ++ ++ do ++ { /* repeat if x too small */ ++ expint(_MIPP_ b,n,mr_mip->w1); ++ bigrand(_MIPP_ mr_mip->w1,x); ++ subdiv(_MIPP_ mr_mip->w1,b,mr_mip->w1); ++ } while (!mr_mip->ERNUM && mr_compare(x,mr_mip->w1)<0); ++ ++ MR_OUT ++} ++ ++#endif +diff --git a/lib/sbi/sm/gm/miracl/mrsroot.c b/lib/sbi/sm/gm/miracl/mrsroot.c +new file mode 100644 +index 0000000..de1c0e4 +--- /dev/null ++++ b/lib/sbi/sm/gm/miracl/mrsroot.c +@@ -0,0 +1,188 @@ ++ ++/*************************************************************************** ++ * ++Copyright 2013 CertiVox UK Ltd. * ++ * ++This file is part of CertiVox MIRACL Crypto SDK. * ++ * ++The CertiVox MIRACL Crypto SDK provides developers with an * ++extensive and efficient set of cryptographic functions. * ++For further information about its features and functionalities please * ++refer to http://www.certivox.com * ++ * ++* The CertiVox MIRACL Crypto SDK is free software: you can * ++ redistribute it and/or modify it under the terms of the * ++ GNU Affero General Public License as published by the * ++ Free Software Foundation, either version 3 of the License, * ++ or (at your option) any later version. * ++ * ++* The CertiVox MIRACL Crypto SDK is distributed in the hope * ++ that it will be useful, but WITHOUT ANY WARRANTY; without even the * ++ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * ++ See the GNU Affero General Public License for more details. * ++ * ++* You should have received a copy of the GNU Affero General Public * ++ License along with CertiVox MIRACL Crypto SDK. * ++ If not, see . * ++ * ++You can be released from the requirements of the license by purchasing * ++a commercial license. Buying such a license is mandatory as soon as you * ++develop commercial activities involving the CertiVox MIRACL Crypto SDK * ++without disclosing the source code of your own applications, or shipping * ++the CertiVox MIRACL Crypto SDK with a closed source product. * ++ * ++***************************************************************************/ ++/* ++ * MIRACL method for modular square root ++ * mrsroot.c ++ * ++ * Siguna Mueller's O(lg(p)^3) algorithm, Designs Codes and Cryptography, 2004 ++ * ++ * This is a little slower for p=1 mod 4 primes, but its not time critical, and ++ * more importantly it doesn't pull in the large powmod code into elliptic curve programs ++ * It does require code from mrjack.c and mrlucas.c ++ * ++ * If p=3 mod 4, then sqrt(a)=a^[(p+1)/4] mod p. Note that for many elliptic curves ++ * (p+1)/4 has very low hamming weight. ++ * ++ * (was sqrt(a) = V_{(p+1)/4}(a+1/a,1)/(1+1/a)) ++ * ++ * Mueller's method is also very simple, uses very little memory, and it works just fine for p=1 mod 8 primes ++ * (for example the "annoying" NIST modulus 2^224-2^96+1) ++ * Also doesn't waste time on non-squares, as a jacobi test is done first ++ * ++ * If you know that the prime is 3 mod 4, and you know that x is almost certainly a QR ++ * then the jacobi-dependent code can be deleted with some space savings. ++ * ++ * NOTE - IF p IS NOT PRIME, THIS CODE WILL FAIL SILENTLY! ++ * ++ */ ++ ++#include "sm/gm/miracl/miracl.h" ++#include ++ ++BOOL nres_sqroot(_MIPD_ big x,big w) ++{ /* w=sqrt(x) mod p. This depends on p being prime! */ ++ int t,js; ++ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return FALSE; ++ ++ copy(x,w); ++ if (size(w)==0) return TRUE; ++ ++ MR_IN(100) ++ ++ redc(_MIPP_ w,w); /* get it back into normal form */ ++ ++ if (size(w)==1) /* square root of 1 is 1 */ ++ { ++ nres(_MIPP_ w,w); ++ MR_OUT ++ return TRUE; ++ } ++ ++ if (size(w)==4) /* square root of 4 is 2 */ ++ { ++ convert(_MIPP_ 2,w); ++ nres(_MIPP_ w,w); ++ MR_OUT ++ return TRUE; ++ } ++ ++ if (jack(_MIPP_ w,mr_mip->modulus)!=1) ++ { /* Jacobi test */ ++ zero(w); ++ MR_OUT ++ return FALSE; ++ } ++ ++ js=mr_mip->pmod8%4-2; /* 1 mod 4 or 3 mod 4 prime? */ ++ ++ incr(_MIPP_ mr_mip->modulus,js,mr_mip->w10); ++ subdiv(_MIPP_ mr_mip->w10,4,mr_mip->w10); /* (p+/-1)/4 */ ++ ++ if (js==1) ++ { /* 3 mod 4 primes - do a quick and dirty sqrt(x)=x^(p+1)/4 mod p */ ++ nres(_MIPP_ w,mr_mip->w2); ++ copy(mr_mip->one,w); ++ forever ++ { /* Simple Right-to-Left exponentiation */ ++ ++ if (mr_mip->user!=NULL) (*mr_mip->user)(); ++ if (subdiv(_MIPP_ mr_mip->w10,2,mr_mip->w10)!=0) ++ nres_modmult(_MIPP_ w,mr_mip->w2,w); ++ if (mr_mip->ERNUM || size(mr_mip->w10)==0) break; ++ nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w2); ++ } ++ ++ /* nres_moddiv(_MIPP_ mr_mip->one,w,mr_mip->w11); ++ nres_modadd(_MIPP_ mr_mip->w11,w,mr_mip->w3); ++ nres_lucas(_MIPP_ mr_mip->w3,mr_mip->w10,w,w); ++ nres_modadd(_MIPP_ mr_mip->w11,mr_mip->one,mr_mip->w11); ++ nres_moddiv(_MIPP_ w,mr_mip->w11,w); */ ++ } ++ else ++ { /* 1 mod 4 primes */ ++ for (t=1; ;t++) ++ { /* t=1.5 on average */ ++ if (t==1) copy(w,mr_mip->w4); ++ else ++ { ++ premult(_MIPP_ w,t,mr_mip->w4); ++ divide(_MIPP_ mr_mip->w4,mr_mip->modulus,mr_mip->modulus); ++ premult(_MIPP_ mr_mip->w4,t,mr_mip->w4); ++ divide(_MIPP_ mr_mip->w4,mr_mip->modulus,mr_mip->modulus); ++ } ++ ++ decr(_MIPP_ mr_mip->w4,4,mr_mip->w1); ++ if (jack(_MIPP_ mr_mip->w1,mr_mip->modulus)==js) break; ++ if (mr_mip->ERNUM) break; ++ } ++ ++ decr(_MIPP_ mr_mip->w4,2,mr_mip->w3); ++ nres(_MIPP_ mr_mip->w3,mr_mip->w3); ++ nres_lucas(_MIPP_ mr_mip->w3,mr_mip->w10,w,w); /* heavy lifting done here */ ++ if (t!=1) ++ { ++ convert(_MIPP_ t,mr_mip->w11); ++ nres(_MIPP_ mr_mip->w11,mr_mip->w11); ++ nres_moddiv(_MIPP_ w,mr_mip->w11,w); ++ } ++ } ++ ++ MR_OUT ++ return TRUE; ++} ++ ++BOOL sqroot(_MIPD_ big x,big p,big w) ++{ /* w = sqrt(x) mod p */ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (mr_mip->ERNUM) return FALSE; ++ ++ MR_IN(101) ++ ++ if (subdivisible(_MIPP_ p,2)) ++ { /* p must be odd */ ++ zero(w); ++ MR_OUT ++ return FALSE; ++ } ++ ++ prepare_monty(_MIPP_ p); ++ nres(_MIPP_ x,w); ++ if (nres_sqroot(_MIPP_ w,w)) ++ { ++ redc(_MIPP_ w,w); ++ MR_OUT ++ return TRUE; ++ } ++ ++ zero(w); ++ MR_OUT ++ return FALSE; ++} +diff --git a/lib/sbi/sm/gm/miracl/mrxgcd.c b/lib/sbi/sm/gm/miracl/mrxgcd.c +new file mode 100644 +index 0000000..eaf1066 +--- /dev/null ++++ b/lib/sbi/sm/gm/miracl/mrxgcd.c +@@ -0,0 +1,495 @@ ++ ++/*************************************************************************** ++ * ++Copyright 2013 CertiVox UK Ltd. * ++ * ++This file is part of CertiVox MIRACL Crypto SDK. * ++ * ++The CertiVox MIRACL Crypto SDK provides developers with an * ++extensive and efficient set of cryptographic functions. * ++For further information about its features and functionalities please * ++refer to http://www.certivox.com * ++ * ++* The CertiVox MIRACL Crypto SDK is free software: you can * ++ redistribute it and/or modify it under the terms of the * ++ GNU Affero General Public License as published by the * ++ Free Software Foundation, either version 3 of the License, * ++ or (at your option) any later version. * ++ * ++* The CertiVox MIRACL Crypto SDK is distributed in the hope * ++ that it will be useful, but WITHOUT ANY WARRANTY; without even the * ++ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * ++ See the GNU Affero General Public License for more details. * ++ * ++* You should have received a copy of the GNU Affero General Public * ++ License along with CertiVox MIRACL Crypto SDK. * ++ If not, see . * ++ * ++You can be released from the requirements of the license by purchasing * ++a commercial license. Buying such a license is mandatory as soon as you * ++develop commercial activities involving the CertiVox MIRACL Crypto SDK * ++without disclosing the source code of your own applications, or shipping * ++the CertiVox MIRACL Crypto SDK with a closed source product. * ++ * ++***************************************************************************/ ++/* ++ * MIRACL Extended Greatest Common Divisor module. ++ * mrxgcd.c ++ */ ++ ++#include "sm/gm/miracl/miracl.h" ++ ++#ifdef MR_FP ++#include ++#endif ++ ++#ifdef MR_COUNT_OPS ++extern int fpx; ++#endif ++ ++#ifndef MR_USE_BINARY_XGCD ++ ++#ifdef mr_dltype ++ ++static mr_small qdiv(mr_large u,mr_large v) ++{ /* fast division - small quotient expected. */ ++ mr_large lq,x=u; ++#ifdef MR_FP ++ mr_small dres; ++#endif ++ x-=v; ++ if (x=MAXBASE) return 0; ++ return (mr_small)lq; ++} ++ ++#else ++ ++static mr_small qdiv(mr_small u,mr_small v) ++{ /* fast division - small quotient expected */ ++ mr_small x=u; ++ x-=v; ++ if (xERNUM) return 0; ++ ++ MR_IN(30) ++ ++#ifdef MR_COUNT_OPS ++ fpx++; ++#endif ++ ++ copy(x,mr_mip->w1); ++ copy(y,mr_mip->w2); ++ s=exsign(mr_mip->w1); ++ insign(PLUS,mr_mip->w1); ++ insign(PLUS,mr_mip->w2); ++ convert(_MIPP_ 1,mr_mip->w3); ++ zero(mr_mip->w4); ++ last=FALSE; ++ a=b=c=d=0; ++ iter=0; ++ ++ while (size(mr_mip->w2)!=0) ++ { ++ if (b==0) ++ { /* update mr_mip->w1 and mr_mip->w2 */ ++ ++ divide(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w5); ++ t=mr_mip->w1,mr_mip->w1=mr_mip->w2,mr_mip->w2=t; /* swap(mr_mip->w1,mr_mip->w2) */ ++ multiply(_MIPP_ mr_mip->w4,mr_mip->w5,mr_mip->w0); ++ add(_MIPP_ mr_mip->w3,mr_mip->w0,mr_mip->w3); ++ t=mr_mip->w3,mr_mip->w3=mr_mip->w4,mr_mip->w4=t; /* swap(xd,yd) */ ++ iter++; ++ ++ } ++ else ++ { ++ ++ /* printf("a= %I64u b= %I64u c= %I64u d= %I64u \n",a,b,c,d); */ ++ ++ mr_pmul(_MIPP_ mr_mip->w1,c,mr_mip->w5); /* c*w1 */ ++ mr_pmul(_MIPP_ mr_mip->w1,a,mr_mip->w1); /* a*w1 */ ++ mr_pmul(_MIPP_ mr_mip->w2,b,mr_mip->w0); /* b*w2 */ ++ mr_pmul(_MIPP_ mr_mip->w2,d,mr_mip->w2); /* d*w2 */ ++ ++ if (!dplus) ++ { ++ mr_psub(_MIPP_ mr_mip->w0,mr_mip->w1,mr_mip->w1); /* b*w2-a*w1 */ ++ mr_psub(_MIPP_ mr_mip->w5,mr_mip->w2,mr_mip->w2); /* c*w1-d*w2 */ ++ } ++ else ++ { ++ mr_psub(_MIPP_ mr_mip->w1,mr_mip->w0,mr_mip->w1); /* a*w1-b*w2 */ ++ mr_psub(_MIPP_ mr_mip->w2,mr_mip->w5,mr_mip->w2); /* d*w2-c*w1 */ ++ } ++ mr_pmul(_MIPP_ mr_mip->w3,c,mr_mip->w5); ++ mr_pmul(_MIPP_ mr_mip->w3,a,mr_mip->w3); ++ mr_pmul(_MIPP_ mr_mip->w4,b,mr_mip->w0); ++ mr_pmul(_MIPP_ mr_mip->w4,d,mr_mip->w4); ++ ++ if (a==0) copy(mr_mip->w0,mr_mip->w3); ++ else mr_padd(_MIPP_ mr_mip->w3,mr_mip->w0,mr_mip->w3); ++ mr_padd(_MIPP_ mr_mip->w4,mr_mip->w5,mr_mip->w4); ++ } ++ if (mr_mip->ERNUM || size(mr_mip->w2)==0) break; ++ ++ ++ n=(int)mr_mip->w1->len; ++ if (n==1) ++ { ++ last=TRUE; ++ u=mr_mip->w1->w[0]; ++ v=mr_mip->w2->w[0]; ++ } ++ else ++ { ++ m=mr_mip->w1->w[n-1]+1; ++#ifndef MR_SIMPLE_BASE ++ if (mr_mip->base==0) ++ { ++#endif ++#ifndef MR_NOFULLWIDTH ++#ifdef mr_dltype ++ /* use double length type if available */ ++ if (n>2 && m!=0) ++ { /* squeeze out as much significance as possible */ ++ uu.h[MR_TOP]=muldvm(mr_mip->w1->w[n-1],mr_mip->w1->w[n-2],m,&sr); ++ uu.h[MR_BOT]=muldvm(sr,mr_mip->w1->w[n-3],m,&sr); ++ vv.h[MR_TOP]=muldvm(mr_mip->w2->w[n-1],mr_mip->w2->w[n-2],m,&sr); ++ vv.h[MR_BOT]=muldvm(sr,mr_mip->w2->w[n-3],m,&sr); ++ } ++ else ++ { ++ uu.h[MR_TOP]=mr_mip->w1->w[n-1]; ++ uu.h[MR_BOT]=mr_mip->w1->w[n-2]; ++ vv.h[MR_TOP]=mr_mip->w2->w[n-1]; ++ vv.h[MR_BOT]=mr_mip->w2->w[n-2]; ++ if (n==2) last=TRUE; ++ } ++ ++ u=uu.d; ++ v=vv.d; ++#else ++ if (m==0) ++ { ++ u=mr_mip->w1->w[n-1]; ++ v=mr_mip->w2->w[n-1]; ++ } ++ else ++ { ++ u=muldvm(mr_mip->w1->w[n-1],mr_mip->w1->w[n-2],m,&sr); ++ v=muldvm(mr_mip->w2->w[n-1],mr_mip->w2->w[n-2],m,&sr); ++ } ++#endif ++#endif ++#ifndef MR_SIMPLE_BASE ++ } ++ else ++ { ++#ifdef mr_dltype ++ if (n>2) ++ { /* squeeze out as much significance as possible */ ++ u=muldiv(mr_mip->w1->w[n-1],mr_mip->base,mr_mip->w1->w[n-2],m,&sr); ++ u=u*mr_mip->base+muldiv(sr,mr_mip->base,mr_mip->w1->w[n-3],m,&sr); ++ v=muldiv(mr_mip->w2->w[n-1],mr_mip->base,mr_mip->w2->w[n-2],m,&sr); ++ v=v*mr_mip->base+muldiv(sr,mr_mip->base,mr_mip->w2->w[n-3],m,&sr); ++ } ++ else ++ { ++ u=(mr_large)mr_mip->base*mr_mip->w1->w[n-1]+mr_mip->w1->w[n-2]; ++ v=(mr_large)mr_mip->base*mr_mip->w2->w[n-1]+mr_mip->w2->w[n-2]; ++ last=TRUE; ++ } ++#else ++ u=muldiv(mr_mip->w1->w[n-1],mr_mip->base,mr_mip->w1->w[n-2],m,&sr); ++ v=muldiv(mr_mip->w2->w[n-1],mr_mip->base,mr_mip->w2->w[n-2],m,&sr); ++#endif ++ } ++#endif ++ } ++ ++ dplus=TRUE; ++ a=1; b=0; c=0; d=1; ++ ++ forever ++ { /* work only with most significant piece */ ++ if (last) ++ { ++ if (v==0) break; ++ q=qdiv(u,v); ++ if (q==0) break; ++ } ++ else ++ { ++ if (dplus) ++ { ++ if ((mr_small)(v-c)==0 || (mr_small)(v+d)==0) break; ++ ++ q=qdiv(u+a,v-c); ++ ++ if (q==0) break; ++ ++ if (q!=qdiv(u-b,v+d)) break; ++ } ++ else ++ { ++ if ((mr_small)(v+c)==0 || (mr_small)(v-d)==0) break; ++ q=qdiv(u-a,v+c); ++ if (q==0) break; ++ if (q!=qdiv(u+b,v-d)) break; ++ } ++ } ++ ++ if (q==1) ++ { ++ if ((mr_small)(b+d) >= MAXBASE) break; ++ r=a+c; a=c; c=r; ++ r=b+d; b=d; d=r; ++ lr=u-v; u=v; v=lr; ++ } ++ else ++ { ++ if (q>=MR_DIV(MAXBASE-b,d)) break; ++ r=a+q*c; a=c; c=r; ++ r=b+q*d; b=d; d=r; ++ lr=u-q*v; u=v; v=lr; ++ } ++ iter++; ++ dplus=!dplus; ++ } ++ iter%=2; ++ ++ } ++ ++ if (s==MINUS) iter++; ++ if (iter%2==1) subtract(_MIPP_ y,mr_mip->w3,mr_mip->w3); ++ ++ if (xd!=yd) ++ { ++ negify(x,mr_mip->w2); ++ mad(_MIPP_ mr_mip->w2,mr_mip->w3,mr_mip->w1,y,mr_mip->w4,mr_mip->w4); ++ copy(mr_mip->w4,yd); ++ } ++ copy(mr_mip->w3,xd); ++ if (z!=xd && z!=yd) copy(mr_mip->w1,z); ++ ++ MR_OUT ++ return (size(mr_mip->w1)); ++} ++ ++int invmodp(_MIPD_ big x,big y,big z) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ int gcd; ++ ++ MR_IN(213); ++ gcd=xgcd(_MIPP_ x,y,z,z,z); ++ MR_OUT ++ return gcd; ++} ++ ++#else ++ ++/* much smaller, much slower binary inversion algorithm */ ++/* fails silently if a is not co-prime to p */ ++ ++/* experimental! At least 3 times slower than standard method.. */ ++ ++int invmodp(_MIPD_ big a,big p,big z) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ big u,v,x1,x2; ++ ++ MR_IN(213); ++ ++ u=mr_mip->w1; v=mr_mip->w2; x1=mr_mip->w3; x2=mr_mip->w4; ++ copy(a,u); ++ copy(p,v); ++ convert(_MIPP_ 1,x1); ++ zero(x2); ++ ++ while (size(u)!=1 && size(v)!=1) ++ { ++ while (remain(_MIPP_ u,2)==0) ++ { ++ subdiv(_MIPP_ u,2,u); ++ if (remain(_MIPP_ x1,2)!=0) add(_MIPP_ x1,p,x1); ++ subdiv(_MIPP_ x1,2,x1); ++ } ++ while (remain(_MIPP_ v,2)==0) ++ { ++ subdiv(_MIPP_ v,2,v); ++ if (remain(_MIPP_ x2,2)!=0) add(_MIPP_ x2,p,x2); ++ subdiv(_MIPP_ x2,2,x2); ++ } ++ if (mr_compare(u,v)>=0) ++ { ++ mr_psub(_MIPP_ u,v,u); ++ subtract(_MIPP_ x1,x2,x1); ++ } ++ else ++ { ++ mr_psub(_MIPP_ v,u,v); ++ subtract(_MIPP_ x2,x1,x2); ++ } ++ } ++ if (size(u)==1) copy(x1,z); ++ else copy(x2,z); ++ ++ if (size(z)<0) add(_MIPP_ z,p,z); ++ ++ MR_OUT ++ return 1; /* note - no checking that gcd=1 */ ++} ++ ++#endif ++ ++#ifndef MR_STATIC ++ ++/* Montgomery's method for multiple ++ simultaneous modular inversions */ ++ ++BOOL double_inverse(_MIPD_ big n,big x,big y,big w,big z) ++{ ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ ++ MR_IN(146) ++ ++ mad(_MIPP_ x,w,w,n,n,mr_mip->w6); ++ if (size(mr_mip->w6)==0) ++ { ++ mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); ++ MR_OUT ++ return FALSE; ++ } ++ invmodp(_MIPP_ mr_mip->w6,n,mr_mip->w6); ++ ++ mad(_MIPP_ w,mr_mip->w6,w,n,n,y); ++ mad(_MIPP_ x,mr_mip->w6,x,n,n,z); ++ ++ MR_OUT ++ return TRUE; ++} ++ ++BOOL multi_inverse(_MIPD_ int m,big *x,big n,big *w) ++{ /* find w[i]=1/x[i] mod n, for i=0 to m-1 * ++ * x and w MUST be distinct */ ++ int i; ++#ifdef MR_OS_THREADS ++ miracl *mr_mip=get_mip(); ++#endif ++ if (m==0) return TRUE; ++ if (m<0) return FALSE; ++ ++ MR_IN(25) ++ ++ if (x==w) ++ { ++ mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); ++ MR_OUT ++ return FALSE; ++ } ++ if (m==1) ++ { ++ invmodp(_MIPP_ x[0],n,w[0]); ++ MR_OUT ++ return TRUE; ++ } ++ ++ convert(_MIPP_ 1,w[0]); ++ copy(x[0],w[1]); ++ for (i=2;iw6); /* y=x[0]*x[1]*x[2]....x[m-1] */ ++ if (size(mr_mip->w6)==0) ++ { ++ mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); ++ MR_OUT ++ return FALSE; ++ } ++ ++ invmodp(_MIPP_ mr_mip->w6,n,mr_mip->w6); ++ ++/* Now y=1/y */ ++ ++ copy(x[m-1],mr_mip->w5); ++ mad(_MIPP_ w[m-1],mr_mip->w6,mr_mip->w6,n,n,w[m-1]); ++ ++ for (i=m-2;;i--) ++ { ++ if (i==0) ++ { ++ mad(_MIPP_ mr_mip->w5,mr_mip->w6,mr_mip->w6,n,n,w[0]); ++ break; ++ } ++ mad(_MIPP_ w[i],mr_mip->w5,w[i],n,n,w[i]); ++ mad(_MIPP_ w[i],mr_mip->w6,w[i],n,n,w[i]); ++ mad(_MIPP_ mr_mip->w5,x[i],x[i],n,n,mr_mip->w5); ++ } ++ ++ MR_OUT ++ return TRUE; ++} ++ ++#endif +diff --git a/lib/sbi/sm/platform/README.md b/lib/sbi/sm/platform/README.md +new file mode 100644 +index 0000000..f81659b +--- /dev/null ++++ b/lib/sbi/sm/platform/README.md +@@ -0,0 +1,9 @@ ++## Platforms ++ ++Penglai is designed to naturally support different platforms with their own isolation methods. ++ ++Currently, it supports: ++ ++- PMP-only platforms: this is suitable for most devices ++- PMP + sPMP/MPU: Penglai can achieve better scalability with sPMP/MPU ++- TVM (or Guarded Paging): please refer to another repo for more details about TVM +diff --git a/lib/sbi/sm/platform/pmp/enclave_mm.c b/lib/sbi/sm/platform/pmp/enclave_mm.c +new file mode 100644 +index 0000000..29db9a1 +--- /dev/null ++++ b/lib/sbi/sm/platform/pmp/enclave_mm.c +@@ -0,0 +1,1291 @@ ++#include ++#include ++#include ++//#include ++#include ++#include ++//#include "mtrap.h" ++#include ++#include ++ ++/* ++ * Only NPMP-3 enclave regions are supported. ++ * The last PMP is used to allow kernel to access memory. ++ * The 1st PMP is used to protect security monitor from kernel. ++ * The 2nd PMP is used to allow kernel to configure enclave's page table. ++ * Othres, (NPMP-3) PMPs are for enclaves, i.e., secure memory ++ * ++ * TODO: this array can be removed as we can get ++ * existing enclave regions via pmp registers ++ */ ++// static struct mm_region_t mm_regions[N_PMP_REGIONS]; ++struct mm_region_t mm_regions[N_PMP_REGIONS]; ++volatile unsigned long pmp_bitmap = 0; ++static spinlock_t pmp_bitmap_lock = SPIN_LOCK_INITIALIZER; ++ ++void acquire_big_emem_lock(const char *str) ++{ ++ if (LOCK_DEBUG) ++ printm("[PENGLAI SM @%s_%d] %s try lock\n", __func__, ++ current_hartid(), str); ++ spin_lock(&pmp_bitmap_lock); ++ if (LOCK_DEBUG) ++ printm("[PENGLAI SM @%s_%d] %s get lock\n", __func__, ++ current_hartid(), str); ++} ++int try_big_emem_lock(const char *str) ++{ ++ if (LOCK_DEBUG) ++ printm("[PENGLAI SM @%s_%d] %s try lock\n", __func__, ++ current_hartid(), str); ++ if (!spin_trylock(&pmp_bitmap_lock)) ++ { ++ return RETRY_SPIN_LOCK; ++ } ++ if (LOCK_DEBUG) ++ printm("[PENGLAI SM @%s_%d] %s get lock\n", __func__, ++ current_hartid(), str); ++ return 0; ++} ++ ++void release_big_emem_lock(const char *str) ++{ ++ spin_unlock(&pmp_bitmap_lock); ++ if (LOCK_DEBUG) ++ printm("[PENGLAI SM@%s_%d] %s release lock\n", __func__, ++ current_hartid(), str); ++} ++ ++int check_mem_overlap(uintptr_t paddr, unsigned long size) ++{ ++ unsigned long sm_base = SM_BASE; ++ unsigned long sm_size = SM_SIZE; ++ int region_idx = 0; ++ ++ //check whether the new region overlaps with security monitor ++ if(region_overlap(sm_base, sm_size, paddr, size)) ++ { ++ printm_err("pmp memory overlaps with security monitor!\r\n"); ++ return -1; ++ } ++ ++ //check whether the new region overlap with existing enclave region ++ for(region_idx = 0; region_idx < N_PMP_REGIONS; ++region_idx) ++ { ++ if(mm_regions[region_idx].valid ++ && region_overlap(mm_regions[region_idx].paddr, mm_regions[region_idx].size, ++ paddr, size)) ++ { ++ printm_err("pmp memory overlaps with existing pmp memory!region_idx:%d\r\n", region_idx); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++int data_is_nonsecure(uintptr_t paddr, unsigned long size) ++{ ++ return !check_mem_overlap(paddr, size); ++} ++ ++uintptr_t copy_from_host(void* dest, void* src, size_t size) ++{ ++ int retval = -1; ++ //get lock to prevent TOCTTOU ++ // acquire_big_emem_lock(__func__); ++ retval=try_big_emem_lock(__func__); ++ ++ int re_try = RETRY_TIMES; ++ while (retval == RETRY_SPIN_LOCK && re_try) { ++ re_try--; ++ retval=try_big_emem_lock(__func__); ++ } ++ if (retval == RETRY_SPIN_LOCK) ++ { ++ return retval; ++ } ++ ++ //check data is nonsecure ++ //prevent coping from memory in secure region ++ if(data_is_nonsecure((uintptr_t)src, size)) ++ { ++ sbi_memcpy(dest, src, size); ++ retval = 0; ++ } ++ ++ // spin_unlock(&pmp_bitmap_lock); ++ release_big_emem_lock(__func__); ++ return retval; ++} ++ ++uintptr_t copy_to_host(void* dest, void* src, size_t size) ++{ ++ int retval = -1; ++ // spin_lock(&pmp_bitmap_lock); ++ acquire_big_emem_lock(__func__); ++ ++ //check data is nonsecure ++ //prevent coping from memory in secure region ++ if(data_is_nonsecure((uintptr_t)dest, size)) ++ { ++ sbi_memcpy(dest, src, size); ++ retval = 0; ++ } ++ ++ // spin_unlock(&pmp_bitmap_lock); ++ release_big_emem_lock(__func__); ++ return retval; ++} ++ ++int copy_word_to_host(unsigned int* ptr, uintptr_t value) ++{ ++ int retval = -1; ++ // spin_lock(&pmp_bitmap_lock); ++ acquire_big_emem_lock(__func__); ++ ++ //check data is nonsecure ++ //prevent coping from memory in secure region ++ if(data_is_nonsecure((uintptr_t)ptr, sizeof(unsigned int))) ++ { ++ *ptr = value; ++ retval = 0; ++ } ++ ++ // spin_unlock(&pmp_bitmap_lock); ++ release_big_emem_lock(__func__); ++ return retval; ++} ++ ++static inline uintptr_t pte2pa(pte_t pte) ++{ ++ return (pte >> PTE_PPN_SHIFT) << RISCV_PGSHIFT; ++} ++ ++static inline int get_pt_index(uintptr_t vaddr, int level) ++{ ++ int index = vaddr >> (VA_BITS - (level + 1)*RISCV_PGLEVEL_BITS); ++ ++ return index & ((1 << RISCV_PGLEVEL_BITS) - 1) ; ++} ++ ++static pte_t* walk_enclave_pt(pte_t *enclave_root_pt, uintptr_t vaddr) ++{ ++ pte_t *pgdir = enclave_root_pt; ++ int i; ++ int level = (VA_BITS - RISCV_PGSHIFT) / RISCV_PGLEVEL_BITS; ++ for (i = 0; i < level - 1; i++) ++ { ++ int pt_index = get_pt_index(vaddr , i); ++ pte_t pt_entry = pgdir[pt_index]; ++ if(unlikely(!PTE_TABLE(pt_entry))) ++ { ++ return 0; ++ } ++ pgdir = (pte_t *)pte2pa(pt_entry); ++ } ++ ++ return &pgdir[get_pt_index(vaddr , level - 1)]; ++} ++ ++/*static int iterate_over_enclave_pages(pte_t* ptes, int level, uintptr_t va, ++ int (*check)(uintptr_t, uintptr_t, int)) ++{ ++ uintptr_t pte_per_page = RISCV_PGSIZE/sizeof(pte_t); ++ pte_t *pte; ++ uintptr_t i = 0; ++ ++ //should never happen ++ if(level <= 0) ++ return 1; ++ ++ for(pte = ptes, i = 0; i < pte_per_page; pte += 1, i += 1) ++ { ++ if(!(*pte & PTE_V)) ++ { ++ continue; ++ } ++ ++ uintptr_t curr_va = 0; ++ if(level == ((VA_BITS - RISCV_PGSHIFT) / RISCV_PGLEVEL_BITS)) ++ curr_va = (uintptr_t)(-1UL << VA_BITS) + ++ (i << (VA_BITS - RISCV_PGLEVEL_BITS)); ++ else ++ curr_va = va + ++ (i << ((level-1) * RISCV_PGLEVEL_BITS + RISCV_PGSHIFT)); ++ uintptr_t pa = (*pte >> PTE_PPN_SHIFT) << RISCV_PGSHIFT; ++ ++ //found leaf pte ++ if ((*pte & PTE_R) || (*pte & PTE_X)) { ++ //4K page ++ if (level == 1) { ++ if (check(curr_va, pa, 1 << RISCV_PGSHIFT) != 0) ++ return -1; ++ } ++ //2M page ++ else if (level == 2) { ++ if (check(curr_va, pa, 1 << (RISCV_PGSHIFT + ++ RISCV_PGLEVEL_BITS)) != 0) ++ return -1; ++ } ++ } else { ++ if (iterate_over_enclave_pages((pte_t *)pa, level - 1, ++ curr_va, check) != 0) ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++*/ ++ ++/** ++ * \brief This function check the enclave page table set up by ++ * kernel driver. Check two things: ++ * 1. Enclave's trusted memory pages are mapped to its own secure ++ * memory, falling within a pmp region and not out of bound to ++ * other enclave's memory. ++ * 2. Untrusted memory and kbuffer are mapped to normal kernel ++ * memory that doesn't belong to any existing pmp regions. ++ * ++ * Note: ++ * Need invocate hash_verify() and whitelist_check() first to ++ * guarantee the validness of enclave vaddr and the authenticity ++ * of untrusted memory and kbuffer which were passed by kernel ++ * driver. ++ * When SM hash an enclave, it will take into account configuration ++ * parameters such as untrusted memory and kbuffer (each has two ++ * part: a start vaddr in enclave address space and a size). ++ */ ++int check_enclave_pt(struct enclave_t *enclave) ++{ ++ uintptr_t retval = 0; ++ // umem and kbuffer pointer specified by user may only specify ++ // low-order VA_BITS bits, but without high-order 1s. ++ unsigned long enclave_untrusted_vaddr = ++ (uintptr_t)(-1UL << VA_BITS) | enclave->untrusted_ptr; ++ unsigned long enclave_kbuffer_vaddr = ++ (uintptr_t)(-1UL << VA_BITS) | enclave->kbuffer; ++ unsigned long page_mask = (1 << RISCV_PGSHIFT) - 1; ++ ++ // check umem and kbuffer pointer and size, align by page. ++ if ((enclave_untrusted_vaddr & page_mask) != 0 || ++ (enclave->untrusted_size & page_mask) != 0 || ++ (enclave_kbuffer_vaddr & page_mask) != 0 || ++ (enclave->kbuffer_size & page_mask) != 0) { ++ printm_err( ++ "[Penglai Monitor@%s] Error: Enclave untrusted mem or " ++ "kbuffer are not aligned by page.\r\n", ++ __func__); ++ return -1; ++ } ++ ++ /* For Debug */ ++ printm("Enclave's own secure momery: pa: 0x%lx, size: 0x%lx\r\n", ++ enclave->paddr, enclave->size); ++ ++ // check trusted mem, untrusted mem and kbuffer ++ int check_page(uintptr_t va, uintptr_t pa, int page_size) ++ { ++ if (region_contain(enclave_untrusted_vaddr, ++ enclave->untrusted_size, va, page_size) || ++ region_contain(enclave_kbuffer_vaddr, enclave->kbuffer_size, va, ++ page_size)) { ++ if (!data_is_nonsecure(pa, page_size)) { ++ printm_err("Error: untrusted memory pages fall within " ++ "secure region! va: 0x:%lx, pa: 0x%lx, size: 0x%x\r\n", ++ va, pa, page_size); ++ return -1; ++ } ++ } else { ++ if (!region_contain(enclave->paddr, enclave->size, pa, ++ page_size)) { ++ printm_err( ++ "Error: trusted memory pages fall out of enclave's " ++ "own secure momery! va: 0x%lx, pa: 0x%lx, size: 0x%x\r\n", ++ va, pa, page_size); ++ return -1; ++ } ++ } ++ ++ return 0; ++ } ++ int iterate_over_enclave_pages(pte_t* ptes, int level, uintptr_t va) ++{ ++ uintptr_t pte_per_page = RISCV_PGSIZE/sizeof(pte_t); ++ pte_t *pte; ++ uintptr_t i = 0; ++ ++ //should never happen ++ if(level <= 0) ++ return 1; ++ ++ for(pte = ptes, i = 0; i < pte_per_page; pte += 1, i += 1) ++ { ++ if(!(*pte & PTE_V)) ++ { ++ continue; ++ } ++ ++ uintptr_t curr_va = 0; ++ if(level == ((VA_BITS - RISCV_PGSHIFT) / RISCV_PGLEVEL_BITS)) ++ curr_va = (uintptr_t)(-1UL << VA_BITS) + ++ (i << (VA_BITS - RISCV_PGLEVEL_BITS)); ++ else ++ curr_va = va + ++ (i << ((level-1) * RISCV_PGLEVEL_BITS + RISCV_PGSHIFT)); ++ uintptr_t pa = (*pte >> PTE_PPN_SHIFT) << RISCV_PGSHIFT; ++ ++ //found leaf pte ++ if ((*pte & PTE_R) || (*pte & PTE_X)) { ++ //4K page ++ if (level == 1) { ++ if (check_page(curr_va, pa, 1 << RISCV_PGSHIFT) != 0) ++ return -1; ++ } ++ //2M page ++ else if (level == 2) { ++ if (check_page(curr_va, pa, 1 << (RISCV_PGSHIFT + ++ RISCV_PGLEVEL_BITS)) != 0) ++ return -1; ++ } ++ } else { ++ if (iterate_over_enclave_pages((pte_t *)pa, level - 1, ++ curr_va) != 0) ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ retval = iterate_over_enclave_pages( ++ (pte_t*)(enclave->thread_context.encl_ptbr << RISCV_PGSHIFT), ++ (VA_BITS - RISCV_PGSHIFT) / RISCV_PGLEVEL_BITS, 0 ++ ); ++ if(retval != 0){ ++ printm_err("[Penglai Monitor@%s] Error: Enclave page table check failed, retval %d.\n", ++ __func__, (int)retval); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++uintptr_t get_enclave_paddr_from_va(pte_t *enclave_root_pt, uintptr_t vaddr) ++{ ++ pte_t *pte = walk_enclave_pt(enclave_root_pt, vaddr); ++ if(!(*pte & PTE_V)){ ++ return 0; ++ } ++ uintptr_t pa = pte2pa(*pte) | (vaddr & ((1 << PAGE_SHIFT) - 1)); ++ return pa; ++} ++ ++uintptr_t copy_from_enclave(pte_t *enclave_root_pt, void* dest_pa, void* src_enclave_va, size_t size) ++{ ++ uintptr_t src_pa; ++ uintptr_t page_offset = (uintptr_t)src_enclave_va & ((1 << PAGE_SHIFT) - 1); ++ uintptr_t page_left = PAGE_SIZE - page_offset; ++ uintptr_t left_size = size; ++ uintptr_t copy_size; ++ if (page_left >= left_size) { ++ // do copy in one time ++ copy_size = left_size; ++ src_pa = get_enclave_paddr_from_va(enclave_root_pt, (uintptr_t)src_enclave_va); ++ if(src_pa == 0) ++ { ++ sbi_printf("ERROR: va is not mapped\n"); ++ return -1; ++ } ++ sbi_memcpy(dest_pa, (void *)src_pa, copy_size); ++ } ++ else { ++ // do left ++ copy_size = page_left; ++ src_pa = get_enclave_paddr_from_va(enclave_root_pt, (uintptr_t)src_enclave_va); ++ if(src_pa == 0) ++ { ++ sbi_printf("ERROR: va is not mapped\n"); ++ return -1; ++ } ++ sbi_memcpy(dest_pa, (void *)src_pa, copy_size); ++ left_size -= page_left; ++ src_enclave_va += page_left; ++ dest_pa += page_left; ++ // do while ++ while(left_size > 0){ ++ copy_size = (left_size > PAGE_SIZE) ? PAGE_SIZE : left_size; ++ src_pa = get_enclave_paddr_from_va(enclave_root_pt, (uintptr_t)src_enclave_va); ++ if(src_pa == 0) ++ { ++ sbi_printf("ERROR: va is not mapped\n"); ++ return -1; ++ } ++ sbi_memcpy(dest_pa, (void *)src_pa, copy_size); ++ left_size -= copy_size; ++ src_enclave_va += copy_size; ++ dest_pa += page_left; ++ } ++ } ++ ++ return 0; ++} ++ ++uintptr_t copy_to_enclave(pte_t *enclave_root_pt, void* dest_enclave_va, void* src_pa, size_t size) ++{ ++ uintptr_t dest_pa; ++ uintptr_t page_offset = (uintptr_t)dest_enclave_va & ((1 << PAGE_SHIFT) - 1); ++ uintptr_t page_left = PAGE_SIZE - page_offset; ++ uintptr_t left_size = size; ++ uintptr_t copy_size; ++ if (page_left >= left_size) { ++ // do copy in one time ++ copy_size = left_size; ++ dest_pa = get_enclave_paddr_from_va(enclave_root_pt, (uintptr_t)dest_enclave_va); ++ if(dest_pa == 0) ++ { ++ sbi_printf("ERROR: va is not mapped\n"); ++ return -1; ++ } ++ sbi_memcpy((void *)dest_pa, src_pa, copy_size); ++ } ++ else { ++ // do copy in the first page ++ copy_size = page_left; ++ dest_pa = get_enclave_paddr_from_va(enclave_root_pt, (uintptr_t)dest_enclave_va); ++ if(dest_pa == 0) ++ { ++ sbi_printf("ERROR: va is not mapped\n"); ++ return -1; ++ } ++ sbi_memcpy((void *)dest_pa, src_pa, copy_size); ++ left_size -= page_left; ++ dest_enclave_va += page_left; ++ src_pa += page_left; ++ // do while for other pages ++ while(left_size > 0){ ++ copy_size = (left_size > PAGE_SIZE) ? PAGE_SIZE : left_size; ++ dest_pa = get_enclave_paddr_from_va(enclave_root_pt, (uintptr_t)dest_enclave_va); ++ if(dest_pa == 0) ++ { ++ sbi_printf("ERROR: va is not mapped\n"); ++ return -1; ++ } ++ sbi_memcpy((void *)dest_pa, src_pa, copy_size); ++ left_size -= copy_size; ++ dest_enclave_va += copy_size; ++ src_pa += page_left; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * Check the validness of the paddr and size ++ * */ ++static int check_mem_size(uintptr_t paddr, unsigned long size) ++{ ++ if((size == 0) || (size & (size - 1))) ++ { ++ printm_err("pmp size should be 2^power!\r\n"); ++ return -1; ++ } ++ ++ if(size < RISCV_PGSIZE) ++ { ++ printm_err("pmp size should be no less than one page!\r\n"); ++ return -1; ++ } ++ ++ if(paddr & (size - 1)) ++ { ++ printm_err("pmp size should be %ld aligned!\r\n", size); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * TODO: we should protect kernel temporal region with lock ++ * A possible malicious case: ++ * kernel@Hart-0: acquire memory region, set to PMP-1 ++ * kernel@Hart-1: acquire memory region, set to PMP-1 <- this will overlap the prior region ++ * kernel@Hart-0: release memory region <- dangerous behavior now ++ * */ ++ ++/** ++ * \brief This function grants kernel (temporaily) access to allocated enclave memory ++ * for initializing enclave and configuring page table. ++ */ ++int grant_kernel_access(void* req_paddr, unsigned long size) ++{ ++ //pmp1 is used for allowing kernel to access enclave memory ++ int pmp_idx = 1; ++ struct pmp_config_t pmp_config; ++ uintptr_t paddr = (uintptr_t)req_paddr; ++ ++ pmp_config = get_pmp(pmp_idx); ++ if((pmp_config.mode != PMP_OFF)) ++ { ++ printm_err( ++ "grant_kernel_access: can't grant kernel access to a new memory" ++ "region if kernel has already access to another one\r\n"); ++ return -1; ++ } ++ ++ if(check_mem_size(paddr, size) != 0){ ++ printm("[Penglai Monitor@%s] check_mem_size failed\n", __func__); ++ return -1; ++ } ++ ++ pmp_config.paddr = paddr; ++ pmp_config.size = size; ++ pmp_config.perm = PMP_R | PMP_W | PMP_X; ++ pmp_config.mode = PMP_A_NAPOT; ++ set_pmp(pmp_idx, pmp_config); ++ ++ return 0; ++} ++ ++/* ++ * This function retrieves kernel access to allocated enclave memory. ++ */ ++int retrieve_kernel_access(void* req_paddr, unsigned long size) ++{ ++ //pmp1 is used for allowing kernel to access enclave memory ++ int pmp_idx = 1; ++ struct pmp_config_t pmp_config; ++ uintptr_t paddr = (uintptr_t)req_paddr; ++ ++ pmp_config = get_pmp(pmp_idx); ++ ++ if((pmp_config.mode != PMP_A_NAPOT) || (pmp_config.paddr != paddr) || (pmp_config.size != size)) ++ { ++ printm_err("retrieve_kernel_access: error pmp_config\r\n"); ++ return -1; ++ } ++ ++ // clear_pmp_and_sync(pmp_idx); ++ clear_pmp(pmp_idx); ++ ++ return 0; ++} ++ ++//grant enclave access to enclave's memory ++int grant_enclave_access(struct enclave_t* enclave) ++{ ++ int region_idx = 0; ++ int pmp_idx = 0; ++ struct pmp_config_t pmp_config; ++ ++ if(check_mem_size(enclave->paddr, enclave->size) < 0) ++ return -1; ++ ++ //set pmp permission, ensure that enclave's paddr and size is pmp legal ++ //TODO: support multiple memory regions ++ // spin_lock(&pmp_bitmap_lock); ++ acquire_big_emem_lock(__func__); ++ for (region_idx = 0; region_idx < N_PMP_REGIONS; ++region_idx) { ++ if(mm_regions[region_idx].valid && region_contain( ++ mm_regions[region_idx].paddr, mm_regions[region_idx].size, ++ enclave->paddr, enclave->size)) ++ { ++ break; ++ } ++ } ++ // spin_unlock(&pmp_bitmap_lock); ++ release_big_emem_lock(__func__); ++ ++ if(region_idx >= N_PMP_REGIONS) ++ { ++ printm_err("M mode: grant_enclave_access: can not find exact mm_region\r\n"); ++ return -1; ++ } ++ ++ pmp_idx = REGION_TO_PMP(region_idx); ++#if 0 ++ pmp_config.paddr = enclave->paddr; ++ pmp_config.size = enclave->size; ++#else ++ /* Even if we set this PMP region only contain the enclave's secure memory, ++ * the enclave still have access to the secure memory of other enclaves, ++ * which using the same pmp to protect their memory from OS access before. ++ * That's because the last pmp makes all momery accessible. ++ * And we rule out this possibility by checking the enclave page table. ++ * ++ * So we just make this PMP region readable, writable and executable. ++ */ ++ pmp_config.paddr = mm_regions[region_idx].paddr; ++ pmp_config.size = mm_regions[region_idx].size; ++#endif ++ pmp_config.perm = PMP_R | PMP_W | PMP_X; ++ pmp_config.mode = PMP_A_NAPOT; ++ ++ /* Note: here we only set the PMP regions in local Hart*/ ++ set_pmp(pmp_idx, pmp_config); ++ ++ /*FIXME: we should handle the case that the PMP region contains larger region */ ++ if (pmp_config.paddr != enclave->paddr || pmp_config.size != enclave->size){/* ++ printm("[Penglai Monitor@%s] warning, region != enclave mem\n", __func__); ++ printm("[Penglai Monitor@%s] region: paddr(0x%lx) size(0x%lx)\n", ++ __func__, pmp_config.paddr, pmp_config.size); ++ printm("[Penglai Monitor@%s] enclave mem: paddr(0x%lx) size(0x%lx)\n", ++ __func__, enclave->paddr, enclave->size); ++ */} ++ ++ return 0; ++} ++ ++int retrieve_enclave_access(struct enclave_t *enclave) ++{ ++ int region_idx = 0; ++ int pmp_idx = 0; ++ struct pmp_config_t pmp_config; ++ ++ //set pmp permission, ensure that enclave's paddr and size is pmp legal ++ //TODO: support multiple memory regions ++ // spin_lock(&pmp_bitmap_lock); ++ acquire_big_emem_lock(__func__); ++ for (region_idx = 0; region_idx < N_PMP_REGIONS; ++region_idx) { ++ if(mm_regions[region_idx].valid && region_contain( ++ mm_regions[region_idx].paddr, mm_regions[region_idx].size, ++ enclave->paddr, enclave->size)) ++ { ++ break; ++ } ++ } ++ // spin_unlock(&pmp_bitmap_lock); ++ release_big_emem_lock(__func__); ++ ++ if(region_idx >= N_PMP_REGIONS) ++ { ++ printm_err("M mode: Error: %s\r\n", __func__); ++ /* For Debug */ ++ for (region_idx = 0; region_idx < N_PMP_REGIONS; ++region_idx) { ++ printm("[Monitor Debug@%s] mm_region[%d], valid(%d), paddr(0x%lx) size(0x%lx)\n", ++ __func__, region_idx, mm_regions[region_idx].valid, mm_regions[region_idx].paddr, ++ mm_regions[region_idx].size); ++ } ++ printm("[Monitor Debug@%s] enclave paddr(0x%lx) size(0x%lx)\n", ++ __func__, enclave->paddr, enclave->size); ++ ++ return -1; ++ } ++ ++ pmp_idx = REGION_TO_PMP(region_idx); ++ ++ // set PMP to protect the entire PMP region ++ pmp_config.paddr = mm_regions[region_idx].paddr; ++ pmp_config.size = mm_regions[region_idx].size; ++ pmp_config.perm = PMP_NO_PERM; ++ pmp_config.mode = PMP_A_NAPOT; ++ ++ /* Note: here we only set the PMP regions in local Hart*/ ++ set_pmp(pmp_idx, pmp_config); ++ ++ return 0; ++} ++ ++uintptr_t mm_init(uintptr_t paddr, unsigned long size) ++{ ++ uintptr_t retval = 0; ++ int region_idx = 0; ++ int pmp_idx =0; ++ struct pmp_config_t pmp_config; ++ ++ //check align of paddr and size ++ if(check_mem_size(paddr, size) < 0) ++ return -1UL; ++ ++ //acquire a free enclave region ++ // spin_lock(&pmp_bitmap_lock); ++ // acquire_big_emem_lock(__func__); ++ if (try_big_emem_lock(__func__)) ++ { ++ return RETRY_SPIN_LOCK; ++ } ++ ++ //memory overlap should be checked after acquire lock ++ if(check_mem_overlap(paddr, size) < 0) ++ { ++ retval = -1UL; ++ goto out; ++ } ++ ++ //alloc a free pmp ++ for(region_idx = 0; region_idx < N_PMP_REGIONS; ++region_idx) ++ { ++ pmp_idx = REGION_TO_PMP(region_idx); ++ if(!(pmp_bitmap & (1<= N_PMP_REGIONS) ++ { ++ retval = -1UL; ++ goto out; ++ } ++ ++ //set PMP to protect enclave memory region ++ pmp_config.paddr = paddr; ++ pmp_config.size = size; ++ pmp_config.perm = PMP_NO_PERM; ++ pmp_config.mode = PMP_A_NAPOT; ++ set_pmp_and_sync(pmp_idx, pmp_config); ++ ++ //mark this region is valid and init mm_list ++ mm_regions[region_idx].valid = 1; ++ mm_regions[region_idx].paddr = paddr; ++ mm_regions[region_idx].size = size; ++ struct mm_list_t *mm_list = (struct mm_list_t*)PADDR_2_MM_LIST(paddr); ++ mm_list->order = ilog2(size-1) + 1; ++ mm_list->prev_mm = NULL; ++ mm_list->next_mm = NULL; ++ struct mm_list_head_t *mm_list_head = (struct mm_list_head_t*)paddr; ++ mm_list_head->order = mm_list->order; ++ mm_list_head->prev_list_head = NULL; ++ mm_list_head->next_list_head = NULL; ++ mm_list_head->mm_list = mm_list; ++ mm_regions[region_idx].mm_list_head = mm_list_head; ++ ++out: ++ // spin_unlock(&pmp_bitmap_lock); ++ release_big_emem_lock(__func__); ++ return retval; ++} ++ ++//NOTE: this function may modify the arg mm_list_head ++//remember to acquire lock before calling this function ++//be sure that mm_region does exist in mm_list and mm_list does exist in mm_lists ++static int delete_certain_region(int region_idx, struct mm_list_head_t** mm_list_head, struct mm_list_t *mm_region) ++{ ++ struct mm_list_t* prev_mm = mm_region->prev_mm; ++ struct mm_list_t* next_mm = mm_region->next_mm; ++ struct mm_list_head_t* prev_list_head = (*mm_list_head)->prev_list_head; ++ struct mm_list_head_t* next_list_head = (*mm_list_head)->next_list_head; ++ ++ //delete mm_region from old mm_list ++ //mm_region is in the middle of the mm_list ++ if(prev_mm) ++ { ++ prev_mm->next_mm = next_mm; ++ if(next_mm) ++ next_mm->prev_mm = prev_mm; ++ } ++ //mm_region is in the first place of old mm_list ++ else if(next_mm) ++ { ++ next_mm->prev_mm = NULL; ++ struct mm_list_head_t* new_list_head = (struct mm_list_head_t*)MM_LIST_2_PADDR(next_mm); ++ new_list_head->order = next_mm->order; ++ new_list_head->prev_list_head = prev_list_head; ++ new_list_head->next_list_head = next_list_head; ++ new_list_head->mm_list = next_mm; ++ if(prev_list_head) ++ prev_list_head->next_list_head = new_list_head; ++ else ++ mm_regions[region_idx].mm_list_head = new_list_head; ++ if(next_list_head) ++ next_list_head->prev_list_head = new_list_head; ++ ++ *mm_list_head = new_list_head; ++ } ++ //mm_region is the only region in old mm_list ++ else ++ { ++ if(prev_list_head) ++ prev_list_head->next_list_head = next_list_head; ++ else ++ mm_regions[region_idx].mm_list_head = next_list_head; ++ if(next_list_head) ++ next_list_head->prev_list_head = prev_list_head; ++ ++ *mm_list_head = NULL; ++ } ++ ++ return 0; ++} ++ ++//remember to acquire a lock before calling this function ++static struct mm_list_t* alloc_one_region(int region_idx, int order) ++{ ++ if(!mm_regions[region_idx].valid || !mm_regions[region_idx].mm_list_head) ++ { ++ printm("M mode: alloc_one_region: m_regions[%d] is invalid/NULL\r\n", region_idx); ++ return NULL; ++ } ++ ++ struct mm_list_head_t *mm_list_head = mm_regions[region_idx].mm_list_head; ++ while(mm_list_head && (mm_list_head->order < order)) ++ { ++ mm_list_head = mm_list_head->next_list_head; ++ } ++ ++ //current region has no enough free space ++ if(!mm_list_head) ++ return NULL; ++ ++ //pick a mm region from current mm_list ++ struct mm_list_t *mm_region = mm_list_head->mm_list; ++ ++ //delete the mm region from current mm_list ++ delete_certain_region(region_idx, &mm_list_head, mm_region); ++ ++ return mm_region; ++} ++ ++//remember to acquire lock before calling this function ++//be sure that mm_list_head does exist in mm_lists ++static int merge_regions(int region_idx, struct mm_list_head_t* mm_list_head, struct mm_list_t *mm_region) ++{ ++ if(region_idx<0 || region_idx>=N_PMP_REGIONS || !mm_list_head || !mm_region) ++ return -1; ++ if(mm_list_head->order != mm_region->order) ++ return -1; ++ ++ struct mm_list_head_t* current_list_head = mm_list_head; ++ struct mm_list_t* current_region = mm_region; ++ while(current_list_head) ++ { ++ struct mm_list_t* buddy_region = current_list_head->mm_list; ++ unsigned long paddr = (unsigned long)MM_LIST_2_PADDR(current_region); ++ unsigned long buddy_paddr = (unsigned long)MM_LIST_2_PADDR(buddy_region); ++ while(buddy_region) ++ { ++ buddy_paddr = (unsigned long)MM_LIST_2_PADDR(buddy_region); ++ if((paddr | (1 << current_region->order)) == (buddy_paddr | (1 << current_region->order))) ++ break; ++ buddy_region = buddy_region->next_mm; ++ } ++ ++ struct mm_list_head_t* new_list_head = (struct mm_list_head_t*)MM_LIST_2_PADDR(current_region); ++ struct mm_list_head_t* prev_list_head = current_list_head->prev_list_head; ++ struct mm_list_head_t* next_list_head = current_list_head->next_list_head; ++ //didn't find buddy region, just insert this region in current mm_list ++ if(!buddy_region) ++ { ++ current_region->prev_mm = NULL; ++ current_region->next_mm = current_list_head->mm_list; ++ current_list_head->mm_list->prev_mm = current_region; ++ new_list_head->order = current_region->order; ++ new_list_head->prev_list_head = prev_list_head; ++ new_list_head->next_list_head = next_list_head; ++ new_list_head->mm_list = current_region; ++ ++ if(prev_list_head) ++ prev_list_head->next_list_head = new_list_head; ++ else ++ mm_regions[region_idx].mm_list_head = new_list_head; ++ if(next_list_head) ++ next_list_head->prev_list_head = new_list_head; ++ ++ break; ++ } ++ ++ //found buddy_region, merge it and current region ++ ++ //first delete buddy_region from old mm_list ++ //Note that this function may modify prev_list and next_list ++ //but won't modify their positions relative to new mm_region ++ delete_certain_region(region_idx, ¤t_list_head, buddy_region); ++ ++ //then merge buddy_region with current region ++ int order = current_region->order; ++ current_region = paddr < buddy_paddr ? PADDR_2_MM_LIST(paddr) : PADDR_2_MM_LIST(buddy_paddr); ++ current_region->order = order + 1; ++ current_region->prev_mm = NULL; ++ current_region->next_mm = NULL; ++ ++ //next mm_list doesn't exist or has a different order, no need to merge ++ if(!next_list_head || next_list_head->order != current_region->order) ++ { ++ //current_list_head may be NULL now after delete buddy region ++ if(current_list_head) ++ prev_list_head = current_list_head; ++ new_list_head = (struct mm_list_head_t*)MM_LIST_2_PADDR(current_region); ++ new_list_head->order = current_region->order; ++ new_list_head->prev_list_head = prev_list_head; ++ new_list_head->next_list_head = next_list_head; ++ new_list_head->mm_list = current_region; ++ ++ if(prev_list_head) ++ prev_list_head->next_list_head = new_list_head; ++ else ++ mm_regions[region_idx].mm_list_head = new_list_head; ++ if(next_list_head) ++ next_list_head->prev_list_head = new_list_head; ++ ++ break; ++ } ++ ++ //continue to merge with next mm_list ++ current_list_head = next_list_head; ++ } ++ ++ return 0; ++} ++ ++//remember to acquire lock before calling this function ++static int insert_mm_region(int region_idx, struct mm_list_t* mm_region, int merge) ++{ ++ if(region_idx<0 || region_idx>=N_PMP_REGIONS || !mm_regions[region_idx].valid || !mm_region) ++ return -1; ++ ++ struct mm_list_head_t* mm_list_head = mm_regions[region_idx].mm_list_head; ++ struct mm_list_head_t* prev_list_head = NULL; ++ ++ //there is no mm_list in current pmp_region ++ if(!mm_list_head) ++ { ++ mm_list_head = (struct mm_list_head_t*)MM_LIST_2_PADDR(mm_region); ++ mm_list_head->order = mm_region->order; ++ mm_list_head->prev_list_head = NULL; ++ mm_list_head->next_list_head = NULL; ++ mm_list_head->mm_list = mm_region; ++ mm_regions[region_idx].mm_list_head = mm_list_head; ++ return 0; ++ } ++ ++ //traversal from front to back ++ while(mm_list_head && mm_list_head->order < mm_region->order) ++ { ++ prev_list_head = mm_list_head; ++ mm_list_head = mm_list_head->next_list_head; ++ } ++ ++ //found the exact mm_list ++ int ret_val = 0; ++ struct mm_list_head_t *new_list_head = (struct mm_list_head_t*)MM_LIST_2_PADDR(mm_region); ++ if(mm_list_head && mm_list_head->order == mm_region->order) ++ { ++ if(!merge) ++ { ++ //insert mm_region to the first pos in mm_list ++ mm_region->prev_mm = NULL; ++ mm_region->next_mm = mm_list_head->mm_list; ++ mm_list_head->mm_list->prev_mm = mm_region; ++ ++ //set mm_list_head ++ struct mm_list_head_t* next_list_head = mm_list_head->next_list_head; ++ new_list_head->order = mm_region->order; ++ new_list_head->prev_list_head = prev_list_head; ++ new_list_head->next_list_head = next_list_head; ++ new_list_head->mm_list = mm_region; ++ if(prev_list_head) ++ prev_list_head->next_list_head = new_list_head; ++ else ++ mm_regions[region_idx].mm_list_head = new_list_head; ++ if(next_list_head) ++ next_list_head->prev_list_head = new_list_head; ++ } ++ else ++ { ++ //insert with merge ++ ret_val = merge_regions(region_idx, mm_list_head, mm_region); ++ } ++ } ++ //should create a new mm_list for this mm region ++ //note that mm_list_head might be NULL ++ else ++ { ++ new_list_head->order = mm_region->order; ++ new_list_head->prev_list_head = prev_list_head; ++ new_list_head->next_list_head = mm_list_head; ++ new_list_head->mm_list = mm_region; ++ if(prev_list_head) ++ prev_list_head->next_list_head = new_list_head; ++ else ++ mm_regions[region_idx].mm_list_head = new_list_head; ++ if(mm_list_head) ++ mm_list_head->prev_list_head = new_list_head; ++ } ++ ++ return ret_val; ++} ++ ++//TODO: delete this function ++void print_buddy_system() ++{ ++ // spin_lock(&pmp_bitmap_lock); ++ ++ for (size_t i = 0; i < N_PMP_REGIONS; i++) ++ { ++ if (!mm_regions[i].valid) ++ { ++ break; ++ } ++ ++ struct mm_list_head_t* mm_list_head = mm_regions[i].mm_list_head; ++ // printm("struct mm_list_head_t size is 0x%lx\r\n", sizeof(struct mm_list_head_t)); ++ // printm("struct mm_list_t size is 0x%lx\r\n", sizeof(struct mm_list_t)); ++ while(mm_list_head) ++ { ++ printm("mm_list_head[%ld] addr is 0x%ln, order is %d\r\n",i, (long int *)mm_list_head, mm_list_head->order); ++ printm("mm_list_head prev is 0x%ln, next is 0x%ln, mm_list is 0x%ln\r\n", ++ (long int *)mm_list_head->prev_list_head, ++ (long int *)mm_list_head->next_list_head, ++ (long int*)mm_list_head->mm_list); ++ struct mm_list_t *mm_region = mm_list_head->mm_list; ++ while(mm_region) ++ { ++ printm(" mm_region addr is 0x%ln=0x%p, paddr is 0x%p, order is %d\r\n", (long int *)mm_region,(long int *)MM_LIST_2_PADDR(mm_region),(long int *)MM_LIST_2_PADDR(mm_region), mm_region->order); ++ printm(" mm_region prev is 0x%ln, next is 0x%ln\r\n\n", (long int*)mm_region->prev_mm, (long int*)mm_region->next_mm); ++ mm_region = mm_region->next_mm; ++ } ++ mm_list_head = mm_list_head->next_list_head; ++ } ++ } ++ ++ printm("************\r\n"); ++ ++ // spin_unlock(&pmp_bitmap_lock); ++} ++ ++void* mm_alloc(unsigned long req_size, unsigned long *resp_size) ++{ ++ void* ret_addr = NULL; ++ if(req_size == 0) ++ return ret_addr; ++ ++ //TODO: reduce lock granularity ++ acquire_big_emem_lock(__func__); ++ ++ print_buddy_system(); ++ ++ unsigned long order = ilog2(req_size-1) + 1; ++ for(int region_idx=0; region_idx < N_PMP_REGIONS; ++region_idx) ++ { ++ struct mm_list_t* mm_region = alloc_one_region(region_idx, order); ++ ++ //there is no enough space in current pmp region ++ if(!mm_region) ++ continue; ++ ++ while(mm_region->order > order) ++ { ++ //allocated mm region need to be split ++ mm_region->order -= 1; ++ mm_region->prev_mm = NULL; ++ mm_region->next_mm = NULL; ++ ++ void* new_mm_region_paddr = MM_LIST_2_PADDR(mm_region) + (1 << mm_region->order); ++ struct mm_list_t* new_mm_region = PADDR_2_MM_LIST(new_mm_region_paddr); ++ new_mm_region->order = mm_region->order; ++ new_mm_region->prev_mm = NULL; ++ new_mm_region->next_mm = NULL; ++ insert_mm_region(region_idx, new_mm_region, 0); ++ } ++ ++ ret_addr = MM_LIST_2_PADDR(mm_region); ++ break; ++ } ++ ++ // print_buddy_system(); ++ ++ release_big_emem_lock(__func__); ++ ++ if(ret_addr && resp_size) ++ { ++ *resp_size = 1 << order; ++ sbi_memset(ret_addr, 0, *resp_size); ++ } ++ ++ return ret_addr; ++} ++ ++int mm_free(void* req_paddr, unsigned long free_size) ++{ ++ //check this paddr is 2^power aligned ++ uintptr_t paddr = (uintptr_t)req_paddr; ++ unsigned long order = ilog2(free_size-1) + 1; ++ unsigned long size = 1 << order; ++ if(check_mem_size(paddr, size) < 0) ++ return -1; ++ ++ int ret_val = 0; ++ int region_idx = 0; ++ struct mm_list_t* mm_region = PADDR_2_MM_LIST(paddr); ++ mm_region->order = order; ++ mm_region->prev_mm = NULL; ++ mm_region->next_mm = NULL; ++ ++ // spin_lock(&pmp_bitmap_lock); ++ acquire_big_emem_lock(__func__); ++ ++ for(region_idx=0; region_idx < N_PMP_REGIONS; ++region_idx) ++ { ++ if(mm_regions[region_idx].valid && region_contain(mm_regions[region_idx].paddr, mm_regions[region_idx].size, paddr, size)) ++ { ++ break; ++ } ++ } ++ if(region_idx >= N_PMP_REGIONS) ++ { ++ printm("mm_free: buddy system doesn't contain memory(addr 0x%lx, order %ld)\r\n", paddr, order); ++ ret_val = -1; ++ goto mm_free_out; ++ } ++ ++ //check whether this region overlap with existing free mm_lists ++ struct mm_list_head_t* mm_list_head = mm_regions[region_idx].mm_list_head; ++ while(mm_list_head) ++ { ++ struct mm_list_t* mm_region = mm_list_head->mm_list; ++ while(mm_region) ++ { ++ uintptr_t region_paddr = (uintptr_t)MM_LIST_2_PADDR(mm_region); ++ unsigned long region_size = 1 << mm_region->order; ++ if(region_overlap(paddr, size, region_paddr, region_size)) ++ { ++ printm("mm_free: memory(addr 0x%lx order %ld) overlap with free memory(addr 0x%lx order %d)\r\n", paddr, order, region_paddr, mm_region->order); ++ ret_val = -1; ++ break; ++ } ++ mm_region = mm_region->next_mm; ++ } ++ if(mm_region) ++ break; ++ ++ mm_list_head = mm_list_head->next_list_head; ++ } ++ if(mm_list_head) ++ { ++ goto mm_free_out; ++ } ++ ++ //insert with merge ++ ret_val = insert_mm_region(region_idx, mm_region, 1); ++ if(ret_val < 0) ++ { ++ printm("mm_free: failed to insert mm(addr 0x%lx, order %ld)\r\n in mm_regions[%d]\r\n", paddr, order, region_idx); ++ } ++ ++ printm("after mm_free\r\n"); ++ print_buddy_system(); ++ ++mm_free_out: ++ release_big_emem_lock(__func__); ++ return ret_val; ++} ++//TODO:Reserved interfaces for calls to reclaim unused memory ++int mm_free_clear(void* req_paddr, unsigned long free_size) ++{ ++ //check this paddr is 2^power aligned ++ uintptr_t paddr = (uintptr_t)req_paddr; ++ unsigned long order = ilog2(free_size-1) + 1; ++ unsigned long size = 1 << order; ++ if(check_mem_size(paddr, size) < 0) ++ return -1; ++ ++ int ret_val = 0; ++ int region_idx = 0; ++ struct mm_list_t* mm_region = PADDR_2_MM_LIST(paddr); ++ mm_region->order = order; ++ mm_region->prev_mm = NULL; ++ mm_region->next_mm = NULL; ++ ++ acquire_big_emem_lock(__func__); ++ //print_buddy_system(); ++ ++ for(region_idx=0; region_idx < N_PMP_REGIONS; ++region_idx) ++ { ++ if(mm_regions[region_idx].valid && region_contain(mm_regions[region_idx].paddr, mm_regions[region_idx].size, paddr, size)) ++ { ++ break; ++ } ++ } ++ if(region_idx >= N_PMP_REGIONS) ++ { ++ printm("mm_free_clear: buddy system doesn't contain memory(addr 0x%lx, order %ld)\r\n", paddr, order); ++ ret_val = -1; ++ goto mm_free_out; ++ } ++ ++ //check whether this region overlap with existing free mm_lists ++ struct mm_list_head_t* mm_list_head = mm_regions[region_idx].mm_list_head; ++ while(mm_list_head) ++ { ++ struct mm_list_t* mm_region = mm_list_head->mm_list; ++ while(mm_region) ++ { ++ uintptr_t region_paddr = (uintptr_t)MM_LIST_2_PADDR(mm_region); ++ unsigned long region_size = 1 << mm_region->order; ++ if(region_overlap(paddr, size, region_paddr, region_size)) ++ { ++ printm("mm_free_clear: memory(addr 0x%lx order %ld) overlap with free memory(addr 0x%lx order %d)\r\n", paddr, order, region_paddr, mm_region->order); ++ ret_val = -1; ++ break; ++ } ++ mm_region = mm_region->next_mm; ++ } ++ if(mm_region) ++ break; ++ ++ mm_list_head = mm_list_head->next_list_head; ++ } ++ if(mm_list_head) ++ { ++ goto mm_free_out; ++ } ++ ++ //insert with merge ++ ret_val = insert_mm_region(region_idx, mm_region, 1); ++ if(ret_val < 0) ++ { ++ printm("mm_free_clear: failed to insert mm(addr 0x%lx, order %ld)\r\n in mm_regions[%d]\r\n", paddr, order, region_idx); ++ } ++ ++ //printm("after mm_free\r\n"); ++ //print_buddy_system(); ++ int pmp_idx; ++ struct pmp_config_t pmp_config; ++ pmp_idx = REGION_TO_PMP(region_idx); ++ pmp_config = get_pmp(pmp_idx); ++ ++ struct mm_region_t mm_regiont = mm_regions[region_idx]; ++ mm_list_head = mm_regiont.mm_list_head; ++ struct mm_list_t *mm_list = mm_list_head->mm_list; ++ if (((long int *)MM_LIST_2_PADDR(mm_list) == (long int *)pmp_config.paddr)&&((pmp_config.size) == (1<order))) ++ { ++ delete_certain_region(region_idx, &mm_list_head, mm_list); ++ mm_regions[region_idx].valid = 0; ++ mm_regions[region_idx].paddr = 0; ++ mm_regions[region_idx].size = 0; ++ mm_regions[region_idx].mm_list_head = NULL; ++ clear_pmp_and_sync(pmp_idx); ++ pmp_bitmap &= ~(1 << pmp_idx); ++ } ++ ++ printm("***after mm_free***\r\n"); ++ print_buddy_system(); ++ dump_pmps(); ++ ++mm_free_out: ++ // spin_unlock(&pmp_bitmap_lock); ++ release_big_emem_lock(__func__); ++ return ret_val; ++} ++ ++int memory_reclaim(unsigned long* resp_size) ++{ ++ uintptr_t retval = 0; ++ ++ printm("[Penglai Monitor@%s %d] invoked\r\n", __func__, current_hartid()); ++ print_buddy_system(); ++ ++ retval = free_enclave_metadata(); ++ if(retval != 0) ++ { ++ printm_err("M mode: sm_memory_reclaim: free_enclave_metadata error\r\n"); ++ dump_pmps(); ++ return ENCLAVE_ERROR; ++ } ++ print_buddy_system(); ++ dump_pmps(); ++ return ENCLAVE_SUCCESS; ++} +\ No newline at end of file +diff --git a/lib/sbi/sm/platform/pmp/platform.c b/lib/sbi/sm/platform/pmp/platform.c +new file mode 100644 +index 0000000..995b63f +--- /dev/null ++++ b/lib/sbi/sm/platform/pmp/platform.c +@@ -0,0 +1,46 @@ ++#include "enclave_mm.c" ++#include "platform_thread.c" ++ ++#include ++ ++unsigned long ALIGN_UP_POWER_OF_2(unsigned long size){ ++ if (size <= 0) return 1; ++ if ((size & (size - 1)) == 0) return size; ++ size |= size >> 1; ++ size |= size >> 2; ++ size |= size >> 4; ++ size |= size >> 8; ++ size |= size >> 16; ++ size |= size >> 32; ++ return size + 1; ++} ++ ++int platform_init() ++{ ++ struct pmp_config_t pmp_config; ++ ++ //Clear pmp1, this pmp is reserved for allowing kernel ++ //to config page table for enclave in enclave's memory. ++ //There is no need to broadcast to other hart as every ++ //hart will execute this function. ++ //clear_pmp(1); ++ clear_pmp_and_sync(1); ++ printm("[Penglai Monitor@%s] init platfrom and prepare PMP\n", __func__); ++ //config the PMP 0 to protect security monitor ++ pmp_config.paddr = (uintptr_t)SM_BASE; ++ pmp_config.size = ALIGN_UP_POWER_OF_2((unsigned long)SM_SIZE); ++ pmp_config.mode = PMP_A_NAPOT; ++ pmp_config.perm = PMP_NO_PERM; ++ set_pmp_and_sync(0, pmp_config); ++ ++ //config the last PMP to allow kernel to access memory ++ pmp_config.paddr = 0; ++ pmp_config.size = -1UL; ++ pmp_config.mode = PMP_A_NAPOT; ++ pmp_config.perm = PMP_R | PMP_W | PMP_X; ++ //set_pmp(NPMP-1, pmp_config); ++ set_pmp_and_sync(NPMP-1, pmp_config); ++ ++ printm("[Penglai Monitor@%s] setting initial PMP ready\n", __func__); ++ return 0; ++} +\ No newline at end of file +diff --git a/lib/sbi/sm/platform/pmp/platform_thread.c b/lib/sbi/sm/platform/pmp/platform_thread.c +new file mode 100644 +index 0000000..8aa9df6 +--- /dev/null ++++ b/lib/sbi/sm/platform/pmp/platform_thread.c +@@ -0,0 +1,31 @@ ++void platform_enter_enclave_world() ++{ ++ return; ++} ++ ++void platform_exit_enclave_world() ++{ ++ return; ++} ++ ++int platform_check_in_enclave_world() ++{ ++ return 0; ++} ++ ++int platform_check_enclave_authentication(struct enclave_t* enclave) ++{ ++ if(enclave->thread_context.encl_ptbr != csr_read(CSR_SATP)) ++ return -1; ++ return 0; ++} ++ ++void platform_switch_to_enclave_ptbr(struct thread_state_t* thread, uintptr_t enclave_ptbr) ++{ ++ csr_write(CSR_SATP, enclave_ptbr); ++} ++ ++void platform_switch_to_host_ptbr(struct thread_state_t* thread, uintptr_t host_ptbr) ++{ ++ csr_write(CSR_SATP, host_ptbr); ++} +diff --git a/lib/sbi/sm/platform/spmp/enclave_mm.c b/lib/sbi/sm/platform/spmp/enclave_mm.c +new file mode 100644 +index 0000000..339cf15 +--- /dev/null ++++ b/lib/sbi/sm/platform/spmp/enclave_mm.c +@@ -0,0 +1,692 @@ ++#include ++#include ++#include ++//#include ++#include ++#include ++//#include "mtrap.h" ++#include ++#include ++ ++/* ++ * Only NPMP-3 enclave regions are supported. ++ * The last PMP is used to allow kernel to access memory. ++ * The second to last PMP is used to protect security monitor from kernel. ++ * The first PMP is used to allow kernel to configure enclave's page table. ++ * ++ * TODO: this array can be removed as we can get ++ * existing enclave regions via pmp registers ++ */ ++static struct mm_region_t mm_regions[N_PMP_REGIONS]; ++static unsigned long pmp_bitmap = 0; ++static spinlock_t pmp_bitmap_lock = SPINLOCK_INIT; ++ ++ ++static int check_mem_size(uintptr_t paddr, unsigned long size) ++{ ++ if((size == 0) || (size & (size - 1))) ++ { ++ printm("pmp size should be 2^power!\r\n"); ++ return -1; ++ } ++ ++ if(size < RISCV_PGSIZE) ++ { ++ printm("pmp size should be no less than one page!\r\n"); ++ return -1; ++ } ++ ++ if(paddr & (size - 1)) ++ { ++ printm("pmp size should be %d aligned!\r\n", size); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * This function grants kernel access to allocated enclave memory ++ * for initializing enclave and configuring page table. ++ */ ++int grant_kernel_access(void* req_paddr, unsigned long size) ++{ ++ //pmp0 is used for allowing kernel to access enclave memory ++ int pmp_idx = 0; ++ struct pmp_config_t pmp_config; ++ uintptr_t paddr = (uintptr_t)req_paddr; ++ ++ if(check_mem_size(paddr, size) != 0) ++ return -1; ++ ++ pmp_config.paddr = paddr; ++ pmp_config.size = size; ++ pmp_config.perm = PMP_R | PMP_W | PMP_X; ++ pmp_config.mode = PMP_A_NAPOT; ++ set_pmp_and_sync(pmp_idx, pmp_config); ++ ++ return 0; ++} ++ ++/* ++ * This function retrieves kernel access to allocated enclave memory. ++ */ ++int retrieve_kernel_access(void* req_paddr, unsigned long size) ++{ ++#if 0 ++ //pmp0 is used for allowing kernel to access enclave memory ++ int pmp_idx = 0; ++ struct pmp_config_t pmp_config; ++ uintptr_t paddr = (uintptr_t)req_paddr; ++ ++ pmp_config = get_pmp(pmp_idx); ++ ++ if((pmp_config.mode != PMP_NAPOT) || (pmp_config.paddr != paddr) || (pmp_config.size != size)) ++ { ++ printm("retrieve_kernel_access: error pmp_config\r\n"); ++ return -1; ++ } ++ ++ clear_pmp_and_sync(pmp_idx); ++ ++ return 0; ++#else ++ //FIXME(DD): we always allow kernel access the memory now ++ return 0; ++#endif ++} ++ ++//grant enclave access to enclave's memory ++int grant_enclave_access(struct enclave_t* enclave) ++{ ++#if 0 ++ int region_idx = 0; ++ int pmp_idx = 0; ++ struct pmp_config_t pmp_config; ++ struct spmp_config_t spmp_config; ++ ++ if(check_mem_size(enclave->paddr, enclave->size) < 0) ++ return -1; ++ ++ //set pmp permission, ensure that enclave's paddr and size is pmp legal ++ //TODO: support multiple memory regions ++ spinlock_lock(&pmp_bitmap_lock); ++ for(region_idx = 0; region_idx < N_PMP_REGIONS; ++region_idx) ++ { ++ if(mm_regions[region_idx].valid && region_contain( ++ mm_regions[region_idx].paddr, mm_regions[region_idx].size, ++ enclave->paddr, enclave->size)) ++ { ++ break; ++ } ++ } ++ spinlock_unlock(&pmp_bitmap_lock); ++ ++ if(region_idx >= N_PMP_REGIONS) ++ { ++ printm("M mode: grant_enclave_access: can not find exact mm_region\r\n"); ++ return -1; ++ } ++ ++ pmp_idx = REGION_TO_PMP(region_idx); ++ pmp_config.paddr = mm_regions[region_idx].paddr; ++ pmp_config.size = mm_regions[region_idx].size; ++ pmp_config.perm = PMP_R | PMP_W | PMP_X; ++ pmp_config.mode = PMP_NAPOT; ++ set_pmp(pmp_idx, pmp_config); ++ ++ spmp_config.paddr = enclave->paddr; ++ spmp_config.size = enclave->size; ++ spmp_config.perm = SPMP_R | SPMP_W | SPMP_X; ++ spmp_config.mode = SPMP_NAPOT; ++ set_spmp(0, spmp_config); ++ ++ spmp_config.paddr = mm_regions[region_idx].paddr; ++ spmp_config.size = mm_regions[region_idx].size; ++ spmp_config.perm = SPMP_NO_PERM; ++ spmp_config.mode = SPMP_NAPOT; ++ set_spmp(1, spmp_config); ++ ++ return 0; ++#else ++ /* FIXME(DD): do nothing on PMP now */ ++ return 0; ++#endif ++} ++ ++int retrieve_enclave_access(struct enclave_t *enclave) ++{ ++ int region_idx = 0; ++ int pmp_idx = 0; ++ struct pmp_config_t pmp_config; ++ ++ //set pmp permission, ensure that enclave's paddr and size is pmp legal ++ //TODO: support multiple memory regions ++ spin_lock(&pmp_bitmap_lock); ++ for(region_idx = 0; region_idx < N_PMP_REGIONS; ++region_idx) ++ { ++ if(mm_regions[region_idx].valid && region_contain( ++ mm_regions[region_idx].paddr, mm_regions[region_idx].size, ++ enclave->paddr, enclave->size)) ++ { ++ break; ++ } ++ } ++ spin_unlock(&pmp_bitmap_lock); ++ ++#if 0 //FIXME(DD): disable PMP ops now ++ if(region_idx >= N_PMP_REGIONS) ++ { ++ printm("M mode: Error: retriece_enclave_access\r\n"); ++ return -1; ++ } ++ ++ pmp_idx = REGION_TO_PMP(region_idx); ++ pmp_config = get_pmp(pmp_idx); ++ pmp_config.perm = PMP_NO_PERM; ++ set_pmp(pmp_idx, pmp_config); ++ ++ clear_spmp(0); ++ clear_spmp(1); ++#endif ++ ++ return 0; ++} ++ ++int check_mem_overlap(uintptr_t paddr, unsigned long size) ++{ ++ unsigned long sm_base = SM_BASE; ++ unsigned long sm_size = SM_SIZE; ++ int region_idx = 0; ++ ++ //check whether the new region overlaps with security monitor ++ if(region_overlap(sm_base, sm_size, paddr, size)) ++ { ++ printm("pmp memory overlaps with security monitor!\r\n"); ++ return -1; ++ } ++ ++ //check whether the new region overlap with existing enclave region ++ for(region_idx = 0; region_idx < N_PMP_REGIONS; ++region_idx) ++ { ++ if(mm_regions[region_idx].valid ++ && region_overlap(mm_regions[region_idx].paddr, mm_regions[region_idx].size, ++ paddr, size)) ++ { ++ printm("pmp memory overlaps with existing pmp memory!\r\n"); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++uintptr_t mm_init(uintptr_t paddr, unsigned long size) ++{ ++ uintptr_t retval = 0; ++ int region_idx = 0; ++ int pmp_idx =0; ++ struct pmp_config_t pmp_config; ++ ++ //check align of paddr and size ++ if(check_mem_size(paddr, size) < 0) ++ return -1UL; ++ ++ //acquire a free enclave region ++ spin_lock(&pmp_bitmap_lock); ++ ++ //check memory overlap ++ //memory overlap should be checked after acquire lock ++ if(check_mem_overlap(paddr, size) < 0) ++ { ++ retval = -1UL; ++ goto out; ++ } ++ ++ //alloc a free pmp ++ for(region_idx = 0; region_idx < N_PMP_REGIONS; ++region_idx) ++ { ++ pmp_idx = REGION_TO_PMP(region_idx); ++ if(!(pmp_bitmap & (1<= N_PMP_REGIONS) ++ { ++ retval = -1UL; ++ goto out; ++ } ++ ++ //set PMP to protect enclave memory region ++ pmp_config.paddr = paddr; ++ pmp_config.size = size; ++ pmp_config.perm = PMP_NO_PERM; ++ pmp_config.mode = PMP_A_NAPOT; ++ set_pmp_and_sync(pmp_idx, pmp_config); ++ ++ //mark this region is valid and init mm_list ++ mm_regions[region_idx].valid = 1; ++ mm_regions[region_idx].paddr = paddr; ++ mm_regions[region_idx].size = size; ++ struct mm_list_t *mm_list = (struct mm_list_t*)PADDR_2_MM_LIST(paddr); ++ mm_list->order = ilog2(size-1) + 1; ++ mm_list->prev_mm = NULL; ++ mm_list->next_mm = NULL; ++ struct mm_list_head_t *mm_list_head = (struct mm_list_head_t*)paddr; ++ mm_list_head->order = mm_list->order; ++ mm_list_head->prev_list_head = NULL; ++ mm_list_head->next_list_head = NULL; ++ mm_list_head->mm_list = mm_list; ++ mm_regions[region_idx].mm_list_head = mm_list_head; ++ ++out: ++ spin_unlock(&pmp_bitmap_lock); ++ return retval; ++} ++ ++//NOTE: this function may modify the arg mm_list_head ++//remember to acquire lock before calling this function ++//be sure that mm_region does exist in mm_list and mm_list does exist in mm_lists ++static int delete_certain_region(int region_idx, struct mm_list_head_t** mm_list_head, struct mm_list_t *mm_region) ++{ ++ struct mm_list_t* prev_mm = mm_region->prev_mm; ++ struct mm_list_t* next_mm = mm_region->next_mm; ++ struct mm_list_head_t* prev_list_head = (*mm_list_head)->prev_list_head; ++ struct mm_list_head_t* next_list_head = (*mm_list_head)->next_list_head; ++ ++ //delete mm_region from old mm_list ++ //mm_region is in the middle of the mm_list ++ if(prev_mm) ++ { ++ prev_mm->next_mm = next_mm; ++ if(next_mm) ++ next_mm->prev_mm = prev_mm; ++ } ++ //mm_region is in the first place of old mm_list ++ else if(next_mm) ++ { ++ next_mm->prev_mm = NULL; ++ struct mm_list_head_t* new_list_head = (struct mm_list_head_t*)MM_LIST_2_PADDR(next_mm); ++ new_list_head->order = next_mm->order; ++ new_list_head->prev_list_head = prev_list_head; ++ new_list_head->next_list_head = next_list_head; ++ new_list_head->mm_list = next_mm; ++ if(prev_list_head) ++ prev_list_head->next_list_head = new_list_head; ++ else ++ mm_regions[region_idx].mm_list_head = new_list_head; ++ if(next_list_head) ++ next_list_head->prev_list_head = new_list_head; ++ ++ *mm_list_head = new_list_head; ++ } ++ //mm_region is the only region in old mm_list ++ else ++ { ++ if(prev_list_head) ++ prev_list_head->next_list_head = next_list_head; ++ else ++ mm_regions[region_idx].mm_list_head = next_list_head; ++ if(next_list_head) ++ next_list_head->prev_list_head = prev_list_head; ++ ++ *mm_list_head = NULL; ++ } ++ ++ return 0; ++} ++ ++//remember to acquire a lock before calling this function ++static struct mm_list_t* alloc_one_region(int region_idx, int order) ++{ ++ if(!mm_regions[region_idx].valid || !mm_regions[region_idx].mm_list_head) ++ { ++ printm("M mode: alloc_one_region: m_regions[%d] is invalid/NULL\r\n", region_idx); ++ return NULL; ++ } ++ ++ struct mm_list_head_t *mm_list_head = mm_regions[region_idx].mm_list_head; ++ while(mm_list_head && (mm_list_head->order < order)) ++ { ++ mm_list_head = mm_list_head->next_list_head; ++ } ++ ++ //current region has no enough free space ++ if(!mm_list_head) ++ return NULL; ++ ++ //pick a mm region from current mm_list ++ struct mm_list_t *mm_region = mm_list_head->mm_list; ++ ++ //delete the mm region from current mm_list ++ delete_certain_region(region_idx, &mm_list_head, mm_region); ++ ++ return mm_region; ++} ++ ++//remember to acquire lock before calling this function ++//be sure that mm_list_head does exist in mm_lists ++static int merge_regions(int region_idx, struct mm_list_head_t* mm_list_head, struct mm_list_t *mm_region) ++{ ++ if(region_idx<0 || region_idx>=N_PMP_REGIONS || !mm_list_head || !mm_region) ++ return -1; ++ if(mm_list_head->order != mm_region->order) ++ return -1; ++ ++ struct mm_list_head_t* current_list_head = mm_list_head; ++ struct mm_list_t* current_region = mm_region; ++ while(current_list_head) ++ { ++ struct mm_list_t* buddy_region = current_list_head->mm_list; ++ unsigned long paddr = (unsigned long)MM_LIST_2_PADDR(current_region); ++ unsigned long buddy_paddr = (unsigned long)MM_LIST_2_PADDR(buddy_region); ++ while(buddy_region) ++ { ++ buddy_paddr = (unsigned long)MM_LIST_2_PADDR(buddy_region); ++ if((paddr | (1 << current_region->order)) == (buddy_paddr | (1 << current_region->order))) ++ break; ++ buddy_region = buddy_region->next_mm; ++ } ++ ++ struct mm_list_head_t* new_list_head = (struct mm_list_head_t*)MM_LIST_2_PADDR(current_region); ++ struct mm_list_head_t* prev_list_head = current_list_head->prev_list_head; ++ struct mm_list_head_t* next_list_head = current_list_head->next_list_head; ++ //didn't find buddy region, just insert this region in current mm_list ++ if(!buddy_region) ++ { ++ current_region->prev_mm = NULL; ++ current_region->next_mm = current_list_head->mm_list; ++ current_list_head->mm_list->prev_mm = current_region; ++ new_list_head->order = current_region->order; ++ new_list_head->prev_list_head = prev_list_head; ++ new_list_head->next_list_head = next_list_head; ++ new_list_head->mm_list = current_region; ++ ++ if(prev_list_head) ++ prev_list_head->next_list_head = new_list_head; ++ else ++ mm_regions[region_idx].mm_list_head = new_list_head; ++ if(next_list_head) ++ next_list_head->prev_list_head = new_list_head; ++ ++ break; ++ } ++ ++ //found buddy_region, merge it and current region ++ ++ //first delete buddy_region from old mm_list ++ //Note that this function may modify prev_list and next_list ++ //but won't modify their positions relative to new mm_region ++ delete_certain_region(region_idx, ¤t_list_head, buddy_region); ++ ++ //then merge buddy_region with current region ++ int order = current_region->order; ++ current_region = paddr < buddy_paddr ? PADDR_2_MM_LIST(paddr) : PADDR_2_MM_LIST(buddy_paddr); ++ current_region->order = order + 1; ++ current_region->prev_mm = NULL; ++ current_region->next_mm = NULL; ++ ++ //next mm_list doesn't exist or has a different order, no need to merge ++ if(!next_list_head || next_list_head->order != current_region->order) ++ { ++ //current_list_head may be NULL now after delete buddy region ++ if(current_list_head) ++ prev_list_head = current_list_head; ++ new_list_head = (struct mm_list_head_t*)MM_LIST_2_PADDR(current_region); ++ new_list_head->order = current_region->order; ++ new_list_head->prev_list_head = prev_list_head; ++ new_list_head->next_list_head = next_list_head; ++ new_list_head->mm_list = current_region; ++ ++ if(prev_list_head) ++ prev_list_head->next_list_head = new_list_head; ++ else ++ mm_regions[region_idx].mm_list_head = new_list_head; ++ if(next_list_head) ++ next_list_head->prev_list_head = new_list_head; ++ ++ break; ++ } ++ ++ //continue to merge with next mm_list ++ current_list_head = next_list_head; ++ } ++ ++ return 0; ++} ++ ++//remember to acquire lock before calling this function ++static int insert_mm_region(int region_idx, struct mm_list_t* mm_region, int merge) ++{ ++ if(region_idx<0 || region_idx>=N_PMP_REGIONS || !mm_regions[region_idx].valid || !mm_region) ++ return -1; ++ ++ struct mm_list_head_t* mm_list_head = mm_regions[region_idx].mm_list_head; ++ struct mm_list_head_t* prev_list_head = NULL; ++ ++ //there is no mm_list in current pmp_region ++ if(!mm_list_head) ++ { ++ mm_list_head = (struct mm_list_head_t*)MM_LIST_2_PADDR(mm_region); ++ mm_list_head->order = mm_region->order; ++ mm_list_head->prev_list_head = NULL; ++ mm_list_head->next_list_head = NULL; ++ mm_list_head->mm_list = mm_region; ++ mm_regions[region_idx].mm_list_head = mm_list_head; ++ return 0; ++ } ++ ++ //traversal from front to back ++ while(mm_list_head && mm_list_head->order < mm_region->order) ++ { ++ prev_list_head = mm_list_head; ++ mm_list_head = mm_list_head->next_list_head; ++ } ++ ++ //found the exact mm_list ++ int ret_val = 0; ++ struct mm_list_head_t *new_list_head = (struct mm_list_head_t*)MM_LIST_2_PADDR(mm_region); ++ if(mm_list_head && mm_list_head->order == mm_region->order) ++ { ++ if(!merge) ++ { ++ //insert mm_region to the first pos in mm_list ++ mm_region->prev_mm = NULL; ++ mm_region->next_mm = mm_list_head->mm_list; ++ mm_list_head->mm_list->prev_mm = mm_region; ++ ++ //set mm_list_head ++ struct mm_list_head_t* next_list_head = mm_list_head->next_list_head; ++ new_list_head->order = mm_region->order; ++ new_list_head->prev_list_head = prev_list_head; ++ new_list_head->next_list_head = next_list_head; ++ new_list_head->mm_list = mm_region; ++ if(prev_list_head) ++ prev_list_head->next_list_head = new_list_head; ++ else ++ mm_regions[region_idx].mm_list_head = new_list_head; ++ if(next_list_head) ++ next_list_head->prev_list_head = new_list_head; ++ } ++ else ++ { ++ //insert with merge ++ ret_val = merge_regions(region_idx, mm_list_head, mm_region); ++ } ++ } ++ //should create a new mm_list for this mm region ++ //note that mm_list_head might be NULL ++ else ++ { ++ new_list_head->order = mm_region->order; ++ new_list_head->prev_list_head = prev_list_head; ++ new_list_head->next_list_head = mm_list_head; ++ new_list_head->mm_list = mm_region; ++ if(prev_list_head) ++ prev_list_head->next_list_head = new_list_head; ++ else ++ mm_regions[region_idx].mm_list_head = new_list_head; ++ if(mm_list_head) ++ mm_list_head->prev_list_head = new_list_head; ++ } ++ ++ return ret_val; ++} ++ ++//TODO: delete this function ++void print_buddy_system() ++{ ++ //spinlock_lock(&pmp_bitmap_lock); ++ ++ struct mm_list_head_t* mm_list_head = mm_regions[0].mm_list_head; ++ printm("struct mm_list_head_t size is 0x%lx\r\n", sizeof(struct mm_list_head_t)); ++ printm("struct mm_list_t size is 0x%lx\r\n", sizeof(struct mm_list_t)); ++ while(mm_list_head) ++ { ++ printm("mm_list_head addr is 0x%lx, order is %d\r\n", mm_list_head, mm_list_head->order); ++ printm("mm_list_head prev is 0x%lx, next is 0x%lx, mm_list is 0x%lx\r\n", mm_list_head->prev_list_head, mm_list_head->next_list_head, mm_list_head->mm_list); ++ struct mm_list_t *mm_region = mm_list_head->mm_list; ++ while(mm_region) ++ { ++ printm(" mm_region addr is 0x%lx, order is %d\r\n", mm_region, mm_region->order); ++ printm(" mm_region prev is 0x%lx, next is 0x%lx\r\n", mm_region->prev_mm, mm_region->next_mm); ++ mm_region = mm_region->next_mm; ++ } ++ mm_list_head = mm_list_head->next_list_head; ++ } ++ ++ //spinlock_unlock(&pmp_bitmap_lock); ++} ++ ++void* mm_alloc(unsigned long req_size, unsigned long *resp_size) ++{ ++ void* ret_addr = NULL; ++ if(req_size == 0) ++ return ret_addr; ++ ++ //TODO: reduce lock granularity ++ spin_lock(&pmp_bitmap_lock); ++ ++ //printm("before mm_alloc, req_order = %d\r\n", ilog2(req_size - 1) + 1); ++ //print_buddy_system(); ++ ++ unsigned long order = ilog2(req_size-1) + 1; ++ for(int region_idx=0; region_idx < N_PMP_REGIONS; ++region_idx) ++ { ++ struct mm_list_t* mm_region = alloc_one_region(region_idx, order); ++ ++ //there is no enough space in current pmp region ++ if(!mm_region) ++ continue; ++ ++ while(mm_region->order > order) ++ { ++ //allocated mm region need to be split ++ mm_region->order -= 1; ++ mm_region->prev_mm = NULL; ++ mm_region->next_mm = NULL; ++ ++ void* new_mm_region_paddr = MM_LIST_2_PADDR(mm_region) + (1 << mm_region->order); ++ struct mm_list_t* new_mm_region = PADDR_2_MM_LIST(new_mm_region_paddr); ++ new_mm_region->order = mm_region->order; ++ new_mm_region->prev_mm = NULL; ++ new_mm_region->next_mm = NULL; ++ insert_mm_region(region_idx, new_mm_region, 0); ++ } ++ ++ ret_addr = MM_LIST_2_PADDR(mm_region); ++ break; ++ } ++ ++ //printm("after mm_alloc\r\n"); ++ //print_buddy_system(); ++ ++ spin_unlock(&pmp_bitmap_lock); ++ ++ if(ret_addr && resp_size) ++ { ++ *resp_size = 1 << order; ++ sbi_memset(ret_addr, 0, *resp_size); ++ } ++ ++ return ret_addr; ++} ++ ++int mm_free(void* req_paddr, unsigned long free_size) ++{ ++ //check this paddr is 2^power aligned ++ uintptr_t paddr = (uintptr_t)req_paddr; ++ unsigned long order = ilog2(free_size-1) + 1; ++ unsigned long size = 1 << order; ++ if(check_mem_size(paddr, size) < 0) ++ return -1; ++ ++ int ret_val = 0; ++ int region_idx = 0; ++ struct mm_list_t* mm_region = PADDR_2_MM_LIST(paddr); ++ mm_region->order = order; ++ mm_region->prev_mm = NULL; ++ mm_region->next_mm = NULL; ++ ++ spin_lock(&pmp_bitmap_lock); ++ ++ //printm("before mm_free, addr to free is 0x%lx, order is %d\r\n", paddr, order); ++ //print_buddy_system(); ++ ++ for(region_idx=0; region_idx < N_PMP_REGIONS; ++region_idx) ++ { ++ if(mm_regions[region_idx].valid && region_contain(mm_regions[region_idx].paddr, mm_regions[region_idx].size, paddr, size)) ++ { ++ break; ++ } ++ } ++ if(region_idx >= N_PMP_REGIONS) ++ { ++ printm("mm_free: buddy system doesn't contain memory(addr 0x%lx, order %d)\r\n", paddr, order); ++ ret_val = -1; ++ goto mm_free_out; ++ } ++ ++ //check whether this region overlap with existing free mm_lists ++ struct mm_list_head_t* mm_list_head = mm_regions[region_idx].mm_list_head; ++ while(mm_list_head) ++ { ++ struct mm_list_t* mm_region = mm_list_head->mm_list; ++ while(mm_region) ++ { ++ uintptr_t region_paddr = (uintptr_t)MM_LIST_2_PADDR(mm_region); ++ unsigned long region_size = 1 << mm_region->order; ++ if(region_overlap(paddr, size, region_paddr, region_size)) ++ { ++ printm("mm_free: memory(addr 0x%lx order %d) overlap with free memory(addr 0x%lx order %d)\r\n", paddr, order, region_paddr, mm_region->order); ++ ret_val = -1; ++ break; ++ } ++ mm_region = mm_region->next_mm; ++ } ++ if(mm_region) ++ break; ++ ++ mm_list_head = mm_list_head->next_list_head; ++ } ++ if(mm_list_head) ++ { ++ goto mm_free_out; ++ } ++ ++ //insert with merge ++ ret_val = insert_mm_region(region_idx, mm_region, 1); ++ if(ret_val < 0) ++ { ++ printm("mm_free: failed to insert mm(addr 0x%lx, order %d)\r\n in mm_regions[%d]\r\n", paddr, order, region_idx); ++ } ++ ++ //printm("after mm_free\r\n"); ++ //print_buddy_system(); ++ ++mm_free_out: ++ spin_unlock(&pmp_bitmap_lock); ++ return ret_val; ++} +diff --git a/lib/sbi/sm/platform/spmp/ipi_handler.c b/lib/sbi/sm/platform/spmp/ipi_handler.c +new file mode 100644 +index 0000000..83b868f +--- /dev/null ++++ b/lib/sbi/sm/platform/spmp/ipi_handler.c +@@ -0,0 +1,21 @@ ++#include ++#include ++ ++void handle_ipi_mail() ++{ ++ char* mail_data = ipi_mail.data; ++ int pmp_idx = 0; ++ struct pmp_config_t pmp_config; ++ //printm("hart%d: handle ipi event%x\r\n", read_csr(mhartid), ipi_mail.event); ++ ++ switch(ipi_mail.event) ++ { ++ case IPI_PMP_SYNC: ++ pmp_config = *(struct pmp_config_t*)(ipi_mail.data); ++ pmp_idx = *(int*)((void*)ipi_mail.data + sizeof(struct pmp_config_t)); ++ set_pmp(pmp_idx, pmp_config); ++ break; ++ default: ++ break; ++ } ++} +diff --git a/lib/sbi/sm/platform/spmp/platform.c b/lib/sbi/sm/platform/spmp/platform.c +new file mode 100644 +index 0000000..285a775 +--- /dev/null ++++ b/lib/sbi/sm/platform/spmp/platform.c +@@ -0,0 +1,42 @@ ++#include "spmp.c" ++#include "enclave_mm.c" ++#include "ipi_handler.c" ++#include "platform_thread.c" ++ ++#include ++ ++int platform_init() ++{ ++ //Clear pmp0, this pmp is reserved for allowing kernel ++ //to config page table for enclave in enclave's memory. ++ //There is no need to broadcast to other hart as every ++ //hart will execute this function. ++ clear_pmp(0); ++ printm("[Penglai Monitor@%s] init platfrom and prepare PMP\n", __func__); ++ //config the last PMP to allow kernel to access memory ++ struct pmp_config_t pmp_config; ++ pmp_config.paddr = 0; ++ pmp_config.size = -1UL; ++ pmp_config.mode = PMP_A_NAPOT; ++ pmp_config.perm = PMP_R | PMP_W | PMP_X; ++ set_pmp(NPMP-1, pmp_config); ++ ++ //config the last-1 PMP to protect security monitor ++ pmp_config.paddr = (uintptr_t)SM_BASE; ++ pmp_config.size = (unsigned long)SM_SIZE; ++ pmp_config.mode = PMP_A_NAPOT; ++ pmp_config.perm = PMP_NO_PERM; ++ set_pmp(NPMP-2, pmp_config); ++ ++ printm("[Penglai Monitor@%s] PMP is ready, now setup sPMP\n", __func__); ++ ++ //config the last sPMP to allow user to access memory ++ struct spmp_config_t spmp_config; ++ spmp_config.paddr = 0; ++ spmp_config.size = -1UL; ++ spmp_config.mode = SPMP_NAPOT; ++ spmp_config.perm = SPMP_R | SPMP_W | SPMP_X; ++ set_spmp(NSPMP-1, spmp_config); ++ ++ return 0; ++} +diff --git a/lib/sbi/sm/platform/spmp/platform_thread.c b/lib/sbi/sm/platform/spmp/platform_thread.c +new file mode 100644 +index 0000000..eb8e680 +--- /dev/null ++++ b/lib/sbi/sm/platform/spmp/platform_thread.c +@@ -0,0 +1,34 @@ ++void platform_enter_enclave_world() ++{ ++ //TODO: add register to indicate whether in encalve world or not ++ return; ++} ++ ++void platform_exit_enclave_world() ++{ ++ //TODO: add register to indicate whether in encalve world or not ++ return; ++} ++ ++int platform_check_in_enclave_world() ++{ ++ //TODO: add register to indicate whether in encalve world or not ++ return 0; ++} ++ ++int platform_check_enclave_authentication(struct enclave_t* enclave) ++{ ++ if(enclave->thread_context.encl_ptbr != csr_read(CSR_SATP)) ++ return -1; ++ return 0; ++} ++ ++void platform_switch_to_enclave_ptbr(struct thread_state_t* thread, uintptr_t enclave_ptbr) ++{ ++ csr_write(CSR_SATP, enclave_ptbr); ++} ++ ++void platform_switch_to_host_ptbr(struct thread_state_t* thread, uintptr_t host_ptbr) ++{ ++ csr_write(CSR_SATP, host_ptbr); ++} +diff --git a/lib/sbi/sm/platform/spmp/spmp.c b/lib/sbi/sm/platform/spmp/spmp.c +new file mode 100644 +index 0000000..2ce3fcd +--- /dev/null ++++ b/lib/sbi/sm/platform/spmp/spmp.c +@@ -0,0 +1,171 @@ ++#include ++#include ++#include ++ ++void set_spmp(int spmp_idx, struct spmp_config_t spmp_cfg_t) ++{ ++#if 0 ++ uintptr_t spmp_address = 0; ++ uintptr_t old_config = 0; ++ uintptr_t spmp_config = ((spmp_cfg_t.mode & SPMP_A) | (spmp_cfg_t.perm & (SPMP_R|SPMP_W|SPMP_X))) ++ << ((uintptr_t)SPMPCFG_BIT_NUM * (spmp_idx % SPMP_PER_CFG_REG)); ++ ++ switch(spmp_cfg_t.mode) ++ { ++ case SPMP_NAPOT: ++ if(spmp_cfg_t.paddr == 0 && spmp_cfg_t.size == -1UL) ++ spmp_address = -1UL; ++ else ++ spmp_address = (spmp_cfg_t.paddr | ((spmp_cfg_t.size>>1)-1)) >> 2; ++ break; ++ case SPMP_TOR: ++ spmp_address = spmp_cfg_t.paddr; ++ case SPMP_NA4: ++ spmp_address = spmp_cfg_t.paddr; ++ case SPMP_OFF: ++ spmp_address = 0; ++ default: ++ break; ++ } ++ ++ switch(spmp_idx) ++ { ++ case 0: ++ old_config = read_spmpcfg(spmpcfg0); ++ spmp_config |= (old_config & ++ ~((uintptr_t)SPMPCFG_BITS << (uintptr_t)SPMPCFG_BIT_NUM*(0%SPMP_PER_CFG_REG))); ++ SPMP_SET(spmpaddr0, spmpcfg0, spmp_address, spmp_config); ++ break; ++ case 1: ++ old_config = read_spmpcfg(spmpcfg0); ++ spmp_config |= (old_config & ++ ~((uintptr_t)SPMPCFG_BITS << (uintptr_t)SPMPCFG_BIT_NUM*(1%SPMP_PER_CFG_REG))); ++ SPMP_SET(spmpaddr1, spmpcfg0, spmp_address, spmp_config); ++ break; ++ case 2: ++ old_config = read_spmpcfg(spmpcfg0); ++ spmp_config |= (old_config & ++ ~((uintptr_t)SPMPCFG_BITS << (uintptr_t)SPMPCFG_BIT_NUM*(2%SPMP_PER_CFG_REG))); ++ SPMP_SET(spmpaddr2, spmpcfg0, spmp_address, spmp_config); ++ break; ++ case 3: ++ old_config = read_spmpcfg(spmpcfg0); ++ spmp_config |= (old_config & ++ ~((uintptr_t)SPMPCFG_BITS << (uintptr_t)SPMPCFG_BIT_NUM*(3%SPMP_PER_CFG_REG))); ++ SPMP_SET(spmpaddr3, spmpcfg0, spmp_address, spmp_config); ++ break; ++ case 4: ++ old_config = read_spmpcfg(spmpcfg0); ++ spmp_config |= (old_config & ++ ~((uintptr_t)SPMPCFG_BITS << (uintptr_t)SPMPCFG_BIT_NUM*(4%SPMP_PER_CFG_REG))); ++ SPMP_SET(spmpaddr4, spmpcfg0, spmp_address, spmp_config); ++ break; ++ case 5: ++ old_config = read_spmpcfg(spmpcfg0); ++ spmp_config |= (old_config & ++ ~((uintptr_t)SPMPCFG_BITS << (uintptr_t)SPMPCFG_BIT_NUM*(5%SPMP_PER_CFG_REG))); ++ SPMP_SET(spmpaddr5, spmpcfg0, spmp_address, spmp_config); ++ break; ++ case 6: ++ old_config = read_spmpcfg(spmpcfg0); ++ spmp_config |= (old_config & ++ ~((uintptr_t)SPMPCFG_BITS << (uintptr_t)SPMPCFG_BIT_NUM*(6%SPMP_PER_CFG_REG))); ++ SPMP_SET(spmpaddr6, spmpcfg0, spmp_address, spmp_config); ++ break; ++ case 7: ++ old_config = read_spmpcfg(spmpcfg0); ++ spmp_config |= (old_config & ++ ~((uintptr_t)SPMPCFG_BITS << (uintptr_t)SPMPCFG_BIT_NUM*(7%SPMP_PER_CFG_REG))); ++ SPMP_SET(spmpaddr7, spmpcfg0, spmp_address, spmp_config); ++ break; ++ default: ++ break; ++ } ++#endif ++ return; ++} ++ ++void clear_spmp(int spmp_idx) ++{ ++#if 0 ++ struct spmp_config_t spmp_cfg; ++ ++ spmp_cfg.mode = SPMP_OFF; ++ spmp_cfg.perm = SPMP_NO_PERM; ++ spmp_cfg.paddr = 0; ++ spmp_cfg.size = 0; ++ set_spmp(spmp_idx, spmp_cfg); ++#endif ++ return; ++} ++ ++struct spmp_config_t get_spmp(int spmp_idx) ++{ ++ struct spmp_config_t spmp={0,}; ++#if 0 ++ uintptr_t spmp_address = 0; ++ uintptr_t spmp_config = 0; ++ unsigned long order = 0; ++ unsigned long size = 0; ++ ++ switch(spmp_idx) ++ { ++ case 0: ++ SPMP_READ(spmpaddr0, spmpcfg0, spmp_address, spmp_config); ++ break; ++ case 1: ++ SPMP_READ(spmpaddr1, spmpcfg0, spmp_address, spmp_config); ++ break; ++ case 2: ++ SPMP_READ(spmpaddr2, spmpcfg0, spmp_address, spmp_config); ++ break; ++ case 3: ++ SPMP_READ(spmpaddr3, spmpcfg0, spmp_address, spmp_config); ++ break; ++ case 4: ++ SPMP_READ(spmpaddr4, spmpcfg0, spmp_address, spmp_config); ++ break; ++ case 5: ++ SPMP_READ(spmpaddr5, spmpcfg0, spmp_address, spmp_config); ++ break; ++ case 6: ++ SPMP_READ(spmpaddr6, spmpcfg0, spmp_address, spmp_config); ++ break; ++ case 7: ++ SPMP_READ(spmpaddr7, spmpcfg0, spmp_address, spmp_config); ++ break; ++ default: ++ break; ++ } ++ ++ spmp_config >>= (uintptr_t)SPMPCFG_BIT_NUM * (spmp_idx % SPMP_PER_CFG_REG); ++ spmp_config &= SPMPCFG_BITS; ++ switch(spmp_config & SPMP_A) ++ { ++ case SPMP_NAPOT: ++ while(spmp_address & 1) ++ { ++ order += 1; ++ spmp_address >>= 1; ++ } ++ order += 3; ++ size = 1 << order; ++ spmp_address <<= (order-1); ++ break; ++ case SPMP_NA4: ++ size = 4; ++ case SPMP_TOR: ++ break; ++ case SPMP_OFF: ++ spmp_address = 0; ++ size = 0; ++ break; ++ } ++ ++ spmp.mode = spmp_config & SPMP_A; ++ spmp.perm = spmp_config & (SPMP_R | SPMP_W | SPMP_X); ++ spmp.paddr = spmp_address; ++ spmp.size = size; ++#endif ++ return spmp; ++} +diff --git a/lib/sbi/sm/pmp.c b/lib/sbi/sm/pmp.c +new file mode 100644 +index 0000000..4977248 +--- /dev/null ++++ b/lib/sbi/sm/pmp.c +@@ -0,0 +1,321 @@ ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * \brief Set pmp and sync all harts. ++ * ++ * \param pmp_idx_arg The pmp index. ++ * \param pmp_config_arg The pmp config. ++ */ ++void set_pmp_and_sync(int pmp_idx_arg, struct pmp_config_t pmp_config_arg) ++{ ++ struct pmp_data_t pmp_data; ++ ++ u32 source_hart = current_hartid(); ++ ++ //set current hart's pmp ++ set_pmp(pmp_idx_arg, pmp_config_arg); ++ //sync all other harts ++ SBI_PMP_DATA_INIT(&pmp_data, pmp_config_arg, pmp_idx_arg, source_hart); ++ sbi_send_pmp(0xFFFFFFFF&(~(1<>1)-1)) >> 2; ++ } ++ break; ++ case PMP_A_TOR: ++ pmp_address = pmp_cfg_t.paddr; ++ break; ++ case PMP_A_NA4: ++ pmp_address = pmp_cfg_t.paddr; ++ case PMP_OFF: ++ pmp_address = 0; ++ break; ++ default: ++ pmp_address = 0; ++ break; ++ } ++ set_pmp_reg(pmp_idx, &pmp_address, &pmp_config); ++ ++ return; ++} ++ ++/** ++ * \brief clear the configuration of a PMP register ++ * ++ * \param pmp_idx the index of target PMP register ++ */ ++void clear_pmp(int pmp_idx) ++{ ++ struct pmp_config_t pmp_cfg_t; ++ ++ pmp_cfg_t.mode = PMP_OFF; ++ pmp_cfg_t.perm = PMP_NO_PERM; ++ pmp_cfg_t.paddr = 0; ++ pmp_cfg_t.size = 0; ++ set_pmp(pmp_idx, pmp_cfg_t); ++ // set_pmp_and_sync(pmp_idx, pmp_cfg_t); ++ ++ return; ++} ++ ++/** ++ * \brief Get the configuration of a pmp register (pmp_idx) ++ * ++ * \param pmp_idx the index of target PMP register ++ */ ++struct pmp_config_t get_pmp(int pmp_idx) ++{ ++ struct pmp_config_t pmp = {0,}; ++ uintptr_t pmp_address = 0; ++ uintptr_t pmp_config = 0; ++ unsigned long order = 0; ++ unsigned long size = 0; ++ ++ //set_pmp_reg(pmp_idx, &pmp_address, &pmp_config); ++ get_pmp_reg(pmp_idx, &pmp_address, &pmp_config); ++ ++ ++ pmp_config >>= (uintptr_t)PMPCFG_BIT_NUM * (pmp_idx % PMP_PER_CFG_REG); ++ pmp_config &= PMPCFG_BITS; ++ switch(pmp_config & PMP_A) ++ { ++ case PMP_A_NAPOT: ++ while(pmp_address & 1) ++ { ++ order += 1; ++ pmp_address >>= 1; ++ } ++ order += 3; ++ size = 1 << order; ++ pmp_address <<= (order-1); ++ break; ++ case PMP_A_NA4: ++ size = 4; ++ break; ++ case PMP_A_TOR: ++ break; ++ case PMP_OFF: ++ pmp_address = 0; ++ size = 0; ++ break; ++ } ++ ++ pmp.mode = pmp_config & PMP_A; ++ pmp.perm = pmp_config & (PMP_R | PMP_W | PMP_X); ++ pmp.paddr = pmp_address; ++ pmp.size = size; ++ ++ return pmp; ++} ++ ++/** ++ * \brief Dump PMP registers, only used for debug ++ */ ++void dump_pmps(void) ++{ ++ /*FIXME: we can have different number of PMP regions */ ++ int i; ++ for (i=0; i<16; i++){ ++ struct pmp_config_t pmp = get_pmp(i); ++ (void)pmp; //to ignore the unused variable warnings ++ printm("[Debug:SM@%s %u] pmp_%d: mode(0x%lx) perm(0x%lx) paddr(0x%lx) size(0x%lx)\n", ++ __func__, current_hartid(),i, pmp.mode, pmp.perm, pmp.paddr, pmp.size); ++ } ++} +diff --git a/lib/sbi/sm/sm.ac b/lib/sbi/sm/sm.ac +new file mode 100644 +index 0000000..0479971 +--- /dev/null ++++ b/lib/sbi/sm/sm.ac +@@ -0,0 +1,3 @@ ++AC_ARG_WITH([target_platform], AS_HELP_STRING([--with-target-platform], [Set a specific platform for the sm to build with]), ++ [AC_SUBST([TARGET_PLATFORM], $with_target_platform, [Set a specific platform for the sm to build with])], ++ [AC_SUBST([TARGET_PLATFORM], pmp, [Set a specific platform for the sm to build with])]) +diff --git a/lib/sbi/sm/sm.c b/lib/sbi/sm/sm.c +new file mode 100644 +index 0000000..dd4b4f2 +--- /dev/null ++++ b/lib/sbi/sm/sm.c +@@ -0,0 +1,390 @@ ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++extern volatile int print_m_mode; ++extern volatile unsigned long pmp_bitmap; ++ ++//static int sm_initialized = 0; ++//static spinlock_t sm_init_lock = SPINLOCK_INIT; ++static spinlock_t sm_alloc_enclave_mem_lock = SPIN_LOCK_INITIALIZER; ++void acquire_big_sm_lock(const char *str) ++{ ++ if (LOCK_DEBUG) ++ printm("[PENGLAI SM@%s_%d] %s try lock\n", __func__, ++ current_hartid(), str); ++ spin_lock(&sm_alloc_enclave_mem_lock); ++ if (LOCK_DEBUG) ++ printm("[PENGLAI SM@%s_%d] %s get lock\n", __func__, ++ current_hartid(), str); ++} ++ ++void release_big_sm_lock(const char *str) ++{ ++ spin_unlock(&sm_alloc_enclave_mem_lock); ++ if (LOCK_DEBUG) ++ printm("[PENGLAI SM@%s_%d] %s release lock\n", __func__, ++ current_hartid(), str); ++} ++ ++void sm_init() ++{ ++ printm("[Penglai Monitor] %s invoked\r\n", __func__); ++ platform_init(); ++ attest_init(); ++} ++ ++uintptr_t sm_mm_init(uintptr_t paddr, unsigned long size) ++{ ++ uintptr_t retval = 0; ++ ++ printm("[Penglai Monitor] %s invoked\r\n", __func__); ++ ++ printm("[Penglai Monitor] %s paddr:0x%lx, size:0x%lx\r\n", __func__, ++ paddr, size); ++ /*DEBUG: Dump PMP registers here */ ++ dump_pmps(); ++ retval = mm_init(paddr, size); ++ /*DEBUG: Dump PMP registers here */ ++ dump_pmps(); ++ ++ printm("[Penglai Monitor] %s ret:%ld \r\n", __func__, retval); ++ return retval; ++} ++ ++uintptr_t sm_mm_extend(uintptr_t paddr, unsigned long size) ++{ ++ uintptr_t retval = 0; ++ printm("[Penglai Monitor %d] %s invoked\r\n", current_hartid(), __func__); ++ print_m_mode = 1; ++ retval = mm_init(paddr, size); ++ printm("[Penglai Monitor %d] %s return:%ld\r\n", current_hartid(), __func__, retval); ++ return retval; ++} ++ ++uintptr_t sm_debug_print(uintptr_t *regs, uintptr_t arg0) ++{ ++ print_buddy_system(); ++ return 0; ++} ++ ++uintptr_t sm_alloc_enclave_mem(uintptr_t mm_alloc_arg) ++{ ++ struct mm_alloc_arg_t mm_alloc_arg_local; ++ uintptr_t retval = 0; ++ ++ printm("[Penglai Monitor] %s invoked\r\n", __func__); ++ ++ retval = copy_from_host(&mm_alloc_arg_local, ++ (struct mm_alloc_arg_t *)mm_alloc_arg, ++ sizeof(struct mm_alloc_arg_t)); ++ if (retval != 0) { ++ printm_err( ++ "M mode: sm_alloc_enclave_mem: unknown error happended when copy from host\r\n"); ++ return ENCLAVE_ERROR; ++ } ++ ++ dump_pmps(); ++ unsigned long resp_size = 0; ++ void *paddr = mm_alloc(mm_alloc_arg_local.req_size, &resp_size); ++ if (paddr == NULL) { ++ printm("M mode: sm_alloc_enclave_mem: no enough memory\r\n"); ++ return ENCLAVE_NO_MEMORY; ++ } ++ //grant kernel access to this memory ++ if (grant_kernel_access(paddr, resp_size) != 0) { ++ printm_err( ++ "M mode: ERROR: faile to grant kernel access to pa 0x%lx, size 0x%lx\r\n", ++ (unsigned long)paddr, resp_size); ++ mm_free(paddr, resp_size); ++ return ENCLAVE_ERROR; ++ } ++ ++ mm_alloc_arg_local.resp_addr = (uintptr_t)paddr; ++ mm_alloc_arg_local.resp_size = resp_size; ++ ++ retval = copy_to_host((struct mm_alloc_arg_t *)mm_alloc_arg, ++ &mm_alloc_arg_local, ++ sizeof(struct mm_alloc_arg_t)); ++ if (retval != 0) { ++ printm_err( ++ "M mode: sm_alloc_enclave_mem: unknown error happended when copy to host\r\n"); ++ return ENCLAVE_ERROR; ++ } ++ ++ printm("[Penglai Monitor] %s return:%ld\r\n", __func__, retval); ++ ++ return ENCLAVE_SUCCESS; ++} ++ ++uintptr_t sm_memory_reclaim(uintptr_t mm_reclaim_arg, unsigned long eid) ++{ ++ uintptr_t retval = 0; ++ unsigned long resp_size = 0; ++ printm("[Penglai Monitor] %s invoked\r\n", __func__); ++ struct mm_reclaim_arg_t mm_reclaim_arg_local; ++ ++ retval = memory_reclaim(&resp_size); ++ if (retval == RETRY_SPIN_LOCK) { ++ return retval; ++ } ++ ++ retval = copy_from_host(&mm_reclaim_arg_local, ++ (struct mm_reclaim_arg_t *)mm_reclaim_arg, ++ sizeof(struct mm_reclaim_arg_t)); ++ if (retval != 0) { ++ printm_err( ++ "M mode: sm_memory_reclaim: unknown error happended when copy from host\r\n"); ++ return ENCLAVE_ERROR; ++ } ++ ++ mm_reclaim_arg_local.resp_size = resp_size; ++ retval = copy_to_host((struct mm_reclaim_arg_t *)mm_reclaim_arg, ++ &mm_reclaim_arg_local, ++ sizeof(struct mm_reclaim_arg_t)); ++ if (retval != 0) { ++ printm_err( ++ "M mode: sm_memory_reclaim: unknown error happended when copy to host\r\n"); ++ return ENCLAVE_ERROR; ++ } ++ printm("[Penglai Monitor] %s return:%ld\r\n", __func__, retval); ++ return retval; ++} ++ ++uintptr_t sm_create_enclave(uintptr_t enclave_sbi_param, bool retry) ++{ ++ struct enclave_sbi_param_t enclave_sbi_param_local; ++ uintptr_t retval = 0; ++ ++ printm("[Penglai Monitor] %s invoked\r\n", __func__); ++ ++ retval = copy_from_host(&enclave_sbi_param_local, ++ (struct enclave_sbi_param_t *)enclave_sbi_param, ++ sizeof(struct enclave_sbi_param_t)); ++ if (retval == RETRY_SPIN_LOCK) ++ { ++ return retval; ++ } ++ ++ if (retval != 0) { ++ printm_err( ++ "M mode: sm_create_enclave: unknown error happended when copy from host\r\n"); ++ return ENCLAVE_ERROR; ++ } ++ ++ void *paddr = (void *)enclave_sbi_param_local.paddr; ++ unsigned long size = (unsigned long)enclave_sbi_param_local.size; ++ if (!retry && retrieve_kernel_access(paddr, size) != ++ 0) //we always allow kernel access the memory now ++ { ++ mm_free(paddr, size); ++ return -1UL; ++ } ++ ++ retval = create_enclave(enclave_sbi_param_local, retry); ++ ++ printm("[Penglai Monitor] %s created return value:%ld \r\n", __func__, ++ retval); ++ return retval; ++} ++ ++uintptr_t sm_attest_enclave(uintptr_t eid, uintptr_t report, uintptr_t nonce) ++{ ++ uintptr_t retval; ++ printm("[Penglai Monitor] %s invoked, eid:%ld\r\n", __func__, eid); ++ ++ retval = attest_enclave(eid, report, nonce); ++ ++ printm("[Penglai Monitor] %s return: %ld\r\n", __func__, retval); ++ ++ return retval; ++} ++ ++uintptr_t sm_run_enclave(uintptr_t *regs, unsigned long eid) ++{ ++ uintptr_t retval; ++ printm("[Penglai Monitor] %s invoked, eid:%ld\r\n", __func__, eid); ++ ++ retval = run_enclave(regs, (unsigned int)eid); ++ ++ printm("[Penglai Monitor] %s return: %ld\r\n", __func__, retval); ++ ++ return retval; ++} ++ ++uintptr_t sm_stop_enclave(uintptr_t *regs, unsigned long eid) ++{ ++ uintptr_t retval; ++ printm("[Penglai Monitor] %s invoked, eid:%ld\r\n", __func__, eid); ++ ++ retval = stop_enclave(regs, (unsigned int)eid); ++ ++ printm("[Penglai Monitor] %s return: %ld\r\n", __func__, retval); ++ return retval; ++} ++ ++uintptr_t sm_resume_enclave(uintptr_t *regs, unsigned long eid) ++{ ++ uintptr_t retval = 0; ++ uintptr_t resume_func_id = regs[11]; ++ ++ switch (resume_func_id) { ++ case RESUME_FROM_TIMER_IRQ: ++ retval = resume_enclave(regs, eid); ++ break; ++ case RESUME_FROM_STOP: ++ retval = resume_from_stop(regs, eid); ++ break; ++ case RESUME_FROM_OCALL: ++ retval = resume_from_ocall(regs, eid); ++ break; ++ default: ++ break; ++ } ++ ++ return retval; ++} ++ ++uintptr_t sm_exit_enclave(uintptr_t *regs, unsigned long retval) ++{ ++ uintptr_t ret; ++ printm("[Penglai Monitor %d] %s invoked\r\n", current_hartid(), __func__); ++ ++ ret = exit_enclave(regs, retval); ++ ++ printm("[Penglai Monitor %d] %s return: %ld\r\n", current_hartid(), __func__, ret); ++ return ret; ++} ++ ++uintptr_t sm_enclave_ocall(uintptr_t *regs, uintptr_t ocall_id, uintptr_t arg0, ++ uintptr_t arg1) ++{ ++ uintptr_t ret = 0; ++ switch (ocall_id) { ++ case OCALL_SYS_WRITE: ++ ret = enclave_sys_write(regs); ++ break; ++ case OCALL_USER_DEFINED: ++ ret = enclave_user_defined_ocall(regs, arg0); ++ break; ++ default: ++ printm_err("[Penglai Monitor@%s] wrong ocall_id(%ld)\r\n", ++ __func__, ocall_id); ++ ret = -1UL; ++ break; ++ } ++ return ret; ++} ++ ++/** ++ * \brief Retrun key to enclave. ++ * ++ * \param regs The enclave regs. ++ * \param salt_va Salt pointer in enclave address space. ++ * \param salt_len Salt length in bytes. ++ * \param key_buf_va Key buffer pointer in enclave address space. ++ * \param key_buf_len Key buffer length in bytes. ++ */ ++uintptr_t sm_enclave_get_key(uintptr_t *regs, uintptr_t salt_va, ++ uintptr_t salt_len, uintptr_t key_buf_va, ++ uintptr_t key_buf_len) ++{ ++ uintptr_t ret = 0; ++ ++ ret = enclave_derive_seal_key(regs, salt_va, salt_len, key_buf_va, ++ key_buf_len); ++ ++ return ret; ++} ++ ++/** ++ * \brief This transitional function is used to destroy the enclave. ++ * ++ * \param regs The host reg. ++ * \param enclave_eid The enclave id. ++ */ ++uintptr_t sm_destroy_enclave(uintptr_t *regs, uintptr_t enclave_id) ++{ ++ uintptr_t ret = 0; ++ printm("[Penglai Monitor] %s invoked\r\n", __func__); ++ ++ ret = destroy_enclave(regs, enclave_id); ++ ++ printm("[Penglai Monitor] %s return: %ld\r\n", __func__, ret); ++ ++ return ret; ++} ++ ++uintptr_t sm_do_timer_irq(uintptr_t *regs, uintptr_t mcause, uintptr_t mepc) ++{ ++ uintptr_t ret; ++ ++ ret = do_timer_irq(regs, mcause, mepc); ++ ++ regs[10] = 0; //no errors in all cases for timer handler ++ regs[11] = ret; //value ++ return ret; ++} ++/** ++ * \brief Used to clear pmp settings when uninstalling kernel modules\ ++ * ++ * \param size_ptr Used to pass the size of the freed memory to the driver ++ * \param flag Select whether to clear a specific pmp ++*/ ++uintptr_t sm_free_enclave_mem(uintptr_t size_ptr, unsigned long flag) ++{ ++ uintptr_t ret = 0; ++ unsigned long size = 0; ++ dump_pmps(); ++ switch (flag) { ++ case FREE_MAX_MEMORY: ++ free_enclave_metadata(); ++ ++ for (size_t i = NPMP - 2; i >= 0; i--) { ++ int pmp_idx = i; ++ struct pmp_config_t pmp_config = get_pmp(pmp_idx); ++ ++ if (pmp_config.paddr == 0 || pmp_config.size == 0) { ++ continue; ++ } ++ ++ if (pmp_idx == 0) { ++ sbi_printf("M mode: sm_free_enclave_mem: There is no mem to reclaim\r\n"); ++ dump_pmps(); ++ size = 0; ++ ret = 0; ++ break; ++ } ++ ++ clear_pmp_and_sync(pmp_idx); ++ pmp_bitmap &= ~(1 << pmp_idx); ++ ret = pmp_config.paddr; ++ size = pmp_config.size; ++ ++ break; ++ } ++ break; ++ case FREE_SPEC_MEMORY: ++ /*free */ ++ { //TODO:Reserved interfaces for calls to reclaim unused memory ++ struct pmp_config_t pmp_config = get_pmp(15); ++ clear_pmp_and_sync(15); ++ ret = pmp_config.paddr; ++ size = 0; ++ } ++ break; ++ default: ++ ret = 0; ++ size = 0; ++ break; ++ } ++ ++ copy_to_host((void *)size_ptr, (void *)(&size), sizeof(unsigned long)); ++ return ret; ++} +\ No newline at end of file +diff --git a/lib/sbi/sm/sm.mk.in b/lib/sbi/sm/sm.mk.in +new file mode 100644 +index 0000000..649d773 +--- /dev/null ++++ b/lib/sbi/sm/sm.mk.in +@@ -0,0 +1,25 @@ ++sm_hdrs = \ ++ pmp.h \ ++ sm.h \ ++ enclave_args.h \ ++ enclave.h \ ++ platform/@TARGET_PLATFORM@/platform.h \ ++ thread.h \ ++ math.h ++ ++sm_c_srcs = \ ++ ipi.c \ ++ pmp.c \ ++ platform/@TARGET_PLATFORM@/platform.c \ ++ sm.c \ ++ enclave.c \ ++ thread.c \ ++ math.c ++ ++sm_asm_srcs = \ ++ ++ ++sm_test_srcs = ++ ++ ++sm_install_prog_srcs = +diff --git a/lib/sbi/sm/thread.c b/lib/sbi/sm/thread.c +new file mode 100644 +index 0000000..2ecc419 +--- /dev/null ++++ b/lib/sbi/sm/thread.c +@@ -0,0 +1,67 @@ ++#include ++//#include ++#include ++#include ++ ++void swap_prev_state(struct thread_state_t* thread, uintptr_t* regs) ++{ ++ int i; ++ ++ uintptr_t* prev = (uintptr_t*) &thread->prev_state; ++ for(i = 1; i < N_GENERAL_REGISTERS; ++i) ++ { ++ /* swap general registers */ ++ uintptr_t tmp = prev[i]; ++ prev[i] = regs[i]; ++ regs[i] = tmp; ++ } ++ ++ return; ++} ++ ++void swap_prev_mepc(struct thread_state_t* thread, uintptr_t current_mepc) ++{ ++ uintptr_t tmp = thread->prev_mepc; ++ thread->prev_mepc = current_mepc; ++ csr_write(CSR_MEPC, tmp); ++} ++ ++void swap_prev_stvec(struct thread_state_t* thread, uintptr_t current_stvec) ++{ ++ uintptr_t tmp = thread->prev_stvec; ++ thread->prev_stvec = current_stvec; ++ csr_write(CSR_STVEC, tmp); ++} ++ ++/* ++ * Cache line binding is only workable ++ * when the hardware supports penglai's on-demand cacheline locking ++ * */ ++void swap_prev_cache_binding(struct thread_state_t* thread, uintptr_t current_cache_binding) ++{ ++#if 0 ++ uintptr_t tmp = thread->prev_cache_binding; ++ thread->prev_cache_binding = current_cache_binding; ++#endif ++} ++ ++void swap_prev_mie(struct thread_state_t* thread, uintptr_t current_mie) ++{ ++ uintptr_t tmp = thread->prev_mie; ++ thread->prev_mie = current_mie; ++ csr_write(CSR_MIE, tmp); ++} ++ ++void swap_prev_mideleg(struct thread_state_t* thread, uintptr_t current_mideleg) ++{ ++ uintptr_t tmp = thread->prev_mideleg; ++ thread->prev_mideleg = current_mideleg; ++ csr_write(CSR_MIDELEG, tmp); ++} ++ ++void swap_prev_medeleg(struct thread_state_t* thread, uintptr_t current_medeleg) ++{ ++ uintptr_t tmp = thread->prev_medeleg; ++ thread->prev_medeleg = current_medeleg; ++ csr_write(CSR_MEDELEG, tmp); ++} +diff --git a/lib/sbi/sm/utils.c b/lib/sbi/sm/utils.c +new file mode 100644 +index 0000000..091209b +--- /dev/null ++++ b/lib/sbi/sm/utils.c +@@ -0,0 +1,40 @@ ++/* ++ * Author: Dong Du ++ * */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Go through and dump a page table, used for debug ++ * */ ++void dump_pt(unsigned long *page_table, int level) ++{ ++ int l1, i; ++ unsigned long* l1_pt = page_table; ++ ++ if (!l1_pt) ++ return; ++ ++ //only consider sv39 now ++ for (l1=0; l1<512; l1++){ ++ if (!(l1_pt[l1] & PTE_V)) //this entry is not valid ++ continue; ++ ++ for (i=0; i>PTE_PPN_SHIFT)< Date: Mon, 1 Apr 2024 16:43:47 +0800 Subject: [PATCH 2/2] bump release and add changelog --- opensbi.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/opensbi.spec b/opensbi.spec index 764c4b3..5546cc8 100644 --- a/opensbi.spec +++ b/opensbi.spec @@ -5,7 +5,7 @@ Name: opensbi Version: 1.2 -Release: 1 +Release: 2 Summary: RISC-V Open Source Supervisor Binary Interface URL: https://github.com/riscv-software-src/opensbi License: BSD @@ -70,6 +70,9 @@ cp %{buildroot}/share/opensbi/lp64/generic/firmware/fw_payload.elf \ /share/opensbi/lp64/generic/* %changelog +* Tue Mar 19 2024 ZhaoXi - 1.2-2-riscv64 +- Add patch for Penglai-Enclave-sPMP - 2403 + * Mon Mar 18 2024 jchzhou - 1.2-1-riscv64 - Upgrade opensbi to v1.2 -- Gitee