This commit is contained in:
2025-09-07 16:02:22 +02:00
commit 627acef32c
145 changed files with 74048 additions and 0 deletions

151
User/FreeRTOSConfig.h Normal file
View File

@@ -0,0 +1,151 @@
/*
FreeRTOS V202112.00
All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
This file is part of the FreeRTOS distribution.
FreeRTOS is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License (version 2) as published by the
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
***************************************************************************
>>! NOTE: The modification to the GPL is included to allow you to !<<
>>! distribute a combined work that includes FreeRTOS without being !<<
>>! obliged to provide the source code for proprietary components !<<
>>! outside of the FreeRTOS kernel. !<<
***************************************************************************
FreeRTOS 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. Full license text is available on the following
link: http://www.freertos.org/a00114.html
***************************************************************************
* *
* FreeRTOS provides completely free yet professionally developed, *
* robust, strictly quality controlled, supported, and cross *
* platform software that is more than just the market leader, it *
* is the industry's de facto standard. *
* *
* Help yourself get started quickly while simultaneously helping *
* to support the FreeRTOS project by purchasing a FreeRTOS *
* tutorial book, reference manual, or both: *
* http://www.FreeRTOS.org/Documentation *
* *
***************************************************************************
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
the FAQ page "My application does not run, what could be wrong?". Have you
defined configASSERT()?
http://www.FreeRTOS.org/support - In return for receiving this top quality
embedded software for free we request you assist our global community by
participating in the support forum.
http://www.FreeRTOS.org/training - Investing in training allows your team to
be as productive as possible as early as possible. Now you can receive
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
Ltd, and the world's leading authority on the world's leading RTOS.
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
compatible FAT file system, and our tiny thread aware UDP/IP stack.
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
licenses offer ticketed support, indemnification and commercial middleware.
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
engineered and independently SIL3 certified version for use in safety and
mission critical applications that require provable dependability.
1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
#include "debug.h"
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html.
*----------------------------------------------------------*/
/* See https://www.freertos.org/Using-FreeRTOS-on-RISC-V.html */
/* don't have MTIME */
#define configMTIME_BASE_ADDRESS ( 0 )
#define configMTIMECMP_BASE_ADDRESS ( 0 )
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ SystemCoreClock
#define configTICK_RATE_HZ ( ( TickType_t ) 500 )
#define configMAX_PRIORITIES ( 15 )
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 1024 ) /* Can be as low as 60 but some of the demo tasks that use this constant require it to be higher. */
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 32 * 1024 ) )
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_TRACE_FACILITY 0
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 0
#define configUSE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configCHECK_FOR_STACK_OVERFLOW 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/* Software timer definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH 4
#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE )
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskAbortDelay 1
#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_xSemaphoreGetMutexHolder 1
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); printf("err at line %d of file \"%s\". \r\n ",__LINE__,__FILE__); while(1); }
/* Map to the platform printf function. */
#define configPRINT_STRING( pcString ) printf( pcString )
#endif /* FREERTOS_CONFIG_H */

45
User/ch32v30x_conf.h Normal file
View File

@@ -0,0 +1,45 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ch32v30x_conf.h
* Author : WCH
* Version : V1.0.0
* Date : 2021/06/06
* Description : Library configuration file.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH32V30x_CONF_H
#define __CH32V30x_CONF_H
#include "ch32v30x_adc.h"
#include "ch32v30x_bkp.h"
#include "ch32v30x_can.h"
#include "ch32v30x_crc.h"
#include "ch32v30x_dac.h"
#include "ch32v30x_dbgmcu.h"
#include "ch32v30x_dma.h"
#include "ch32v30x_exti.h"
#include "ch32v30x_flash.h"
#include "ch32v30x_fsmc.h"
#include "ch32v30x_gpio.h"
#include "ch32v30x_i2c.h"
#include "ch32v30x_iwdg.h"
#include "ch32v30x_pwr.h"
#include "ch32v30x_rcc.h"
#include "ch32v30x_rtc.h"
#include "ch32v30x_sdio.h"
#include "ch32v30x_spi.h"
#include "ch32v30x_tim.h"
#include "ch32v30x_usart.h"
#include "ch32v30x_wwdg.h"
#include "ch32v30x_it.h"
#include "ch32v30x_misc.h"
#endif /* __CH32V30x_CONF_H */

246
User/ch32v30x_it.c Normal file
View File

@@ -0,0 +1,246 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ch32v30x_it.c
* Author : WCH
* Version : V1.0.0
* Date : 2024/03/05
* Description : Main Interrupt Service Routines.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#include "ch32v30x_it.h"
#include <stdarg.h>
void NMI_Handler (void) __attribute__ ((interrupt ("WCH-Interrupt-fast")));
void HardFault_Handler (void) __attribute__ ((interrupt ("WCH-Interrupt-fast")));
/*********************************************************************
* @fn NMI_Handler
*
* @brief This function handles NMI exception.
*
* @return none
*/
void NMI_Handler (void) {
while (1) {
}
}
typedef struct {
uint32_t ra;
uint32_t t0;
uint32_t t1;
uint32_t t2;
uint32_t s0;
uint32_t s1;
uint32_t a0;
uint32_t a1;
uint32_t a2;
uint32_t a3;
uint32_t a4;
uint32_t a5;
uint32_t a6;
uint32_t a7;
uint32_t s2;
uint32_t s3;
uint32_t s4;
uint32_t s5;
uint32_t s6;
uint32_t s7;
uint32_t s8;
uint32_t s9;
uint32_t s10;
uint32_t s11;
uint32_t t3;
uint32_t t4;
uint32_t t5;
uint32_t t6;
} HardFaultRegs;
// Minimal printf over UART
void uart_printf (const char *fmt) {
while (*fmt) {
USART_SendData (USART1, *fmt);
while (USART_GetFlagStatus (USART1, USART_FLAG_TXE) == RESET);
fmt++;
}
}
static void print_hex32 (unsigned long val) {
const char hex[] = "0123456789ABCDEF";
USART_SendData (USART1, '0');
while (USART_GetFlagStatus (USART1, USART_FLAG_TXE) == RESET);
USART_SendData (USART1, 'x');
while (USART_GetFlagStatus (USART1, USART_FLAG_TXE) == RESET);
for (int i = 7; i >= 0; i--) {
USART_SendData (USART1, hex[(val >> (i * 4)) & 0xF]);
while (USART_GetFlagStatus (USART1, USART_FLAG_TXE) == RESET);
}
}
volatile HardFaultRegs hardfault_regs; // visible in debugger
/*********************************************************************
* @fn HardFault_Handler
*
* @brief This function handles Hard Fault exception.
*
* @return none
*/
void HardFault_Handler (void) {
uint32_t *sp;
__asm volatile ("mv %0, sp"
: "=r"(sp)); // get current stack pointer
// Copy the stacked registers to the volatile struct
hardfault_regs.ra = sp[0];
hardfault_regs.t0 = sp[1];
hardfault_regs.t1 = sp[2];
hardfault_regs.t2 = sp[3];
hardfault_regs.s0 = sp[4];
hardfault_regs.s1 = sp[5];
hardfault_regs.a0 = sp[6];
hardfault_regs.a1 = sp[7];
hardfault_regs.a2 = sp[8];
hardfault_regs.a3 = sp[9];
hardfault_regs.a4 = sp[10];
hardfault_regs.a5 = sp[11];
hardfault_regs.a6 = sp[12];
hardfault_regs.a7 = sp[13];
hardfault_regs.s2 = sp[14];
hardfault_regs.s3 = sp[15];
hardfault_regs.s4 = sp[16];
hardfault_regs.s5 = sp[17];
hardfault_regs.s6 = sp[18];
hardfault_regs.s7 = sp[19];
hardfault_regs.s8 = sp[20];
hardfault_regs.s9 = sp[21];
hardfault_regs.s10 = sp[22];
hardfault_regs.s11 = sp[23];
hardfault_regs.t3 = sp[24];
hardfault_regs.t4 = sp[25];
hardfault_regs.t5 = sp[26];
hardfault_regs.t6 = sp[27];
// Print all registers
uart_printf ("HardFault! Registers:\n");
uart_printf ("RA: ");
print_hex32 (hardfault_regs.ra);
uart_printf ("\n");
uart_printf ("T0: ");
print_hex32 (hardfault_regs.t0);
uart_printf ("\n");
uart_printf ("T1: ");
print_hex32 (hardfault_regs.t1);
uart_printf ("\n");
uart_printf ("T2: ");
print_hex32 (hardfault_regs.t2);
uart_printf ("\n");
uart_printf ("S0: ");
print_hex32 (hardfault_regs.s0);
uart_printf ("\n");
uart_printf ("S1: ");
print_hex32 (hardfault_regs.s1);
uart_printf ("\n");
uart_printf ("A0: ");
print_hex32 (hardfault_regs.a0);
uart_printf ("\n");
uart_printf ("A1: ");
print_hex32 (hardfault_regs.a1);
uart_printf ("\n");
uart_printf ("A2: ");
print_hex32 (hardfault_regs.a2);
uart_printf ("\n");
uart_printf ("A3: ");
print_hex32 (hardfault_regs.a3);
uart_printf ("\n");
uart_printf ("A4: ");
print_hex32 (hardfault_regs.a4);
uart_printf ("\n");
uart_printf ("A5: ");
print_hex32 (hardfault_regs.a5);
uart_printf ("\n");
uart_printf ("A6: ");
print_hex32 (hardfault_regs.a6);
uart_printf ("\n");
uart_printf ("A7: ");
print_hex32 (hardfault_regs.a7);
uart_printf ("\n");
uart_printf ("S2: ");
print_hex32 (hardfault_regs.s2);
uart_printf ("\n");
uart_printf ("S3: ");
print_hex32 (hardfault_regs.s3);
uart_printf ("\n");
uart_printf ("S4: ");
print_hex32 (hardfault_regs.s4);
uart_printf ("\n");
uart_printf ("S5: ");
print_hex32 (hardfault_regs.s5);
uart_printf ("\n");
uart_printf ("S6: ");
print_hex32 (hardfault_regs.s6);
uart_printf ("\n");
uart_printf ("S7: ");
print_hex32 (hardfault_regs.s7);
uart_printf ("\n");
uart_printf ("S8: ");
print_hex32 (hardfault_regs.s8);
uart_printf ("\n");
uart_printf ("S9: ");
print_hex32 (hardfault_regs.s9);
uart_printf ("\n");
uart_printf ("S10: ");
print_hex32 (hardfault_regs.s10);
uart_printf ("\n");
uart_printf ("S11: ");
print_hex32 (hardfault_regs.s11);
uart_printf ("\n");
uart_printf ("T3: ");
print_hex32 (hardfault_regs.t3);
uart_printf ("\n");
uart_printf ("T4: ");
print_hex32 (hardfault_regs.t4);
uart_printf ("\n");
uart_printf ("T5: ");
print_hex32 (hardfault_regs.t5);
uart_printf ("\n");
uart_printf ("T6: ");
print_hex32 (hardfault_regs.t6);
uart_printf ("\n");
Delay_Ms (1000);
NVIC_SystemReset();
while (1) {
}
}

20
User/ch32v30x_it.h Normal file
View File

@@ -0,0 +1,20 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ch32v30x_it.h
* Author : WCH
* Version : V1.0.0
* Date : 2021/06/06
* Description : This file contains the headers of the interrupt handlers.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __CH32V30x_IT_H
#define __CH32V30x_IT_H
#include "debug.h"
#endif /* __CH32V30x_IT_H */

25
User/lib/base64.c Normal file
View File

@@ -0,0 +1,25 @@
#include "base64.h"
#include <stdint.h>
#include <stddef.h>
static const char b64_enc_table[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int base64_encode(const uint8_t *in, size_t ilen, char *out)
{
size_t out_len = 0;
for (size_t i = 0; i < ilen; i += 3) {
uint32_t triple = 0;
int remain = ilen - i;
triple |= in[i] << 16;
if (remain > 1) triple |= in[i + 1] << 8;
if (remain > 2) triple |= in[i + 2];
out[out_len++] = b64_enc_table[(triple >> 18) & 0x3F];
out[out_len++] = b64_enc_table[(triple >> 12) & 0x3F];
out[out_len++] = (remain > 1) ? b64_enc_table[(triple >> 6) & 0x3F] : '=';
out[out_len++] = (remain > 2) ? b64_enc_table[triple & 0x3F] : '=';
}
return 0;
}

7
User/lib/base64.h Normal file
View File

@@ -0,0 +1,7 @@
#ifdef B64_HEADER
#define B64_HEADER
#include <stddef.h>
int base64_encode(const uint8_t *in, size_t ilen, char *out);
#endif

417
User/lib/cifra/aes.c Normal file
View File

@@ -0,0 +1,417 @@
/*
* cifra - embedded cryptography library
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <string.h>
#include <stdlib.h>
#include "cf_config.h"
#include "aes.h"
#include "handy.h"
#include "bitops.h"
#include "tassert.h"
static const uint8_t S[256] =
{
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe,
0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4,
0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7,
0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3,
0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09,
0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3,
0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe,
0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92,
0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c,
0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19,
0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2,
0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5,
0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25,
0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86,
0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e,
0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42,
0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
};
static const uint8_t Rcon[11] =
{
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36
};
#ifdef INLINE_FUNCS
static inline uint32_t word4(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3)
{
return b0 << 24 | b1 << 16 | b2 << 8 | b3;
}
static inline uint8_t byte(uint32_t w, unsigned x)
{
/* nb. bytes are numbered 0 (leftmost, top)
* to 3 (rightmost). */
x = 3 - x;
return (w >> (x * 8)) & 0xff;
}
static uint32_t round_constant(uint32_t i)
{
return Rcon[i] << 24;
}
static uint32_t rot_word(uint32_t w)
{
/* Takes
* word [a0,a1,a2,a3]
* returns
* word [a1,a2,a3,a0]
*
*/
return rotl32(w, 8);
}
#endif
#define word4(a, b, c, d) (((uint32_t)(a) << 24) | ((uint32_t)(b) << 16) | ((uint32_t)(c) << 8) | (d))
#define byte(w, x) ((w >> ((3 - (x)) << 3)) & 0xff)
#define round_constant(i) ((uint32_t)(Rcon[i]) << 24)
#define rot_word(w) rotl32((w), 8)
static uint32_t sub_word(uint32_t w, const uint8_t *sbox)
{
uint8_t a = byte(w, 0),
b = byte(w, 1),
c = byte(w, 2),
d = byte(w, 3);
#if CF_CACHE_SIDE_CHANNEL_PROTECTION
select_u8x4(&a, &b, &c, &d, sbox, 256);
#else
a = sbox[a];
b = sbox[b];
c = sbox[c];
d = sbox[d];
#endif
return word4(a, b, c, d);
}
static void aes_schedule(cf_aes_context *ctx, const uint8_t *key, size_t nkey)
{
size_t i,
nb = AES_BLOCKSZ / 4,
nk = nkey / 4,
n = nb * (ctx->rounds + 1);
uint32_t *w = ctx->ks;
/* First words are just the key. */
for (i = 0; i < nk; i++)
{
w[i] = read32_be(key + i * 4);
}
uint32_t i_div_nk = 1;
uint32_t i_mod_nk = 0;
for (; i < n; i++, i_mod_nk++)
{
uint32_t temp = w[i - 1];
if (i_mod_nk == nk)
{
i_div_nk++;
i_mod_nk = 0;
}
if (i_mod_nk == 0)
temp = sub_word(rot_word(temp), S) ^ round_constant(i_div_nk);
else if (nk > 6 && i_mod_nk == 4)
temp = sub_word(temp, S);
w[i] = w[i - nk] ^ temp;
}
}
void cf_aes_init(cf_aes_context *ctx, const uint8_t *key, size_t nkey)
{
memset(ctx, 0, sizeof *ctx);
switch (nkey)
{
#if CF_AES_MAXROUNDS >= AES128_ROUNDS
case 16:
ctx->rounds = AES128_ROUNDS;
aes_schedule(ctx, key, nkey);
break;
#endif
#if CF_AES_MAXROUNDS >= AES192_ROUNDS
case 24:
ctx->rounds = AES192_ROUNDS;
aes_schedule(ctx, key, nkey);
break;
#endif
#if CF_AES_MAXROUNDS >= AES256_ROUNDS
case 32:
ctx->rounds = AES256_ROUNDS;
aes_schedule(ctx, key, nkey);
break;
#endif
default:
abort();
}
}
static void add_round_key(uint32_t state[4], const uint32_t rk[4])
{
state[0] ^= rk[0];
state[1] ^= rk[1];
state[2] ^= rk[2];
state[3] ^= rk[3];
}
static void sub_block(uint32_t state[4])
{
state[0] = sub_word(state[0], S);
state[1] = sub_word(state[1], S);
state[2] = sub_word(state[2], S);
state[3] = sub_word(state[3], S);
}
static void shift_rows(uint32_t state[4])
{
uint32_t u, v, x, y;
u = word4(byte(state[0], 0),
byte(state[1], 1),
byte(state[2], 2),
byte(state[3], 3));
v = word4(byte(state[1], 0),
byte(state[2], 1),
byte(state[3], 2),
byte(state[0], 3));
x = word4(byte(state[2], 0),
byte(state[3], 1),
byte(state[0], 2),
byte(state[1], 3));
y = word4(byte(state[3], 0),
byte(state[0], 1),
byte(state[1], 2),
byte(state[2], 3));
state[0] = u;
state[1] = v;
state[2] = x;
state[3] = y;
}
static uint32_t gf_poly_mul2(uint32_t x)
{
return
((x & 0x7f7f7f7f) << 1) ^
(((x & 0x80808080) >> 7) * 0x1b);
}
static uint32_t mix_column(uint32_t x)
{
uint32_t x2 = gf_poly_mul2(x);
return x2 ^ rotr32(x ^ x2, 24) ^ rotr32(x, 16) ^ rotr32(x, 8);
}
static void mix_columns(uint32_t state[4])
{
state[0] = mix_column(state[0]);
state[1] = mix_column(state[1]);
state[2] = mix_column(state[2]);
state[3] = mix_column(state[3]);
}
void cf_aes_encrypt(const cf_aes_context *ctx,
const uint8_t in[AES_BLOCKSZ],
uint8_t out[AES_BLOCKSZ])
{
assert(ctx->rounds == AES128_ROUNDS ||
ctx->rounds == AES192_ROUNDS ||
ctx->rounds == AES256_ROUNDS);
uint32_t state[4] = {
read32_be(in + 0),
read32_be(in + 4),
read32_be(in + 8),
read32_be(in + 12)
};
const uint32_t *round_keys = ctx->ks;
add_round_key(state, round_keys);
round_keys += 4;
for (uint32_t round = 1; round < ctx->rounds; round++)
{
sub_block(state);
shift_rows(state);
mix_columns(state);
add_round_key(state, round_keys);
round_keys += 4;
}
sub_block(state);
shift_rows(state);
add_round_key(state, round_keys);
write32_be(state[0], out + 0);
write32_be(state[1], out + 4);
write32_be(state[2], out + 8);
write32_be(state[3], out + 12);
}
#if CF_AES_ENCRYPT_ONLY == 0
static const uint8_t S_inv[256] =
{
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81,
0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e,
0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23,
0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66,
0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72,
0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65,
0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46,
0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca,
0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91,
0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6,
0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f,
0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2,
0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8,
0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93,
0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb,
0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6,
0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
};
static void inv_sub_block(uint32_t state[4])
{
state[0] = sub_word(state[0], S_inv);
state[1] = sub_word(state[1], S_inv);
state[2] = sub_word(state[2], S_inv);
state[3] = sub_word(state[3], S_inv);
}
static void inv_shift_rows(uint32_t state[4])
{
uint32_t u, v, x, y;
u = word4(byte(state[0], 0),
byte(state[3], 1),
byte(state[2], 2),
byte(state[1], 3));
v = word4(byte(state[1], 0),
byte(state[0], 1),
byte(state[3], 2),
byte(state[2], 3));
x = word4(byte(state[2], 0),
byte(state[1], 1),
byte(state[0], 2),
byte(state[3], 3));
y = word4(byte(state[3], 0),
byte(state[2], 1),
byte(state[1], 2),
byte(state[0], 3));
state[0] = u;
state[1] = v;
state[2] = x;
state[3] = y;
}
static uint32_t inv_mix_column(uint32_t x)
{
uint32_t x2 = gf_poly_mul2(x),
x4 = gf_poly_mul2(x2),
x9 = x ^ gf_poly_mul2(x4),
x11 = x2 ^ x9,
x13 = x4 ^ x9;
return x ^ x2 ^ x13 ^ rotr32(x11, 24) ^ rotr32(x13, 16) ^ rotr32(x9, 8);
}
static void inv_mix_columns(uint32_t state[4])
{
state[0] = inv_mix_column(state[0]);
state[1] = inv_mix_column(state[1]);
state[2] = inv_mix_column(state[2]);
state[3] = inv_mix_column(state[3]);
}
void cf_aes_decrypt(const cf_aes_context *ctx,
const uint8_t in[AES_BLOCKSZ],
uint8_t out[AES_BLOCKSZ])
{
assert(ctx->rounds == AES128_ROUNDS ||
ctx->rounds == AES192_ROUNDS ||
ctx->rounds == AES256_ROUNDS);
uint32_t state[4] = {
read32_be(in + 0),
read32_be(in + 4),
read32_be(in + 8),
read32_be(in + 12)
};
const uint32_t *round_keys = &ctx->ks[ctx->rounds << 2];
add_round_key(state, round_keys);
round_keys -= 4;
for (uint32_t round = ctx->rounds - 1; round != 0; round--)
{
inv_shift_rows(state);
inv_sub_block(state);
add_round_key(state, round_keys);
inv_mix_columns(state);
round_keys -= 4;
}
inv_shift_rows(state);
inv_sub_block(state);
add_round_key(state, round_keys);
write32_be(state[0], out + 0);
write32_be(state[1], out + 4);
write32_be(state[2], out + 8);
write32_be(state[3], out + 12);
}
#else
void cf_aes_decrypt(const cf_aes_context *ctx,
const uint8_t in[AES_BLOCKSZ],
uint8_t out[AES_BLOCKSZ])
{
abort();
}
#endif
void cf_aes_finish(cf_aes_context *ctx)
{
mem_clean(ctx, sizeof *ctx);
}
const cf_prp cf_aes = {
.blocksz = AES_BLOCKSZ,
.encrypt = (cf_prp_block) cf_aes_encrypt,
.decrypt = (cf_prp_block) cf_aes_decrypt
};

152
User/lib/cifra/aes.h Normal file
View File

@@ -0,0 +1,152 @@
/*
* cifra - embedded cryptography library
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
/**
* The AES block cipher
* ====================
*
* This is a small, simple implementation of AES. Key expansion is done
* first, filling in a :c:type:`cf_aes_context`. Then encryption and
* decryption can be performed as desired.
*
* Usually you don't want to use AES directly; you should use it via
* a :doc:`block cipher mode <modes>`.
*/
#ifndef AES_H
#define AES_H
#include <stddef.h>
#include <stdint.h>
#include "prp.h"
/* .. c:macro:: AES_BLOCKSZ
* AES has a 128-bit block size. This quantity is in bytes.
*/
#define AES_BLOCKSZ 16
/* --- Size configuration --- */
/* .. c:macro:: AES128_ROUNDS
* .. c:macro:: AES192_ROUNDS
* .. c:macro:: AES256_ROUNDS
*
* Round counts for different key sizes.
*/
#define AES128_ROUNDS 10
#define AES192_ROUNDS 12
#define AES256_ROUNDS 14
/* .. c:macro:: CF_AES_MAXROUNDS
*
* You can reduce the maximum number of rounds this implementation
* supports. This reduces the storage needed by :c:type:`cf_aes_context`.
*
* The default is :c:macro:`AES256_ROUNDS` and is good for all key
* sizes.
*/
#ifndef CF_AES_MAXROUNDS
# define CF_AES_MAXROUNDS AES256_ROUNDS
#endif
/* .. c:macro:: CF_AES_ENCRYPT_ONLY
*
* Define this to 1 if you don't need to decrypt anything.
* This saves space. :c:func:`cf_aes_decrypt` calls `abort(3)`.
*/
#ifndef CF_AES_ENCRYPT_ONLY
# define CF_AES_ENCRYPT_ONLY 0
#endif
/* .. c:type:: cf_aes_context
* This type represents an expanded AES key. Create one
* using :c:func:`cf_aes_init`, make use of one using
* :c:func:`cf_aes_encrypt` or :c:func:`cf_aes_decrypt`.
*
* The contents of this structure are equivalent to the
* original key material. You should clean the
* contents of this structure with :c:func:`cf_aes_finish`
* when you're done.
*
* .. c:member:: cf_aes_context.rounds
*
* Number of rounds to use, set by :c:func:`cf_aes_init`.
*
* This depends on the original key size, and will be
* :c:macro:`AES128_ROUNDS`, :c:macro:`AES192_ROUNDS` or
* :c:macro:`AES256_ROUNDS`.
*
* .. c:member:: cf_aes_context.ks
*
* Expanded key material. Filled in by :c:func:`cf_aes_init`.
*/
typedef struct
{
uint32_t rounds;
uint32_t ks[AES_BLOCKSZ / 4 * (CF_AES_MAXROUNDS + 1)];
} cf_aes_context;
/* .. c:function:: $DECL
* This function does AES key expansion. It destroys
* existing contents of :c:data:`ctx`.
*
* :param ctx: expanded key context, filled in by this function.
* :param key: pointer to key material, of :c:data:`nkey` bytes.
* :param nkey: length of key material. Must be `16`, `24` or `32`.
*/
extern void cf_aes_init(cf_aes_context *ctx,
const uint8_t *key,
size_t nkey);
/* .. c:function:: $DECL
* Encrypts the given block, from :c:data:`in` to :c:data:`out`.
* These may alias.
*
* Fails at runtime if :c:data:`ctx` is invalid.
*
* :param ctx: expanded key context
* :param in: input block (read)
* :param out: output block (written)
*/
extern void cf_aes_encrypt(const cf_aes_context *ctx,
const uint8_t in[AES_BLOCKSZ],
uint8_t out[AES_BLOCKSZ]);
/* .. c:function:: $DECL
* Decrypts the given block, from :c:data:`in` to :c:data:`out`.
* These may alias.
*
* Fails at runtime if :c:data:`ctx` is invalid.
*
* :param ctx: expanded key context
* :param in: input block (read)
* :param out: output block (written)
*/
extern void cf_aes_decrypt(const cf_aes_context *ctx,
const uint8_t in[AES_BLOCKSZ],
uint8_t out[AES_BLOCKSZ]);
/* .. c:function:: $DECL
* Erase scheduled key material.
*
* Call this when you're done to erase the round keys. */
extern void cf_aes_finish(cf_aes_context *ctx);
/* .. c:var:: const cf_prp cf_aes
* Abstract interface to AES. See :c:type:`cf_prp` for
* more information. */
extern const cf_prp cf_aes;
#endif

294
User/lib/cifra/bitops.h Normal file
View File

@@ -0,0 +1,294 @@
/*
* cifra - embedded cryptography library
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#ifndef BITOPS_H
#define BITOPS_H
#include <stdint.h>
#include <stddef.h>
/* Assorted bitwise and common operations used in ciphers. */
/** Circularly rotate right x by n bits.
* 0 > n > 32. */
static inline uint32_t rotr32(uint32_t x, unsigned n)
{
return (x >> n) | (x << (32 - n));
}
/** Circularly rotate left x by n bits.
* 0 > n > 32. */
static inline uint32_t rotl32(uint32_t x, unsigned n)
{
return (x << n) | (x >> (32 - n));
}
/** Circularly rotate right x by n bits.
* 0 > n > 64. */
static inline uint64_t rotr64(uint64_t x, unsigned n)
{
return (x >> n) | (x << (64 - n));
}
/** Circularly rotate left x by n bits.
* 0 > n > 64. */
static inline uint64_t rotl64(uint64_t x, unsigned n)
{
return (x << n) | (x >> (64 - n));
}
/** Read 4 bytes from buf, as a 32-bit big endian quantity. */
static inline uint32_t read32_be(const uint8_t buf[4])
{
return (buf[0] << 24) |
(buf[1] << 16) |
(buf[2] << 8) |
(buf[3]);
}
/** Read 4 bytes from buf, as a 32-bit little endian quantity. */
static inline uint32_t read32_le(const uint8_t buf[4])
{
return (buf[3] << 24) |
(buf[2] << 16) |
(buf[1] << 8) |
(buf[0]);
}
/** Read 8 bytes from buf, as a 64-bit big endian quantity. */
static inline uint64_t read64_be(const uint8_t buf[8])
{
uint32_t hi = read32_be(buf),
lo = read32_be(buf + 4);
return ((uint64_t)hi) << 32 |
lo;
}
/** Read 8 bytes from buf, as a 64-bit little endian quantity. */
static inline uint64_t read64_le(const uint8_t buf[8])
{
uint32_t hi = read32_le(buf + 4),
lo = read32_le(buf);
return ((uint64_t)hi) << 32 |
lo;
}
/** Encode v as a 32-bit big endian quantity into buf. */
static inline void write32_be(uint32_t v, uint8_t buf[4])
{
*buf++ = (v >> 24) & 0xff;
*buf++ = (v >> 16) & 0xff;
*buf++ = (v >> 8) & 0xff;
*buf = v & 0xff;
}
/** Encode v as a 32-bit little endian quantity into buf. */
static inline void write32_le(uint32_t v, uint8_t buf[4])
{
*buf++ = v & 0xff;
*buf++ = (v >> 8) & 0xff;
*buf++ = (v >> 16) & 0xff;
*buf = (v >> 24) & 0xff;
}
/** Encode v as a 64-bit big endian quantity into buf. */
static inline void write64_be(uint64_t v, uint8_t buf[8])
{
*buf++ = (v >> 56) & 0xff;
*buf++ = (v >> 48) & 0xff;
*buf++ = (v >> 40) & 0xff;
*buf++ = (v >> 32) & 0xff;
*buf++ = (v >> 24) & 0xff;
*buf++ = (v >> 16) & 0xff;
*buf++ = (v >> 8) & 0xff;
*buf = v & 0xff;
}
/** Encode v as a 64-bit little endian quantity into buf. */
static inline void write64_le(uint64_t v, uint8_t buf[8])
{
*buf++ = v & 0xff;
*buf++ = (v >> 8) & 0xff;
*buf++ = (v >> 16) & 0xff;
*buf++ = (v >> 24) & 0xff;
*buf++ = (v >> 32) & 0xff;
*buf++ = (v >> 40) & 0xff;
*buf++ = (v >> 48) & 0xff;
*buf = (v >> 56) & 0xff;
}
/** out = in ^ b8.
* out and in may alias. */
static inline void xor_b8(uint8_t *out, const uint8_t *in, uint8_t b8, size_t len)
{
for (size_t i = 0; i < len; i++)
out[i] = in[i] ^ b8;
}
/** out = x ^ y.
* out, x and y may alias. */
static inline void xor_bb(uint8_t *out, const uint8_t *x, const uint8_t *y, size_t len)
{
for (size_t i = 0; i < len; i++)
out[i] = x[i] ^ y[i];
}
/* out ^= x
* out and x may alias. */
static inline void xor_words(uint32_t *out, const uint32_t *x, size_t nwords)
{
for (size_t i = 0; i < nwords; i++)
out[i] ^= x[i];
}
/** Produce 0xffffffff if x == y, zero otherwise, without branching. */
static inline uint32_t mask_u32(uint32_t x, uint32_t y)
{
uint32_t diff = x ^ y;
uint32_t diff_is_zero = ~diff & (diff - 1);
return - (diff_is_zero >> 31);
}
/** Product 0xff if x == y, zero otherwise, without branching. */
static inline uint8_t mask_u8(uint32_t x, uint32_t y)
{
uint32_t diff = x ^ y;
uint8_t diff_is_zero = ~diff & (diff - 1);
return - (diff_is_zero >> 7);
}
/** Select the ith entry from the given table of n values, in a side channel-silent
* way. */
static inline uint32_t select_u32(uint32_t i, volatile const uint32_t *tab, uint32_t n)
{
uint32_t r = 0;
for (uint32_t ii = 0; ii < n; ii++)
{
uint32_t mask = mask_u32(i, ii);
r = (r & ~mask) | (tab[ii] & mask);
}
return r;
}
/** Select the ith entry from the given table of n values, in a side channel-silent
* way. */
static inline uint8_t select_u8(uint32_t i, volatile const uint8_t *tab, uint32_t n)
{
uint8_t r = 0;
for (uint32_t ii = 0; ii < n; ii++)
{
uint8_t mask = mask_u8(i, ii);
r = (r & ~mask) | (tab[ii] & mask);
}
return r;
}
/** Select the ath, bth, cth and dth entries from the given table of n values,
* placing the results into a, b, c and d. */
static inline void select_u8x4(uint8_t *a, uint8_t *b, uint8_t *c, uint8_t *d,
volatile const uint8_t *tab, uint32_t n)
{
uint8_t ra = 0,
rb = 0,
rc = 0,
rd = 0;
uint8_t mask;
for (uint32_t i = 0; i < n; i++)
{
uint8_t item = tab[i];
mask = mask_u8(*a, i); ra = (ra & ~mask) | (item & mask);
mask = mask_u8(*b, i); rb = (rb & ~mask) | (item & mask);
mask = mask_u8(*c, i); rc = (rc & ~mask) | (item & mask);
mask = mask_u8(*d, i); rd = (rd & ~mask) | (item & mask);
}
*a = ra;
*b = rb;
*c = rc;
*d = rd;
}
/** out ^= if0 or if1, depending on the value of bit. */
static inline void select_xor128(uint32_t out[4],
const uint32_t if0[4],
const uint32_t if1[4],
uint8_t bit)
{
uint32_t mask1 = mask_u32(bit, 1);
uint32_t mask0 = ~mask1;
out[0] ^= (if0[0] & mask0) | (if1[0] & mask1);
out[1] ^= (if0[1] & mask0) | (if1[1] & mask1);
out[2] ^= (if0[2] & mask0) | (if1[2] & mask1);
out[3] ^= (if0[3] & mask0) | (if1[3] & mask1);
}
/** Increments the integer stored at v (of non-zero length len)
* with the least significant byte first. */
static inline void incr_le(uint8_t *v, size_t len)
{
size_t i = 0;
while (1)
{
if (++v[i] != 0)
return;
i++;
if (i == len)
return;
}
}
/** Increments the integer stored at v (of non-zero length len)
* with the most significant byte last. */
static inline void incr_be(uint8_t *v, size_t len)
{
len--;
while (1)
{
if (++v[len] != 0)
return;
if (len == 0)
return;
len--;
}
}
/** Copies len bytes from in to out, with in shifted left by offset bits
* to the right. */
static inline void copy_bytes_unaligned(uint8_t *out, const uint8_t *in, size_t len, uint8_t offset)
{
uint8_t byte_off = offset / 8;
uint8_t bit_off = offset & 7;
uint8_t rmask = (1 << bit_off) - 1;
uint8_t lmask = ~rmask;
for (size_t i = 0; i < len; i++)
{
out[i] = (in[i + byte_off] << bit_off) & lmask;
out[i] |= (in[i + byte_off + 1] >> (8 - bit_off)) & rmask;
}
}
static inline uint32_t count_trailing_zeroes(uint32_t x)
{
return (uint32_t) __builtin_ctzl(x);
}
#endif

195
User/lib/cifra/blockwise.c Normal file
View File

@@ -0,0 +1,195 @@
/*
* cifra - embedded cryptography library
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include "blockwise.h"
#include "bitops.h"
#include "handy.h"
#include "tassert.h"
#include <string.h>
void cf_blockwise_accumulate(uint8_t *partial, size_t *npartial, size_t nblock,
const void *inp, size_t nbytes,
cf_blockwise_in_fn process,
void *ctx)
{
cf_blockwise_accumulate_final(partial, npartial, nblock,
inp, nbytes,
process, process, ctx);
}
void cf_blockwise_accumulate_final(uint8_t *partial, size_t *npartial, size_t nblock,
const void *inp, size_t nbytes,
cf_blockwise_in_fn process,
cf_blockwise_in_fn process_final,
void *ctx)
{
const uint8_t *bufin = inp;
assert(partial && *npartial < nblock);
assert(inp || !nbytes);
assert(process && ctx);
/* If we have partial data, copy in to buffer. */
if (*npartial && nbytes)
{
size_t space = nblock - *npartial;
size_t taken = MIN(space, nbytes);
memcpy(partial + *npartial, bufin, taken);
bufin += taken;
nbytes -= taken;
*npartial += taken;
/* If that gives us a full block, process it. */
if (*npartial == nblock)
{
if (nbytes == 0)
process_final(ctx, partial);
else
process(ctx, partial);
*npartial = 0;
}
}
/* now nbytes < nblock or *npartial == 0. */
/* If we have a full block of data, process it directly. */
while (nbytes >= nblock)
{
/* Partial buffer must be empty, or we're ignoring extant data */
assert(*npartial == 0);
if (nbytes == nblock)
process_final(ctx, bufin);
else
process(ctx, bufin);
bufin += nblock;
nbytes -= nblock;
}
/* Finally, if we have remaining data, buffer it. */
while (nbytes)
{
size_t space = nblock - *npartial;
size_t taken = MIN(space, nbytes);
memcpy(partial + *npartial, bufin, taken);
bufin += taken;
nbytes -= taken;
*npartial += taken;
/* If we started with *npartial, we must have copied it
* in first. */
assert(*npartial < nblock);
}
}
void cf_blockwise_xor(uint8_t *partial, size_t *npartial, size_t nblock,
const void *inp, void *outp, size_t nbytes,
cf_blockwise_out_fn process, void *ctx)
{
const uint8_t *inb = inp;
uint8_t *outb = outp;
assert(partial && *npartial < nblock);
assert(inp || !nbytes);
assert(process && ctx);
while (nbytes)
{
/* If we're out of material, and need more, produce a block. */
if (*npartial == 0)
{
process(ctx, partial);
*npartial = nblock;
}
size_t offset = nblock - *npartial;
size_t taken = MIN(*npartial, nbytes);
xor_bb(outb, inb, partial + offset, taken);
*npartial -= taken;
nbytes -= taken;
outb += taken;
inb += taken;
}
}
void cf_blockwise_acc_byte(uint8_t *partial, size_t *npartial,
size_t nblock,
uint8_t byte, size_t nbytes,
cf_blockwise_in_fn process,
void *ctx)
{
/* only memset the whole of the block once */
int filled = 0;
while (nbytes)
{
size_t start = *npartial;
size_t count = MIN(nbytes, nblock - start);
if (!filled)
memset(partial + start, byte, count);
if (start == 0 && count == nblock)
filled = 1;
if (start + count == nblock)
{
process(ctx, partial);
*npartial = 0;
} else {
*npartial += count;
}
nbytes -= count;
}
}
void cf_blockwise_acc_pad(uint8_t *partial, size_t *npartial,
size_t nblock,
uint8_t fbyte, uint8_t mbyte, uint8_t lbyte,
size_t nbytes,
cf_blockwise_in_fn process,
void *ctx)
{
switch (nbytes)
{
case 0: break;
case 1: fbyte ^= lbyte;
cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
break;
case 2:
cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
cf_blockwise_accumulate(partial, npartial, nblock, &lbyte, 1, process, ctx);
break;
default:
cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
/* If the middle and last bytes differ, then process the last byte separately.
* Otherwise, just extend the middle block size. */
if (lbyte != mbyte)
{
cf_blockwise_acc_byte(partial, npartial, nblock, mbyte, nbytes - 2, process, ctx);
cf_blockwise_accumulate(partial, npartial, nblock, &lbyte, 1, process, ctx);
} else {
cf_blockwise_acc_byte(partial, npartial, nblock, mbyte, nbytes - 1, process, ctx);
}
break;
}
}

147
User/lib/cifra/blockwise.h Normal file
View File

@@ -0,0 +1,147 @@
/*
* cifra - embedded cryptography library
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#ifndef BLOCKWISE_H
#define BLOCKWISE_H
#include <stdint.h>
#include <stddef.h>
/* Processing function for cf_blockwise_accumulate. */
typedef void (*cf_blockwise_in_fn)(void *ctx, const uint8_t *data);
/* Processing function for cf_blockwise_xor. */
typedef void (*cf_blockwise_out_fn)(void *ctx, uint8_t *data);
/* This function manages the common abstraction of accumulating input in
* a buffer, and processing it when a full block is available.
*
* partial is the buffer (maintained by the caller)
* on entry, npartial is the currently valid count of used bytes on
* the front of partial.
* on exit, npartial is updated to reflect the status of partial.
* nblock is the blocksize to accumulate -- partial must be at least
* this long!
* input is the new data to process, of length nbytes.
* process is the processing function, passed ctx and a pointer
* to the data to process (always exactly nblock bytes long!)
* which may not neccessarily be the same as partial.
*/
void cf_blockwise_accumulate(uint8_t *partial, size_t *npartial,
size_t nblock,
const void *input, size_t nbytes,
cf_blockwise_in_fn process,
void *ctx);
/* This function manages the common abstraction of accumulating input in
* a buffer, and processing it when a full block is available.
* This version supports calling a different processing function for
* the last block.
*
* partial is the buffer (maintained by the caller)
* on entry, npartial is the currently valid count of used bytes on
* the front of partial.
* on exit, npartial is updated to reflect the status of partial.
* nblock is the blocksize to accumulate -- partial must be at least
* this long!
* input is the new data to process, of length nbytes.
* process is the processing function, passed ctx and a pointer
* to the data to process (always exactly nblock bytes long!)
* which may not neccessarily be the same as partial.
* process_final is called last (but may not be called at all if
* all input is buffered).
*/
void cf_blockwise_accumulate_final(uint8_t *partial, size_t *npartial,
size_t nblock,
const void *input, size_t nbytes,
cf_blockwise_in_fn process,
cf_blockwise_in_fn process_final,
void *ctx);
/* This function manages XORing an input stream with a keystream
* to produce an output stream. The keystream is produced in blocks
* (ala a block cipher in counter mode).
*
* partial is the keystream buffer (maintained by the caller)
* on entry, *npartial is the currently valid count of bytes in partial:
* unused bytes are at the *end*. So *npartial = 4 means the last four
* bytes of partial are usable as keystream.
* on exit, npartial is updated to reflect the new state of partial.
* nblock is the blocksize to accumulate -- partial must be at least
* this long!
* input is the new data to process, of length nbytes.
* output is where to write input xored with the keystream -- also length
* nbytes.
* process is the processing function, passed ctx and partial which it
* should fill with fresh key stream.
*/
void cf_blockwise_xor(uint8_t *partial, size_t *npartial,
size_t nblock,
const void *input, void *output, size_t nbytes,
cf_blockwise_out_fn newblock,
void *ctx);
/* This function processes a single byte a number of times. It's useful
* for padding, and more efficient than calling cf_blockwise_accumulate
* a bunch of times.
*
* partial is the buffer (maintained by the caller)
* on entry, npartial is the currently valid count of used bytes on
* the front of partial.
* on exit, npartial is updated to reflect the status of partial.
* nblock is the blocksize to accumulate -- partial must be at least
* this long!
* process is the processing function, passed ctx and a pointer
* to the data to process (always exactly nblock bytes long!)
* which may not neccessarily be the same as partial.
* byte is the byte to process, nbytes times.
*/
void cf_blockwise_acc_byte(uint8_t *partial, size_t *npartial,
size_t nblock,
uint8_t byte, size_t nbytes,
cf_blockwise_in_fn process,
void *ctx);
/* This function attempts to process patterns of bytes common in
* block cipher padding.
*
* This takes three bytes:
* - a first byte, fbyte,
* - a middle byte, mbyte,
* - a last byte, lbyte.
*
* If nbytes is zero, nothing happens.
* If nbytes is one, the byte fbyte ^ lbyte is processed.
* If nbytes is two, the fbyte then lbyte are processed.
* If nbytes is three or more, fbyte, then one or more mbytes, then fbyte
* is processed.
*
* partial is the buffer (maintained by the caller)
* on entry, npartial is the currently valid count of used bytes on
* the front of partial.
* on exit, npartial is updated to reflect the status of partial.
* nblock is the blocksize to accumulate -- partial must be at least
* this long!
* process is the processing function, passed ctx and a pointer
* to the data to process (always exactly nblock bytes long!)
* which may not neccessarily be the same as partial.
*/
void cf_blockwise_acc_pad(uint8_t *partial, size_t *npartial,
size_t nblock,
uint8_t fbyte, uint8_t mbyte, uint8_t lbyte,
size_t nbytes,
cf_blockwise_in_fn process,
void *ctx);
#endif

View File

@@ -0,0 +1,59 @@
/*
* cifra - embedded cryptography library
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#ifndef CF_CONFIG_H
#define CF_CONFIG_H
/**
* Library configuration
* =====================
*/
/* .. c:macro:: CF_SIDE_CHANNEL_PROTECTION
* Define this as 1 if you need all available side channel protections.
* **This option may alter the ABI**.
*
* This has a non-trivial performance penalty. Where a
* side-channel free option is cheap or free (like checking
* a MAC) this is always done in a side-channel free way.
*
* The default is **on** for all available protections.
*/
#ifndef CF_SIDE_CHANNEL_PROTECTION
# define CF_SIDE_CHANNEL_PROTECTION 1
#endif
/* .. c:macro:: CF_TIME_SIDE_CHANNEL_PROTECTION
* Define this as 1 if you need timing/branch prediction side channel
* protection.
*
* You probably want this. The default is on. */
#ifndef CF_TIME_SIDE_CHANNEL_PROTECTION
# define CF_TIME_SIDE_CHANNEL_PROTECTION CF_SIDE_CHANNEL_PROTECTION
#endif
/* .. c:macro:: CF_CACHE_SIDE_CHANNEL_PROTECTION
* Define this as 1 if you need cache side channel protection.
*
* If you have a microcontroller with no cache, you can turn this off
* without negative effects.
*
* The default is on. This will have some performance impact,
* especially on AES.
*/
#ifndef CF_CACHE_SIDE_CHANNEL_PROTECTION
# define CF_CACHE_SIDE_CHANNEL_PROTECTION CF_SIDE_CHANNEL_PROTECTION
#endif
#endif

28
User/lib/cifra/chash.c Normal file
View File

@@ -0,0 +1,28 @@
/*
* cifra - embedded cryptography library
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include "chash.h"
#include "handy.h"
#include "tassert.h"
void cf_hash(const cf_chash *h, const void *m, size_t nm, uint8_t *out)
{
cf_chash_ctx ctx;
assert(h);
h->init(&ctx);
h->update(&ctx, m, nm);
h->digest(&ctx, out);
mem_clean(&ctx, sizeof ctx);
}

137
User/lib/cifra/chash.h Normal file
View File

@@ -0,0 +1,137 @@
/*
* cifra - embedded cryptography library
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#ifndef CHASH_H
#define CHASH_H
#include <stddef.h>
#include <stdint.h>
/**
* General hash function description
* =================================
* This allows us to make use of hash functions without depending
* on a specific one. This is useful in implementing, for example,
* :doc:`HMAC <hmac>`.
*/
/* .. c:type:: cf_chash_init
* Hashing initialisation function type.
*
* Functions of this type should initialise the context in preparation
* for hashing a message with `cf_chash_update` functions.
*
* :rtype: void
* :param ctx: hash function-specific context structure.
*/
typedef void (*cf_chash_init)(void *ctx);
/* .. c:type:: cf_chash_update
* Hashing data processing function type.
*
* Functions of this type hash `count` bytes of data at `data`,
* updating the contents of `ctx`.
*
* :rtype: void
* :param ctx: hash function-specific context structure.
* :param data: input data to hash.
* :param count: number of bytes to hash.
*/
typedef void (*cf_chash_update)(void *ctx, const void *data, size_t count);
/* .. c:type:: cf_chash_digest
* Hashing completion function type.
*
* Functions of this type complete a hashing operation,
* writing :c:member:`cf_chash.hashsz` bytes to `hash`.
*
* This function does not change `ctx` -- any padding which needs doing
* must be done seperately (in a copy of `ctx`, say).
*
* This means you can interlave `_update` and `_digest` calls to
* learn `H(A)` and `H(A || B)` without hashing `A` twice.
*
* :rtype: void
* :param ctx: hash function-specific context structure.
* :param hash: location to write hash result.
*/
typedef void (*cf_chash_digest)(const void *ctx, uint8_t *hash);
/* .. c:type:: cf_chash
* This type describes an incremental hash function in an abstract way.
*
* .. c:member:: cf_chash.hashsz
* The hash function's output, in bytes.
*
* .. c:member:: cf_chash.blocksz
* The hash function's internal block size, in bytes.
*
* .. c:member:: cf_chash.init
* Context initialisation function.
*
* .. c:member:: cf_chash:update
* Data processing function.
*
* .. c:member:: cf_chash:digest
* Completion function.
*
*/
typedef struct
{
size_t hashsz;
size_t blocksz;
cf_chash_init init;
cf_chash_update update;
cf_chash_digest digest;
} cf_chash;
/* .. c:macro:: CF_CHASH_MAXCTX
* The maximum size of a :c:type:`cf_chash_ctx`. This allows
* use to put a structure in automatic storage that can
* store working data for any supported hash function. */
#define CF_CHASH_MAXCTX 390
/* .. c:macro:: CF_CHASH_MAXBLK
* Maximum hash function block size (in bytes). */
#define CF_CHASH_MAXBLK 128
/* .. c:macro:: CF_MAXHASH
* Maximum hash function output (in bytes). */
#define CF_MAXHASH 64
/* .. c:type:: cf_chash_ctx
* A type usable with any `cf_chash` as a context. */
typedef union
{
uint8_t ctx[CF_CHASH_MAXCTX];
uint16_t u16;
uint32_t u32;
uint64_t u64;
} cf_chash_ctx;
/* .. c:function:: $DECL
* One shot hashing: `out = h(m)`.
*
* Using the hash function `h`, `nm` bytes at `m` are hashed and `h->hashsz` bytes
* of result is written to the buffer `out`.
*
* :param h: hash function description.
* :param m: message buffer.
* :param nm: message length.
* :param out: hash result buffer (written).
*/
void cf_hash(const cf_chash *h, const void *m, size_t nm, uint8_t *out);
#endif

86
User/lib/cifra/handy.h Normal file
View File

@@ -0,0 +1,86 @@
#ifndef HANDY_H
#define HANDY_H
#include <stddef.h>
#include <stdint.h>
#include <string.h>
/*
* Handy CPP defines and C inline functions.
*/
/* Evaluates to the number of items in array-type variable arr. */
#define ARRAYCOUNT(arr) (sizeof arr / sizeof arr[0])
/* Normal MIN/MAX macros. Evaluate argument expressions only once. */
#ifndef MIN
#define MIN(x, y) \
({ typeof (x) __x = (x); \
typeof (y) __y = (y); \
__x < __y ? __x : __y; })
#endif
#ifndef MAX
#define MAX(x, y) \
({ typeof (x) __x = (x); \
typeof (y) __y = (y); \
__x > __y ? __x : __y; })
#endif
/* Swap two values. Uses GCC type inference magic. */
#ifndef SWAP
#define SWAP(x, y) \
do { \
typeof (x) __tmp = (x); \
(x) = (y); \
(y) = __tmp; \
} while (0)
#endif
/** Stringify its argument. */
#define STRINGIFY(x) STRINGIFY_(x)
#define STRINGIFY_(x) #x
/* Error handling macros.
*
* These expect a zero = success, non-zero = error convention.
*/
/** Error: return.
*
* If the expression fails, return the error from this function. */
#define ER(expr) do { typeof (expr) err_ = (expr); if (err_) return err_; } while (0)
/** Error: goto.
*
* If the expression fails, goto x_err. Assumes defn of label
* x_err and 'error_type err'. */
#define EG(expr) do { err = (expr); if (err) goto x_err; } while (0)
/** Like memset(ptr, 0, len), but not allowed to be removed by
* compilers. */
static inline void mem_clean(volatile void *v, size_t len)
{
if (len)
{
memset((void *) v, 0, len);
(void) *((volatile uint8_t *) v);
}
}
/** Returns 1 if len bytes at va equal len bytes at vb, 0 if they do not.
* Does not leak length of common prefix through timing. */
static inline unsigned mem_eq(const void *va, const void *vb, size_t len)
{
const volatile uint8_t *a = va;
const volatile uint8_t *b = vb;
uint8_t diff = 0;
while (len--)
{
diff |= *a++ ^ *b++;
}
return !diff;
}
#endif

106
User/lib/cifra/hmac.c Normal file
View File

@@ -0,0 +1,106 @@
/*
* cifra - embedded cryptography library
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include "hmac.h"
#include "chash.h"
#include "bitops.h"
#include "handy.h"
#include "tassert.h"
#include <string.h>
void cf_hmac_init(cf_hmac_ctx *ctx,
const cf_chash *hash,
const uint8_t *key, size_t nkey)
{
assert(ctx);
assert(hash);
mem_clean(ctx, sizeof *ctx);
ctx->hash = hash;
/* Prepare key: */
uint8_t k[CF_CHASH_MAXBLK];
/* Shorten long keys. */
if (nkey > hash->blocksz)
{
/* Standard doesn't cover case where blocksz < hashsz.
* FIPS186-1 seems to want to append a negative number of zero bytes.
* In any case, we only have a k buffer of CF_CHASH_MAXBLK! */
assert(hash->hashsz <= hash->blocksz);
cf_hash(hash, key, nkey, k);
key = k;
nkey = hash->hashsz;
}
/* Right zero-pad short keys. */
if (k != key)
memcpy(k, key, nkey);
if (hash->blocksz > nkey)
memset(k + nkey, 0, hash->blocksz - nkey);
/* Start inner hash computation */
uint8_t blk[CF_CHASH_MAXBLK];
xor_b8(blk, k, 0x36, hash->blocksz);
hash->init(&ctx->inner);
hash->update(&ctx->inner, blk, hash->blocksz);
/* And outer. */
xor_b8(blk, k, 0x5c, hash->blocksz);
hash->init(&ctx->outer);
hash->update(&ctx->outer, blk, hash->blocksz);
mem_clean(blk, sizeof blk);
mem_clean(k, sizeof k);
}
void cf_hmac_update(cf_hmac_ctx *ctx, const void *data, size_t ndata)
{
assert(ctx && ctx->hash);
ctx->hash->update(&ctx->inner, data, ndata);
}
void cf_hmac_finish(cf_hmac_ctx *ctx, uint8_t *out)
{
assert(ctx && ctx->hash);
assert(out);
uint8_t innerh[CF_MAXHASH];
ctx->hash->digest(&ctx->inner, innerh);
ctx->hash->update(&ctx->outer, innerh, ctx->hash->hashsz);
ctx->hash->digest(&ctx->outer, out);
mem_clean(ctx, sizeof *ctx);
}
void cf_hmac(const uint8_t *key, size_t nkey,
const uint8_t *msg, size_t nmsg,
uint8_t *out,
const cf_chash *hash)
{
cf_hmac_ctx ctx;
assert(out);
assert(hash);
cf_hmac_init(&ctx, hash, key, nkey);
cf_hmac_update(&ctx, msg, nmsg);
cf_hmac_finish(&ctx, out);
}

78
User/lib/cifra/hmac.h Normal file
View File

@@ -0,0 +1,78 @@
/*
* cifra - embedded cryptography library
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#ifndef HMAC_H
#define HMAC_H
#include <stddef.h>
#include <stdint.h>
#include "chash.h"
/**
* HMAC
* ====
* This is a one-shot and incremental interface to computing
* HMAC with any hash function.
*
* (Note: HMAC with SHA3 is possible, but is probably not a
* sensible thing to want.)
*/
/* .. c:type:: cf_hmac_ctx
* HMAC incremental interface context.
*
* .. c:member:: cf_hmac_ctx.hash
* Hash function description.
*
* .. c:member:: cf_hmac_ctx.inner
* Inner hash computation.
*
* .. c:member:: cf_hmac_ctx.outer
* Outer hash computation.
*/
typedef struct
{
const cf_chash *hash;
cf_chash_ctx inner;
cf_chash_ctx outer;
} cf_hmac_ctx;
/* .. c:function:: $DECL
* Set up ctx for computing a HMAC using the given hash and key. */
void cf_hmac_init(cf_hmac_ctx *ctx,
const cf_chash *hash,
const uint8_t *key, size_t nkey);
/* .. c:function:: $DECL
* Input data. */
void cf_hmac_update(cf_hmac_ctx *ctx,
const void *data, size_t ndata);
/* .. c:function:: $DECL
* Finish and compute HMAC.
* `ctx->hash->hashsz` bytes are written to `out`. */
void cf_hmac_finish(cf_hmac_ctx *ctx, uint8_t *out);
/* .. c:function:: $DECL
* One shot interface: compute `HMAC_hash(key, msg)`, writing the
* answer (which is `hash->hashsz` long) to `out`.
*
* This function does not fail. */
void cf_hmac(const uint8_t *key, size_t nkey,
const uint8_t *msg, size_t nmsg,
uint8_t *out,
const cf_chash *hash);
#endif

64
User/lib/cifra/prp.h Normal file
View File

@@ -0,0 +1,64 @@
/*
* cifra - embedded cryptography library
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#ifndef PRP_H
#define PRP_H
#include <stddef.h>
#include <stdint.h>
/**
* General block cipher description
* ================================
* This allows us to implement block cipher modes which can work
* with different block ciphers.
*/
/* .. c:type:: cf_prp_block
* Block processing function type.
*
* The `in` and `out` blocks may alias.
*
* :rtype: void
* :param ctx: block cipher-specific context object.
* :param in: input block.
* :param out: output block.
*/
typedef void (*cf_prp_block)(void *ctx, const uint8_t *in, uint8_t *out);
/* .. c:type:: cf_prp
* Describes an PRP in a general way.
*
* .. c:member:: cf_prp.blocksz
* Block size in bytes. Must be no more than :c:macro:`CF_MAXBLOCK`.
*
* .. c:member:: cf_prp.encrypt
* Block encryption function.
*
* .. c:member:: cf_prp.decrypt
* Block decryption function.
*/
typedef struct
{
size_t blocksz;
cf_prp_block encrypt;
cf_prp_block decrypt;
} cf_prp;
/* .. c:macro:: CF_MAXBLOCK
* The maximum block cipher blocksize we support, in bytes.
*/
#define CF_MAXBLOCK 16
#endif

235
User/lib/cifra/sha2.h Normal file
View File

@@ -0,0 +1,235 @@
/*
* cifra - embedded cryptography library
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#ifndef SHA2_H
#define SHA2_H
#include <stddef.h>
#include <stdint.h>
#include "chash.h"
/**
* SHA224/SHA256
* =============
*/
/* .. c:macro:: CF_SHA224_HASHSZ
* The output size of SHA224: 28 bytes. */
#define CF_SHA224_HASHSZ 28
/* .. c:macro:: CF_SHA224_BLOCKSZ
* The block size of SHA224: 64 bytes. */
#define CF_SHA224_BLOCKSZ 64
/* .. c:macro:: CF_SHA256_HASHSZ
* The output size of SHA256: 32 bytes. */
#define CF_SHA256_HASHSZ 32
/* .. c:macro:: CF_SHA256_BLOCKSZ
* The block size of SHA256: 64 bytes. */
#define CF_SHA256_BLOCKSZ 64
/* .. c:type:: cf_sha256_context
* Incremental SHA256 hashing context.
*
* .. c:member:: cf_sha256_context.H
* Intermediate values.
*
* .. c:member:: cf_sha256_context.partial
* Unprocessed input.
*
* .. c:member:: cf_sha256_context.npartial
* Number of bytes of unprocessed input.
*
* .. c:member:: cf_sha256_context.blocks
* Number of full blocks processed.
*/
typedef struct
{
uint32_t H[8]; /* State. */
uint8_t partial[CF_SHA256_BLOCKSZ]; /* Partial block of input. */
uint32_t blocks; /* Number of full blocks processed into H. */
size_t npartial; /* Number of bytes in prefix of partial. */
} cf_sha256_context;
/* .. c:function:: $DECL
* Sets up `ctx` ready to hash a new message.
*/
extern void cf_sha256_init(cf_sha256_context *ctx);
/* .. c:function:: $DECL
* Hashes `nbytes` at `data`. Copies the data if there isn't enough to make
* a full block.
*/
extern void cf_sha256_update(cf_sha256_context *ctx, const void *data, size_t nbytes);
/* .. c:function:: $DECL
* Finishes the hash operation, writing `CF_SHA256_HASHSZ` bytes to `hash`.
*
* This leaves `ctx` unchanged.
*/
extern void cf_sha256_digest(const cf_sha256_context *ctx, uint8_t hash[CF_SHA256_HASHSZ]);
/* .. c:function:: $DECL
* Finishes the hash operation, writing `CF_SHA256_HASHSZ` bytes to `hash`.
*
* This destroys `ctx`, but uses less stack than :c:func:`cf_sha256_digest`.
*/
extern void cf_sha256_digest_final(cf_sha256_context *ctx, uint8_t hash[CF_SHA256_HASHSZ]);
/* .. c:function:: $DECL
* Sets up `ctx` ready to hash a new message.
*
* nb. SHA224 uses SHA256's underlying types.
*/
extern void cf_sha224_init(cf_sha256_context *ctx);
/* .. c:function:: $DECL
* Hashes `nbytes` at `data`. Copies the data if there isn't enough to make
* a full block.
*/
extern void cf_sha224_update(cf_sha256_context *ctx, const void *data, size_t nbytes);
/* .. c:function:: $DECL
* Finishes the hash operation, writing `CF_SHA224_HASHSZ` bytes to `hash`.
*
* This leaves `ctx` unchanged.
*/
extern void cf_sha224_digest(const cf_sha256_context *ctx, uint8_t hash[CF_SHA224_HASHSZ]);
/* .. c:function:: $DECL
* Finishes the hash operation, writing `CF_SHA224_HASHSZ` bytes to `hash`.
*
* This destroys `ctx`, but uses less stack than :c:func:`cf_sha224_digest`.
*/
extern void cf_sha224_digest_final(cf_sha256_context *ctx, uint8_t hash[CF_SHA224_HASHSZ]);
/* .. c:var:: cf_sha224
* Abstract interface to SHA224. See :c:type:`cf_chash` for more information.
*/
extern const cf_chash cf_sha224;
/* .. c:var:: cf_sha256
* Abstract interface to SHA256. See :c:type:`cf_chash` for more information.
*/
extern const cf_chash cf_sha256;
/**
* SHA384/SHA512
* =============
*/
/* .. c:macro:: CF_SHA384_HASHSZ
* The output size of SHA384: 48 bytes. */
#define CF_SHA384_HASHSZ 48
/* .. c:macro:: CF_SHA384_BLOCKSZ
* The block size of SHA384: 128 bytes. */
#define CF_SHA384_BLOCKSZ 128
/* .. c:macro:: CF_SHA512_HASHSZ
* The output size of SHA512: 64 bytes. */
#define CF_SHA512_HASHSZ 64
/* .. c:macro:: CF_SHA512_BLOCKSZ
* The block size of SHA512: 128 bytes. */
#define CF_SHA512_BLOCKSZ 128
/* .. c:type:: cf_sha512_context
* Incremental SHA512 hashing context.
*
* .. c:member:: cf_sha512_context.H
* Intermediate values.
*
* .. c:member:: cf_sha512_context.partial
* Unprocessed input.
*
* .. c:member:: cf_sha512_context.npartial
* Number of bytes of unprocessed input.
*
* .. c:member:: cf_sha512_context.blocks
* Number of full blocks processed.
*/
typedef struct
{
uint64_t H[8];
uint8_t partial[CF_SHA512_BLOCKSZ];
uint32_t blocks;
size_t npartial;
} cf_sha512_context;
/* .. c:function:: $DECL
* Sets up `ctx` ready to hash a new message.
*/
extern void cf_sha512_init(cf_sha512_context *ctx);
/* .. c:function:: $DECL
* Hashes `nbytes` at `data`. Copies the data if there isn't enough to make
* a full block.
*/
extern void cf_sha512_update(cf_sha512_context *ctx, const void *data, size_t nbytes);
/* .. c:function:: $DECL
* Finishes the hash operation, writing `CF_SHA512_HASHSZ` bytes to `hash`.
*
* This leaves `ctx` unchanged.
*/
extern void cf_sha512_digest(const cf_sha512_context *ctx, uint8_t hash[CF_SHA512_HASHSZ]);
/* .. c:function:: $DECL
* Finishes the hash operation, writing `CF_SHA512_HASHSZ` bytes to `hash`.
*
* This destroys `ctx`, but uses less stack than :c:func:`cf_sha512_digest`.
*/
extern void cf_sha512_digest_final(cf_sha512_context *ctx, uint8_t hash[CF_SHA512_HASHSZ]);
/* .. c:function:: $DECL
* Sets up `ctx` ready to hash a new message.
*
* nb. SHA384 uses SHA512's underlying types.
*/
extern void cf_sha384_init(cf_sha512_context *ctx);
/* .. c:function:: $DECL
* Hashes `nbytes` at `data`. Copies the data if there isn't enough to make
* a full block.
*/
extern void cf_sha384_update(cf_sha512_context *ctx, const void *data, size_t nbytes);
/* .. c:function:: $DECL
* Finishes the hash operation, writing `CF_SHA384_HASHSZ` bytes to `hash`.
*
* This leaves `ctx` unchanged.
*/
extern void cf_sha384_digest(const cf_sha512_context *ctx, uint8_t hash[CF_SHA384_HASHSZ]);
/* .. c:function:: $DECL
* Finishes the hash operation, writing `CF_SHA384_HASHSZ` bytes to `hash`.
*
* This destroys `ctx`, but uses less stack than :c:func:`cf_sha384_digest`.
*/
extern void cf_sha384_digest_final(cf_sha512_context *ctx, uint8_t hash[CF_SHA384_HASHSZ]);
/* .. c:var:: cf_sha384
* Abstract interface to SHA384. See :c:type:`cf_chash` for more information.
*/
extern const cf_chash cf_sha384;
/* .. c:var:: cf_sha512
* Abstract interface to SHA512. See :c:type:`cf_chash` for more information.
*/
extern const cf_chash cf_sha512;
#endif

231
User/lib/cifra/sha256.c Normal file
View File

@@ -0,0 +1,231 @@
/*
* cifra - embedded cryptography library
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <string.h>
#include "sha2.h"
#include "blockwise.h"
#include "bitops.h"
#include "handy.h"
#include "tassert.h"
static const uint32_t K[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
# define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
# define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
# define BSIG0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22))
# define BSIG1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25))
# define SSIG0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3))
# define SSIG1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10))
void cf_sha256_init(cf_sha256_context *ctx)
{
memset(ctx, 0, sizeof *ctx);
ctx->H[0] = 0x6a09e667;
ctx->H[1] = 0xbb67ae85;
ctx->H[2] = 0x3c6ef372;
ctx->H[3] = 0xa54ff53a;
ctx->H[4] = 0x510e527f;
ctx->H[5] = 0x9b05688c;
ctx->H[6] = 0x1f83d9ab;
ctx->H[7] = 0x5be0cd19;
}
void cf_sha224_init(cf_sha256_context *ctx)
{
memset(ctx, 0, sizeof *ctx);
ctx->H[0] = 0xc1059ed8;
ctx->H[1] = 0x367cd507;
ctx->H[2] = 0x3070dd17;
ctx->H[3] = 0xf70e5939;
ctx->H[4] = 0xffc00b31;
ctx->H[5] = 0x68581511;
ctx->H[6] = 0x64f98fa7;
ctx->H[7] = 0xbefa4fa4;
}
static void sha256_update_block(void *vctx, const uint8_t *inp)
{
cf_sha256_context *ctx = vctx;
/* This is a 16-word window into the whole W array. */
uint32_t W[16];
uint32_t a = ctx->H[0],
b = ctx->H[1],
c = ctx->H[2],
d = ctx->H[3],
e = ctx->H[4],
f = ctx->H[5],
g = ctx->H[6],
h = ctx->H[7],
Wt;
for (size_t t = 0; t < 64; t++)
{
/* For W[0..16] we process the input into W.
* For W[16..64] we compute the next W value:
*
* W[t] = SSIG1(W[t - 2]) + W[t - 7] + SSIG0(W[t - 15]) + W[t - 16];
*
* But all W indices are reduced mod 16 into our window.
*/
if (t < 16)
{
W[t] = Wt = read32_be(inp);
inp += 4;
} else {
Wt = SSIG1(W[(t - 2) % 16]) +
W[(t - 7) % 16] +
SSIG0(W[(t - 15) % 16]) +
W[(t - 16) % 16];
W[t % 16] = Wt;
}
uint32_t T1 = h + BSIG1(e) + CH(e, f, g) + K[t] + Wt;
uint32_t T2 = BSIG0(a) + MAJ(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
}
ctx->H[0] += a;
ctx->H[1] += b;
ctx->H[2] += c;
ctx->H[3] += d;
ctx->H[4] += e;
ctx->H[5] += f;
ctx->H[6] += g;
ctx->H[7] += h;
ctx->blocks++;
}
void cf_sha256_update(cf_sha256_context *ctx, const void *data, size_t nbytes)
{
cf_blockwise_accumulate(ctx->partial, &ctx->npartial, sizeof ctx->partial,
data, nbytes,
sha256_update_block, ctx);
}
void cf_sha224_update(cf_sha256_context *ctx, const void *data, size_t nbytes)
{
cf_sha256_update(ctx, data, nbytes);
}
void cf_sha256_digest(const cf_sha256_context *ctx, uint8_t hash[CF_SHA256_HASHSZ])
{
/* We copy the context, so the finalisation doesn't effect the caller's
* context. This means the caller can do:
*
* x = init()
* x.update('hello')
* h1 = x.digest()
* x.update(' world')
* h2 = x.digest()
*
* to get h1 = H('hello') and h2 = H('hello world')
*
* This wouldn't work if we applied MD-padding to *ctx.
*/
cf_sha256_context ours = *ctx;
cf_sha256_digest_final(&ours, hash);
}
void cf_sha256_digest_final(cf_sha256_context *ctx, uint8_t hash[CF_SHA256_HASHSZ])
{
uint64_t digested_bytes = ctx->blocks;
digested_bytes = digested_bytes * CF_SHA256_BLOCKSZ + ctx->npartial;
uint64_t digested_bits = digested_bytes * 8;
size_t padbytes = CF_SHA256_BLOCKSZ - ((digested_bytes + 8) % CF_SHA256_BLOCKSZ);
/* Hash 0x80 00 ... block first. */
cf_blockwise_acc_pad(ctx->partial, &ctx->npartial, sizeof ctx->partial,
0x80, 0x00, 0x00, padbytes,
sha256_update_block, ctx);
/* Now hash length. */
uint8_t buf[8];
write64_be(digested_bits, buf);
cf_sha256_update(ctx, buf, 8);
/* We ought to have got our padding calculation right! */
assert(ctx->npartial == 0);
write32_be(ctx->H[0], hash + 0);
write32_be(ctx->H[1], hash + 4);
write32_be(ctx->H[2], hash + 8);
write32_be(ctx->H[3], hash + 12);
write32_be(ctx->H[4], hash + 16);
write32_be(ctx->H[5], hash + 20);
write32_be(ctx->H[6], hash + 24);
write32_be(ctx->H[7], hash + 28);
memset(ctx, 0, sizeof *ctx);
}
void cf_sha224_digest(const cf_sha256_context *ctx, uint8_t hash[CF_SHA224_HASHSZ])
{
uint8_t full[CF_SHA256_HASHSZ];
cf_sha256_digest(ctx, full);
memcpy(hash, full, CF_SHA224_HASHSZ);
}
void cf_sha224_digest_final(cf_sha256_context *ctx, uint8_t hash[CF_SHA224_HASHSZ])
{
uint8_t full[CF_SHA256_HASHSZ];
cf_sha256_digest_final(ctx, full);
memcpy(hash, full, CF_SHA224_HASHSZ);
}
const cf_chash cf_sha224 = {
.hashsz = CF_SHA224_HASHSZ,
.blocksz = CF_SHA256_BLOCKSZ,
.init = (cf_chash_init) cf_sha224_init,
.update = (cf_chash_update) cf_sha224_update,
.digest = (cf_chash_digest) cf_sha224_digest
};
const cf_chash cf_sha256 = {
.hashsz = CF_SHA256_HASHSZ,
.blocksz = CF_SHA256_BLOCKSZ,
.init = (cf_chash_init) cf_sha256_init,
.update = (cf_chash_update) cf_sha256_update,
.digest = (cf_chash_digest) cf_sha256_digest
};

32
User/lib/cifra/tassert.h Normal file
View File

@@ -0,0 +1,32 @@
/*
* cifra - embedded cryptography library
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication
* along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#ifndef TASSERT_H
#define TASSERT_H
/* Tiny assert
* -----------
*
* This is an assert(3) definition which doesn't include any
* strings, but just branches to abort(3) on failure.
*/
#ifndef FULL_FAT_ASSERT
# include <stdlib.h>
# define assert(expr) do { if (!(expr)) abort(); } while (0)
#else
# include <assert.h>
#endif
#endif

26
User/lib/config.c Normal file
View File

@@ -0,0 +1,26 @@
#include "config.h"
#include "ch32v30x_flash.h"
PersistentData_t persistent;
void loadConfig() {
memcpy (&persistent, FLASH_USER_PAGE_ADDR, sizeof (persistent));
uint32_t crcSum = *((uint32_t *)(((uint8_t *)&persistent) + (sizeof (persistent) - 2)));
memset ((((uint8_t *)&persistent) + (sizeof (persistent) - sizeof(crcSum))), 0, 4);
CRC_ResetDR();
uint32_t currentSum = CRC_CalcBlockCRC ((uint32_t *)&persistent, sizeof (persistent) - 2);
if (currentSum != crcSum) {
memset (&persistent, 0, sizeof (persistent));
}
}
void saveConfig() {
CRC_ResetDR();
uint32_t currentSum = CRC_CalcBlockCRC ((uint32_t *)&persistent, sizeof (persistent) - 2);
memcpy ((((uint8_t *)&persistent) + (sizeof (persistent) - sizeof(currentSum))), (uint8_t *)currentSum, 4);
FLASH_Unlock();
FLASH_ErasePage_Fast (1919);
FLASH_ProgramPage_Fast (1919, (uint32_t *)&persistent);
FLASH_Lock();
}

22
User/lib/config.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef CONFIG_HEADER
#define CONFIG_HEADER
#include "stdint.h"
#include "string.h"
#define FLASH_USER_PAGE_ADDR ((const void *)(0x08077F00))
typedef struct {
uint32_t magic; // e.g. 0xDEADBEEF
uint8_t privkey[32]; // Ed25519 private
uint8_t pubkey[32]; // Ed25519 public
uint8_t config[128]; // user config
char nodeName[20];
uint8_t extra[40];
uint32_t crc32; // integrity check
} PersistentData_t;
extern PersistentData_t persistent;
void saveConfig();
void loadConfig();
#endif

View File

@@ -0,0 +1,536 @@
// Monocypher version 4.0.2
//
// This file is dual-licensed. Choose whichever licence you want from
// the two licences listed below.
//
// The first licence is a regular 2-clause BSD licence. The second licence
// is the CC-0 from Creative Commons. It is intended to release Monocypher
// to the public domain. The BSD licence serves as a fallback option.
//
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
//
// ------------------------------------------------------------------------
//
// Copyright (c) 2017-2019, Loup Vaillant
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ------------------------------------------------------------------------
//
// Written in 2017-2019 by Loup Vaillant
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along
// with this software. If not, see
// <https://creativecommons.org/publicdomain/zero/1.0/>
#include "monocypher-ed25519.h"
#ifdef MONOCYPHER_CPP_NAMESPACE
namespace MONOCYPHER_CPP_NAMESPACE {
#endif
/////////////////
/// Utilities ///
/////////////////
#define FOR(i, min, max) for (size_t i = min; i < max; i++)
#define COPY(dst, src, size) FOR (_i_, 0, size) (dst)[_i_] = (src)[_i_]
#define ZERO(buf, size) FOR (_i_, 0, size) (buf)[_i_] = 0
#define WIPE_CTX(ctx) crypto_wipe (ctx, sizeof (*(ctx)))
#define WIPE_BUFFER(buffer) crypto_wipe (buffer, sizeof (buffer))
#define MIN(a, b) ((a) <= (b) ? (a) : (b))
typedef uint8_t u8;
typedef uint64_t u64;
// Returns the smallest positive integer y such that
// (x + y) % pow_2 == 0
// Basically, it's how many bytes we need to add to "align" x.
// Only works when pow_2 is a power of 2.
// Note: we use ~x+1 instead of -x to avoid compiler warnings
static size_t align (size_t x, size_t pow_2) {
return (~x + 1) & (pow_2 - 1);
}
static u64 load64_be (const u8 s[8]) {
return ((u64)s[0] << 56) | ((u64)s[1] << 48) | ((u64)s[2] << 40) | ((u64)s[3] << 32) | ((u64)s[4] << 24) | ((u64)s[5] << 16) | ((u64)s[6] << 8) | (u64)s[7];
}
static void store64_be (u8 out[8], u64 in) {
out[0] = (in >> 56) & 0xff;
out[1] = (in >> 48) & 0xff;
out[2] = (in >> 40) & 0xff;
out[3] = (in >> 32) & 0xff;
out[4] = (in >> 24) & 0xff;
out[5] = (in >> 16) & 0xff;
out[6] = (in >> 8) & 0xff;
out[7] = in & 0xff;
}
static void load64_be_buf (u64 *dst, const u8 *src, size_t size) {
FOR (i, 0, size) { dst[i] = load64_be (src + i * 8); }
}
///////////////
/// SHA 512 ///
///////////////
static u64 rot (u64 x, int c) { return (x >> c) | (x << (64 - c)); }
static u64 ch (u64 x, u64 y, u64 z) { return (x & y) ^ (~x & z); }
static u64 maj (u64 x, u64 y, u64 z) { return (x & y) ^ (x & z) ^ (y & z); }
static u64 big_sigma0 (u64 x) { return rot (x, 28) ^ rot (x, 34) ^ rot (x, 39); }
static u64 big_sigma1 (u64 x) { return rot (x, 14) ^ rot (x, 18) ^ rot (x, 41); }
static u64 lit_sigma0 (u64 x) { return rot (x, 1) ^ rot (x, 8) ^ (x >> 7); }
static u64 lit_sigma1 (u64 x) { return rot (x, 19) ^ rot (x, 61) ^ (x >> 6); }
static const u64 K[80] = {
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817};
static void sha512_compress (crypto_sha512_ctx *ctx) {
u64 a = ctx->hash[0];
u64 b = ctx->hash[1];
u64 c = ctx->hash[2];
u64 d = ctx->hash[3];
u64 e = ctx->hash[4];
u64 f = ctx->hash[5];
u64 g = ctx->hash[6];
u64 h = ctx->hash[7];
FOR (j, 0, 16) {
u64 in = K[j] + ctx->input[j];
u64 t1 = big_sigma1 (e) + ch (e, f, g) + h + in;
u64 t2 = big_sigma0 (a) + maj (a, b, c);
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
size_t i16 = 0;
FOR (i, 1, 5) {
i16 += 16;
FOR (j, 0, 16) {
ctx->input[j] += lit_sigma1 (ctx->input[(j - 2) & 15]);
ctx->input[j] += lit_sigma0 (ctx->input[(j - 15) & 15]);
ctx->input[j] += ctx->input[(j - 7) & 15];
u64 in = K[i16 + j] + ctx->input[j];
u64 t1 = big_sigma1 (e) + ch (e, f, g) + h + in;
u64 t2 = big_sigma0 (a) + maj (a, b, c);
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
}
ctx->hash[0] += a;
ctx->hash[1] += b;
ctx->hash[2] += c;
ctx->hash[3] += d;
ctx->hash[4] += e;
ctx->hash[5] += f;
ctx->hash[6] += g;
ctx->hash[7] += h;
}
// Write 1 input byte
static void sha512_set_input (crypto_sha512_ctx *ctx, u8 input) {
size_t word = ctx->input_idx >> 3;
size_t byte = ctx->input_idx & 7;
ctx->input[word] |= (u64)input << (8 * (7 - byte));
}
// Increment a 128-bit "word".
static void sha512_incr (u64 x[2], u64 y) {
x[1] += y;
if (x[1] < y) {
x[0]++;
}
}
void crypto_sha512_init (crypto_sha512_ctx *ctx) {
ctx->hash[0] = 0x6a09e667f3bcc908;
ctx->hash[1] = 0xbb67ae8584caa73b;
ctx->hash[2] = 0x3c6ef372fe94f82b;
ctx->hash[3] = 0xa54ff53a5f1d36f1;
ctx->hash[4] = 0x510e527fade682d1;
ctx->hash[5] = 0x9b05688c2b3e6c1f;
ctx->hash[6] = 0x1f83d9abfb41bd6b;
ctx->hash[7] = 0x5be0cd19137e2179;
ctx->input_size[0] = 0;
ctx->input_size[1] = 0;
ctx->input_idx = 0;
ZERO (ctx->input, 16);
}
void crypto_sha512_update (crypto_sha512_ctx *ctx,
const u8 *message, size_t message_size) {
// Avoid undefined NULL pointer increments with empty messages
if (message_size == 0) {
return;
}
// Align ourselves with word boundaries
if ((ctx->input_idx & 7) != 0) {
size_t nb_bytes = MIN (align (ctx->input_idx, 8), message_size);
FOR (i, 0, nb_bytes) {
sha512_set_input (ctx, message[i]);
ctx->input_idx++;
}
message += nb_bytes;
message_size -= nb_bytes;
}
// Align ourselves with block boundaries
if ((ctx->input_idx & 127) != 0) {
size_t nb_words = MIN (align (ctx->input_idx, 128), message_size) >> 3;
load64_be_buf (ctx->input + (ctx->input_idx >> 3), message, nb_words);
ctx->input_idx += nb_words << 3;
message += nb_words << 3;
message_size -= nb_words << 3;
}
// Compress block if needed
if (ctx->input_idx == 128) {
sha512_incr (ctx->input_size, 1024); // size is in bits
sha512_compress (ctx);
ctx->input_idx = 0;
ZERO (ctx->input, 16);
}
// Process the message block by block
FOR (i, 0, message_size >> 7) { // number of blocks
load64_be_buf (ctx->input, message, 16);
sha512_incr (ctx->input_size, 1024); // size is in bits
sha512_compress (ctx);
ctx->input_idx = 0;
ZERO (ctx->input, 16);
message += 128;
}
message_size &= 127;
if (message_size != 0) {
// Remaining words
size_t nb_words = message_size >> 3;
load64_be_buf (ctx->input, message, nb_words);
ctx->input_idx += nb_words << 3;
message += nb_words << 3;
message_size -= nb_words << 3;
// Remaining bytes
FOR (i, 0, message_size) {
sha512_set_input (ctx, message[i]);
ctx->input_idx++;
}
}
}
void crypto_sha512_final (crypto_sha512_ctx *ctx, u8 hash[64]) {
// Add padding bit
if (ctx->input_idx == 0) {
ZERO (ctx->input, 16);
}
sha512_set_input (ctx, 128);
// Update size
sha512_incr (ctx->input_size, ctx->input_idx * 8);
// Compress penultimate block (if any)
if (ctx->input_idx > 111) {
sha512_compress (ctx);
ZERO (ctx->input, 14);
}
// Compress last block
ctx->input[14] = ctx->input_size[0];
ctx->input[15] = ctx->input_size[1];
sha512_compress (ctx);
// Copy hash to output (big endian)
FOR (i, 0, 8) {
store64_be (hash + i * 8, ctx->hash[i]);
}
WIPE_CTX (ctx);
}
void crypto_sha512 (u8 hash[64], const u8 *message, size_t message_size) {
crypto_sha512_ctx ctx;
crypto_sha512_init (&ctx);
crypto_sha512_update (&ctx, message, message_size);
crypto_sha512_final (&ctx, hash);
}
////////////////////
/// HMAC SHA 512 ///
////////////////////
void crypto_sha512_hmac_init (crypto_sha512_hmac_ctx *ctx,
const u8 *key, size_t key_size) {
// hash key if it is too long
if (key_size > 128) {
crypto_sha512 (ctx->key, key, key_size);
key = ctx->key;
key_size = 64;
}
// Compute inner key: padded key XOR 0x36
FOR (i, 0, key_size) { ctx->key[i] = key[i] ^ 0x36; }
FOR (i, key_size, 128) { ctx->key[i] = 0x36; }
// Start computing inner hash
crypto_sha512_init (&ctx->ctx);
crypto_sha512_update (&ctx->ctx, ctx->key, 128);
}
void crypto_sha512_hmac_update (crypto_sha512_hmac_ctx *ctx,
const u8 *message, size_t message_size) {
crypto_sha512_update (&ctx->ctx, message, message_size);
}
void crypto_sha512_hmac_final (crypto_sha512_hmac_ctx *ctx, u8 hmac[64]) {
// Finish computing inner hash
crypto_sha512_final (&ctx->ctx, hmac);
// Compute outer key: padded key XOR 0x5c
FOR (i, 0, 128) {
ctx->key[i] ^= 0x36 ^ 0x5c;
}
// Compute outer hash
crypto_sha512_init (&ctx->ctx);
crypto_sha512_update (&ctx->ctx, ctx->key, 128);
crypto_sha512_update (&ctx->ctx, hmac, 64);
crypto_sha512_final (&ctx->ctx, hmac); // outer hash
WIPE_CTX (ctx);
}
void crypto_sha512_hmac (u8 hmac[64], const u8 *key, size_t key_size,
const u8 *message, size_t message_size) {
crypto_sha512_hmac_ctx ctx;
crypto_sha512_hmac_init (&ctx, key, key_size);
crypto_sha512_hmac_update (&ctx, message, message_size);
crypto_sha512_hmac_final (&ctx, hmac);
}
////////////////////
/// HKDF SHA 512 ///
////////////////////
void crypto_sha512_hkdf_expand (u8 *okm, size_t okm_size,
const u8 *prk, size_t prk_size,
const u8 *info, size_t info_size) {
int not_first = 0;
u8 ctr = 1;
u8 blk[64];
while (okm_size > 0) {
size_t out_size = MIN (okm_size, sizeof (blk));
crypto_sha512_hmac_ctx ctx;
crypto_sha512_hmac_init (&ctx, prk, prk_size);
if (not_first) {
// For some reason HKDF uses some kind of CBC mode.
// For some reason CTR mode alone wasn't enough.
// Like what, they didn't trust HMAC in 2010? Really??
crypto_sha512_hmac_update (&ctx, blk, sizeof (blk));
}
crypto_sha512_hmac_update (&ctx, info, info_size);
crypto_sha512_hmac_update (&ctx, &ctr, 1);
crypto_sha512_hmac_final (&ctx, blk);
COPY (okm, blk, out_size);
not_first = 1;
okm += out_size;
okm_size -= out_size;
ctr++;
}
}
void crypto_sha512_hkdf (u8 *okm, size_t okm_size,
const u8 *ikm, size_t ikm_size,
const u8 *salt, size_t salt_size,
const u8 *info, size_t info_size) {
// Extract
u8 prk[64];
crypto_sha512_hmac (prk, salt, salt_size, ikm, ikm_size);
// Expand
crypto_sha512_hkdf_expand (okm, okm_size, prk, sizeof (prk), info, info_size);
}
///////////////
/// Ed25519 ///
///////////////
void crypto_ed25519_key_pair (u8 secret_key[64], u8 public_key[32], u8 seed[32]) {
u8 a[64];
COPY (a, seed, 32); // a[ 0..31] = seed
crypto_wipe (seed, 32);
COPY (secret_key, a, 32); // secret key = seed
crypto_sha512 (a, a, 32); // a[ 0..31] = scalar
crypto_eddsa_trim_scalar (a, a); // a[ 0..31] = trimmed scalar
crypto_eddsa_scalarbase (public_key, a); // public key = [trimmed scalar]B
COPY (secret_key + 32, public_key, 32); // secret key includes public half
WIPE_BUFFER (a);
}
static void hash_reduce (u8 h[32],
const u8 *a, size_t a_size,
const u8 *b, size_t b_size,
const u8 *c, size_t c_size,
const u8 *d, size_t d_size) {
u8 hash[64];
crypto_sha512_ctx ctx;
crypto_sha512_init (&ctx);
crypto_sha512_update (&ctx, a, a_size);
crypto_sha512_update (&ctx, b, b_size);
crypto_sha512_update (&ctx, c, c_size);
crypto_sha512_update (&ctx, d, d_size);
crypto_sha512_final (&ctx, hash);
crypto_eddsa_reduce (h, hash);
}
static void ed25519_dom_sign (u8 signature[64], const u8 secret_key[32],
const u8 *dom, size_t dom_size,
const u8 *message, size_t message_size) {
u8 a[64]; // secret scalar and prefix
u8 r[32]; // secret deterministic "random" nonce
u8 h[32]; // publically verifiable hash of the message (not wiped)
u8 R[32]; // first half of the signature (allows overlapping inputs)
const u8 *pk = secret_key + 32;
crypto_sha512 (a, secret_key, 32);
crypto_eddsa_trim_scalar (a, a);
hash_reduce (r, dom, dom_size, a + 32, 32, message, message_size, 0, 0);
crypto_eddsa_scalarbase (R, r);
hash_reduce (h, dom, dom_size, R, 32, pk, 32, message, message_size);
COPY (signature, R, 32);
crypto_eddsa_mul_add (signature + 32, h, a, r);
WIPE_BUFFER (a);
WIPE_BUFFER (r);
}
// Meshcore-parity Ed25519 signing (non-standard, do NOT use outside Meshcore networks)
static void ed25519_meshcore_sign(u8 signature[64],
const u8 priv_seed[32], // secret seed (32 bytes)
const u8 pub_key[32], // public key (32 bytes)
const u8 *message, size_t message_size)
{
u8 a[64]; // secret scalar and prefix (same buffer as Monocypher)
u8 r[32]; // nonce scalar
u8 h[32]; // challenge scalar
u8 R[32]; // encoded R
// 1. Derive scalar a (clamped) and prefix (discarded here, Meshcore doesn<73><6E>t use it)
crypto_sha512(a, priv_seed, 32); // hash the seed
crypto_eddsa_trim_scalar(a, a); // clamp scalar a
// 2. Derive nonce r = H(public_key || message) instead of H(prefix || message)
hash_reduce(r, 0, 0, pub_key, 32, message, message_size, 0, 0);
// 3. R = r * basepoint
crypto_eddsa_scalarbase(R, r);
// 4. h = H(R || public_key || message)
hash_reduce(h, 0, 0, R, 32, pub_key, 32, message, message_size);
// 5. signature = R || (h*a + r)
COPY(signature, R, 32);
crypto_eddsa_mul_add(signature + 32, h, a, r);
// wipe secrets
WIPE_BUFFER(a);
WIPE_BUFFER(r);
}
void crypto_ed25519_meshcore_sign(u8 signature[64],
const u8 priv_seed[32],
const u8 pub_key[32],
const u8 *message, size_t message_size)
{
ed25519_meshcore_sign(signature, priv_seed, pub_key, message, message_size);
}
void crypto_ed25519_sign (u8 signature[64], const u8 secret_key[64],
const u8 *message, size_t message_size) {
ed25519_dom_sign (signature, secret_key, 0, 0, message, message_size);
}
int crypto_ed25519_check (const u8 signature[64], const u8 public_key[32],
const u8 *msg, size_t msg_size) {
u8 h_ram[32];
hash_reduce (h_ram, signature, 32, public_key, 32, msg, msg_size, 0, 0);
return crypto_eddsa_check_equation (signature, public_key, h_ram);
}
static const u8 domain[34] = "SigEd25519 no Ed25519 collisions\1";
void crypto_ed25519_ph_sign (uint8_t signature[64], const uint8_t secret_key[64],
const uint8_t message_hash[64]) {
ed25519_dom_sign (signature, secret_key, domain, sizeof (domain),
message_hash, 64);
}
int crypto_ed25519_ph_check (const uint8_t sig[64], const uint8_t pk[32],
const uint8_t msg_hash[64]) {
u8 h_ram[32];
hash_reduce (h_ram, domain, sizeof (domain), sig, 32, pk, 32, msg_hash, 64);
return crypto_eddsa_check_equation (sig, pk, h_ram);
}
#ifdef MONOCYPHER_CPP_NAMESPACE
}
#endif

View File

@@ -0,0 +1,144 @@
// Monocypher version 4.0.2
//
// This file is dual-licensed. Choose whichever licence you want from
// the two licences listed below.
//
// The first licence is a regular 2-clause BSD licence. The second licence
// is the CC-0 from Creative Commons. It is intended to release Monocypher
// to the public domain. The BSD licence serves as a fallback option.
//
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
//
// ------------------------------------------------------------------------
//
// Copyright (c) 2017-2019, Loup Vaillant
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ------------------------------------------------------------------------
//
// Written in 2017-2019 by Loup Vaillant
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along
// with this software. If not, see
// <https://creativecommons.org/publicdomain/zero/1.0/>
#ifndef ED25519_H
#define ED25519_H
#include "monocypher.h"
#ifdef MONOCYPHER_CPP_NAMESPACE
namespace MONOCYPHER_CPP_NAMESPACE {
#elif defined(__cplusplus)
extern "C" {
#endif
////////////////////////
/// Type definitions ///
////////////////////////
// Do not rely on the size or content on any of those types,
// they may change without notice.
typedef struct {
uint64_t hash[8];
uint64_t input[16];
uint64_t input_size[2];
size_t input_idx;
} crypto_sha512_ctx;
typedef struct {
uint8_t key[128];
crypto_sha512_ctx ctx;
} crypto_sha512_hmac_ctx;
void crypto_ed25519_meshcore_sign (uint8_t signature[64],
const uint8_t priv_seed[32],
const uint8_t pub_key[32],
const uint8_t *message, size_t message_size);
// SHA 512
// -------
void crypto_sha512_init (crypto_sha512_ctx *ctx);
void crypto_sha512_update (crypto_sha512_ctx *ctx,
const uint8_t *message, size_t message_size);
void crypto_sha512_final (crypto_sha512_ctx *ctx, uint8_t hash[64]);
void crypto_sha512 (uint8_t hash[64],
const uint8_t *message, size_t message_size);
// SHA 512 HMAC
// ------------
void crypto_sha512_hmac_init (crypto_sha512_hmac_ctx *ctx,
const uint8_t *key, size_t key_size);
void crypto_sha512_hmac_update (crypto_sha512_hmac_ctx *ctx,
const uint8_t *message, size_t message_size);
void crypto_sha512_hmac_final (crypto_sha512_hmac_ctx *ctx, uint8_t hmac[64]);
void crypto_sha512_hmac (uint8_t hmac[64],
const uint8_t *key, size_t key_size,
const uint8_t *message, size_t message_size);
// SHA 512 HKDF
// ------------
void crypto_sha512_hkdf_expand (uint8_t *okm, size_t okm_size,
const uint8_t *prk, size_t prk_size,
const uint8_t *info, size_t info_size);
void crypto_sha512_hkdf (uint8_t *okm, size_t okm_size,
const uint8_t *ikm, size_t ikm_size,
const uint8_t *salt, size_t salt_size,
const uint8_t *info, size_t info_size);
// Ed25519
// -------
// Signatures (EdDSA with curve25519 + SHA-512)
// --------------------------------------------
void crypto_ed25519_key_pair (uint8_t secret_key[64],
uint8_t public_key[32],
uint8_t seed[32]);
void crypto_ed25519_sign (uint8_t signature[64],
const uint8_t secret_key[64],
const uint8_t *message, size_t message_size);
int crypto_ed25519_check (const uint8_t signature[64],
const uint8_t public_key[32],
const uint8_t *message, size_t message_size);
// Pre-hash variants
void crypto_ed25519_ph_sign (uint8_t signature[64],
const uint8_t secret_key[64],
const uint8_t message_hash[64]);
int crypto_ed25519_ph_check (const uint8_t signature[64],
const uint8_t public_key[32],
const uint8_t message_hash[64]);
#ifdef __cplusplus
}
#endif
#endif // ED25519_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,321 @@
// Monocypher version 4.0.2
//
// This file is dual-licensed. Choose whichever licence you want from
// the two licences listed below.
//
// The first licence is a regular 2-clause BSD licence. The second licence
// is the CC-0 from Creative Commons. It is intended to release Monocypher
// to the public domain. The BSD licence serves as a fallback option.
//
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
//
// ------------------------------------------------------------------------
//
// Copyright (c) 2017-2019, Loup Vaillant
// All rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ------------------------------------------------------------------------
//
// Written in 2017-2019 by Loup Vaillant
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along
// with this software. If not, see
// <https://creativecommons.org/publicdomain/zero/1.0/>
#ifndef MONOCYPHER_H
#define MONOCYPHER_H
#include <stddef.h>
#include <stdint.h>
#ifdef MONOCYPHER_CPP_NAMESPACE
namespace MONOCYPHER_CPP_NAMESPACE {
#elif defined(__cplusplus)
extern "C" {
#endif
// Constant time comparisons
// -------------------------
// Return 0 if a and b are equal, -1 otherwise
int crypto_verify16(const uint8_t a[16], const uint8_t b[16]);
int crypto_verify32(const uint8_t a[32], const uint8_t b[32]);
int crypto_verify64(const uint8_t a[64], const uint8_t b[64]);
// Erase sensitive data
// --------------------
void crypto_wipe(void *secret, size_t size);
// Authenticated encryption
// ------------------------
void crypto_aead_lock(uint8_t *cipher_text,
uint8_t mac [16],
const uint8_t key [32],
const uint8_t nonce[24],
const uint8_t *ad, size_t ad_size,
const uint8_t *plain_text, size_t text_size);
int crypto_aead_unlock(uint8_t *plain_text,
const uint8_t mac [16],
const uint8_t key [32],
const uint8_t nonce[24],
const uint8_t *ad, size_t ad_size,
const uint8_t *cipher_text, size_t text_size);
// Authenticated stream
// --------------------
typedef struct {
uint64_t counter;
uint8_t key[32];
uint8_t nonce[8];
} crypto_aead_ctx;
void crypto_aead_init_x(crypto_aead_ctx *ctx,
const uint8_t key[32], const uint8_t nonce[24]);
void crypto_aead_init_djb(crypto_aead_ctx *ctx,
const uint8_t key[32], const uint8_t nonce[8]);
void crypto_aead_init_ietf(crypto_aead_ctx *ctx,
const uint8_t key[32], const uint8_t nonce[12]);
void crypto_aead_write(crypto_aead_ctx *ctx,
uint8_t *cipher_text,
uint8_t mac[16],
const uint8_t *ad , size_t ad_size,
const uint8_t *plain_text, size_t text_size);
int crypto_aead_read(crypto_aead_ctx *ctx,
uint8_t *plain_text,
const uint8_t mac[16],
const uint8_t *ad , size_t ad_size,
const uint8_t *cipher_text, size_t text_size);
// General purpose hash (BLAKE2b)
// ------------------------------
// Direct interface
void crypto_blake2b(uint8_t *hash, size_t hash_size,
const uint8_t *message, size_t message_size);
void crypto_blake2b_keyed(uint8_t *hash, size_t hash_size,
const uint8_t *key, size_t key_size,
const uint8_t *message, size_t message_size);
// Incremental interface
typedef struct {
// Do not rely on the size or contents of this type,
// for they may change without notice.
uint64_t hash[8];
uint64_t input_offset[2];
uint64_t input[16];
size_t input_idx;
size_t hash_size;
} crypto_blake2b_ctx;
void crypto_blake2b_init(crypto_blake2b_ctx *ctx, size_t hash_size);
void crypto_blake2b_keyed_init(crypto_blake2b_ctx *ctx, size_t hash_size,
const uint8_t *key, size_t key_size);
void crypto_blake2b_update(crypto_blake2b_ctx *ctx,
const uint8_t *message, size_t message_size);
void crypto_blake2b_final(crypto_blake2b_ctx *ctx, uint8_t *hash);
// Password key derivation (Argon2)
// --------------------------------
#define CRYPTO_ARGON2_D 0
#define CRYPTO_ARGON2_I 1
#define CRYPTO_ARGON2_ID 2
typedef struct {
uint32_t algorithm; // Argon2d, Argon2i, Argon2id
uint32_t nb_blocks; // memory hardness, >= 8 * nb_lanes
uint32_t nb_passes; // CPU hardness, >= 1 (>= 3 recommended for Argon2i)
uint32_t nb_lanes; // parallelism level (single threaded anyway)
} crypto_argon2_config;
typedef struct {
const uint8_t *pass;
const uint8_t *salt;
uint32_t pass_size;
uint32_t salt_size; // 16 bytes recommended
} crypto_argon2_inputs;
typedef struct {
const uint8_t *key; // may be NULL if no key
const uint8_t *ad; // may be NULL if no additional data
uint32_t key_size; // 0 if no key (32 bytes recommended otherwise)
uint32_t ad_size; // 0 if no additional data
} crypto_argon2_extras;
extern const crypto_argon2_extras crypto_argon2_no_extras;
void crypto_argon2(uint8_t *hash, uint32_t hash_size, void *work_area,
crypto_argon2_config config,
crypto_argon2_inputs inputs,
crypto_argon2_extras extras);
// Key exchange (X-25519)
// ----------------------
// Shared secrets are not quite random.
// Hash them to derive an actual shared key.
void crypto_x25519_public_key(uint8_t public_key[32],
const uint8_t secret_key[32]);
void crypto_x25519(uint8_t raw_shared_secret[32],
const uint8_t your_secret_key [32],
const uint8_t their_public_key [32]);
// Conversion to EdDSA
void crypto_x25519_to_eddsa(uint8_t eddsa[32], const uint8_t x25519[32]);
// scalar "division"
// Used for OPRF. Be aware that exponential blinding is less secure
// than Diffie-Hellman key exchange.
void crypto_x25519_inverse(uint8_t blind_salt [32],
const uint8_t private_key[32],
const uint8_t curve_point[32]);
// "Dirty" versions of x25519_public_key().
// Use with crypto_elligator_rev().
// Leaks 3 bits of the private key.
void crypto_x25519_dirty_small(uint8_t pk[32], const uint8_t sk[32]);
void crypto_x25519_dirty_fast (uint8_t pk[32], const uint8_t sk[32]);
// Signatures
// ----------
// EdDSA with curve25519 + BLAKE2b
void crypto_eddsa_key_pair(uint8_t secret_key[64],
uint8_t public_key[32],
uint8_t seed[32]);
void crypto_eddsa_sign(uint8_t signature [64],
const uint8_t secret_key[64],
const uint8_t *message, size_t message_size);
int crypto_eddsa_check(const uint8_t signature [64],
const uint8_t public_key[32],
const uint8_t *message, size_t message_size);
// Conversion to X25519
void crypto_eddsa_to_x25519(uint8_t x25519[32], const uint8_t eddsa[32]);
// EdDSA building blocks
void crypto_eddsa_trim_scalar(uint8_t out[32], const uint8_t in[32]);
void crypto_eddsa_reduce(uint8_t reduced[32], const uint8_t expanded[64]);
void crypto_eddsa_mul_add(uint8_t r[32],
const uint8_t a[32],
const uint8_t b[32],
const uint8_t c[32]);
void crypto_eddsa_scalarbase(uint8_t point[32], const uint8_t scalar[32]);
int crypto_eddsa_check_equation(const uint8_t signature[64],
const uint8_t public_key[32],
const uint8_t h_ram[32]);
// Chacha20
// --------
// Specialised hash.
// Used to hash X25519 shared secrets.
void crypto_chacha20_h(uint8_t out[32],
const uint8_t key[32],
const uint8_t in [16]);
// Unauthenticated stream cipher.
// Don't forget to add authentication.
uint64_t crypto_chacha20_djb(uint8_t *cipher_text,
const uint8_t *plain_text,
size_t text_size,
const uint8_t key[32],
const uint8_t nonce[8],
uint64_t ctr);
uint32_t crypto_chacha20_ietf(uint8_t *cipher_text,
const uint8_t *plain_text,
size_t text_size,
const uint8_t key[32],
const uint8_t nonce[12],
uint32_t ctr);
uint64_t crypto_chacha20_x(uint8_t *cipher_text,
const uint8_t *plain_text,
size_t text_size,
const uint8_t key[32],
const uint8_t nonce[24],
uint64_t ctr);
// Poly 1305
// ---------
// This is a *one time* authenticator.
// Disclosing the mac reveals the key.
// See crypto_lock() on how to use it properly.
// Direct interface
void crypto_poly1305(uint8_t mac[16],
const uint8_t *message, size_t message_size,
const uint8_t key[32]);
// Incremental interface
typedef struct {
// Do not rely on the size or contents of this type,
// for they may change without notice.
uint8_t c[16]; // chunk of the message
size_t c_idx; // How many bytes are there in the chunk.
uint32_t r [4]; // constant multiplier (from the secret key)
uint32_t pad[4]; // random number added at the end (from the secret key)
uint32_t h [5]; // accumulated hash
} crypto_poly1305_ctx;
void crypto_poly1305_init (crypto_poly1305_ctx *ctx, const uint8_t key[32]);
void crypto_poly1305_update(crypto_poly1305_ctx *ctx,
const uint8_t *message, size_t message_size);
void crypto_poly1305_final (crypto_poly1305_ctx *ctx, uint8_t mac[16]);
// Elligator 2
// -----------
// Elligator mappings proper
void crypto_elligator_map(uint8_t curve [32], const uint8_t hidden[32]);
int crypto_elligator_rev(uint8_t hidden[32], const uint8_t curve [32],
uint8_t tweak);
// Easy to use key pair generation
void crypto_elligator_key_pair(uint8_t hidden[32], uint8_t secret_key[32],
uint8_t seed[32]);
#ifdef __cplusplus
}
#endif
#endif // MONOCYPHER_H

255
User/lib/rtc/rtc.c Normal file
View File

@@ -0,0 +1,255 @@
#include "stdint.h"
#include "FreeRTOS.h"
#include "task.h"
#include "rtc.h"
_calendar_obj calendar;
uint8_t const table_week[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
const uint8_t mon_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/*********************************************************************
* @fn RTC_NVIC_Config
*
* @brief Initializes RTC Int.
*
* @return none
*/
void RTC_NVIC_Config (void) {
NVIC_InitTypeDef NVIC_InitStructure = {0};
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init (&NVIC_InitStructure);
}
/*********************************************************************
* @fn Is_Leap_Year
*
* @brief Judging whether it is a leap year.
*
* @param year
*
* @return 1 - Yes
* 0 - No
*/
uint8_t Is_Leap_Year (u16 year) {
if (year % 4 == 0) {
if (year % 100 == 0) {
if (year % 400 == 0)
return 1;
else
return 0;
} else
return 1;
} else
return 0;
}
/*********************************************************************
* @fn RTC_Set
*
* @brief Set Time.
*
* @param Struct of _calendar_obj
*
* @return 1 - error
* 0 - success
*/
uint8_t RTC_Set (u16 syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec) {
u16 t;
u32 seccount = 0;
if (syear < 1970 || syear > 2099)
return 1;
for (t = 1970; t < syear; t++) {
if (Is_Leap_Year (t))
seccount += 31622400;
else
seccount += 31536000;
}
smon -= 1;
for (t = 0; t < smon; t++) {
seccount += (u32)mon_table[t] * 86400;
if (Is_Leap_Year (syear) && t == 1)
seccount += 86400;
}
seccount += (u32)(sday - 1) * 86400;
seccount += (u32)hour * 3600;
seccount += (u32)min * 60;
seccount += sec;
RCC_APB1PeriphClockCmd (RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd (ENABLE);
RTC_SetCounter (seccount);
RTC_WaitForLastTask();
return 0;
}
/*********************************************************************
* @fn RTC_Alarm_Set
*
* @brief Set Alarm Time.
*
* @param Struct of _calendar_obj
*
* @return 1 - error
* 0 - success
*/
uint8_t RTC_Alarm_Set (u16 syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec) {
u16 t;
u32 seccount = 0;
if (syear < 1970 || syear > 2099)
return 1;
for (t = 1970; t < syear; t++) {
if (Is_Leap_Year (t))
seccount += 31622400;
else
seccount += 31536000;
}
smon -= 1;
for (t = 0; t < smon; t++) {
seccount += (u32)mon_table[t] * 86400;
if (Is_Leap_Year (syear) && t == 1)
seccount += 86400;
}
seccount += (u32)(sday - 1) * 86400;
seccount += (u32)hour * 3600;
seccount += (u32)min * 60;
seccount += sec;
RCC_APB1PeriphClockCmd (RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd (ENABLE);
RTC_SetAlarm (seccount);
RTC_WaitForLastTask();
return 0;
}
/*********************************************************************
* @fn RTC_Get_Week
*
* @brief Get the current day of the week.
*
* @param year/month/day
*
* @return week
*/
uint8_t RTC_Get_Week (u16 year, uint8_t month, uint8_t day) {
u16 temp2;
uint8_t yearH, yearL;
yearH = year / 100;
yearL = year % 100;
if (yearH > 19)
yearL += 100;
temp2 = yearL + yearL / 4;
temp2 = temp2 % 7;
temp2 = temp2 + day + table_week[month - 1];
if (yearL % 4 == 0 && month < 3)
temp2--;
return (temp2 % 7);
}
/*********************************************************************
* @fn RTC_Get
*
* @brief Get current time.
*
* @return 1 - error
* 0 - success
*/
uint8_t RTC_Get (void) {
static u16 daycnt = 0;
u32 timecount = 0;
u32 temp = 0;
u16 temp1 = 0;
timecount = RTC_GetCounter();
temp = timecount / 86400;
if (daycnt != temp) {
daycnt = temp;
temp1 = 1970;
while (temp >= 365) {
if (Is_Leap_Year (temp1)) {
if (temp >= 366)
temp -= 366;
else {
break;
}
} else
temp -= 365;
temp1++;
}
calendar.w_year = temp1;
temp1 = 0;
while (temp >= 28) {
if (Is_Leap_Year (calendar.w_year) && temp1 == 1) {
if (temp >= 29)
temp -= 29;
else
break;
} else {
if (temp >= mon_table[temp1])
temp -= mon_table[temp1];
else
break;
}
temp1++;
}
calendar.w_month = temp1 + 1;
calendar.w_date = temp + 1;
}
temp = timecount % 86400;
calendar.hour = temp / 3600;
calendar.min = (temp % 3600) / 60;
calendar.sec = (temp % 3600) % 60;
calendar.week = RTC_Get_Week (calendar.w_year, calendar.w_month, calendar.w_date);
return 0;
}
/*********************************************************************
* @fn RTC_Init
*
* @brief Initializes RTC collection.
*
* @return 1 - Init Fail
* 0 - Init Success
*/
uint8_t RTC_Init (void) {
uint8_t temp = 0;
RCC_APB1PeriphClockCmd (RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd (ENABLE);
RTC_ClearITPendingBit (RTC_IT_ALR);
RTC_ClearITPendingBit (RTC_IT_SEC);
/* Is it the first configuration */
BKP_DeInit();
RCC_LSEConfig (RCC_LSE_ON);
while (RCC_GetFlagStatus (RCC_FLAG_LSERDY) == RESET && temp < 250) {
temp++;
vTaskDelay (pdMS_TO_TICKS (20));
}
if (temp >= 250)
return 1;
RCC_RTCCLKConfig (RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd (ENABLE);
RTC_WaitForLastTask();
RTC_WaitForSynchro();
RTC_ITConfig (RTC_IT_SEC, DISABLE);
RTC_ITConfig (RTC_IT_ALR, DISABLE);
RTC_ITConfig (RTC_IT_OW, DISABLE);
RTC_WaitForLastTask();
RTC_EnterConfigMode();
RTC_SetPrescaler (32767);
RTC_WaitForLastTask();
RTC_Set (2025, 9, 7, 11, 33, 30); /* Setup Time */
RTC_ExitConfigMode();
BKP_WriteBackupRegister (BKP_DR1, 0XA1A1);
RTC_NVIC_Config();
RTC_Get();
return 0;
}

95
User/lib/rtc/rtc.h Normal file
View File

@@ -0,0 +1,95 @@
#include "stdint.h"
#include "FreeRTOS.h"
#include "task.h"
typedef struct
{
volatile uint8_t hour;
volatile uint8_t min;
volatile uint8_t sec;
volatile uint16_t w_year;
volatile uint8_t w_month;
volatile uint8_t w_date;
volatile uint8_t week;
} _calendar_obj;
extern _calendar_obj calendar;
extern uint8_t const table_week[12];
extern const uint8_t mon_table[12];
/*********************************************************************
* @fn RTC_NVIC_Config
*
* @brief Initializes RTC Int.
*
* @return none
*/
void RTC_NVIC_Config (void);
/*********************************************************************
* @fn Is_Leap_Year
*
* @brief Judging whether it is a leap year.
*
* @param year
*
* @return 1 - Yes
* 0 - No
*/
uint8_t Is_Leap_Year (u16 year);
/*********************************************************************
* @fn RTC_Set
*
* @brief Set Time.
*
* @param Struct of _calendar_obj
*
* @return 1 - error
* 0 - success
*/
uint8_t RTC_Set (u16 syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec) ;
/*********************************************************************
* @fn RTC_Alarm_Set
*
* @brief Set Alarm Time.
*
* @param Struct of _calendar_obj
*
* @return 1 - error
* 0 - success
*/
uint8_t RTC_Alarm_Set (u16 syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec) ;
/*********************************************************************
* @fn RTC_Get_Week
*
* @brief Get the current day of the week.
*
* @param year/month/day
*
* @return week
*/
uint8_t RTC_Get_Week (u16 year, uint8_t month, uint8_t day) ;
/*********************************************************************
* @fn RTC_Get
*
* @brief Get current time.
*
* @return 1 - error
* 0 - success
*/
uint8_t RTC_Get (void) ;
/*********************************************************************
* @fn RTC_Init
*
* @brief Initializes RTC collection.
*
* @return 1 - Init Fail
* 0 - Init Success
*/
uint8_t RTC_Init (void);

229
User/main.c Normal file
View File

@@ -0,0 +1,229 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : main.c
* Author : WCH
* Version : V1.0.0
* Date : 2021/06/06
* Description : Main program body.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
/*
*@Note
*task1 and task2 alternate printing
*/
#include "FreeRTOS.h"
#include "task.h"
#include "meshcore/packetstructs.h"
#include "sx1262.h"
#include "util/log.h"
#include "string.h"
#include "meshcore/meshcore.h"
#include "lib/base64.h"
#include "lib/config.h"
#include "lib/rtc/rtc.h"
#define TAG "MeshCore"
/* Global define */
#define TASK1_TASK_PRIO 5
#define TASK1_STK_SIZE 2048
uint8_t publKey[32] = {0x73, 0x78, 0x46, 0x76, 0x87, 0x3c, 0x9f, 0xeb, 0x00, 0x95, 0x05, 0xba, 0xdd, 0x3a, 0x4b, 0x33, 0xc8, 0xf5, 0x88, 0xa3, 0x8f, 0xaa, 0x30, 0x85, 0x3b, 0x91, 0xe6, 0xde, 0x97, 0x8c, 0xf1, 0xb2};
uint8_t privKey[32] = {0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20, 0x8a, 0x27, 0xca, 0x33, 0x85, 0xa5, 0x3b, 0x7d, 0x88, 0xce, 0x92, 0x23, 0xc4, 0x40, 0xc3, 0xac};
/* Global Variable */
TaskHandle_t Task1Task_Handler;
TaskHandle_t Task2Task_Handler;
/*********************************************************************
* @fn task1_task
*
* @brief task1 program.
*
* @param *pvParameters - Parameters point of task1
*
* @return none
*/
uint8_t bufIn[256];
void task2_task (void *pvParameters) {
RTC_Init();
while (1) {
// char tempBuf[180];
// vTaskDelay (pdMS_TO_TICKS (10000));
// snprintf (tempBuf, 180, "BRN RISCV: SySTick is %d", xTaskGetTickCount());
// makeSendGroupMessage (tempBuf, 1);
vTaskDelay (pdMS_TO_TICKS (10000));
memcpy (persistent.privkey, privKey, 32);
memcpy (persistent.pubkey, publKey, 32);
strcpy (persistent.nodeName, "BRN RiscV");
sendAdvert();
vTaskDelay (pdMS_TO_TICKS (20000));
}
}
void task1_task (void *pvParameters) {
//loadConfig();
const int64_t interval_ms = 10; // 10 ms
int64_t start_time, end_time, elapsed;
ESP_LOGW (TAG, "LoraInit");
LoRaInit();
int8_t txPowerInDbm = 20;
uint32_t frequencyInHz = 869618000;
ESP_LOGW (TAG, "Enable TCXO");
float tcxoVoltage = 2.2; // ebyte
// float tcxoVoltage = 1.8; // heltec
char useRegulatorLDO = 1;
LoRaDebugPrint (0);
ESP_LOGW (TAG, "Starting lora");
uint16_t loraBeginStat = LoRaBegin (frequencyInHz, txPowerInDbm, tcxoVoltage, useRegulatorLDO);
if (loraBeginStat != 0) {
ESP_LOGE (TAG, "Does not recognize the module");
while (1) {
vTaskDelay (pdMS_TO_TICKS (1000));
}
}
uint8_t spreadingFactor = 8;
uint8_t bandwidth = SX126X_LORA_BW_62_5;
uint8_t codingRate = SX126X_LORA_CR_4_8;
uint16_t preambleLength = 16;
char crcOn = 1;
char invertIrq = 0;
LoRaConfig (spreadingFactor, bandwidth, codingRate, preambleLength, 0, crcOn,
invertIrq);
while (1) {
start_time = xTaskGetTickCount();
uint8_t rxLen = LoRaReceive (bufIn, sizeof (bufIn));
if (rxLen > 0) {
// ESP_LOGI (TAG, "%d byte packet received", rxLen);
int8_t rssi, snr;
GetPacketStatus (&rssi, &snr);
ESP_LOGI (TAG, "rssi=%d[dBm] snr=%d[dB]", rssi, snr);
FrameStruct frame = decodeFrame (bufIn, rxLen);
printFrameHeader (frame);
unsigned char checkSumBuf[10];
AdvertisementPayload advert;
GroupTextMessage msg;
switch (frame.header & PAYLOAD_TYPE_MASK) {
case PAYLOAD_TYPE_REQ:
break;
case PAYLOAD_TYPE_RESPONSE:
break;
case PAYLOAD_TYPE_TXT_MSG:
break;
case PAYLOAD_TYPE_ACK:
memset (checkSumBuf, 0, sizeof (checkSumBuf));
base64_encode (frame.payload, 4, checkSumBuf);
printf ("Checksum: %s\n", checkSumBuf);
break;
case PAYLOAD_TYPE_ADVERT:
advert = decodeAdvertisement (frame);
printAdvertisement (advert);
break;
case PAYLOAD_TYPE_GRP_TXT:
msg = decodeGroupMessage (frame);
printGroupMessage (msg);
break;
case PAYLOAD_TYPE_GRP_DATA:
break;
case PAYLOAD_TYPE_ANON_REQ:
break;
case PAYLOAD_TYPE_PATH:
break;
case PAYLOAD_TYPE_TRACE:
break;
case PAYLOAD_TYPE_MULTIPART:
break;
case PAYLOAD_TYPE_RAW_CUSTOM:
break;
}
}
int lost = GetPacketLost();
if (lost != 0) {
ESP_LOGW (TAG, "%d packets lost", lost);
}
end_time = xTaskGetTickCount();
elapsed = end_time - start_time;
if (elapsed < (interval_ms / 2)) {
vTaskDelay (pdMS_TO_TICKS ((interval_ms - elapsed)));
}
}
}
void vApplicationStackOverflowHook (TaskHandle_t xTask, char *pcTaskName) {
printf ("stackoverflow");
}
/*********************************************************************
* @fn main
*
* @brief ; program.
*
* @return none
*/
int main (void) {
NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2);
SystemCoreClockUpdate();
Delay_Init();
USART_Printf_Init (115200);
printf ("SystemClk:%d\r\n", SystemCoreClock);
printf ("ChipID:%08x\r\n", DBGMCU_GetCHIPID());
printf ("FreeRTOS Kernel Version:%s\r\n", tskKERNEL_VERSION_NUMBER);
xTaskCreate ((TaskFunction_t)task1_task,
(const char *)"task1",
(uint16_t)TASK1_STK_SIZE,
(void *)NULL,
(UBaseType_t)TASK1_TASK_PRIO,
(TaskHandle_t *)&Task1Task_Handler);
xTaskCreate ((TaskFunction_t)task2_task,
(const char *)"task2",
(uint16_t)1024,
(void *)NULL,
(UBaseType_t)TASK1_TASK_PRIO,
(TaskHandle_t *)&Task2Task_Handler);
vTaskStartScheduler();
while (1) {
printf ("shouldn't run at here!!\n");
}
}

547
User/meshcore/meshcore.c Normal file
View File

@@ -0,0 +1,547 @@
#include "meshcore.h"
#include "FreeRTOS.h"
#include "lib/monocypher/monocypher-ed25519.h"
#include "task.h"
#include "lib/base64.h"
#include "lib/cifra/aes.h"
#include "lib/cifra/sha2.h"
#include "lib/cifra/hmac.h"
#include "lib/config.h"
#define AESKeyCount 8
const uint8_t aesKeys[AESKeyCount][17] = {
{0x11, 0x8b, 0x33, 0x87, 0xe9, 0xc5,
0xcd, 0xea, 0x6a, 0xc9, 0xe5, 0xed,
0xba, 0xa1, 0x15, 0xcd, 0x72},
{0x0a, 0x44, 0x81, 0xda, 0x0e, 0x4e,
0x03, 0xc4, 0x9e, 0x84, 0x77, 0x25,
0xd8, 0x3a, 0x93, 0xbf, 0x80}
};
#define TAG "MeshCore"
// requires at least a 256 byte data
FrameStruct decodeFrame (unsigned char *data, unsigned char dataLen) {
hexdump ("RxDump", data, dataLen);
FrameStruct frame;
memset (&frame, 0, sizeof (frame));
unsigned char index = 0;
frame.header = data[index++];
if ((frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
(frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
memcpy (frame.transportCodes, data + index, 4);
index += 4;
}
frame.pathLen = data[index++];
memcpy (frame.path, data + index, frame.pathLen);
index += frame.pathLen;
frame.payloadLen = dataLen - index;
memcpy (frame.payload, data + index, frame.payloadLen);
return frame;
}
int aes_encrypt_ecb (const uint8_t *key, const uint8_t *input, size_t ilen,
uint8_t *output) {
if (ilen % 16 != 0)
return -1;
cf_aes_context ctx;
cf_aes_init (&ctx, key, 16);
for (size_t i = 0; i < ilen; i += 16) {
cf_aes_encrypt (&ctx, input + i, output + i);
}
cf_aes_finish (&ctx);
return 0;
}
int aes_decrypt_ecb (const uint8_t *key, const uint8_t *input, size_t ilen,
uint8_t *output) {
if (ilen % 16 != 0)
return -1;
cf_aes_context ctx;
cf_aes_init (&ctx, key, 16);
for (size_t i = 0; i < ilen; i += 16) {
cf_aes_decrypt (&ctx, input + i, output + i);
}
cf_aes_finish (&ctx);
return 0;
}
// HMAC-SHA256
int hmac_sha256 (const uint8_t *key, size_t keylen,
const uint8_t *input, size_t ilen,
uint8_t *output) {
cf_hmac_ctx ctx;
cf_hmac_init (&ctx, &cf_sha256, key, keylen);
cf_hmac_update (&ctx, input, ilen);
cf_hmac_finish (&ctx, output);
return 0;
}
// Verify MAC + Decrypt
#define KEY_SIZE 16 // AES-128
int encrypt_then_mac (const uint8_t *aes_key,
const uint8_t *plaintext, size_t plen,
uint8_t *output, size_t *olen) {
if (plen == 0)
return -1;
// ciphertext will go right after HMAC
uint8_t *ciphertext = output + HMAC_SIZE;
// encrypt plaintext
aes_encrypt_ecb (aes_key, plaintext, plen, ciphertext);
// compute HMAC over ciphertext
uint8_t mac[32]; // full SHA-256
hmac_sha256 (aes_key, KEY_SIZE, ciphertext, plen, mac);
// copy only HMAC_SIZE bytes of MAC
memcpy (output, mac, HMAC_SIZE);
// return total length = HMAC + ciphertext
*olen = HMAC_SIZE + plen;
return 0;
}
int mac_then_decrypt (const uint8_t *aes_key, const uint8_t *input, size_t ilen,
uint8_t *plaintext) {
if (ilen <= HMAC_SIZE)
return -1;
const uint8_t *mac = input;
const uint8_t *ciphertext = input + HMAC_SIZE;
size_t clen = ilen - HMAC_SIZE;
uint8_t calc_mac[32]; // full SHA-256
hmac_sha256 (aes_key, KEY_SIZE, ciphertext, clen, calc_mac);
if (memcmp (mac, calc_mac, HMAC_SIZE) != 0)
return -2;
return aes_decrypt_ecb (aes_key, ciphertext, clen, plaintext);
}
void hexdump (const char *label, const uint8_t *data, size_t len) {
if (label)
printf ("%s (len=%zu):\n", label, len);
for (size_t i = 0; i < len; i += 16) {
printf ("%04zx ", i); // offset
for (size_t j = 0; j < 16; j++) {
if (i + j < len)
printf ("%02X ", data[i + j]);
else
printf (" "); // pad spacing
}
printf (" ");
for (size_t j = 0; j < 16 && i + j < len; j++) {
uint8_t c = data[i + j];
printf ("%c", isprint (c) ? c : '.');
}
printf ("\n");
}
}
// EncryptedPayloadStruct decodeEncryptedPayload(FrameStruct frame) {
// EncryptedPayloadStruct enc;
// memset(&enc, 0, sizeof(enc));
// if ((frame.header & PAYLOAD_TYPE_MASK) != PAYLOAD_TYPE_GRP_TXT) {
// return enc;
// }
// unsigned char index = 0;
// enc.destinationHash = frame.payload[index++];
// enc.sourceHash = frame.payload[index++];
// index = 0;
// memcpy(&msg.timestamp, tmp + index, 4);
// index += 4;
// msg.flags = tmp[index++];
// memcpy(msg.text, tmp + index, plaintextLen - index);
// return end;
// }
GroupTextMessage decodeGroupMessage (FrameStruct frame) {
GroupTextMessage msg;
memset (&msg, 0, sizeof (msg));
if ((frame.header & PAYLOAD_TYPE_MASK) != PAYLOAD_TYPE_GRP_TXT) {
ESP_LOGW (TAG, "Not a group text");
return msg;
}
unsigned char index = 0;
msg.channelHash = frame.payload[index++];
unsigned char tmp[184];
unsigned char decrypted = 0;
for (unsigned char i = 0; i < AESKeyCount; i++) {
if (msg.channelHash != aesKeys[i][0]) {
ESP_LOGW (TAG, "Hash %d does not equal %d", aesKeys[i][0], msg.channelHash);
continue;
}
ESP_LOGW (TAG, "Hash does equal %d", msg.channelHash);
if (mac_then_decrypt (aesKeys[i] + 1, frame.payload + index, frame.payloadLen - index, tmp) != 0) {
ESP_LOGW (TAG, "HMAC failed on grouphash key %d not matching %d", aesKeys[i][0], msg.channelHash);
continue;
}
hexdump ("RxDumpDec", tmp, frame.payloadLen - index);
decrypted = 1;
break;
}
if (!decrypted) {
return msg;
}
unsigned char plaintextLen = frame.payloadLen - index;
index = 0;
ESP_LOGI (TAG, "Starting memcpy");
vTaskDelay (pdMS_TO_TICKS (10));
memcpy (&msg.timestamp, tmp + index, 4);
index += 4;
msg.flags = tmp[index++];
memcpy (msg.text, tmp + index, plaintextLen - index);
return msg;
}
void printGroupMessage (GroupTextMessage msg) {
printf ("Message with channel hash %d, flags %d: %s\n", msg.channelHash,
msg.flags, msg.text);
}
AdvertisementPayload decodeAdvertisement (FrameStruct frame) {
AdvertisementPayload advert;
memset (&advert, 0, sizeof (advert));
if ((frame.header & PAYLOAD_TYPE_MASK) != PAYLOAD_TYPE_ADVERT) {
return advert;
}
unsigned char index = 0;
memcpy (advert.pubKey, frame.payload + index, 32);
index += 32;
memcpy (&advert.timestamp, frame.payload + index, 4);
index += 4;
memcpy (advert.signature, frame.payload + index, 64);
index += 64;
advert.dataFlags = frame.payload[index++];
if (advert.dataFlags & ADVERTISEMENT_FLAG_HAS_LOCATION) {
memcpy (&advert.latitude, frame.payload + index, 4);
index += 4;
memcpy (&advert.longitude, frame.payload + index, 4);
index += 4;
}
if (advert.dataFlags & ADVERTISEMENT_FLAG_RFU1) {
memcpy (&advert.rfu1, frame.payload + index, 2);
index += 2;
}
if (advert.dataFlags & ADVERTISEMENT_FLAG_RFU2) {
memcpy (&advert.rfu2, frame.payload + index, 2);
index += 2;
}
memcpy (advert.nodeName, frame.payload + index, frame.payloadLen - index);
advert.nodeName[frame.payloadLen - index] = 0;
return advert;
}
void printAdvertisement (AdvertisementPayload advert) {
unsigned char keyBuf[50];
unsigned char sigBuf[90];
memset (keyBuf, 0, sizeof (keyBuf));
memset (sigBuf, 0, sizeof (sigBuf));
base64_encode (advert.pubKey, 32, keyBuf);
base64_encode (advert.signature, 64, sigBuf);
printf ("%s on %ld with type %s on %s location %ld %ld, public key %s and "
"signature %s\n",
advert.dataFlags & ADVERTISEMENT_FLAG_HAS_NAME ? advert.nodeName
: "nameless node",
advert.timestamp,
(advert.dataFlags & 0x07) == 0x04
? "sensor"
: ((advert.dataFlags & 0x07) == 0x03
? "room server"
: ((advert.dataFlags & 0x07) == 0x02 ? "repeater"
: "chat node")),
advert.dataFlags & 0x80 ? "known" : "unknown", advert.latitude,
advert.longitude, keyBuf, sigBuf);
}
void printFrameHeader (FrameStruct frame) {
switch (frame.header & ROUTE_TYPE_MASK) {
case ROUTE_TYPE_TRANSPORT_FLOOD:
printf ("transport flood");
break;
case ROUTE_TYPE_FLOOD:
printf ("flood");
break;
case ROUTE_TYPE_DIRECT:
printf ("direct");
break;
case ROUTE_TYPE_TRANSPORT_DIRECT:
printf ("transport direct");
break;
}
printf (", payload type is ");
switch (frame.header & PAYLOAD_TYPE_MASK) {
case PAYLOAD_TYPE_REQ:
printf ("request");
break;
case PAYLOAD_TYPE_RESPONSE:
printf ("response");
break;
case PAYLOAD_TYPE_TXT_MSG:
printf ("text message");
break;
case PAYLOAD_TYPE_ACK:
printf ("acknowledgement");
break;
case PAYLOAD_TYPE_ADVERT:
printf ("advert");
break;
case PAYLOAD_TYPE_GRP_TXT:
printf ("group text");
break;
case PAYLOAD_TYPE_GRP_DATA:
printf ("group data");
break;
case PAYLOAD_TYPE_ANON_REQ:
printf ("anon request");
break;
case PAYLOAD_TYPE_PATH:
printf ("path");
break;
case PAYLOAD_TYPE_TRACE:
printf ("trace");
break;
case PAYLOAD_TYPE_MULTIPART:
printf ("multipart");
break;
case PAYLOAD_TYPE_RAW_CUSTOM:
printf ("raw");
break;
}
char version[2];
version[0] = (frame.header >> 6) + '0';
version[1] = 0;
printf (", payload version is %s ", version);
if ((frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
(frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
printf ("Transport codes: %d %d\n", *((uint16_t *)frame.transportCodes),
*((uint16_t *)&(frame.transportCodes[2])));
}
printf ("Path is %d nodes long", frame.pathLen);
for (uint8_t pathIndex = 0; pathIndex < frame.pathLen; pathIndex++) {
printf ("node %d - %02X, ", pathIndex, frame.path[pathIndex]);
}
putchar ('\n');
}
void sendFrame (FrameStruct frame) {
uint8_t txBuf[256];
size_t offset = 0;
txBuf[offset++] = frame.header;
if ((frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
(frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
memcpy (txBuf + offset, frame.transportCodes, 4);
offset += 4;
}
if (frame.pathLen > 64) {
frame.pathLen = 64;
}
txBuf[offset++] = frame.pathLen;
memcpy (txBuf + offset, frame.path, frame.pathLen);
offset += frame.pathLen;
uint16_t maxPayloadLen = 256 - offset;
uint16_t payloadLen = frame.payloadLen > maxPayloadLen ? maxPayloadLen : frame.payloadLen;
memcpy (txBuf + offset, frame.payload, payloadLen);
offset += payloadLen;
hexdump ("TxDump", txBuf, offset);
LoRaSend (txBuf, offset, SX126x_TXMODE_SYNC);
}
void sendGroupMessage (GroupTextMessage msg) {
msg.channelHash = aesKeys[msg.keyIndex][0];
msg.flags = 0;
msg.timestamp = RTC_GetCounter();
FrameStruct frame;
frame.header = ROUTE_TYPE_FLOOD | PAYLOAD_TYPE_GRP_TXT | PAYLOAD_VERSION_0;
frame.pathLen = 0;
size_t offset = 0;
memset (frame.payload, 0, sizeof (frame.payload));
frame.payload[offset++] = msg.channelHash;
uint8_t cipherBuf[176];
size_t offset2 = 0;
memcpy (cipherBuf, (const void *)&(msg.timestamp), 4);
offset2 += 4;
cipherBuf[offset2++] = msg.flags;
size_t textSize = offset2 + strlen ((const char *)msg.text);
if (textSize > 175) {
textSize = 175;
}
memcpy (cipherBuf + offset2, msg.text, textSize);
offset2 += textSize;
offset2 = (((offset2 / 16) + 1) * 16);
size_t olen = 0;
hexdump ("TxDumpDec", cipherBuf, offset2);
encrypt_then_mac (&(aesKeys[msg.keyIndex][1]), cipherBuf, offset2, &(frame.payload[offset]), &olen);
frame.payloadLen = olen + 1;
sendFrame (frame);
return;
}
void makeSendGroupMessage (char *txt, uint8_t keyIndex) {
GroupTextMessage msg;
strcpy ((char *)msg.text, txt);
msg.keyIndex = keyIndex;
sendGroupMessage (msg);
return;
}
void sendAdvert() {
AdvertisementPayload ad;
memcpy (ad.pubKey, persistent.pubkey, sizeof (ad.pubKey));
ad.dataFlags = ADVERTISEMENT_FLAG_IS_CHAT_NODE | ADVERTISEMENT_FLAG_HAS_NAME;
strcpy (ad.nodeName, persistent.nodeName);
ad.timestamp = RTC_GetCounter();
// 1. Build app_data exactly like AdvertDataBuilder::encodeTo
uint8_t app_data[40];
size_t app_len = 0;
app_data[app_len++] = ad.dataFlags;
if (ad.dataFlags & ADVERTISEMENT_FLAG_HAS_LOCATION) {
memcpy (app_data + app_len, &ad.latitude, sizeof (ad.latitude));
app_len += sizeof (ad.latitude);
memcpy (app_data + app_len, &ad.longitude, sizeof (ad.longitude));
app_len += sizeof (ad.longitude);
}
if (ad.dataFlags & ADVERTISEMENT_FLAG_RFU1) {
memcpy (app_data + app_len, &ad.rfu1, sizeof (ad.rfu1));
app_len += sizeof (ad.rfu1);
}
if (ad.dataFlags & ADVERTISEMENT_FLAG_RFU2) {
memcpy (app_data + app_len, &ad.rfu2, sizeof (ad.rfu2));
app_len += sizeof (ad.rfu2);
}
if (ad.dataFlags & ADVERTISEMENT_FLAG_HAS_NAME) {
size_t nodenameLen = strlen (ad.nodeName);
memcpy (app_data + app_len, ad.nodeName, nodenameLen);
app_len += nodenameLen;
}
// 2. Reserve frame and build payload header
FrameStruct frame;
frame.header = ROUTE_TYPE_FLOOD | PAYLOAD_TYPE_ADVERT | PAYLOAD_VERSION_0;
size_t offset = 0;
memcpy (frame.payload + offset, ad.pubKey, sizeof (ad.pubKey));
offset += sizeof (ad.pubKey);
memcpy (frame.payload + offset, &ad.timestamp, sizeof (ad.timestamp));
offset += sizeof (ad.timestamp);
// reserve signature space
uint8_t *signature_pos = frame.payload + offset;
offset += 64;
// append app_data after signature
memcpy (frame.payload + offset, app_data, app_len);
offset += app_len;
// 3. Sign pubKey + timestamp + app_data
uint8_t message[76];
size_t msg_len = 0;
memcpy (message + msg_len, ad.pubKey, sizeof (ad.pubKey));
msg_len += sizeof (ad.pubKey);
memcpy (message + msg_len, &ad.timestamp, sizeof (ad.timestamp));
msg_len += sizeof (ad.timestamp);
memcpy (message + msg_len, app_data, app_len);
msg_len += app_len;
crypto_ed25519_meshcore_sign (signature_pos, persistent.privkey, persistent.pubkey, message, msg_len);
hexdump ("Complete advert", frame.payload, offset);
hexdump ("Public key", ad.pubKey, 32);
hexdump ("Signature", signature_pos, 64);
hexdump ("Timestamp", &ad.timestamp, 4);
hexdump ("NodeName", ad.nodeName, 20);
hexdump ("Appdata", app_data, app_len);
// 5. Set payload length and send
frame.payloadLen = offset;
frame.pathLen = 0;
sendFrame (frame);
}

61
User/meshcore/meshcore.h Normal file
View File

@@ -0,0 +1,61 @@
#ifndef MESHCORE_HEADER
#define MESHCORE_HEADER
#include "packetstructs.h"
#include "string.h"
#include "sx1262.h"
#include "lib/cifra/aes.h"
#include "lib/cifra/sha2.h"
#include "lib/cifra/hmac.h"
#include "lib/base64.h"
#include "util/log.h"
#include <ctype.h>
#include "stdio.h"
// requires at least a 256 byte data
FrameStruct decodeFrame (unsigned char *data, unsigned char dataLen);
#define KEY_SIZE 16 // 128-bit AES
#define HMAC_SIZE 2 // SHA256 output size
int aes_encrypt_ecb (const uint8_t *key, const uint8_t *input, size_t ilen,
uint8_t *output);
// AES-ECB decrypt (same as Arduino's aes.decryptBlock)
int aes_decrypt_ecb (const uint8_t *key, const uint8_t *input, size_t ilen,
uint8_t *output);
// HMAC-SHA256
int hmac_sha256 (const uint8_t *key, size_t keylen, const uint8_t *input,
size_t ilen, uint8_t *output);
// Verify MAC + Decrypt
int mac_then_decrypt (const uint8_t *aes_key, const uint8_t *input, size_t ilen,
uint8_t *plaintext);
void hexdump (const char *label, const uint8_t *data, size_t len);
#define AESKeyCount 8
// EncryptedPayloadStruct decodeEncryptedPayload(FrameStruct frame);
GroupTextMessage decodeGroupMessage (FrameStruct frame);
void printGroupMessage (GroupTextMessage msg);
AdvertisementPayload decodeAdvertisement (FrameStruct frame);
void printAdvertisement (AdvertisementPayload advert);
void printFrameHeader (FrameStruct frame);
#define AESKeyCount 8
extern const uint8_t aesKeys[AESKeyCount][17];
void sendFrame (FrameStruct frame);
void sendGroupMessage (GroupTextMessage msg);
void makeSendGroupMessage (char *txt, uint8_t keyIndex);
void sendAdvert();
#endif

View File

@@ -0,0 +1,120 @@
#ifndef PACKETSTRUCTS_FILE
#define PACKETSTRUCTS_FILE
#include <stdint.h>
#define ROUTE_TYPE_MASK 0x03
#define PAYLOAD_TYPE_MASK 0x3C
#define PAYLOAD_VERSION_MASK 0xC0
typedef enum RouteType {
ROUTE_TYPE_TRANSPORT_FLOOD = 0x00,
ROUTE_TYPE_FLOOD = 0x01,
ROUTE_TYPE_DIRECT = 0x02,
ROUTE_TYPE_TRANSPORT_DIRECT = 0x03,
} RouteType;
typedef enum PayloadType {
PAYLOAD_TYPE_REQ = 0x00 << 2,
PAYLOAD_TYPE_RESPONSE = 0x01 << 2,
PAYLOAD_TYPE_TXT_MSG = 0x02 << 2,
PAYLOAD_TYPE_ACK = 0x03 << 2,
PAYLOAD_TYPE_ADVERT = 0x04 << 2,
PAYLOAD_TYPE_GRP_TXT = 0x05 << 2,
PAYLOAD_TYPE_GRP_DATA = 0x06 << 2,
PAYLOAD_TYPE_ANON_REQ = 0x07 << 2,
PAYLOAD_TYPE_PATH = 0x08 << 2,
PAYLOAD_TYPE_TRACE = 0x09 << 2,
PAYLOAD_TYPE_MULTIPART = 0x0A << 2,
PAYLOAD_TYPE_RAW_CUSTOM = 0x0F << 2,
} PayloadType;
typedef enum PayloadVersion {
PAYLOAD_VERSION_0 = 0 << 6,
PAYLOAD_VERSION_1 = 1 << 6,
PAYLOAD_VERSION_2 = 2 << 6,
PAYLOAD_VERSION_3 = 3 << 6,
} PayloadVersion;
typedef struct FrameStruct {
unsigned char header;
unsigned char transportCodes[4];
unsigned char pathLen;
unsigned char path[64];
unsigned char payloadLen;
unsigned char payload[184];
} FrameStruct;
typedef enum RequestType {
REQUEST_GET_STATS = 0x01,
REQUEST_KEEPALIVE = 0x02,
REQUEST_GET_TELEMETRY_DATA = 0x03,
REQUEST_GET_MIN_MAX_AVG = 0x04,
REQUEST_GET_ACCESS_LIST = 0x05,
} RequestType;
typedef struct EncryptedPayloadStruct {
FrameStruct rawFrame;
unsigned char destinationHash;
unsigned char sourceHash;
unsigned char payload[180];
} EncryptedPayloadStruct;
typedef enum AdvertisementPayloadFlags {
ADVERTISEMENT_FLAG_IS_CHAT_NODE = 0x01,
ADVERTISEMENT_FLAG_IS_REAPEATER = 0x02,
ADVERTISEMENT_FLAG_IS_ROOM_SERVER = 0x03,
ADVERTISEMENT_FLAG_IS_SENSOR = 0x04,
ADVERTISEMENT_FLAG_HAS_LOCATION = 0x10,
ADVERTISEMENT_FLAG_RFU1 = 0x20,
ADVERTISEMENT_FLAG_RFU2 = 0x40,
ADVERTISEMENT_FLAG_HAS_NAME = 0x80,
} AdvertisementPayloadFlags;
typedef struct AdvertisementPayload {
unsigned char pubKey[32];
int32_t timestamp;
unsigned char signature[64];
unsigned char dataFlags;
int32_t latitude;
int32_t longitude;
int16_t rfu1;
int16_t rfu2;
char nodeName[128];
} AdvertisementPayload;
typedef struct ReturnedPathPayload {
unsigned char destinationHash;
unsigned char sourceHash;
unsigned char pathLen;
} ReturnedPathPayload;
typedef struct RequestPayload {
unsigned char destinationHash;
unsigned char sourceHash;
} RequestPayload;
typedef struct ResponsePayload {
unsigned char destinationHash;
unsigned char sourceHash;
} ResponsePayload;
typedef struct PlainTextMessagePayload {
unsigned char destinationHash;
unsigned char sourceHash;
} PlainTextMessagePayload;
typedef struct GroupTextMessage {
unsigned char channelHash;
unsigned char keyIndex;
int32_t timestamp;
unsigned char flags;
unsigned char text[190];
} GroupTextMessage;
#endif

863
User/sx1262.c Normal file
View File

@@ -0,0 +1,863 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include "FreeRTOS.h"
#include "task.h"
#include "sx1262.h"
#include "util/log.h"
#define TAG "SX1262"
// Global Stuff
static uint8_t PacketParams[6];
static char txActive;
static int txLost = 0;
static char debugPrint;
// Arduino compatible macros
#define delayMicroseconds(us) esp_rom_delay_us (us)
#define delay(ms) esp_rom_delay_us (ms * 1000)
void LoRaError (int error) {
if (debugPrint) {
ESP_LOGE (TAG, "LoRaErrorDefault=%d", error);
}
while (1) {
vTaskDelay (1);
}
}
void LoRaInit (void) {
txActive = 0;
debugPrint = 0;
GPIO_InitTypeDef GPIO_InitStructure = {0};
SPI_InitTypeDef SPI_InitStructure = {0};
// RCC_AHBPeriphClockCmd (RCC_AHBPeriph_SDIO, ENABLE);
RCC_APB1PeriphClockCmd (RCC_APB1Periph_USART2 | RCC_APB1Periph_I2C2, ENABLE);
RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOE | RCC_APB2Periph_SPI1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init (GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init (GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init (GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init (GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init (GPIOE, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init (GPIOE, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init (GPIOE, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init (GPIOE, &GPIO_InitStructure);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init (SPI1, &SPI_InitStructure);
GPIO_WriteBit (GPIOE, GPIO_Pin_3, 1);
SPI_Cmd (SPI1, ENABLE);
}
void spi_write_byte (uint8_t *DataOut, size_t DataLength) {
spi_read_byte (NULL, DataOut, DataLength);
}
// Full-duplex transfer: TX and RX buffers
void spi_read_byte (uint8_t *rx, const uint8_t *tx, size_t len) {
GPIO_WriteBit (GPIOA, GPIO_Pin_4, 0);
for (size_t i = 0; i < len; i++) {
uint8_t out = tx ? tx[i] : 0xFF;
// Wait TX ready
while (SPI_I2S_GetFlagStatus (SPI1, SPI_I2S_FLAG_TXE) == RESET);
if (debugPrint) {
printf ("Sent %02X over spi.\n", out);
}
SPI_I2S_SendData (SPI1, out);
// Wait RX ready
while (SPI_I2S_GetFlagStatus (SPI1, SPI_I2S_FLAG_RXNE) == RESET);
uint8_t in = (uint8_t)SPI_I2S_ReceiveData (SPI1);
if (debugPrint) {
printf ("Got %02X over spi.\n", in);
}
if (rx)
rx[i] = in;
}
GPIO_WriteBit (GPIOA, GPIO_Pin_4, 1);
}
int16_t LoRaBegin (uint32_t frequencyInHz, int8_t txPowerInDbm, float tcxoVoltage, char useRegulatorLDO) {
if (txPowerInDbm > 22) {
txPowerInDbm = 22;
}
if (txPowerInDbm < -3) {
txPowerInDbm = -3;
}
ResetLora();
uint8_t wk[2];
ReadRegister (SX126X_REG_LORA_SYNC_WORD_MSB, wk, 2); // 0x0740
uint16_t syncWord = (wk[0] << 8) + wk[1];
ESP_LOGI (TAG, "syncWord=0x%x", syncWord);
if (syncWord != SX126X_SYNC_WORD_PUBLIC && syncWord != SX126X_SYNC_WORD_PRIVATE) {
ESP_LOGE (TAG, "SX126x error, maybe no SPI connection");
return ERR_INVALID_MODE;
}
ESP_LOGI (TAG, "SX126x installed");
SetStandby (SX126X_STANDBY_RC);
SetDio2AsRfSwitchCtrl (1);
ESP_LOGI (TAG, "tcxoVoltage=%f", tcxoVoltage);
// set TCXO control, if requested
if (tcxoVoltage > 0.0) {
SetDio3AsTcxoCtrl (tcxoVoltage, RADIO_TCXO_SETUP_TIME); // Configure the radio to use a TCXO controlled by DIO3
}
Calibrate (SX126X_CALIBRATE_IMAGE_ON | SX126X_CALIBRATE_ADC_BULK_P_ON | SX126X_CALIBRATE_ADC_BULK_N_ON | SX126X_CALIBRATE_ADC_PULSE_ON | SX126X_CALIBRATE_PLL_ON | SX126X_CALIBRATE_RC13M_ON | SX126X_CALIBRATE_RC64K_ON);
ESP_LOGI (TAG, "useRegulatorLDO=%d", useRegulatorLDO);
if (useRegulatorLDO) {
SetRegulatorMode (SX126X_REGULATOR_LDO); // set regulator mode: LDO
} else {
SetRegulatorMode (SX126X_REGULATOR_DC_DC); // set regulator mode: DC-DC
}
SetBufferBaseAddress (0, 0);
SetPaConfig (0x04, 0x07, 0x00, 0x01); // PA Optimal Settings +22 dBm
SetOvercurrentProtection (60.0); // current max 60mA for the whole device
SetPowerConfig (txPowerInDbm, SX126X_PA_RAMP_200U); // 0 fuer Empfaenger
SetRfFrequency (frequencyInHz);
return ERR_NONE;
}
void FixInvertedIQ (uint8_t iqConfig) {
// fixes IQ configuration for inverted IQ
// see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.4 for details
// When exchanging LoRa packets with inverted IQ polarity, some packet losses may be observed for longer packets.
// Workaround: Bit 2 at address 0x0736 must be set to:
// “0” when using inverted IQ polarity (see the SetPacketParam(...) command)
// “1” when using standard IQ polarity
// read current IQ configuration
uint8_t iqConfigCurrent = 0;
ReadRegister (SX126X_REG_IQ_POLARITY_SETUP, &iqConfigCurrent, 1); // 0x0736
// set correct IQ configuration
// if(iqConfig == SX126X_LORA_IQ_STANDARD) {
if (iqConfig == SX126X_LORA_IQ_INVERTED) {
iqConfigCurrent &= 0xFB; // using inverted IQ polarity
} else {
iqConfigCurrent |= 0x04; // using standard IQ polarity
}
// update with the new value
WriteRegister (SX126X_REG_IQ_POLARITY_SETUP, &iqConfigCurrent, 1); // 0x0736
}
void LoRaConfig (uint8_t spreadingFactor, uint8_t bandwidth, uint8_t codingRate, uint16_t preambleLength, uint8_t payloadLen, char crcOn, char invertIrq) {
SetStopRxTimerOnPreambleDetect (0);
SetLoRaSymbNumTimeout (0);
SetPacketType (SX126X_PACKET_TYPE_LORA); // SX126x.ModulationParams.PacketType : MODEM_LORA
uint8_t ldro = 0; // LowDataRateOptimize OFF
SetModulationParams (spreadingFactor, bandwidth, codingRate, ldro);
PacketParams[0] = (preambleLength >> 8) & 0xFF;
PacketParams[1] = preambleLength;
if (payloadLen) {
PacketParams[2] = 0x01; // Fixed length packet (implicit header)
PacketParams[3] = payloadLen;
} else {
PacketParams[2] = 0x00; // Variable length packet (explicit header)
PacketParams[3] = 0xFF;
}
if (crcOn)
PacketParams[4] = SX126X_LORA_CRC_ON;
else
PacketParams[4] = SX126X_LORA_CRC_OFF;
if (invertIrq)
PacketParams[5] = 0x01; // Inverted LoRa I and Q signals setup
else
PacketParams[5] = 0x00; // Standard LoRa I and Q signals setup
// fixes IQ configuration for inverted IQ
FixInvertedIQ (PacketParams[5]);
WriteCommand (SX126X_CMD_SET_PACKET_PARAMS, PacketParams, 6); // 0x8C
// Do not use DIO interruptst
SetDioIrqParams (SX126X_IRQ_ALL, // all interrupts enabled
SX126X_IRQ_NONE, // interrupts on DIO1
SX126X_IRQ_NONE, // interrupts on DIO2
SX126X_IRQ_NONE // interrupts on DIO3
);
ESP_LOGI (TAG, "Almost done setting LoRa");
// Receive state no receive timeoout
SetRx (0xFFFFFF);
}
void LoRaDebugPrint (char enable) {
debugPrint = enable;
}
uint8_t LoRaReceive (uint8_t *pData, int16_t len) {
uint8_t rxLen = 0;
uint16_t irqRegs = GetIrqStatus();
// uint8_t status = GetStatus();
if (irqRegs & SX126X_IRQ_RX_DONE) {
// ClearIrqStatus(SX126X_IRQ_RX_DONE);
ClearIrqStatus (SX126X_IRQ_ALL);
rxLen = ReadBuffer (pData, len);
}
return rxLen;
}
char LoRaSend (uint8_t *pData, int16_t len, uint8_t mode) {
uint16_t irqStatus;
char rv = 0;
if (txActive == 0) {
txActive = 1;
if (PacketParams[2] == 0x00) { // Variable length packet (explicit header)
PacketParams[3] = len;
}
WriteCommand (SX126X_CMD_SET_PACKET_PARAMS, PacketParams, 6); // 0x8C
// ClearIrqStatus(SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT);
ClearIrqStatus (SX126X_IRQ_ALL);
WriteBuffer (pData, len);
SetTx (5000);
if (mode & SX126x_TXMODE_SYNC) {
irqStatus = GetIrqStatus();
while ((!(irqStatus & SX126X_IRQ_TX_DONE)) && (!(irqStatus & SX126X_IRQ_TIMEOUT))) {
vTaskDelay (1);
irqStatus = GetIrqStatus();
}
if (debugPrint) {
ESP_LOGI (TAG, "irqStatus=0x%x", irqStatus);
if (irqStatus & SX126X_IRQ_TX_DONE) {
ESP_LOGI (TAG, "SX126X_IRQ_TX_DONE");
}
if (irqStatus & SX126X_IRQ_TIMEOUT) {
ESP_LOGI (TAG, "SX126X_IRQ_TIMEOUT");
}
}
txActive = 0;
SetRx (0xFFFFFF);
if (irqStatus & SX126X_IRQ_TX_DONE) {
rv = 1;
}
} else {
rv = 1;
}
}
if (debugPrint) {
ESP_LOGI (TAG, "Send rv=0x%x", rv);
}
if (rv == 0)
txLost++;
return rv;
}
char ReceiveMode (void) {
uint16_t irq;
char rv = 0;
if (txActive == 0) {
rv = 1;
} else {
irq = GetIrqStatus();
if (irq & (SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT)) {
SetRx (0xFFFFFF);
txActive = 0;
rv = 1;
}
}
return rv;
}
void GetPacketStatus (int8_t *rssiPacket, int8_t *snrPacket) {
uint8_t buf[4];
ReadCommand (SX126X_CMD_GET_PACKET_STATUS, buf, 4); // 0x14
*rssiPacket = (buf[3] >> 1) * -1;
(buf[2] < 128) ? (*snrPacket = buf[2] >> 2) : (*snrPacket = ((buf[2] - 256) >> 2));
}
void SetTxPower (int8_t txPowerInDbm) {
SetPowerConfig (txPowerInDbm, SX126X_PA_RAMP_200U);
}
void ResetLora (void) {
vTaskDelay (pdMS_TO_TICKS (10));
GPIO_WriteBit (GPIOE, GPIO_Pin_3, 0);
vTaskDelay (pdMS_TO_TICKS (20));
GPIO_WriteBit (GPIOE, GPIO_Pin_3, 1);
ESP_LOGW (TAG, "Waiting for idle");
vTaskDelay (pdMS_TO_TICKS (10));
// ensure BUSY is low (state meachine ready)
WaitForIdle (BUSY_WAIT, "Reset", 1);
}
void Wakeup (void) {
GetStatus();
}
void SetStandby (uint8_t mode) {
uint8_t data = mode;
WriteCommand (SX126X_CMD_SET_STANDBY, &data, 1); // 0x80
}
uint8_t GetStatus (void) {
uint8_t rv;
ReadCommand (SX126X_CMD_GET_STATUS, &rv, 1); // 0xC0
return rv;
}
void SetDio3AsTcxoCtrl (float voltage, uint32_t delay) {
uint8_t buf[4];
// buf[0] = tcxoVoltage & 0x07;
if (fabs (voltage - 1.6) <= 0.001) {
buf[0] = SX126X_DIO3_OUTPUT_1_6;
} else if (fabs (voltage - 1.7) <= 0.001) {
buf[0] = SX126X_DIO3_OUTPUT_1_7;
} else if (fabs (voltage - 1.8) <= 0.001) {
buf[0] = SX126X_DIO3_OUTPUT_1_8;
} else if (fabs (voltage - 2.2) <= 0.001) {
buf[0] = SX126X_DIO3_OUTPUT_2_2;
} else if (fabs (voltage - 2.4) <= 0.001) {
buf[0] = SX126X_DIO3_OUTPUT_2_4;
} else if (fabs (voltage - 2.7) <= 0.001) {
buf[0] = SX126X_DIO3_OUTPUT_2_7;
} else if (fabs (voltage - 3.0) <= 0.001) {
buf[0] = SX126X_DIO3_OUTPUT_3_0;
} else {
buf[0] = SX126X_DIO3_OUTPUT_3_3;
}
uint32_t delayValue = (float)delay / 15.625;
buf[1] = (uint8_t)((delayValue >> 16) & 0xFF);
buf[2] = (uint8_t)((delayValue >> 8) & 0xFF);
buf[3] = (uint8_t)(delayValue & 0xFF);
WriteCommand (SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, buf, 4); // 0x97
}
void Calibrate (uint8_t calibParam) {
uint8_t data = calibParam;
WriteCommand (SX126X_CMD_CALIBRATE, &data, 1); // 0x89
}
void SetDio2AsRfSwitchCtrl (uint8_t enable) {
uint8_t data = enable;
WriteCommand (SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1); // 0x9D
}
void SetRfFrequency (uint32_t frequency) {
uint8_t buf[4];
uint32_t freq = 0;
CalibrateImage (frequency);
freq = (uint32_t)((double)frequency / (double)FREQ_STEP);
buf[0] = (uint8_t)((freq >> 24) & 0xFF);
buf[1] = (uint8_t)((freq >> 16) & 0xFF);
buf[2] = (uint8_t)((freq >> 8) & 0xFF);
buf[3] = (uint8_t)(freq & 0xFF);
WriteCommand (SX126X_CMD_SET_RF_FREQUENCY, buf, 4); // 0x86
}
void CalibrateImage (uint32_t frequency) {
uint8_t calFreq[2];
if (frequency > 900000000) {
calFreq[0] = 0xE1;
calFreq[1] = 0xE9;
} else if (frequency > 850000000) {
calFreq[0] = 0xD7;
calFreq[1] = 0xDB;
} else if (frequency > 770000000) {
calFreq[0] = 0xC1;
calFreq[1] = 0xC5;
} else if (frequency > 460000000) {
calFreq[0] = 0x75;
calFreq[1] = 0x81;
} else if (frequency > 425000000) {
calFreq[0] = 0x6B;
calFreq[1] = 0x6F;
}
WriteCommand (SX126X_CMD_CALIBRATE_IMAGE, calFreq, 2); // 0x98
}
void SetRegulatorMode (uint8_t mode) {
uint8_t data = mode;
WriteCommand (SX126X_CMD_SET_REGULATOR_MODE, &data, 1); // 0x96
}
void SetBufferBaseAddress (uint8_t txBaseAddress, uint8_t rxBaseAddress) {
uint8_t buf[2];
buf[0] = txBaseAddress;
buf[1] = rxBaseAddress;
WriteCommand (SX126X_CMD_SET_BUFFER_BASE_ADDRESS, buf, 2); // 0x8F
}
void SetPowerConfig (int8_t power, uint8_t rampTime) {
uint8_t buf[2];
if (power > 22) {
power = 22;
} else if (power < -3) {
power = -3;
}
buf[0] = power;
buf[1] = (uint8_t)rampTime;
WriteCommand (SX126X_CMD_SET_TX_PARAMS, buf, 2); // 0x8E
}
void SetPaConfig (uint8_t paDutyCycle, uint8_t hpMax, uint8_t deviceSel, uint8_t paLut) {
uint8_t buf[4];
buf[0] = paDutyCycle;
buf[1] = hpMax;
buf[2] = deviceSel;
buf[3] = paLut;
WriteCommand (SX126X_CMD_SET_PA_CONFIG, buf, 4); // 0x95
}
void SetOvercurrentProtection (float currentLimit) {
if ((currentLimit >= 0.0) && (currentLimit <= 140.0)) {
uint8_t buf[1];
buf[0] = (uint8_t)(currentLimit / 2.5);
WriteRegister (SX126X_REG_OCP_CONFIGURATION, buf, 1); // 0x08E7
}
}
void SetSyncWord (int16_t sync) {
uint8_t buf[2];
buf[0] = (uint8_t)((sync >> 8) & 0x00FF);
buf[1] = (uint8_t)(sync & 0x00FF);
WriteRegister (SX126X_REG_LORA_SYNC_WORD_MSB, buf, 2); // 0x0740
}
void SetDioIrqParams (uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) {
uint8_t buf[8];
buf[0] = (uint8_t)((irqMask >> 8) & 0x00FF);
buf[1] = (uint8_t)(irqMask & 0x00FF);
buf[2] = (uint8_t)((dio1Mask >> 8) & 0x00FF);
buf[3] = (uint8_t)(dio1Mask & 0x00FF);
buf[4] = (uint8_t)((dio2Mask >> 8) & 0x00FF);
buf[5] = (uint8_t)(dio2Mask & 0x00FF);
buf[6] = (uint8_t)((dio3Mask >> 8) & 0x00FF);
buf[7] = (uint8_t)(dio3Mask & 0x00FF);
WriteCommand (SX126X_CMD_SET_DIO_IRQ_PARAMS, buf, 8); // 0x08
}
void SetStopRxTimerOnPreambleDetect (char enable) {
ESP_LOGI (TAG, "SetStopRxTimerOnPreambleDetect enable=%d", enable);
// uint8_t data = (uint8_t)enable;
uint8_t data = 0;
if (enable)
data = 1;
WriteCommand (SX126X_CMD_STOP_TIMER_ON_PREAMBLE, &data, 1); // 0x9F
}
void SetLoRaSymbNumTimeout (uint8_t SymbNum) {
uint8_t data = SymbNum;
WriteCommand (SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT, &data, 1); // 0xA0
}
void SetPacketType (uint8_t packetType) {
uint8_t data = packetType;
WriteCommand (SX126X_CMD_SET_PACKET_TYPE, &data, 1); // 0x01
}
void SetModulationParams (uint8_t spreadingFactor, uint8_t bandwidth, uint8_t codingRate, uint8_t lowDataRateOptimize) {
uint8_t data[4];
// currently only LoRa supported
data[0] = spreadingFactor;
data[1] = bandwidth;
data[2] = codingRate;
data[3] = lowDataRateOptimize;
WriteCommand (SX126X_CMD_SET_MODULATION_PARAMS, data, 4); // 0x8B
}
void SetCadParams (uint8_t cadSymbolNum, uint8_t cadDetPeak, uint8_t cadDetMin, uint8_t cadExitMode, uint32_t cadTimeout) {
uint8_t data[7];
data[0] = cadSymbolNum;
data[1] = cadDetPeak;
data[2] = cadDetMin;
data[3] = cadExitMode;
data[4] = (uint8_t)((cadTimeout >> 16) & 0xFF);
data[5] = (uint8_t)((cadTimeout >> 8) & 0xFF);
data[6] = (uint8_t)(cadTimeout & 0xFF);
WriteCommand (SX126X_CMD_SET_CAD_PARAMS, data, 7); // 0x88
}
void SetCad() {
uint8_t data = 0;
WriteCommand (SX126X_CMD_SET_CAD, &data, 0); // 0xC5
}
uint16_t GetIrqStatus (void) {
uint8_t data[3];
ReadCommand (SX126X_CMD_GET_IRQ_STATUS, data, 3); // 0x12
return (data[1] << 8) | data[2];
}
void ClearIrqStatus (uint16_t irq) {
uint8_t buf[2];
buf[0] = (uint8_t)(((uint16_t)irq >> 8) & 0x00FF);
buf[1] = (uint8_t)((uint16_t)irq & 0x00FF);
WriteCommand (SX126X_CMD_CLEAR_IRQ_STATUS, buf, 2); // 0x02
}
void SetRx (uint32_t timeout) {
if (debugPrint) {
ESP_LOGI (TAG, "----- SetRx timeout=%d", timeout);
}
SetStandby (SX126X_STANDBY_RC);
uint8_t buf[3];
buf[0] = (uint8_t)((timeout >> 16) & 0xFF);
buf[1] = (uint8_t)((timeout >> 8) & 0xFF);
buf[2] = (uint8_t)(timeout & 0xFF);
WriteCommand (SX126X_CMD_SET_RX, buf, 3); // 0x82
for (int retry = 0; retry < 10; retry++) {
if ((GetStatus() & 0x70) == 0x50)
break;
vTaskDelay (pdMS_TO_TICKS (1));
}
if ((GetStatus() & 0x70) != 0x50) {
ESP_LOGE (TAG, "SetRx Illegal Status");
LoRaError (ERR_INVALID_SETRX_STATE);
}
}
void SetTx (uint32_t timeoutInMs) {
if (debugPrint) {
ESP_LOGI (TAG, "----- SetTx timeoutInMs=%d", timeoutInMs);
}
SetStandby (SX126X_STANDBY_RC);
uint8_t buf[3];
uint32_t tout = timeoutInMs;
if (timeoutInMs != 0) {
uint32_t timeoutInUs = timeoutInMs * 1000;
tout = (uint32_t)(timeoutInUs / 0.015625);
}
if (debugPrint) {
ESP_LOGI (TAG, "SetTx timeoutInMs=%d" " tout=%d", timeoutInMs, tout);
}
buf[0] = (uint8_t)((tout >> 16) & 0xFF);
buf[1] = (uint8_t)((tout >> 8) & 0xFF);
buf[2] = (uint8_t)(tout & 0xFF);
WriteCommand (SX126X_CMD_SET_TX, buf, 3); // 0x83
for (int retry = 0; retry < 10; retry++) {
if ((GetStatus() & 0x70) == 0x60)
break;
vTaskDelay (1);
}
if ((GetStatus() & 0x70) != 0x60) {
ESP_LOGE (TAG, "SetTx Illegal Status");
LoRaError (ERR_INVALID_SETTX_STATE);
}
}
int GetPacketLost() {
return txLost;
}
uint8_t GetRssiInst() {
uint8_t buf[2];
ReadCommand (SX126X_CMD_GET_RSSI_INST, buf, 2); // 0x15
return buf[1];
}
void GetRxBufferStatus (uint8_t *payloadLength, uint8_t *rxStartBufferPointer) {
uint8_t buf[3];
ReadCommand (SX126X_CMD_GET_RX_BUFFER_STATUS, buf, 3); // 0x13
*payloadLength = buf[1];
*rxStartBufferPointer = buf[2];
}
void WaitForIdleBegin (unsigned long timeout, char *text) {
// ensure BUSY is low (state meachine ready)
char stop = 0;
for (int retry = 0; retry < 10; retry++) {
if (retry == 9)
stop = 1;
char ret = WaitForIdle (BUSY_WAIT, text, stop);
if (ret == 1)
break;
ESP_LOGW (TAG, "WaitForIdle fail retry=%d", retry);
vTaskDelay (pdMS_TO_TICKS (10));
}
}
char WaitForIdle (unsigned long timeout, char *text, char stop) {
char ret = 1;
TickType_t start = xTaskGetTickCount();
vTaskDelay (pdMS_TO_TICKS (1));
while (xTaskGetTickCount() - start < (timeout / portTICK_PERIOD_MS)) {
if (GPIO_ReadInputDataBit (GPIOE, GPIO_Pin_1) == 0)
break;
vTaskDelay (pdMS_TO_TICKS (1));
}
if (GPIO_ReadInputDataBit (GPIOE, GPIO_Pin_1)) {
if (stop) {
ESP_LOGE (TAG, "WaitForIdle Timeout text=%s timeout=%lu start=%d", text, timeout, start);
LoRaError (ERR_IDLE_TIMEOUT);
} else {
ESP_LOGW (TAG, "WaitForIdle Timeout text=%s timeout=%lu start=%d", text, timeout, start);
ret = 0;
}
}
return ret;
}
uint8_t ReadBuffer (uint8_t *rxData, int16_t rxDataLen) {
uint8_t offset = 0;
uint8_t payloadLength = 0;
GetRxBufferStatus (&payloadLength, &offset);
if (payloadLength > rxDataLen) {
ESP_LOGW (TAG, "ReadBuffer rxDataLen too small. payloadLength=%d rxDataLen=%d", payloadLength, rxDataLen);
return 0;
}
// ensure BUSY is low (state meachine ready)
WaitForIdle (BUSY_WAIT, "start ReadBuffer", 1);
// start transfer
uint8_t *buf;
buf = malloc (payloadLength + 3);
if (buf != NULL) {
buf[0] = SX126X_CMD_READ_BUFFER; // 0x1E
buf[1] = offset; // offset in rx fifo
buf[2] = SX126X_CMD_NOP;
memset (&buf[3], SX126X_CMD_NOP, payloadLength);
spi_read_byte (buf, buf, payloadLength + 3);
memcpy (rxData, &buf[3], payloadLength);
free (buf);
} else {
ESP_LOGE (TAG, "ReadBuffer malloc fail");
payloadLength = 0;
}
// wait for BUSY to go low
WaitForIdle (BUSY_WAIT, "end ReadBuffer", 0);
return payloadLength;
}
void WriteBuffer (uint8_t *txData, int16_t txDataLen) {
// ensure BUSY is low (state meachine ready)
WaitForIdle (BUSY_WAIT, "start WriteBuffer", 1);
// start transfer
uint8_t *buf;
buf = malloc (txDataLen + 2);
if (buf != NULL) {
buf[0] = SX126X_CMD_WRITE_BUFFER; // 0x0E
buf[1] = 0; // offset in tx fifo
memcpy (&buf[2], txData, txDataLen);
spi_write_byte (buf, txDataLen + 2);
free (buf);
} else {
ESP_LOGE (TAG, "WriteBuffer malloc fail");
}
// wait for BUSY to go low
WaitForIdle (BUSY_WAIT, "end WriteBuffer", 0);
}
void WriteRegister (uint16_t reg, uint8_t *data, uint8_t numBytes) {
// ensure BUSY is low (state meachine ready)
WaitForIdle (BUSY_WAIT, "start WriteRegister", 1);
if (debugPrint) {
ESP_LOGI (TAG, "WriteRegister: REG=0x%02x", reg);
for (uint8_t n = 0; n < numBytes; n++) {
ESP_LOGI (TAG, "DataOut:%02x ", data[n]);
}
}
// start transfer
uint8_t buf[16];
buf[0] = SX126X_CMD_WRITE_REGISTER;
buf[1] = (reg & 0xFF00) >> 8;
buf[2] = reg & 0xff;
memcpy (&buf[3], data, numBytes);
spi_write_byte (buf, 3 + numBytes);
// wait for BUSY to go low
WaitForIdle (BUSY_WAIT, "end WriteRegister", 0);
}
void ReadRegister (uint16_t reg, uint8_t *data, uint8_t numBytes) {
// ensure BUSY is low (state meachine ready)
WaitForIdle (BUSY_WAIT, "start ReadRegister", 1);
if (debugPrint) {
ESP_LOGI (TAG, "ReadRegister: REG=0x%02x", reg);
}
// start transfer
uint8_t buf[16];
uint8_t buf2[16];
memset (buf, SX126X_CMD_NOP, sizeof (buf));
memset (buf2, SX126X_CMD_NOP, sizeof (buf2));
buf[0] = SX126X_CMD_READ_REGISTER;
buf[1] = (reg & 0xFF00) >> 8;
buf[2] = reg & 0xff;
if (debugPrint) {
ESP_LOGI (TAG, "Reading bytes");
}
spi_read_byte (buf2, buf, 4 + numBytes);
ESP_LOGI (TAG, "read a byte");
memcpy (data, &buf2[4], numBytes);
if (debugPrint) {
for (uint8_t n = 0; n < numBytes; n++) {
ESP_LOGI (TAG, "DataIn:%02x ", data[n]);
}
}
// wait for BUSY to go low
WaitForIdle (BUSY_WAIT, "end ReadRegister", 0);
}
// WriteCommand with retry
void WriteCommand (uint8_t cmd, uint8_t *data, uint8_t numBytes) {
uint8_t status;
for (int retry = 1; retry < 10; retry++) {
status = WriteCommand2 (cmd, data, numBytes);
if (debugPrint) {
ESP_LOGD (TAG, "status=%02x", status);
}
if (status == 0)
break;
ESP_LOGW (TAG, "WriteCommand2 status=%02x retry=%d", status, retry);
}
if (status != 0) {
ESP_LOGE (TAG, "SPI Transaction error:0x%02x", status);
LoRaError (ERR_SPI_TRANSACTION);
}
}
uint8_t WriteCommand2 (uint8_t cmd, uint8_t *data, uint8_t numBytes) {
// ensure BUSY is low (state meachine ready)
WaitForIdle (BUSY_WAIT, "start WriteCommand2", 1);
if (debugPrint) {
ESP_LOGI (TAG, "WriteCommand: CMD=0x%02x", cmd);
}
// start transfer
uint8_t buf[16];
buf[0] = cmd;
memcpy (&buf[1], data, numBytes);
spi_read_byte (buf, buf, numBytes + 1);
uint8_t status = 0;
uint8_t cmd_status = buf[1] & 0xe;
switch (cmd_status) {
case SX126X_STATUS_CMD_TIMEOUT:
case SX126X_STATUS_CMD_INVALID:
case SX126X_STATUS_CMD_FAILED:
status = cmd_status;
break;
case 0:
case 7:
status = SX126X_STATUS_SPI_FAILED;
break;
// default: break; // success
}
// wait for BUSY to go low
WaitForIdle (BUSY_WAIT, "end WriteCommand2", 0);
return status;
}
void ReadCommand (uint8_t cmd, uint8_t *data, uint8_t numBytes) {
// ensure BUSY is low (state meachine ready)
WaitForIdleBegin (BUSY_WAIT, "start ReadCommand");
if (debugPrint) {
ESP_LOGI (TAG, "ReadCommand: CMD=0x%02x", cmd);
}
// start transfer
uint8_t buf[16];
memset (buf, SX126X_CMD_NOP, sizeof (buf));
buf[0] = cmd;
spi_read_byte (buf, buf, 1 + numBytes);
if (data != NULL && numBytes)
memcpy (data, &buf[1], numBytes);
// wait for BUSY to go low
vTaskDelay (1);
WaitForIdle (BUSY_WAIT, "end ReadCommand", 0);
}

433
User/sx1262.h Normal file
View File

@@ -0,0 +1,433 @@
#ifndef _RA01S_H
#define _RA01S_H
//return values
#define ERR_NONE 0
#define ERR_PACKET_TOO_LONG 1
#define ERR_UNKNOWN 2
#define ERR_TX_TIMEOUT 3
#define ERR_RX_TIMEOUT 4
#define ERR_CRC_MISMATCH 5
#define ERR_WRONG_MODEM 6
#define ERR_INVALID_BANDWIDTH 7
#define ERR_INVALID_SPREADING_FACTOR 8
#define ERR_INVALID_CODING_RATE 9
#define ERR_INVALID_FREQUENCY_DEVIATION 10
#define ERR_INVALID_BIT_RATE 11
#define ERR_INVALID_RX_BANDWIDTH 12
#define ERR_INVALID_DATA_SHAPING 13
#define ERR_INVALID_SYNC_WORD 14
#define ERR_INVALID_OUTPUT_POWER 15
#define ERR_INVALID_MODE 16
#define ERR_INVALID_TRANCEIVER 17
#define ERR_INVALID_SETRX_STATE 18
#define ERR_INVALID_SETTX_STATE 19
#define ERR_IDLE_TIMEOUT 20
#define ERR_SPI_TRANSACTION 21
// SX126X physical layer properties
#define XTAL_FREQ ( double )32000000
#define FREQ_DIV ( double )pow( 2.0, 25.0 )
#define FREQ_STEP ( double )( XTAL_FREQ / FREQ_DIV )
#define LOW 0
#define HIGH 1
#define BUSY_WAIT 5000
// SX126X Model
#define SX1261_TRANCEIVER 0x01
#define SX1262_TRANCEIVER 0x02
#define SX1268_TRANCEIVER 0x08
// SX126X SPI commands
// operational modes commands
#define SX126X_CMD_NOP 0x00
#define SX126X_CMD_SET_SLEEP 0x84
#define SX126X_CMD_SET_STANDBY 0x80
#define SX126X_CMD_SET_FS 0xC1
#define SX126X_CMD_SET_TX 0x83
#define SX126X_CMD_SET_RX 0x82
#define SX126X_CMD_STOP_TIMER_ON_PREAMBLE 0x9F
#define SX126X_CMD_SET_RX_DUTY_CYCLE 0x94
#define SX126X_CMD_SET_CAD 0xC5
#define SX126X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1
#define SX126X_CMD_SET_TX_INFINITE_PREAMBLE 0xD2
#define SX126X_CMD_SET_REGULATOR_MODE 0x96
#define SX126X_CMD_CALIBRATE 0x89
#define SX126X_CMD_CALIBRATE_IMAGE 0x98
#define SX126X_CMD_SET_PA_CONFIG 0x95
#define SX126X_CMD_SET_RX_TX_FALLBACK_MODE 0x93
// register and buffer access commands
#define SX126X_CMD_WRITE_REGISTER 0x0D
#define SX126X_CMD_READ_REGISTER 0x1D
#define SX126X_CMD_WRITE_BUFFER 0x0E
#define SX126X_CMD_READ_BUFFER 0x1E
// DIO and IRQ control
#define SX126X_CMD_SET_DIO_IRQ_PARAMS 0x08
#define SX126X_CMD_GET_IRQ_STATUS 0x12
#define SX126X_CMD_CLEAR_IRQ_STATUS 0x02
#define SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL 0x9D
#define SX126X_CMD_SET_DIO3_AS_TCXO_CTRL 0x97
// RF, modulation and packet commands
#define SX126X_CMD_SET_RF_FREQUENCY 0x86
#define SX126X_CMD_SET_PACKET_TYPE 0x8A
#define SX126X_CMD_GET_PACKET_TYPE 0x11
#define SX126X_CMD_SET_TX_PARAMS 0x8E
#define SX126X_CMD_SET_MODULATION_PARAMS 0x8B
#define SX126X_CMD_SET_PACKET_PARAMS 0x8C
#define SX126X_CMD_SET_CAD_PARAMS 0x88
#define SX126X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F
#define SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT 0xA0
#define SX126X_PA_CONFIG_SX1261 0x01
#define SX126X_PA_CONFIG_SX1262 0x00
// status commands
#define SX126X_CMD_GET_STATUS 0xC0
#define SX126X_CMD_GET_RSSI_INST 0x15
#define SX126X_CMD_GET_RX_BUFFER_STATUS 0x13
#define SX126X_CMD_GET_PACKET_STATUS 0x14
#define SX126X_CMD_GET_DEVICE_ERRORS 0x17
#define SX126X_CMD_CLEAR_DEVICE_ERRORS 0x07
#define SX126X_CMD_GET_STATS 0x10
#define SX126X_CMD_RESET_STATS 0x00
// SX126X register map
#define SX126X_REG_HOPPING_ENABLE 0x0385
#define SX126X_REG_PACKECT_LENGTH 0x0386
#define SX126X_REG_NB_HOPPING_BLOCKS 0x0387
#define SX126X_REG_NB_SYMBOLS0 0x0388
#define SX126X_REG_FREQ0 0x038A
#define SX126X_REG_NB_SYMBOLS15 0x03E2
#define SX126X_REG_FREQ15 0x03E4
#define SX126X_REG_DIOX_OUTPUT_ENABLE 0x0580
#define SX126X_REG_DIOX_INPUT_ENABLE 0x0583
#define SX126X_REG_DIOX_PILL_UP_CONTROL 0x0584
#define SX126X_REG_DIOX_PULL_DOWN_CONTROL 0x0585
#define SX126X_REG_WHITENING_INITIAL_MSB 0x06B8
#define SX126X_REG_WHITENING_INITIAL_LSB 0x06B9
#define SX126X_REG_CRC_INITIAL_MSB 0x06BC
#define SX126X_REG_CRC_INITIAL_LSB 0x06BD
#define SX126X_REG_CRC_POLYNOMIAL_MSB 0x06BE
#define SX126X_REG_CRC_POLYNOMIAL_LSB 0x06BF
#define SX126X_REG_SYNC_WORD_0 0x06C0
#define SX126X_REG_SYNC_WORD_1 0x06C1
#define SX126X_REG_SYNC_WORD_2 0x06C2
#define SX126X_REG_SYNC_WORD_3 0x06C3
#define SX126X_REG_SYNC_WORD_4 0x06C4
#define SX126X_REG_SYNC_WORD_5 0x06C5
#define SX126X_REG_SYNC_WORD_6 0x06C6
#define SX126X_REG_SYNC_WORD_7 0x06C7
#define SX126X_REG_NODE_ADDRESS 0x06CD
#define SX126X_REG_BROADCAST_ADDRESS 0x06CE
#define SX126X_REG_IQ_POLARITY_SETUP 0x0736
#define SX126X_REG_LORA_SYNC_WORD_MSB 0x0740
#define SX126X_REG_LORA_SYNC_WORD_LSB 0x0741
#define SX126X_REG_RANDOM_NUMBER_0 0x0819
#define SX126X_REG_RANDOM_NUMBER_1 0x081A
#define SX126X_REG_RANDOM_NUMBER_2 0x081B
#define SX126X_REG_RANDOM_NUMBER_3 0x081C
#define SX126X_REG_TX_MODULETION 0x0889
#define SX126X_REG_RX_GAIN 0x08AC
#define SX126X_REG_TX_CLAMP_CONFIG 0x08D8
#define SX126X_REG_OCP_CONFIGURATION 0x08E7
#define SX126X_REG_RTC_CONTROL 0x0902
#define SX126X_REG_XTA_TRIM 0x0911
#define SX126X_REG_XTB_TRIM 0x0912
#define SX126X_REG_DIO3_OUTPUT_VOLTAGE_CONTROL 0x0920
#define SX126X_REG_EVENT_MASK 0x0944
// SX126X SPI command variables
//SX126X_CMD_SET_SLEEP
#define SX126X_SLEEP_START_COLD 0b00000000 // 2 2 sleep mode: cold start, configuration is lost (default)
#define SX126X_SLEEP_START_WARM 0b00000100 // 2 2 warm start, configuration is retained
#define SX126X_SLEEP_RTC_OFF 0b00000000 // 0 0 wake on RTC timeout: disabled
#define SX126X_SLEEP_RTC_ON 0b00000001 // 0 0 enabled
//SX126X_CMD_SET_STANDBY
#define SX126X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator
#define SX126X_STANDBY_XOSC 0x01 // 7 0 32 MHz crystal oscillator
//SX126X_CMD_SET_RX
#define SX126X_RX_TIMEOUT_NONE 0x000000 // 23 0 Rx timeout duration: no timeout (Rx single mode)
#define SX126X_RX_TIMEOUT_INF 0xFFFFFF // 23 0 infinite (Rx continuous mode)
//SX126X_CMD_STOP_TIMER_ON_PREAMBLE
#define SX126X_STOP_ON_PREAMBLE_OFF 0x00 // 7 0 stop timer on: sync word or header (default)
#define SX126X_STOP_ON_PREAMBLE_ON 0x01 // 7 0 preamble detection
//SX126X_CMD_SET_REGULATOR_MODE
#define SX126X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default)
#define SX126X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC
//SX126X_CMD_CALIBRATE
#define SX126X_CALIBRATE_IMAGE_OFF 0b00000000 // 6 6 image calibration: disabled
#define SX126X_CALIBRATE_IMAGE_ON 0b01000000 // 6 6 enabled
#define SX126X_CALIBRATE_ADC_BULK_P_OFF 0b00000000 // 5 5 ADC bulk P calibration: disabled
#define SX126X_CALIBRATE_ADC_BULK_P_ON 0b00100000 // 5 5 enabled
#define SX126X_CALIBRATE_ADC_BULK_N_OFF 0b00000000 // 4 4 ADC bulk N calibration: disabled
#define SX126X_CALIBRATE_ADC_BULK_N_ON 0b00010000 // 4 4 enabled
#define SX126X_CALIBRATE_ADC_PULSE_OFF 0b00000000 // 3 3 ADC pulse calibration: disabled
#define SX126X_CALIBRATE_ADC_PULSE_ON 0b00001000 // 3 3 enabled
#define SX126X_CALIBRATE_PLL_OFF 0b00000000 // 2 2 PLL calibration: disabled
#define SX126X_CALIBRATE_PLL_ON 0b00000100 // 2 2 enabled
#define SX126X_CALIBRATE_RC13M_OFF 0b00000000 // 1 1 13 MHz RC osc. calibration: disabled
#define SX126X_CALIBRATE_RC13M_ON 0b00000010 // 1 1 enabled
#define SX126X_CALIBRATE_RC64K_OFF 0b00000000 // 0 0 64 kHz RC osc. calibration: disabled
#define SX126X_CALIBRATE_RC64K_ON 0b00000001 // 0 0 enabled
//SX126X_CMD_CALIBRATE_IMAGE
#define SX126X_CAL_IMG_430_MHZ_1 0x6B
#define SX126X_CAL_IMG_430_MHZ_2 0x6F
#define SX126X_CAL_IMG_470_MHZ_1 0x75
#define SX126X_CAL_IMG_470_MHZ_2 0x81
#define SX126X_CAL_IMG_779_MHZ_1 0xC1
#define SX126X_CAL_IMG_779_MHZ_2 0xC5
#define SX126X_CAL_IMG_863_MHZ_1 0xD7
#define SX126X_CAL_IMG_863_MHZ_2 0xDB
#define SX126X_CAL_IMG_902_MHZ_1 0xE1
#define SX126X_CAL_IMG_902_MHZ_2 0xE9
//SX126X_CMD_SET_PA_CONFIG
#define SX126X_PA_CONFIG_HP_MAX 0x07
#define SX126X_PA_CONFIG_SX1268 0x01
#define SX126X_PA_CONFIG_PA_LUT 0x01
//SX126X_CMD_SET_RX_TX_FALLBACK_MODE
#define SX126X_RX_TX_FALLBACK_MODE_FS 0x40 // 7 0 after Rx/Tx go to: FS mode
#define SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC 0x30 // 7 0 standby with crystal oscillator
#define SX126X_RX_TX_FALLBACK_MODE_STDBY_RC 0x20 // 7 0 standby with RC oscillator (default)
//SX126X_CMD_SET_DIO_IRQ_PARAMS
#define SX126X_IRQ_TIMEOUT 0b1000000000 // 9 9 Rx or Tx timeout
#define SX126X_IRQ_CAD_DETECTED 0b0100000000 // 8 8 channel activity detected
#define SX126X_IRQ_CAD_DONE 0b0010000000 // 7 7 channel activity detection finished
#define SX126X_IRQ_CRC_ERR 0b0001000000 // 6 6 wrong CRC received
#define SX126X_IRQ_HEADER_ERR 0b0000100000 // 5 5 LoRa header CRC error
#define SX126X_IRQ_HEADER_VALID 0b0000010000 // 4 4 valid LoRa header received
#define SX126X_IRQ_SYNC_WORD_VALID 0b0000001000 // 3 3 valid sync word detected
#define SX126X_IRQ_PREAMBLE_DETECTED 0b0000000100 // 2 2 preamble detected
#define SX126X_IRQ_RX_DONE 0b0000000010 // 1 1 packet received
#define SX126X_IRQ_TX_DONE 0b0000000001 // 0 0 packet transmission completed
#define SX126X_IRQ_ALL 0b1111111111 // 9 0 all interrupts
#define SX126X_IRQ_NONE 0b0000000000 // 9 0 no interrupts
//SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL
#define SX126X_DIO2_AS_IRQ 0x00 // 7 0 DIO2 configuration: IRQ
#define SX126X_DIO2_AS_RF_SWITCH 0x01 // 7 0 RF switch control
//SX126X_CMD_SET_DIO3_AS_TCXO_CTRL
#define SX126X_DIO3_OUTPUT_1_6 0x00 // 7 0 DIO3 voltage output for TCXO: 1.6 V
#define SX126X_DIO3_OUTPUT_1_7 0x01 // 7 0 1.7 V
#define SX126X_DIO3_OUTPUT_1_8 0x02 // 7 0 1.8 V
#define SX126X_DIO3_OUTPUT_2_2 0x03 // 7 0 2.2 V
#define SX126X_DIO3_OUTPUT_2_4 0x04 // 7 0 2.4 V
#define SX126X_DIO3_OUTPUT_2_7 0x05 // 7 0 2.7 V
#define SX126X_DIO3_OUTPUT_3_0 0x06 // 7 0 3.0 V
#define SX126X_DIO3_OUTPUT_3_3 0x07 // 7 0 3.3 V
//Radio complete Wake-up Time with TCXO stabilisation time
#define RADIO_TCXO_SETUP_TIME 5000 // [us]
//SX126X_CMD_SET_PACKET_TYPE
#define SX126X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: GFSK
#define SX126X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa
//SX126X_CMD_SET_TX_PARAMS
#define SX126X_PA_RAMP_10U 0x00 // 7 0 ramp time: 10 us
#define SX126X_PA_RAMP_20U 0x01 // 7 0 20 us
#define SX126X_PA_RAMP_40U 0x02 // 7 0 40 us
#define SX126X_PA_RAMP_80U 0x03 // 7 0 80 us
#define SX126X_PA_RAMP_200U 0x04 // 7 0 200 us
#define SX126X_PA_RAMP_800U 0x05 // 7 0 800 us
#define SX126X_PA_RAMP_1700U 0x06 // 7 0 1700 us
#define SX126X_PA_RAMP_3400U 0x07 // 7 0 3400 us
//SX126X_CMD_SET_MODULATION_PARAMS
#define SX126X_GFSK_FILTER_NONE 0x00 // 7 0 GFSK filter: none
#define SX126X_GFSK_FILTER_GAUSS_0_3 0x08 // 7 0 Gaussian, BT = 0.3
#define SX126X_GFSK_FILTER_GAUSS_0_5 0x09 // 7 0 Gaussian, BT = 0.5
#define SX126X_GFSK_FILTER_GAUSS_0_7 0x0A // 7 0 Gaussian, BT = 0.7
#define SX126X_GFSK_FILTER_GAUSS_1 0x0B // 7 0 Gaussian, BT = 1
#define SX126X_GFSK_RX_BW_4_8 0x1F // 7 0 GFSK Rx bandwidth: 4.8 kHz
#define SX126X_GFSK_RX_BW_5_8 0x17 // 7 0 5.8 kHz
#define SX126X_GFSK_RX_BW_7_3 0x0F // 7 0 7.3 kHz
#define SX126X_GFSK_RX_BW_9_7 0x1E // 7 0 9.7 kHz
#define SX126X_GFSK_RX_BW_11_7 0x16 // 7 0 11.7 kHz
#define SX126X_GFSK_RX_BW_14_6 0x0E // 7 0 14.6 kHz
#define SX126X_GFSK_RX_BW_19_5 0x1D // 7 0 19.5 kHz
#define SX126X_GFSK_RX_BW_23_4 0x15 // 7 0 23.4 kHz
#define SX126X_GFSK_RX_BW_29_3 0x0D // 7 0 29.3 kHz
#define SX126X_GFSK_RX_BW_39_0 0x1C // 7 0 39.0 kHz
#define SX126X_GFSK_RX_BW_46_9 0x14 // 7 0 46.9 kHz
#define SX126X_GFSK_RX_BW_58_6 0x0C // 7 0 58.6 kHz
#define SX126X_GFSK_RX_BW_78_2 0x1B // 7 0 78.2 kHz
#define SX126X_GFSK_RX_BW_93_8 0x13 // 7 0 93.8 kHz
#define SX126X_GFSK_RX_BW_117_3 0x0B // 7 0 117.3 kHz
#define SX126X_GFSK_RX_BW_156_2 0x1A // 7 0 156.2 kHz
#define SX126X_GFSK_RX_BW_187_2 0x12 // 7 0 187.2 kHz
#define SX126X_GFSK_RX_BW_234_3 0x0A // 7 0 234.3 kHz
#define SX126X_GFSK_RX_BW_312_0 0x19 // 7 0 312.0 kHz
#define SX126X_GFSK_RX_BW_373_6 0x11 // 7 0 373.6 kHz
#define SX126X_GFSK_RX_BW_467_0 0x09 // 7 0 467.0 kHz
#define SX126X_LORA_BW_7_8 0x00 // 7 0 LoRa bandwidth: 7.8 kHz
#define SX126X_LORA_BW_10_4 0x08 // 7 0 10.4 kHz
#define SX126X_LORA_BW_15_6 0x01 // 7 0 15.6 kHz
#define SX126X_LORA_BW_20_8 0x09 // 7 0 20.8 kHz
#define SX126X_LORA_BW_31_25 0x02 // 7 0 31.25 kHz
#define SX126X_LORA_BW_41_7 0x0A // 7 0 41.7 kHz
#define SX126X_LORA_BW_62_5 0x03 // 7 0 62.5 kHz
#define SX126X_LORA_BW_125_0 0x04 // 7 0 125.0 kHz
#define SX126X_LORA_BW_250_0 0x05 // 7 0 250.0 kHz
#define SX126X_LORA_BW_500_0 0x06 // 7 0 500.0 kHz
#define SX126X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5
#define SX126X_LORA_CR_4_6 0x02 // 7 0 4/6
#define SX126X_LORA_CR_4_7 0x03 // 7 0 4/7
#define SX126X_LORA_CR_4_8 0x04 // 7 0 4/8
#define SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF 0x00 // 7 0 LoRa low data rate optimization: disabled
#define SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON 0x01 // 7 0 enabled
//SX126X_CMD_SET_PACKET_PARAMS
#define SX126X_GFSK_PREAMBLE_DETECT_OFF 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled
#define SX126X_GFSK_PREAMBLE_DETECT_8 0x04 // 7 0 8 bits
#define SX126X_GFSK_PREAMBLE_DETECT_16 0x05 // 7 0 16 bits
#define SX126X_GFSK_PREAMBLE_DETECT_24 0x06 // 7 0 24 bits
#define SX126X_GFSK_PREAMBLE_DETECT_32 0x07 // 7 0 32 bits
#define SX126X_GFSK_ADDRESS_FILT_OFF 0x00 // 7 0 GFSK address filtering: disabled
#define SX126X_GFSK_ADDRESS_FILT_NODE 0x01 // 7 0 node only
#define SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST 0x02 // 7 0 node and broadcast
#define SX126X_GFSK_PACKET_FIXED 0x00 // 7 0 GFSK packet type: fixed (payload length known in advance to both sides)
#define SX126X_GFSK_PACKET_VARIABLE 0x01 // 7 0 variable (payload length added to packet)
#define SX126X_GFSK_CRC_OFF 0x01 // 7 0 GFSK packet CRC: disabled
#define SX126X_GFSK_CRC_1_BYTE 0x00 // 7 0 1 byte
#define SX126X_GFSK_CRC_2_BYTE 0x02 // 7 0 2 byte
#define SX126X_GFSK_CRC_1_BYTE_INV 0x04 // 7 0 1 byte, inverted
#define SX126X_GFSK_CRC_2_BYTE_INV 0x06 // 7 0 2 byte, inverted
#define SX126X_GFSK_WHITENING_OFF 0x00 // 7 0 GFSK data whitening: disabled
#define SX126X_GFSK_WHITENING_ON 0x01 // 7 0 enabled
#define SX126X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit
#define SX126X_LORA_HEADER_IMPLICIT 0x01 // 7 0 implicit
#define SX126X_LORA_CRC_OFF 0x00 // 7 0 LoRa CRC mode: disabled
#define SX126X_LORA_CRC_ON 0x01 // 7 0 enabled
#define SX126X_LORA_IQ_STANDARD 0x00 // 7 0 LoRa IQ setup: standard
#define SX126X_LORA_IQ_INVERTED 0x01 // 7 0 inverted
//SX126X_CMD_SET_CAD_PARAMS
#define SX126X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1
#define SX126X_CAD_ON_2_SYMB 0x01 // 7 0 2
#define SX126X_CAD_ON_4_SYMB 0x02 // 7 0 4
#define SX126X_CAD_ON_8_SYMB 0x03 // 7 0 8
#define SX126X_CAD_ON_16_SYMB 0x04 // 7 0 16
#define SX126X_CAD_GOTO_STDBY 0x00 // 7 0 after CAD is done, always go to STDBY_RC mode
#define SX126X_CAD_GOTO_RX 0x01 // 7 0 after CAD is done, go to Rx mode if activity is detected
//SX126X_CMD_GET_STATUS
#define SX126X_STATUS_MODE_STDBY_RC 0b00100000 // 6 4 current chip mode: STDBY_RC
#define SX126X_STATUS_MODE_STDBY_XOSC 0b00110000 // 6 4 STDBY_XOSC
#define SX126X_STATUS_MODE_FS 0b01000000 // 6 4 FS
#define SX126X_STATUS_MODE_RX 0b01010000 // 6 4 RX
#define SX126X_STATUS_MODE_TX 0b01100000 // 6 4 TX
#define SX126X_STATUS_DATA_AVAILABLE 0b00000100 // 3 1 command status: packet received and data can be retrieved
#define SX126X_STATUS_CMD_TIMEOUT 0b00000110 // 3 1 SPI command timed out
#define SX126X_STATUS_CMD_INVALID 0b00001000 // 3 1 invalid SPI command
#define SX126X_STATUS_CMD_FAILED 0b00001010 // 3 1 SPI command failed to execute
#define SX126X_STATUS_TX_DONE 0b00001100 // 3 1 packet transmission done
#define SX126X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed
//SX126X_CMD_GET_PACKET_STATUS
#define SX126X_GFSK_RX_STATUS_PREAMBLE_ERR 0b10000000 // 7 7 GFSK Rx status: preamble error
#define SX126X_GFSK_RX_STATUS_SYNC_ERR 0b01000000 // 6 6 sync word error
#define SX126X_GFSK_RX_STATUS_ADRS_ERR 0b00100000 // 5 5 address error
#define SX126X_GFSK_RX_STATUS_CRC_ERR 0b00010000 // 4 4 CRC error
#define SX126X_GFSK_RX_STATUS_LENGTH_ERR 0b00001000 // 3 3 length error
#define SX126X_GFSK_RX_STATUS_ABORT_ERR 0b00000100 // 2 2 abort error
#define SX126X_GFSK_RX_STATUS_PACKET_RECEIVED 0b00000010 // 2 2 packet received
#define SX126X_GFSK_RX_STATUS_PACKET_SENT 0b00000001 // 2 2 packet sent
//SX126X_CMD_GET_DEVICE_ERRORS
#define SX126X_PA_RAMP_ERR 0b100000000 // 8 8 device errors: PA ramping failed
#define SX126X_PLL_LOCK_ERR 0b001000000 // 6 6 PLL failed to lock
#define SX126X_XOSC_START_ERR 0b000100000 // 5 5 crystal oscillator failed to start
#define SX126X_IMG_CALIB_ERR 0b000010000 // 4 4 image calibration failed
#define SX126X_ADC_CALIB_ERR 0b000001000 // 3 3 ADC calibration failed
#define SX126X_PLL_CALIB_ERR 0b000000100 // 2 2 PLL calibration failed
#define SX126X_RC13M_CALIB_ERR 0b000000010 // 1 1 RC13M calibration failed
#define SX126X_RC64K_CALIB_ERR 0b000000001 // 0 0 RC64K calibration failed
// SX126X SPI register variables
//SX126X_REG_LORA_SYNC_WORD_MSB + LSB
//#define SX126X_SYNC_WORD_PUBLIC 0x3444
#define SX126X_SYNC_WORD_PUBLIC 0x24B4 //meshtastic
#define SX126X_SYNC_WORD_PRIVATE 0x1424
#define SX126x_TXMODE_ASYNC 0x01
#define SX126x_TXMODE_SYNC 0x02
#define SX126x_TXMODE_BACK2RX 0x04
// Public function
void LoRaInit(void);
int16_t LoRaBegin(uint32_t frequencyInHz, int8_t txPowerInDbm, float tcxoVoltage, char useRegulatorLDO);
void LoRaConfig(uint8_t spreadingFactor, uint8_t bandwidth, uint8_t codingRate, uint16_t preambleLength, uint8_t payloadLen, char crcOn, char invertIrq);
uint8_t LoRaReceive(uint8_t *pData, int16_t len);
char LoRaSend(uint8_t *pData, int16_t len, uint8_t mode);
void LoRaDebugPrint(char enable);
// Private function
void spi_write_byte(uint8_t* Dataout, size_t DataLength );
void spi_read_byte(uint8_t *rx, const uint8_t *tx, size_t len);
uint8_t spi_transfer(uint8_t address);
char ReceiveMode(void);
void GetPacketStatus(int8_t *rssiPacket, int8_t *snrPacket);
void SetTxPower(int8_t txPowerInDbm);
void FixInvertedIQ(uint8_t iqConfig);
void SetDio3AsTcxoCtrl(float voltage, uint32_t delay);
void SetDio2AsRfSwitchCtrl(uint8_t enable);
void ResetLora(void);
void SetStandby(uint8_t mode);
void SetRfFrequency(uint32_t frequency);
void Calibrate(uint8_t calibParam);
void CalibrateImage(uint32_t frequency);
void SetRegulatorMode(uint8_t mode);
void SetBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress);
void SetPowerConfig(int8_t power, uint8_t rampTime);
void SetOvercurrentProtection(float currentLimit);
void SetSyncWord(int16_t sync);
void SetPaConfig(uint8_t paDutyCycle, uint8_t hpMax, uint8_t deviceSel, uint8_t paLut);
void SetDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask);
void SetStopRxTimerOnPreambleDetect(char enable);
void SetLoRaSymbNumTimeout(uint8_t SymbNum);
void SetPacketType(uint8_t packetType);
void SetModulationParams(uint8_t spreadingFactor, uint8_t bandwidth, uint8_t codingRate, uint8_t lowDataRateOptimize);
void SetCadParams(uint8_t cadSymbolNum, uint8_t cadDetPeak, uint8_t cadDetMin, uint8_t cadExitMode, uint32_t cadTimeout);
void SetCad();
uint8_t GetStatus(void);
uint16_t GetIrqStatus(void);
void ClearIrqStatus(uint16_t irq);
void SetRx(uint32_t timeout);
void SetTx(uint32_t timeoutInMs);
int GetPacketLost();
uint8_t GetRssiInst();
void GetRxBufferStatus(uint8_t *payloadLength, uint8_t *rxStartBufferPointer);
void Wakeup(void);
void WaitForIdleBegin(unsigned long timeout, char *text);
char WaitForIdle(unsigned long timeout, char *text, char stop);
uint8_t ReadBuffer(uint8_t *rxData, int16_t rxDataLen);
void WriteBuffer(uint8_t *txData, int16_t txDataLen);
void WriteRegister(uint16_t reg, uint8_t* data, uint8_t numBytes);
void ReadRegister(uint16_t reg, uint8_t* data, uint8_t numBytes);
void WriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes);
uint8_t WriteCommand2(uint8_t cmd, uint8_t* data, uint8_t numBytes);
void ReadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes);
void SPItransfer(uint8_t cmd, char write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, char waitForBusy);
void LoRaError(int error);
#endif

1036
User/system_ch32v30x.c Normal file

File diff suppressed because it is too large Load Diff

32
User/system_ch32v30x.h Normal file
View File

@@ -0,0 +1,32 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : system_ch32v30x.h
* Author : WCH
* Version : V1.0.0
* Date : 2021/06/06
* Description : CH32V30x Device Peripheral Access Layer System Header File.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
#ifndef __SYSTEM_CH32V30x_H
#define __SYSTEM_CH32V30x_H
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t SystemCoreClock; /* System Clock Frequency (Core Clock) */
/* System_Exported_Functions */
extern void SystemInit(void);
extern void SystemCoreClockUpdate(void);
#ifdef __cplusplus
}
#endif
#endif /*__CH32V30x_SYSTEM_H */

20
User/util/log.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef LOGGER_HEADER
#define LOGGER_HEADER
// Define log levels
#define LOG_ERROR "E"
#define LOG_WARN "W"
#define LOG_INFO "I"
#define LOG_DEBUG "D"
// Define a generic log macro
#define LOG_PRINT(level, tag, fmt, ...) \
printf("[%s] %s: " fmt "\r\n", level, tag, ##__VA_ARGS__)
// Define ESP-like shortcuts
#define ESP_LOGE(tag, fmt, ...) LOG_PRINT(LOG_ERROR, tag, fmt, ##__VA_ARGS__)
#define ESP_LOGW(tag, fmt, ...) LOG_PRINT(LOG_WARN, tag, fmt, ##__VA_ARGS__)
#define ESP_LOGI(tag, fmt, ...) LOG_PRINT(LOG_INFO, tag, fmt, ##__VA_ARGS__)
#define ESP_LOGD(tag, fmt, ...) LOG_PRINT(LOG_DEBUG, tag, fmt, ##__VA_ARGS__)
#endif