From 99c409651754ed88668aa27b9fd39fdca0e28df3 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Mon, 11 Aug 2025 00:55:51 -0500 Subject: [PATCH] Test commit for XEdDSA support --- arch/esp32/esp32.ini | 2 +- arch/esp32/esp32c6.ini | 2 +- arch/nrf52/nrf52.ini | 2 +- arch/portduino/portduino.ini | 3 +- arch/rp2xx0/rp2040.ini | 2 +- arch/rp2xx0/rp2350.ini | 2 +- protobufs | 2 +- src/mesh/CryptoEngine.cpp | 106 ++ src/mesh/CryptoEngine.h | 6 + src/mesh/NodeDB.h | 3 + src/mesh/Router.cpp | 29 +- src/mesh/TypeConversions.cpp | 1 + src/mesh/generated/meshtastic/deviceonly.pb.h | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 40 +- src/mesh/xeddsa.cpp | 1318 +++++++++++++++++ src/mesh/xeddsa.h | 40 + src/modules/NodeInfoModule.cpp | 4 + test/test_crypto/test_main.cpp | 26 + 18 files changed, 1569 insertions(+), 21 deletions(-) create mode 100644 src/mesh/xeddsa.cpp create mode 100644 src/mesh/xeddsa.h diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini index 8990053eb..d66358586 100644 --- a/arch/esp32/esp32.ini +++ b/arch/esp32/esp32.ini @@ -59,7 +59,7 @@ lib_deps = # renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto - rweather/Crypto@0.4.0 + https://github.com/jp-bennett/crypto/archive/148e65930c5bea2b4f1bddfcb200f585413e8961.zip lib_ignore = segger_rtt diff --git a/arch/esp32/esp32c6.ini b/arch/esp32/esp32c6.ini index 1afb9b547..2343f9c14 100644 --- a/arch/esp32/esp32c6.ini +++ b/arch/esp32/esp32c6.ini @@ -32,7 +32,7 @@ lib_deps = # renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto - rweather/Crypto@0.4.0 + https://github.com/jp-bennett/crypto/archive/148e65930c5bea2b4f1bddfcb200f585413e8961.zip build_src_filter = ${esp32_base.build_src_filter} - diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini index 4a77ec4b2..8a07f8874 100644 --- a/arch/nrf52/nrf52.ini +++ b/arch/nrf52/nrf52.ini @@ -29,7 +29,7 @@ lib_deps= ${arduino_base.lib_deps} ${radiolib_base.lib_deps} # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto - rweather/Crypto@0.4.0 + https://github.com/jp-bennett/crypto/archive/148e65930c5bea2b4f1bddfcb200f585413e8961.zip lib_ignore = BluetoothOTA diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini index 693ab63b7..67a40ce92 100644 --- a/arch/portduino/portduino.ini +++ b/arch/portduino/portduino.ini @@ -25,7 +25,8 @@ lib_deps = ${radiolib_base.lib_deps} ${environmental_base.lib_deps} # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto - rweather/Crypto@0.4.0 + #rweather/Crypto@0.4.0 + https://github.com/jp-bennett/crypto/archive/148e65930c5bea2b4f1bddfcb200f585413e8961.zip # renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX lovyan03/LovyanGFX@^1.2.0 # renovate: datasource=git-refs depName=libch341-spi-userspace packageName=https://github.com/pine64/libch341-spi-userspace gitBranch=main diff --git a/arch/rp2xx0/rp2040.ini b/arch/rp2xx0/rp2040.ini index 4f9421872..715a73600 100644 --- a/arch/rp2xx0/rp2040.ini +++ b/arch/rp2xx0/rp2040.ini @@ -31,4 +31,4 @@ lib_deps = ${environmental_extra.lib_deps} ${radiolib_base.lib_deps} # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto - rweather/Crypto@0.4.0 + https://github.com/jp-bennett/crypto/archive/148e65930c5bea2b4f1bddfcb200f585413e8961.zip diff --git a/arch/rp2xx0/rp2350.ini b/arch/rp2xx0/rp2350.ini index e8611a113..f1f40c758 100644 --- a/arch/rp2xx0/rp2350.ini +++ b/arch/rp2xx0/rp2350.ini @@ -28,4 +28,4 @@ lib_deps = ${environmental_extra.lib_deps} ${radiolib_base.lib_deps} # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto - rweather/Crypto@0.4.0 + https://github.com/jp-bennett/crypto/archive/148e65930c5bea2b4f1bddfcb200f585413e8961.zip diff --git a/protobufs b/protobufs index e2c0831aa..22cf0ebd6 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit e2c0831aa3d34a58a36c2b9fdcb828e58961cbc5 +Subproject commit 22cf0ebd6632256538e6884e8102f367f9543177 diff --git a/src/mesh/CryptoEngine.cpp b/src/mesh/CryptoEngine.cpp index 82d0a9f57..93b9e4354 100644 --- a/src/mesh/CryptoEngine.cpp +++ b/src/mesh/CryptoEngine.cpp @@ -6,10 +6,18 @@ #include "NodeDB.h" #include "aes-ccm.h" #include "meshUtils.h" +#include "xeddsa.h" #include #include +#include #include #include + +#ifndef NUM_LIMBS_256BIT +#define NUM_LIMBS_BITS(n) (((n) + sizeof(limb_t) * 8 - 1) / (8 * sizeof(limb_t))) +#define NUM_LIMBS_256BIT NUM_LIMBS_BITS(256) +#endif + #if !(MESHTASTIC_EXCLUDE_PKI_KEYGEN) #if !defined(ARCH_STM32WL) #define CryptRNG RNG @@ -35,6 +43,7 @@ void CryptoEngine::generateKeyPair(uint8_t *pubKey, uint8_t *privKey) Curve25519::dh1(public_key, private_key); memcpy(pubKey, public_key, sizeof(public_key)); memcpy(privKey, private_key, sizeof(private_key)); + priv_curve_to_ed_keys(private_key, xeddsa_private_key, xeddsa_public_key); } /** @@ -54,12 +63,109 @@ bool CryptoEngine::regeneratePublicKey(uint8_t *pubKey, uint8_t *privKey) } memcpy(private_key, privKey, sizeof(private_key)); memcpy(public_key, pubKey, sizeof(public_key)); + priv_curve_to_ed_keys(private_key, xeddsa_private_key, xeddsa_public_key); } else { LOG_WARN("X25519 key generation failed due to blank private key"); return false; } return true; } + +bool CryptoEngine::xeddsa_sign(uint8_t *message, size_t len, uint8_t *signature) +{ + Ed25519::sign(signature, xeddsa_private_key, xeddsa_public_key, message, + len); // sign will need modified to use the raw secret scalar, and not hash it first. + return true; +} +bool CryptoEngine::xeddsa_verify(uint8_t *pubKey, uint8_t *message, size_t len, uint8_t *signature) +{ + uint8_t publicKey[32] = {0}; + curve_to_ed_pub(pubKey, publicKey); + + return Ed25519::verify(signature, publicKey, message, len); +} + +void CryptoEngine::curve_to_ed_pub(uint8_t *curve_pubkey, uint8_t *ed_pubkey) +{ + + // Apply the birational map defined in RFC 7748, section 4.1 "Curve25519" to calculate an Ed25519 public + // key from a Curve25519 public key. Because the serialization format of Curve25519 public keys only + // contains the u coordinate, the x coordinate of the corresponding Ed25519 public key can't be uniquely + // calculated as defined by the birational map. The x coordinate is represented in the serialization + // format of Ed25519 public keys only in a single sign bit. This function assumes that the sign bit is + // known to the user and is passed accordingly. + fe u, y; + fe one; + fe u_minus_one, u_plus_one, u_plus_one_inv; + + // Parse the Curve25519 public key input as a field element containing the u coordinate. RFC 7748, + // section 5 "The X25519 and X448 Functions", mandates that the most significant bit of the Curve25519 + // public key has to be zeroized. This is handled by fe_frombytes internally. + fe_frombytes(u, curve_pubkey); + + // Calculate the parameters (u - 1) and (u + 1) + fe_1(one); + fe_sub(u_minus_one, u, one); + fe_add(u_plus_one, u, one); + + // Invert u + 1 + fe_invert(u_plus_one_inv, u_plus_one); + + // Calculate y = (u - 1) * inv(u + 1) (mod p) + fe_mul(y, u_minus_one, u_plus_one_inv); + + // Serialize the field element containing the y coordinate to the Ed25519 public key output + fe_tobytes(ed_pubkey, y); + + // Set the sign bit to zero + ed_pubkey[31] &= 0x7f; + + // need to convert the pubkey y = ( u - 1) * inv( u + 1) (mod p). +} +void CryptoEngine::priv_curve_to_ed_keys(uint8_t *curve_privkey, uint8_t *ed_privkey, uint8_t *ed_pubkey) +{ + limb_t a[NUM_LIMBS_256BIT]; + limb_t a2[NUM_LIMBS_256BIT]; + uint8_t negKey[32] = {0}; + Ed25519::Point ptA; + Ed25519::Point ptA2; + + for (uint8_t i = 0; i < 32; i++) { + ed_privkey[i] = curve_privkey[i]; + } + + ed_privkey[0] &= 0xF8; + ed_privkey[31] &= 0x7F; + ed_privkey[31] |= 0x40; + + Ed25519::deriveKeys(nullptr, a, ed_privkey); + Ed25519::mul(ptA, a); + Ed25519::encodePoint(ed_pubkey, ptA); + + clean(a); + clean(ptA); + + // check sign + if ((ed_pubkey[31] & 0x80) >> 7 == 0) { + return; + } + sc_muladd(negKey, MINUS_ONE, ed_privkey, ZERO); + + for (uint8_t i = 0; i < 32; i++) { + ed_privkey[i] = negKey[i]; + } + + BigNumberUtil::unpackLE(a2, NUM_LIMBS_256BIT, negKey, 32); + Ed25519::mul(ptA2, a2); + Ed25519::encodePoint(ed_pubkey, ptA2); + if ((ed_pubkey[31] & 0x80) >> 7 == 0) { + } + + // Clean up and exit. + clean(a); + clean(ptA); +} + #endif void CryptoEngine::clearKeys() { diff --git a/src/mesh/CryptoEngine.h b/src/mesh/CryptoEngine.h index 6bbcb3b8a..c10a8e80b 100644 --- a/src/mesh/CryptoEngine.h +++ b/src/mesh/CryptoEngine.h @@ -35,6 +35,8 @@ class CryptoEngine #if !(MESHTASTIC_EXCLUDE_PKI_KEYGEN) virtual void generateKeyPair(uint8_t *pubKey, uint8_t *privKey); virtual bool regeneratePublicKey(uint8_t *pubKey, uint8_t *privKey); + bool xeddsa_sign(uint8_t *message, size_t len, uint8_t *signature); + bool xeddsa_verify(uint8_t *pubKey, uint8_t *message, size_t len, uint8_t *signature); #endif void clearKeys(); @@ -82,6 +84,10 @@ class CryptoEngine #if !(MESHTASTIC_EXCLUDE_PKI) uint8_t shared_key[32] = {0}; uint8_t private_key[32] = {0}; + uint8_t xeddsa_public_key[32] = {0}; + uint8_t xeddsa_private_key[32] = {0}; + void curve_to_ed_pub(uint8_t *curve_pubkey, uint8_t *ed_pubkey); + void priv_curve_to_ed_keys(uint8_t *curve_privkey, uint8_t *ed_privkey, uint8_t *ed_pubkey); #endif /** * Init our 128 bit nonce for a new packet diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 167dc1337..d608b044f 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -353,6 +353,9 @@ extern uint32_t error_address; #define NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_SHIFT 0 #define NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK (1 << NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_SHIFT) +#define NODEINFO_BITFIELD_HAS_XEDDSA_SIGNED_SHIFT 1 +#define NODEINFO_BITFIELD_HAS_XEDDSA_SIGNED_MASK (1 << NODEINFO_BITFIELD_HAS_XEDDSA_SIGNED_SHIFT) + #define Module_Config_size \ (ModuleConfig_CannedMessageConfig_size + ModuleConfig_ExternalNotificationConfig_size + ModuleConfig_MQTTConfig_size + \ ModuleConfig_RangeTestConfig_size + ModuleConfig_SerialConfig_size + ModuleConfig_StoreForwardConfig_size + \ diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 48205cc0f..113561f88 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -422,6 +422,25 @@ DecodeState perhapsDecode(meshtastic_MeshPacket *p) if (p->decoded.has_bitfield) p->decoded.want_response |= p->decoded.bitfield & BITFIELD_WANT_RESPONSE_MASK; + if (p->decoded.has_xeddsa_signature) { + LOG_WARN("packet shows XEdDSA"); + meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(p->from); + if (node && node->user.public_key.size == 32) { + LOG_WARN("attempting to verify"); + p->xeddsa_signed = crypto->xeddsa_verify(node->user.public_key.bytes, p->decoded.payload.bytes, + p->decoded.payload.size, p->decoded.xeddsa_signature.bytes); + } else { + LOG_WARN("Don't have key to verify"); + } + } + if (p->xeddsa_signed) { + LOG_WARN("Received XEdDSA Signed Packet!"); + } else if (p->decoded.has_xeddsa_signature) { + LOG_ERROR("Node sent signed packet, but cannot verify!"); + } else { + LOG_WARN("Received Unsigned Packet!"); + } + /* Not actually ever used. // Decompress if needed. jm if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_COMPRESSED_APP) { @@ -471,6 +490,12 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p) p->decoded.has_bitfield = true; p->decoded.bitfield |= (config.lora.config_ok_to_mqtt << BITFIELD_OK_TO_MQTT_SHIFT); p->decoded.bitfield |= (p->decoded.want_response << BITFIELD_WANT_RESPONSE_SHIFT); + if (p->pki_encrypted == false && isBroadcast(p->to) && p->decoded.payload.size < 120) { + crypto->xeddsa_sign(p->decoded.payload.bytes, p->decoded.payload.size, p->decoded.xeddsa_signature.bytes); + p->decoded.xeddsa_signature.size = 64; + p->decoded.has_xeddsa_signature = true; + LOG_WARN("XEDDSA Signed!"); + } } size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_Data_msg, &p->decoded); @@ -653,7 +678,9 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src) // call modules here if (!skipHandle) { - MeshModule::callModules(*p, src); + if (p->from != nodeDB->getNodeNum()) { + MeshModule::callModules(*p, src); + } #if !MESHTASTIC_EXCLUDE_MQTT // Mark as pki_encrypted if it is not yet decoded and MQTT encryption is also enabled, hash matches and it's a DM not to diff --git a/src/mesh/TypeConversions.cpp b/src/mesh/TypeConversions.cpp index 17cd92851..d0bb9d2e9 100644 --- a/src/mesh/TypeConversions.cpp +++ b/src/mesh/TypeConversions.cpp @@ -14,6 +14,7 @@ meshtastic_NodeInfo TypeConversions::ConvertToNodeInfo(const meshtastic_NodeInfo info.is_favorite = lite->is_favorite; info.is_ignored = lite->is_ignored; info.is_key_manually_verified = lite->bitfield & NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK; + info.has_xeddsa_signed = lite->bitfield & NODEINFO_BITFIELD_HAS_XEDDSA_SIGNED_MASK; if (lite->has_hops_away) { info.has_hops_away = true; diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index f47091384..b2bc16e36 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -362,7 +362,7 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg; #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size #define meshtastic_BackupPreferences_size 2271 #define meshtastic_ChannelFile_size 718 -#define meshtastic_DeviceState_size 1737 +#define meshtastic_DeviceState_size 1944 #define meshtastic_NodeInfoLite_size 196 #define meshtastic_PositionLite_size 28 #define meshtastic_UserLite_size 98 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 1d1ff47e0..71cf02d09 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -710,6 +710,7 @@ typedef struct _meshtastic_Routing { } meshtastic_Routing; typedef PB_BYTES_ARRAY_T(233) meshtastic_Data_payload_t; +typedef PB_BYTES_ARRAY_T(64) meshtastic_Data_xeddsa_signature_t; /* (Formerly called SubPacket) The payload portion fo a packet, this is the actual bytes that are sent inside a radio packet (because from/to are broken out by the comms library) */ @@ -743,6 +744,9 @@ typedef struct _meshtastic_Data { /* Bitfield for extra flags. First use is to indicate that user approves the packet being uploaded to MQTT. */ bool has_bitfield; uint8_t bitfield; + /* XEdDSA signature for the payload */ + bool has_xeddsa_signature; + meshtastic_Data_xeddsa_signature_t xeddsa_signature; } meshtastic_Data; typedef PB_BYTES_ARRAY_T(32) meshtastic_KeyVerification_hash1_t; @@ -885,6 +889,8 @@ typedef struct _meshtastic_MeshPacket { uint32_t tx_after; /* Indicates which transport mechanism this packet arrived over */ meshtastic_MeshPacket_TransportMechanism transport_mechanism; + /* Indicates whether the packet has a valid signature */ + bool xeddsa_signed; } meshtastic_MeshPacket; /* The bluetooth to device link: @@ -938,6 +944,10 @@ typedef struct _meshtastic_NodeInfo { Persists between NodeDB internal clean ups LSB 0 of the bitfield */ bool is_key_manually_verified; + /* True if node is signing its packets via XEdDSA + Persists between NodeDB internal clean ups + LSB 1 of the bitfield */ + bool has_xeddsa_signed; } meshtastic_NodeInfo; typedef PB_BYTES_ARRAY_T(16) meshtastic_MyNodeInfo_device_id_t; @@ -1350,12 +1360,12 @@ extern "C" { #define meshtastic_User_init_default {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} #define meshtastic_RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}} #define meshtastic_Routing_init_default {0, {meshtastic_RouteDiscovery_init_default}} -#define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0} +#define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0, false, {0, {0}}} #define meshtastic_KeyVerification_init_default {0, {0, {0}}, {0, {0}}} #define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0} #define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0} -#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN} -#define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0} +#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN, 0} +#define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0} #define meshtastic_MyNodeInfo_init_default {0, 0, 0, {0, {0}}, "", _meshtastic_FirmwareEdition_MIN, 0} #define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN} #define meshtastic_QueueStatus_init_default {0, 0, 0, 0} @@ -1381,12 +1391,12 @@ extern "C" { #define meshtastic_User_init_zero {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}, false, 0} #define meshtastic_RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}} #define meshtastic_Routing_init_zero {0, {meshtastic_RouteDiscovery_init_zero}} -#define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0} +#define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0, false, {0, {0}}} #define meshtastic_KeyVerification_init_zero {0, {0, {0}}, {0, {0}}} #define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0} #define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0} -#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN} -#define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0} +#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN, 0} +#define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0} #define meshtastic_MyNodeInfo_init_zero {0, 0, 0, {0, {0}}, "", _meshtastic_FirmwareEdition_MIN, 0} #define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN} #define meshtastic_QueueStatus_init_zero {0, 0, 0, 0} @@ -1458,6 +1468,7 @@ extern "C" { #define meshtastic_Data_reply_id_tag 7 #define meshtastic_Data_emoji_tag 8 #define meshtastic_Data_bitfield_tag 9 +#define meshtastic_Data_xeddsa_signature_tag 10 #define meshtastic_KeyVerification_nonce_tag 1 #define meshtastic_KeyVerification_hash1_tag 2 #define meshtastic_KeyVerification_hash2_tag 3 @@ -1494,6 +1505,7 @@ extern "C" { #define meshtastic_MeshPacket_relay_node_tag 19 #define meshtastic_MeshPacket_tx_after_tag 20 #define meshtastic_MeshPacket_transport_mechanism_tag 21 +#define meshtastic_MeshPacket_xeddsa_signed_tag 22 #define meshtastic_NodeInfo_num_tag 1 #define meshtastic_NodeInfo_user_tag 2 #define meshtastic_NodeInfo_position_tag 3 @@ -1506,6 +1518,7 @@ extern "C" { #define meshtastic_NodeInfo_is_favorite_tag 10 #define meshtastic_NodeInfo_is_ignored_tag 11 #define meshtastic_NodeInfo_is_key_manually_verified_tag 12 +#define meshtastic_NodeInfo_has_xeddsa_signed_tag 13 #define meshtastic_MyNodeInfo_my_node_num_tag 1 #define meshtastic_MyNodeInfo_reboot_count_tag 8 #define meshtastic_MyNodeInfo_min_app_version_tag 11 @@ -1666,7 +1679,8 @@ X(a, STATIC, SINGULAR, FIXED32, source, 5) \ X(a, STATIC, SINGULAR, FIXED32, request_id, 6) \ X(a, STATIC, SINGULAR, FIXED32, reply_id, 7) \ X(a, STATIC, SINGULAR, FIXED32, emoji, 8) \ -X(a, STATIC, OPTIONAL, UINT32, bitfield, 9) +X(a, STATIC, OPTIONAL, UINT32, bitfield, 9) \ +X(a, STATIC, OPTIONAL, BYTES, xeddsa_signature, 10) #define meshtastic_Data_CALLBACK NULL #define meshtastic_Data_DEFAULT NULL @@ -1718,7 +1732,8 @@ X(a, STATIC, SINGULAR, BOOL, pki_encrypted, 17) \ X(a, STATIC, SINGULAR, UINT32, next_hop, 18) \ X(a, STATIC, SINGULAR, UINT32, relay_node, 19) \ X(a, STATIC, SINGULAR, UINT32, tx_after, 20) \ -X(a, STATIC, SINGULAR, UENUM, transport_mechanism, 21) +X(a, STATIC, SINGULAR, UENUM, transport_mechanism, 21) \ +X(a, STATIC, SINGULAR, BOOL, xeddsa_signed, 22) #define meshtastic_MeshPacket_CALLBACK NULL #define meshtastic_MeshPacket_DEFAULT NULL #define meshtastic_MeshPacket_payload_variant_decoded_MSGTYPE meshtastic_Data @@ -1735,7 +1750,8 @@ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \ X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \ X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) \ X(a, STATIC, SINGULAR, BOOL, is_ignored, 11) \ -X(a, STATIC, SINGULAR, BOOL, is_key_manually_verified, 12) +X(a, STATIC, SINGULAR, BOOL, is_key_manually_verified, 12) \ +X(a, STATIC, SINGULAR, BOOL, has_xeddsa_signed, 13) #define meshtastic_NodeInfo_CALLBACK NULL #define meshtastic_NodeInfo_DEFAULT NULL #define meshtastic_NodeInfo_user_MSGTYPE meshtastic_User @@ -2018,7 +2034,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_ChunkedPayload_size 245 #define meshtastic_ClientNotification_size 482 #define meshtastic_Compressed_size 239 -#define meshtastic_Data_size 269 +#define meshtastic_Data_size 335 #define meshtastic_DeviceMetadata_size 54 #define meshtastic_DuplicatedPublicKey_size 0 #define meshtastic_FileInfo_size 236 @@ -2030,12 +2046,12 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_KeyVerification_size 79 #define meshtastic_LogRecord_size 426 #define meshtastic_LowEntropyKey_size 0 -#define meshtastic_MeshPacket_size 381 +#define meshtastic_MeshPacket_size 450 #define meshtastic_MqttClientProxyMessage_size 501 #define meshtastic_MyNodeInfo_size 83 #define meshtastic_NeighborInfo_size 258 #define meshtastic_Neighbor_size 22 -#define meshtastic_NodeInfo_size 323 +#define meshtastic_NodeInfo_size 325 #define meshtastic_NodeRemoteHardwarePin_size 29 #define meshtastic_Position_size 144 #define meshtastic_QueueStatus_size 23 diff --git a/src/mesh/xeddsa.cpp b/src/mesh/xeddsa.cpp new file mode 100644 index 000000000..fbe924712 --- /dev/null +++ b/src/mesh/xeddsa.cpp @@ -0,0 +1,1318 @@ +#include "xeddsa.h" + +static crypto_uint64 load_3(const unsigned char *in) +{ + crypto_uint64 result; + result = (crypto_uint64)in[0]; + result |= ((crypto_uint64)in[1]) << 8; + result |= ((crypto_uint64)in[2]) << 16; + return result; +} + +static crypto_uint64 load_4(const unsigned char *in) +{ + crypto_uint64 result; + result = (crypto_uint64)in[0]; + result |= ((crypto_uint64)in[1]) << 8; + result |= ((crypto_uint64)in[2]) << 16; + result |= ((crypto_uint64)in[3]) << 24; + return result; +} + +void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) +{ + crypto_int64 a0 = 2097151 & load_3(a); + crypto_int64 a1 = 2097151 & (load_4(a + 2) >> 5); + crypto_int64 a2 = 2097151 & (load_3(a + 5) >> 2); + crypto_int64 a3 = 2097151 & (load_4(a + 7) >> 7); + crypto_int64 a4 = 2097151 & (load_4(a + 10) >> 4); + crypto_int64 a5 = 2097151 & (load_3(a + 13) >> 1); + crypto_int64 a6 = 2097151 & (load_4(a + 15) >> 6); + crypto_int64 a7 = 2097151 & (load_3(a + 18) >> 3); + crypto_int64 a8 = 2097151 & load_3(a + 21); + crypto_int64 a9 = 2097151 & (load_4(a + 23) >> 5); + crypto_int64 a10 = 2097151 & (load_3(a + 26) >> 2); + crypto_int64 a11 = (load_4(a + 28) >> 7); + crypto_int64 b0 = 2097151 & load_3(b); + crypto_int64 b1 = 2097151 & (load_4(b + 2) >> 5); + crypto_int64 b2 = 2097151 & (load_3(b + 5) >> 2); + crypto_int64 b3 = 2097151 & (load_4(b + 7) >> 7); + crypto_int64 b4 = 2097151 & (load_4(b + 10) >> 4); + crypto_int64 b5 = 2097151 & (load_3(b + 13) >> 1); + crypto_int64 b6 = 2097151 & (load_4(b + 15) >> 6); + crypto_int64 b7 = 2097151 & (load_3(b + 18) >> 3); + crypto_int64 b8 = 2097151 & load_3(b + 21); + crypto_int64 b9 = 2097151 & (load_4(b + 23) >> 5); + crypto_int64 b10 = 2097151 & (load_3(b + 26) >> 2); + crypto_int64 b11 = (load_4(b + 28) >> 7); + crypto_int64 c0 = 2097151 & load_3(c); + crypto_int64 c1 = 2097151 & (load_4(c + 2) >> 5); + crypto_int64 c2 = 2097151 & (load_3(c + 5) >> 2); + crypto_int64 c3 = 2097151 & (load_4(c + 7) >> 7); + crypto_int64 c4 = 2097151 & (load_4(c + 10) >> 4); + crypto_int64 c5 = 2097151 & (load_3(c + 13) >> 1); + crypto_int64 c6 = 2097151 & (load_4(c + 15) >> 6); + crypto_int64 c7 = 2097151 & (load_3(c + 18) >> 3); + crypto_int64 c8 = 2097151 & load_3(c + 21); + crypto_int64 c9 = 2097151 & (load_4(c + 23) >> 5); + crypto_int64 c10 = 2097151 & (load_3(c + 26) >> 2); + crypto_int64 c11 = (load_4(c + 28) >> 7); + crypto_int64 s0; + crypto_int64 s1; + crypto_int64 s2; + crypto_int64 s3; + crypto_int64 s4; + crypto_int64 s5; + crypto_int64 s6; + crypto_int64 s7; + crypto_int64 s8; + crypto_int64 s9; + crypto_int64 s10; + crypto_int64 s11; + crypto_int64 s12; + crypto_int64 s13; + crypto_int64 s14; + crypto_int64 s15; + crypto_int64 s16; + crypto_int64 s17; + crypto_int64 s18; + crypto_int64 s19; + crypto_int64 s20; + crypto_int64 s21; + crypto_int64 s22; + crypto_int64 s23; + crypto_int64 carry0; + crypto_int64 carry1; + crypto_int64 carry2; + crypto_int64 carry3; + crypto_int64 carry4; + crypto_int64 carry5; + crypto_int64 carry6; + crypto_int64 carry7; + crypto_int64 carry8; + crypto_int64 carry9; + crypto_int64 carry10; + crypto_int64 carry11; + crypto_int64 carry12; + crypto_int64 carry13; + crypto_int64 carry14; + crypto_int64 carry15; + crypto_int64 carry16; + crypto_int64 carry17; + crypto_int64 carry18; + crypto_int64 carry19; + crypto_int64 carry20; + crypto_int64 carry21; + crypto_int64 carry22; + + s0 = c0 + a0 * b0; + s1 = c1 + a0 * b1 + a1 * b0; + s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0; + s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; + s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0; + s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0; + s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0; + s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0; + s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1 + a8 * b0; + s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0; + s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0; + s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + + a11 * b0; + s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1; + s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2; + s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + a9 * b5 + a10 * b4 + a11 * b3; + s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + a10 * b5 + a11 * b4; + s16 = a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5; + s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6; + s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7; + s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8; + s20 = a9 * b11 + a10 * b10 + a11 * b9; + s21 = a10 * b11 + a11 * b10; + s22 = a11 * b11; + s23 = 0; + + carry0 = (s0 + (1 << 20)) >> 21; + s1 += carry0; + s0 -= carry0 << 21; + carry2 = (s2 + (1 << 20)) >> 21; + s3 += carry2; + s2 -= carry2 << 21; + carry4 = (s4 + (1 << 20)) >> 21; + s5 += carry4; + s4 -= carry4 << 21; + carry6 = (s6 + (1 << 20)) >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; + s11 += carry10; + s10 -= carry10 << 21; + carry12 = (s12 + (1 << 20)) >> 21; + s13 += carry12; + s12 -= carry12 << 21; + carry14 = (s14 + (1 << 20)) >> 21; + s15 += carry14; + s14 -= carry14 << 21; + carry16 = (s16 + (1 << 20)) >> 21; + s17 += carry16; + s16 -= carry16 << 21; + carry18 = (s18 + (1 << 20)) >> 21; + s19 += carry18; + s18 -= carry18 << 21; + carry20 = (s20 + (1 << 20)) >> 21; + s21 += carry20; + s20 -= carry20 << 21; + carry22 = (s22 + (1 << 20)) >> 21; + s23 += carry22; + s22 -= carry22 << 21; + + carry1 = (s1 + (1 << 20)) >> 21; + s2 += carry1; + s1 -= carry1 << 21; + carry3 = (s3 + (1 << 20)) >> 21; + s4 += carry3; + s3 -= carry3 << 21; + carry5 = (s5 + (1 << 20)) >> 21; + s6 += carry5; + s5 -= carry5 << 21; + carry7 = (s7 + (1 << 20)) >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; + s12 += carry11; + s11 -= carry11 << 21; + carry13 = (s13 + (1 << 20)) >> 21; + s14 += carry13; + s13 -= carry13 << 21; + carry15 = (s15 + (1 << 20)) >> 21; + s16 += carry15; + s15 -= carry15 << 21; + carry17 = (s17 + (1 << 20)) >> 21; + s18 += carry17; + s17 -= carry17 << 21; + carry19 = (s19 + (1 << 20)) >> 21; + s20 += carry19; + s19 -= carry19 << 21; + carry21 = (s21 + (1 << 20)) >> 21; + s22 += carry21; + s21 -= carry21 << 21; + + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + s23 = 0; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + s22 = 0; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + s21 = 0; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + s20 = 0; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + s19 = 0; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + s18 = 0; + + carry6 = (s6 + (1 << 20)) >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; + s11 += carry10; + s10 -= carry10 << 21; + carry12 = (s12 + (1 << 20)) >> 21; + s13 += carry12; + s12 -= carry12 << 21; + carry14 = (s14 + (1 << 20)) >> 21; + s15 += carry14; + s14 -= carry14 << 21; + carry16 = (s16 + (1 << 20)) >> 21; + s17 += carry16; + s16 -= carry16 << 21; + + carry7 = (s7 + (1 << 20)) >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; + s12 += carry11; + s11 -= carry11 << 21; + carry13 = (s13 + (1 << 20)) >> 21; + s14 += carry13; + s13 -= carry13 << 21; + carry15 = (s15 + (1 << 20)) >> 21; + s16 += carry15; + s15 -= carry15 << 21; + + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + s17 = 0; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + s16 = 0; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + s15 = 0; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + s14 = 0; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + s13 = 0; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = (s0 + (1 << 20)) >> 21; + s1 += carry0; + s0 -= carry0 << 21; + carry2 = (s2 + (1 << 20)) >> 21; + s3 += carry2; + s2 -= carry2 << 21; + carry4 = (s4 + (1 << 20)) >> 21; + s5 += carry4; + s4 -= carry4 << 21; + carry6 = (s6 + (1 << 20)) >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; + s11 += carry10; + s10 -= carry10 << 21; + + carry1 = (s1 + (1 << 20)) >> 21; + s2 += carry1; + s1 -= carry1 << 21; + carry3 = (s3 + (1 << 20)) >> 21; + s4 += carry3; + s3 -= carry3 << 21; + carry5 = (s5 + (1 << 20)) >> 21; + s6 += carry5; + s5 -= carry5 << 21; + carry7 = (s7 + (1 << 20)) >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; + s12 += carry11; + s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 << 21; + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 << 21; + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 << 21; + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 << 21; + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 << 21; + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 << 21; + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 << 21; + carry11 = s11 >> 21; + s12 += carry11; + s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 << 21; + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 << 21; + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 << 21; + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 << 21; + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 << 21; + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 << 21; + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 << 21; + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 << 5); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 << 2); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 << 7); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 << 4); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 << 1); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 << 6); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 << 3); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 << 5); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 << 2); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 << 7); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +void fe_sub(fe h, fe f, fe g) +{ + crypto_int32 f0 = f[0]; + crypto_int32 f1 = f[1]; + crypto_int32 f2 = f[2]; + crypto_int32 f3 = f[3]; + crypto_int32 f4 = f[4]; + crypto_int32 f5 = f[5]; + crypto_int32 f6 = f[6]; + crypto_int32 f7 = f[7]; + crypto_int32 f8 = f[8]; + crypto_int32 f9 = f[9]; + crypto_int32 g0 = g[0]; + crypto_int32 g1 = g[1]; + crypto_int32 g2 = g[2]; + crypto_int32 g3 = g[3]; + crypto_int32 g4 = g[4]; + crypto_int32 g5 = g[5]; + crypto_int32 g6 = g[6]; + crypto_int32 g7 = g[7]; + crypto_int32 g8 = g[8]; + crypto_int32 g9 = g[9]; + crypto_int32 h0 = f0 - g0; + crypto_int32 h1 = f1 - g1; + crypto_int32 h2 = f2 - g2; + crypto_int32 h3 = f3 - g3; + crypto_int32 h4 = f4 - g4; + crypto_int32 h5 = f5 - g5; + crypto_int32 h6 = f6 - g6; + crypto_int32 h7 = f7 - g7; + crypto_int32 h8 = f8 - g8; + crypto_int32 h9 = f9 - g9; + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +void fe_frombytes(fe h, const unsigned char *s) +{ + crypto_int64 h0 = load_4(s); + crypto_int64 h1 = load_3(s + 4) << 6; + crypto_int64 h2 = load_3(s + 7) << 5; + crypto_int64 h3 = load_3(s + 10) << 3; + crypto_int64 h4 = load_3(s + 13) << 2; + crypto_int64 h5 = load_4(s + 16); + crypto_int64 h6 = load_3(s + 20) << 7; + crypto_int64 h7 = load_3(s + 23) << 5; + crypto_int64 h8 = load_3(s + 26) << 4; + crypto_int64 h9 = (load_3(s + 29) & 8388607) << 2; + crypto_int64 carry0; + crypto_int64 carry1; + crypto_int64 carry2; + crypto_int64 carry3; + crypto_int64 carry4; + crypto_int64 carry5; + crypto_int64 carry6; + crypto_int64 carry7; + crypto_int64 carry8; + crypto_int64 carry9; + + carry9 = (h9 + (crypto_int64)(1 << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 << 25; + carry1 = (h1 + (crypto_int64)(1 << 24)) >> 25; + h2 += carry1; + h1 -= carry1 << 25; + carry3 = (h3 + (crypto_int64)(1 << 24)) >> 25; + h4 += carry3; + h3 -= carry3 << 25; + carry5 = (h5 + (crypto_int64)(1 << 24)) >> 25; + h6 += carry5; + h5 -= carry5 << 25; + carry7 = (h7 + (crypto_int64)(1 << 24)) >> 25; + h8 += carry7; + h7 -= carry7 << 25; + + carry0 = (h0 + (crypto_int64)(1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + carry2 = (h2 + (crypto_int64)(1 << 25)) >> 26; + h3 += carry2; + h2 -= carry2 << 26; + carry4 = (h4 + (crypto_int64)(1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry6 = (h6 + (crypto_int64)(1 << 25)) >> 26; + h7 += carry6; + h6 -= carry6 << 26; + carry8 = (h8 + (crypto_int64)(1 << 25)) >> 26; + h9 += carry8; + h8 -= carry8 << 26; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +void fe_1(fe h) +{ + h[0] = 1; + h[1] = 0; + h[2] = 0; + h[3] = 0; + h[4] = 0; + h[5] = 0; + h[6] = 0; + h[7] = 0; + h[8] = 0; + h[9] = 0; +} + +void fe_add(fe h, const fe f, const fe g) +{ + crypto_int32 f0 = f[0]; + crypto_int32 f1 = f[1]; + crypto_int32 f2 = f[2]; + crypto_int32 f3 = f[3]; + crypto_int32 f4 = f[4]; + crypto_int32 f5 = f[5]; + crypto_int32 f6 = f[6]; + crypto_int32 f7 = f[7]; + crypto_int32 f8 = f[8]; + crypto_int32 f9 = f[9]; + crypto_int32 g0 = g[0]; + crypto_int32 g1 = g[1]; + crypto_int32 g2 = g[2]; + crypto_int32 g3 = g[3]; + crypto_int32 g4 = g[4]; + crypto_int32 g5 = g[5]; + crypto_int32 g6 = g[6]; + crypto_int32 g7 = g[7]; + crypto_int32 g8 = g[8]; + crypto_int32 g9 = g[9]; + crypto_int32 h0 = f0 + g0; + crypto_int32 h1 = f1 + g1; + crypto_int32 h2 = f2 + g2; + crypto_int32 h3 = f3 + g3; + crypto_int32 h4 = f4 + g4; + crypto_int32 h5 = f5 + g5; + crypto_int32 h6 = f6 + g6; + crypto_int32 h7 = f7 + g7; + crypto_int32 h8 = f8 + g8; + crypto_int32 h9 = f9 + g9; + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +void fe_sq(fe h, const fe f) +{ + crypto_int32 f0 = f[0]; + crypto_int32 f1 = f[1]; + crypto_int32 f2 = f[2]; + crypto_int32 f3 = f[3]; + crypto_int32 f4 = f[4]; + crypto_int32 f5 = f[5]; + crypto_int32 f6 = f[6]; + crypto_int32 f7 = f[7]; + crypto_int32 f8 = f[8]; + crypto_int32 f9 = f[9]; + crypto_int32 f0_2 = 2 * f0; + crypto_int32 f1_2 = 2 * f1; + crypto_int32 f2_2 = 2 * f2; + crypto_int32 f3_2 = 2 * f3; + crypto_int32 f4_2 = 2 * f4; + crypto_int32 f5_2 = 2 * f5; + crypto_int32 f6_2 = 2 * f6; + crypto_int32 f7_2 = 2 * f7; + crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */ + crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */ + crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */ + crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */ + crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */ + crypto_int64 f0f0 = f0 * (crypto_int64)f0; + crypto_int64 f0f1_2 = f0_2 * (crypto_int64)f1; + crypto_int64 f0f2_2 = f0_2 * (crypto_int64)f2; + crypto_int64 f0f3_2 = f0_2 * (crypto_int64)f3; + crypto_int64 f0f4_2 = f0_2 * (crypto_int64)f4; + crypto_int64 f0f5_2 = f0_2 * (crypto_int64)f5; + crypto_int64 f0f6_2 = f0_2 * (crypto_int64)f6; + crypto_int64 f0f7_2 = f0_2 * (crypto_int64)f7; + crypto_int64 f0f8_2 = f0_2 * (crypto_int64)f8; + crypto_int64 f0f9_2 = f0_2 * (crypto_int64)f9; + crypto_int64 f1f1_2 = f1_2 * (crypto_int64)f1; + crypto_int64 f1f2_2 = f1_2 * (crypto_int64)f2; + crypto_int64 f1f3_4 = f1_2 * (crypto_int64)f3_2; + crypto_int64 f1f4_2 = f1_2 * (crypto_int64)f4; + crypto_int64 f1f5_4 = f1_2 * (crypto_int64)f5_2; + crypto_int64 f1f6_2 = f1_2 * (crypto_int64)f6; + crypto_int64 f1f7_4 = f1_2 * (crypto_int64)f7_2; + crypto_int64 f1f8_2 = f1_2 * (crypto_int64)f8; + crypto_int64 f1f9_76 = f1_2 * (crypto_int64)f9_38; + crypto_int64 f2f2 = f2 * (crypto_int64)f2; + crypto_int64 f2f3_2 = f2_2 * (crypto_int64)f3; + crypto_int64 f2f4_2 = f2_2 * (crypto_int64)f4; + crypto_int64 f2f5_2 = f2_2 * (crypto_int64)f5; + crypto_int64 f2f6_2 = f2_2 * (crypto_int64)f6; + crypto_int64 f2f7_2 = f2_2 * (crypto_int64)f7; + crypto_int64 f2f8_38 = f2_2 * (crypto_int64)f8_19; + crypto_int64 f2f9_38 = f2 * (crypto_int64)f9_38; + crypto_int64 f3f3_2 = f3_2 * (crypto_int64)f3; + crypto_int64 f3f4_2 = f3_2 * (crypto_int64)f4; + crypto_int64 f3f5_4 = f3_2 * (crypto_int64)f5_2; + crypto_int64 f3f6_2 = f3_2 * (crypto_int64)f6; + crypto_int64 f3f7_76 = f3_2 * (crypto_int64)f7_38; + crypto_int64 f3f8_38 = f3_2 * (crypto_int64)f8_19; + crypto_int64 f3f9_76 = f3_2 * (crypto_int64)f9_38; + crypto_int64 f4f4 = f4 * (crypto_int64)f4; + crypto_int64 f4f5_2 = f4_2 * (crypto_int64)f5; + crypto_int64 f4f6_38 = f4_2 * (crypto_int64)f6_19; + crypto_int64 f4f7_38 = f4 * (crypto_int64)f7_38; + crypto_int64 f4f8_38 = f4_2 * (crypto_int64)f8_19; + crypto_int64 f4f9_38 = f4 * (crypto_int64)f9_38; + crypto_int64 f5f5_38 = f5 * (crypto_int64)f5_38; + crypto_int64 f5f6_38 = f5_2 * (crypto_int64)f6_19; + crypto_int64 f5f7_76 = f5_2 * (crypto_int64)f7_38; + crypto_int64 f5f8_38 = f5_2 * (crypto_int64)f8_19; + crypto_int64 f5f9_76 = f5_2 * (crypto_int64)f9_38; + crypto_int64 f6f6_19 = f6 * (crypto_int64)f6_19; + crypto_int64 f6f7_38 = f6 * (crypto_int64)f7_38; + crypto_int64 f6f8_38 = f6_2 * (crypto_int64)f8_19; + crypto_int64 f6f9_38 = f6 * (crypto_int64)f9_38; + crypto_int64 f7f7_38 = f7 * (crypto_int64)f7_38; + crypto_int64 f7f8_38 = f7_2 * (crypto_int64)f8_19; + crypto_int64 f7f9_76 = f7_2 * (crypto_int64)f9_38; + crypto_int64 f8f8_19 = f8 * (crypto_int64)f8_19; + crypto_int64 f8f9_38 = f8 * (crypto_int64)f9_38; + crypto_int64 f9f9_38 = f9 * (crypto_int64)f9_38; + crypto_int64 h0 = f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38; + crypto_int64 h1 = f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38; + crypto_int64 h2 = f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19; + crypto_int64 h3 = f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38; + crypto_int64 h4 = f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38; + crypto_int64 h5 = f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38; + crypto_int64 h6 = f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19; + crypto_int64 h7 = f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38; + crypto_int64 h8 = f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38; + crypto_int64 h9 = f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2; + crypto_int64 carry0; + crypto_int64 carry1; + crypto_int64 carry2; + crypto_int64 carry3; + crypto_int64 carry4; + crypto_int64 carry5; + crypto_int64 carry6; + crypto_int64 carry7; + crypto_int64 carry8; + crypto_int64 carry9; + + carry0 = (h0 + (crypto_int64)(1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + carry4 = (h4 + (crypto_int64)(1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + + carry1 = (h1 + (crypto_int64)(1 << 24)) >> 25; + h2 += carry1; + h1 -= carry1 << 25; + carry5 = (h5 + (crypto_int64)(1 << 24)) >> 25; + h6 += carry5; + h5 -= carry5 << 25; + + carry2 = (h2 + (crypto_int64)(1 << 25)) >> 26; + h3 += carry2; + h2 -= carry2 << 26; + carry6 = (h6 + (crypto_int64)(1 << 25)) >> 26; + h7 += carry6; + h6 -= carry6 << 26; + + carry3 = (h3 + (crypto_int64)(1 << 24)) >> 25; + h4 += carry3; + h3 -= carry3 << 25; + carry7 = (h7 + (crypto_int64)(1 << 24)) >> 25; + h8 += carry7; + h7 -= carry7 << 25; + + carry4 = (h4 + (crypto_int64)(1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry8 = (h8 + (crypto_int64)(1 << 25)) >> 26; + h9 += carry8; + h8 -= carry8 << 26; + + carry9 = (h9 + (crypto_int64)(1 << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 << 25; + + carry0 = (h0 + (crypto_int64)(1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +void fe_mul(fe h, const fe f, const fe g) +{ + crypto_int32 f0 = f[0]; + crypto_int32 f1 = f[1]; + crypto_int32 f2 = f[2]; + crypto_int32 f3 = f[3]; + crypto_int32 f4 = f[4]; + crypto_int32 f5 = f[5]; + crypto_int32 f6 = f[6]; + crypto_int32 f7 = f[7]; + crypto_int32 f8 = f[8]; + crypto_int32 f9 = f[9]; + crypto_int32 g0 = g[0]; + crypto_int32 g1 = g[1]; + crypto_int32 g2 = g[2]; + crypto_int32 g3 = g[3]; + crypto_int32 g4 = g[4]; + crypto_int32 g5 = g[5]; + crypto_int32 g6 = g[6]; + crypto_int32 g7 = g[7]; + crypto_int32 g8 = g[8]; + crypto_int32 g9 = g[9]; + crypto_int32 g1_19 = 19 * g1; /* 1.959375*2^29 */ + crypto_int32 g2_19 = 19 * g2; /* 1.959375*2^30; still ok */ + crypto_int32 g3_19 = 19 * g3; + crypto_int32 g4_19 = 19 * g4; + crypto_int32 g5_19 = 19 * g5; + crypto_int32 g6_19 = 19 * g6; + crypto_int32 g7_19 = 19 * g7; + crypto_int32 g8_19 = 19 * g8; + crypto_int32 g9_19 = 19 * g9; + crypto_int32 f1_2 = 2 * f1; + crypto_int32 f3_2 = 2 * f3; + crypto_int32 f5_2 = 2 * f5; + crypto_int32 f7_2 = 2 * f7; + crypto_int32 f9_2 = 2 * f9; + crypto_int64 f0g0 = f0 * (crypto_int64)g0; + crypto_int64 f0g1 = f0 * (crypto_int64)g1; + crypto_int64 f0g2 = f0 * (crypto_int64)g2; + crypto_int64 f0g3 = f0 * (crypto_int64)g3; + crypto_int64 f0g4 = f0 * (crypto_int64)g4; + crypto_int64 f0g5 = f0 * (crypto_int64)g5; + crypto_int64 f0g6 = f0 * (crypto_int64)g6; + crypto_int64 f0g7 = f0 * (crypto_int64)g7; + crypto_int64 f0g8 = f0 * (crypto_int64)g8; + crypto_int64 f0g9 = f0 * (crypto_int64)g9; + crypto_int64 f1g0 = f1 * (crypto_int64)g0; + crypto_int64 f1g1_2 = f1_2 * (crypto_int64)g1; + crypto_int64 f1g2 = f1 * (crypto_int64)g2; + crypto_int64 f1g3_2 = f1_2 * (crypto_int64)g3; + crypto_int64 f1g4 = f1 * (crypto_int64)g4; + crypto_int64 f1g5_2 = f1_2 * (crypto_int64)g5; + crypto_int64 f1g6 = f1 * (crypto_int64)g6; + crypto_int64 f1g7_2 = f1_2 * (crypto_int64)g7; + crypto_int64 f1g8 = f1 * (crypto_int64)g8; + crypto_int64 f1g9_38 = f1_2 * (crypto_int64)g9_19; + crypto_int64 f2g0 = f2 * (crypto_int64)g0; + crypto_int64 f2g1 = f2 * (crypto_int64)g1; + crypto_int64 f2g2 = f2 * (crypto_int64)g2; + crypto_int64 f2g3 = f2 * (crypto_int64)g3; + crypto_int64 f2g4 = f2 * (crypto_int64)g4; + crypto_int64 f2g5 = f2 * (crypto_int64)g5; + crypto_int64 f2g6 = f2 * (crypto_int64)g6; + crypto_int64 f2g7 = f2 * (crypto_int64)g7; + crypto_int64 f2g8_19 = f2 * (crypto_int64)g8_19; + crypto_int64 f2g9_19 = f2 * (crypto_int64)g9_19; + crypto_int64 f3g0 = f3 * (crypto_int64)g0; + crypto_int64 f3g1_2 = f3_2 * (crypto_int64)g1; + crypto_int64 f3g2 = f3 * (crypto_int64)g2; + crypto_int64 f3g3_2 = f3_2 * (crypto_int64)g3; + crypto_int64 f3g4 = f3 * (crypto_int64)g4; + crypto_int64 f3g5_2 = f3_2 * (crypto_int64)g5; + crypto_int64 f3g6 = f3 * (crypto_int64)g6; + crypto_int64 f3g7_38 = f3_2 * (crypto_int64)g7_19; + crypto_int64 f3g8_19 = f3 * (crypto_int64)g8_19; + crypto_int64 f3g9_38 = f3_2 * (crypto_int64)g9_19; + crypto_int64 f4g0 = f4 * (crypto_int64)g0; + crypto_int64 f4g1 = f4 * (crypto_int64)g1; + crypto_int64 f4g2 = f4 * (crypto_int64)g2; + crypto_int64 f4g3 = f4 * (crypto_int64)g3; + crypto_int64 f4g4 = f4 * (crypto_int64)g4; + crypto_int64 f4g5 = f4 * (crypto_int64)g5; + crypto_int64 f4g6_19 = f4 * (crypto_int64)g6_19; + crypto_int64 f4g7_19 = f4 * (crypto_int64)g7_19; + crypto_int64 f4g8_19 = f4 * (crypto_int64)g8_19; + crypto_int64 f4g9_19 = f4 * (crypto_int64)g9_19; + crypto_int64 f5g0 = f5 * (crypto_int64)g0; + crypto_int64 f5g1_2 = f5_2 * (crypto_int64)g1; + crypto_int64 f5g2 = f5 * (crypto_int64)g2; + crypto_int64 f5g3_2 = f5_2 * (crypto_int64)g3; + crypto_int64 f5g4 = f5 * (crypto_int64)g4; + crypto_int64 f5g5_38 = f5_2 * (crypto_int64)g5_19; + crypto_int64 f5g6_19 = f5 * (crypto_int64)g6_19; + crypto_int64 f5g7_38 = f5_2 * (crypto_int64)g7_19; + crypto_int64 f5g8_19 = f5 * (crypto_int64)g8_19; + crypto_int64 f5g9_38 = f5_2 * (crypto_int64)g9_19; + crypto_int64 f6g0 = f6 * (crypto_int64)g0; + crypto_int64 f6g1 = f6 * (crypto_int64)g1; + crypto_int64 f6g2 = f6 * (crypto_int64)g2; + crypto_int64 f6g3 = f6 * (crypto_int64)g3; + crypto_int64 f6g4_19 = f6 * (crypto_int64)g4_19; + crypto_int64 f6g5_19 = f6 * (crypto_int64)g5_19; + crypto_int64 f6g6_19 = f6 * (crypto_int64)g6_19; + crypto_int64 f6g7_19 = f6 * (crypto_int64)g7_19; + crypto_int64 f6g8_19 = f6 * (crypto_int64)g8_19; + crypto_int64 f6g9_19 = f6 * (crypto_int64)g9_19; + crypto_int64 f7g0 = f7 * (crypto_int64)g0; + crypto_int64 f7g1_2 = f7_2 * (crypto_int64)g1; + crypto_int64 f7g2 = f7 * (crypto_int64)g2; + crypto_int64 f7g3_38 = f7_2 * (crypto_int64)g3_19; + crypto_int64 f7g4_19 = f7 * (crypto_int64)g4_19; + crypto_int64 f7g5_38 = f7_2 * (crypto_int64)g5_19; + crypto_int64 f7g6_19 = f7 * (crypto_int64)g6_19; + crypto_int64 f7g7_38 = f7_2 * (crypto_int64)g7_19; + crypto_int64 f7g8_19 = f7 * (crypto_int64)g8_19; + crypto_int64 f7g9_38 = f7_2 * (crypto_int64)g9_19; + crypto_int64 f8g0 = f8 * (crypto_int64)g0; + crypto_int64 f8g1 = f8 * (crypto_int64)g1; + crypto_int64 f8g2_19 = f8 * (crypto_int64)g2_19; + crypto_int64 f8g3_19 = f8 * (crypto_int64)g3_19; + crypto_int64 f8g4_19 = f8 * (crypto_int64)g4_19; + crypto_int64 f8g5_19 = f8 * (crypto_int64)g5_19; + crypto_int64 f8g6_19 = f8 * (crypto_int64)g6_19; + crypto_int64 f8g7_19 = f8 * (crypto_int64)g7_19; + crypto_int64 f8g8_19 = f8 * (crypto_int64)g8_19; + crypto_int64 f8g9_19 = f8 * (crypto_int64)g9_19; + crypto_int64 f9g0 = f9 * (crypto_int64)g0; + crypto_int64 f9g1_38 = f9_2 * (crypto_int64)g1_19; + crypto_int64 f9g2_19 = f9 * (crypto_int64)g2_19; + crypto_int64 f9g3_38 = f9_2 * (crypto_int64)g3_19; + crypto_int64 f9g4_19 = f9 * (crypto_int64)g4_19; + crypto_int64 f9g5_38 = f9_2 * (crypto_int64)g5_19; + crypto_int64 f9g6_19 = f9 * (crypto_int64)g6_19; + crypto_int64 f9g7_38 = f9_2 * (crypto_int64)g7_19; + crypto_int64 f9g8_19 = f9 * (crypto_int64)g8_19; + crypto_int64 f9g9_38 = f9_2 * (crypto_int64)g9_19; + crypto_int64 h0 = f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38; + crypto_int64 h1 = f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19; + crypto_int64 h2 = f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38; + crypto_int64 h3 = f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19; + crypto_int64 h4 = f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38; + crypto_int64 h5 = f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19; + crypto_int64 h6 = f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38; + crypto_int64 h7 = f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19; + crypto_int64 h8 = f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38; + crypto_int64 h9 = f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0; + crypto_int64 carry0; + crypto_int64 carry1; + crypto_int64 carry2; + crypto_int64 carry3; + crypto_int64 carry4; + crypto_int64 carry5; + crypto_int64 carry6; + crypto_int64 carry7; + crypto_int64 carry8; + crypto_int64 carry9; + + /* + |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38)) + i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8 + |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19)) + i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 + */ + + carry0 = (h0 + (crypto_int64)(1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + carry4 = (h4 + (crypto_int64)(1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + /* |h0| <= 2^25 */ + /* |h4| <= 2^25 */ + /* |h1| <= 1.71*2^59 */ + /* |h5| <= 1.71*2^59 */ + + carry1 = (h1 + (crypto_int64)(1 << 24)) >> 25; + h2 += carry1; + h1 -= carry1 << 25; + carry5 = (h5 + (crypto_int64)(1 << 24)) >> 25; + h6 += carry5; + h5 -= carry5 << 25; + /* |h1| <= 2^24; from now on fits into int32 */ + /* |h5| <= 2^24; from now on fits into int32 */ + /* |h2| <= 1.41*2^60 */ + /* |h6| <= 1.41*2^60 */ + + carry2 = (h2 + (crypto_int64)(1 << 25)) >> 26; + h3 += carry2; + h2 -= carry2 << 26; + carry6 = (h6 + (crypto_int64)(1 << 25)) >> 26; + h7 += carry6; + h6 -= carry6 << 26; + /* |h2| <= 2^25; from now on fits into int32 unchanged */ + /* |h6| <= 2^25; from now on fits into int32 unchanged */ + /* |h3| <= 1.71*2^59 */ + /* |h7| <= 1.71*2^59 */ + + carry3 = (h3 + (crypto_int64)(1 << 24)) >> 25; + h4 += carry3; + h3 -= carry3 << 25; + carry7 = (h7 + (crypto_int64)(1 << 24)) >> 25; + h8 += carry7; + h7 -= carry7 << 25; + /* |h3| <= 2^24; from now on fits into int32 unchanged */ + /* |h7| <= 2^24; from now on fits into int32 unchanged */ + /* |h4| <= 1.72*2^34 */ + /* |h8| <= 1.41*2^60 */ + + carry4 = (h4 + (crypto_int64)(1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry8 = (h8 + (crypto_int64)(1 << 25)) >> 26; + h9 += carry8; + h8 -= carry8 << 26; + /* |h4| <= 2^25; from now on fits into int32 unchanged */ + /* |h8| <= 2^25; from now on fits into int32 unchanged */ + /* |h5| <= 1.01*2^24 */ + /* |h9| <= 1.71*2^59 */ + + carry9 = (h9 + (crypto_int64)(1 << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 << 25; + /* |h9| <= 2^24; from now on fits into int32 unchanged */ + /* |h0| <= 1.1*2^39 */ + + carry0 = (h0 + (crypto_int64)(1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + /* |h0| <= 2^25; from now on fits into int32 unchanged */ + /* |h1| <= 1.01*2^24 */ + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +void fe_invert(fe out, const fe z) +{ + fe t0; + fe t1; + fe t2; + fe t3; + int i; + + /* qhasm: z2 = z1^2^1 */ + /* asm 1: fe_sq(>z2=fe#1,z2=fe#1,>z2=fe#1); */ + /* asm 2: fe_sq(>z2=t0,z2=t0,>z2=t0); */ + fe_sq(t0, z); + for (i = 1; i < 1; ++i) + fe_sq(t0, t0); + + /* qhasm: z8 = z2^2^2 */ + /* asm 1: fe_sq(>z8=fe#2,z8=fe#2,>z8=fe#2); */ + /* asm 2: fe_sq(>z8=t1,z8=t1,>z8=t1); */ + fe_sq(t1, t0); + for (i = 1; i < 2; ++i) + fe_sq(t1, t1); + + /* qhasm: z9 = z1*z8 */ + /* asm 1: fe_mul(>z9=fe#2,z9=t1,z11=fe#1,z11=t0,z22=fe#3,z22=fe#3,>z22=fe#3); */ + /* asm 2: fe_sq(>z22=t2,z22=t2,>z22=t2); */ + fe_sq(t2, t0); + for (i = 1; i < 1; ++i) + fe_sq(t2, t2); + + /* qhasm: z_5_0 = z9*z22 */ + /* asm 1: fe_mul(>z_5_0=fe#2,z_5_0=t1,z_10_5=fe#3,z_10_5=fe#3,>z_10_5=fe#3); */ + /* asm 2: fe_sq(>z_10_5=t2,z_10_5=t2,>z_10_5=t2); */ + fe_sq(t2, t1); + for (i = 1; i < 5; ++i) + fe_sq(t2, t2); + + /* qhasm: z_10_0 = z_10_5*z_5_0 */ + /* asm 1: fe_mul(>z_10_0=fe#2,z_10_0=t1,z_20_10=fe#3,z_20_10=fe#3,>z_20_10=fe#3); */ + /* asm 2: fe_sq(>z_20_10=t2,z_20_10=t2,>z_20_10=t2); */ + fe_sq(t2, t1); + for (i = 1; i < 10; ++i) + fe_sq(t2, t2); + + /* qhasm: z_20_0 = z_20_10*z_10_0 */ + /* asm 1: fe_mul(>z_20_0=fe#3,z_20_0=t2,z_40_20=fe#4,z_40_20=fe#4,>z_40_20=fe#4); */ + /* asm 2: fe_sq(>z_40_20=t3,z_40_20=t3,>z_40_20=t3); */ + fe_sq(t3, t2); + for (i = 1; i < 20; ++i) + fe_sq(t3, t3); + + /* qhasm: z_40_0 = z_40_20*z_20_0 */ + /* asm 1: fe_mul(>z_40_0=fe#3,z_40_0=t2,z_50_10=fe#3,z_50_10=fe#3,>z_50_10=fe#3); */ + /* asm 2: fe_sq(>z_50_10=t2,z_50_10=t2,>z_50_10=t2); */ + fe_sq(t2, t2); + for (i = 1; i < 10; ++i) + fe_sq(t2, t2); + + /* qhasm: z_50_0 = z_50_10*z_10_0 */ + /* asm 1: fe_mul(>z_50_0=fe#2,z_50_0=t1,z_100_50=fe#3,z_100_50=fe#3,>z_100_50=fe#3); */ + /* asm 2: fe_sq(>z_100_50=t2,z_100_50=t2,>z_100_50=t2); */ + fe_sq(t2, t1); + for (i = 1; i < 50; ++i) + fe_sq(t2, t2); + + /* qhasm: z_100_0 = z_100_50*z_50_0 */ + /* asm 1: fe_mul(>z_100_0=fe#3,z_100_0=t2,z_200_100=fe#4,z_200_100=fe#4,>z_200_100=fe#4); */ + /* asm 2: fe_sq(>z_200_100=t3,z_200_100=t3,>z_200_100=t3); */ + fe_sq(t3, t2); + for (i = 1; i < 100; ++i) + fe_sq(t3, t3); + + /* qhasm: z_200_0 = z_200_100*z_100_0 */ + /* asm 1: fe_mul(>z_200_0=fe#3,z_200_0=t2,z_250_50=fe#3,z_250_50=fe#3,>z_250_50=fe#3); */ + /* asm 2: fe_sq(>z_250_50=t2,z_250_50=t2,>z_250_50=t2); */ + fe_sq(t2, t2); + for (i = 1; i < 50; ++i) + fe_sq(t2, t2); + + /* qhasm: z_250_0 = z_250_50*z_50_0 */ + /* asm 1: fe_mul(>z_250_0=fe#2,z_250_0=t1,z_255_5=fe#2,z_255_5=fe#2,>z_255_5=fe#2); */ + /* asm 2: fe_sq(>z_255_5=t1,z_255_5=t1,>z_255_5=t1); */ + fe_sq(t1, t1); + for (i = 1; i < 5; ++i) + fe_sq(t1, t1); + + /* qhasm: z_255_21 = z_255_5*z11 */ + /* asm 1: fe_mul(>z_255_21=fe#12,z_255_21=out,> 25; + q = (h0 + q) >> 26; + q = (h1 + q) >> 25; + q = (h2 + q) >> 26; + q = (h3 + q) >> 25; + q = (h4 + q) >> 26; + q = (h5 + q) >> 25; + q = (h6 + q) >> 26; + q = (h7 + q) >> 25; + q = (h8 + q) >> 26; + q = (h9 + q) >> 25; + + /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */ + h0 += 19 * q; + /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ + + carry0 = h0 >> 26; + h1 += carry0; + h0 -= carry0 << 26; + carry1 = h1 >> 25; + h2 += carry1; + h1 -= carry1 << 25; + carry2 = h2 >> 26; + h3 += carry2; + h2 -= carry2 << 26; + carry3 = h3 >> 25; + h4 += carry3; + h3 -= carry3 << 25; + carry4 = h4 >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry5 = h5 >> 25; + h6 += carry5; + h5 -= carry5 << 25; + carry6 = h6 >> 26; + h7 += carry6; + h6 -= carry6 << 26; + carry7 = h7 >> 25; + h8 += carry7; + h7 -= carry7 << 25; + carry8 = h8 >> 26; + h9 += carry8; + h8 -= carry8 << 26; + carry9 = h9 >> 25; + h9 -= carry9 << 25; + /* h10 = carry9 */ + + /* + Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. + Have h0+...+2^230 h9 between 0 and 2^255-1; + evidently 2^255 h10-2^255 q = 0. + Goal: Output h0+...+2^230 h9. + */ + + s[0] = h0 >> 0; + s[1] = h0 >> 8; + s[2] = h0 >> 16; + s[3] = (h0 >> 24) | (h1 << 2); + s[4] = h1 >> 6; + s[5] = h1 >> 14; + s[6] = (h1 >> 22) | (h2 << 3); + s[7] = h2 >> 5; + s[8] = h2 >> 13; + s[9] = (h2 >> 21) | (h3 << 5); + s[10] = h3 >> 3; + s[11] = h3 >> 11; + s[12] = (h3 >> 19) | (h4 << 6); + s[13] = h4 >> 2; + s[14] = h4 >> 10; + s[15] = h4 >> 18; + s[16] = h5 >> 0; + s[17] = h5 >> 8; + s[18] = h5 >> 16; + s[19] = (h5 >> 24) | (h6 << 1); + s[20] = h6 >> 7; + s[21] = h6 >> 15; + s[22] = (h6 >> 23) | (h7 << 3); + s[23] = h7 >> 5; + s[24] = h7 >> 13; + s[25] = (h7 >> 21) | (h8 << 4); + s[26] = h8 >> 4; + s[27] = h8 >> 12; + s[28] = (h8 >> 20) | (h9 << 6); + s[29] = h9 >> 2; + s[30] = h9 >> 10; + s[31] = h9 >> 18; +} \ No newline at end of file diff --git a/src/mesh/xeddsa.h b/src/mesh/xeddsa.h new file mode 100644 index 000000000..df9495482 --- /dev/null +++ b/src/mesh/xeddsa.h @@ -0,0 +1,40 @@ +#include +// imported from SUPERCOP by Daniel J. Bernstein which is public domain + +// Byte-representation of the scalar value of 0 on the Ed25519 curve. Needed by `sc_neg`. +static const uint8_t ZERO[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +// Byte-representation of the scalar value of -1 on the Ed25519 curve. Needed by `sc_neg`. +static const uint8_t MINUS_ONE[32] = {0xec, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, + 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; + +typedef uint64_t crypto_uint64; +typedef int64_t crypto_int64; + +typedef int32_t crypto_int32; + +typedef crypto_int32 fe[10]; + +static crypto_uint64 load_3(const unsigned char *in); + +static crypto_uint64 load_4(const unsigned char *in); + +void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c); + +void fe_sub(fe h, fe f, fe g); + +void fe_frombytes(fe h, const unsigned char *s); + +void fe_1(fe h); + +void fe_add(fe h, const fe f, const fe g); + +void fe_sq(fe h, const fe f); + +void fe_mul(fe h, const fe f, const fe g); + +void fe_invert(fe out, const fe z); + +void fe_tobytes(unsigned char *s, const fe h); \ No newline at end of file diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index b6fee7703..bf6864b23 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -18,6 +18,10 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes LOG_WARN("Invalid nodeInfo detected, is_licensed mismatch!"); return true; } + NodeNum sourceNum = getFrom(&mp); + auto node = nodeDB->getMeshNode(sourceNum); + if ((node->bitfield & NODEINFO_BITFIELD_HAS_XEDDSA_SIGNED_MASK) && !mp.xeddsa_signed) + return true; // Coerce user.id to be derived from the node number snprintf(p.id, sizeof(p.id), "!%08x", getFrom(&mp)); diff --git a/test/test_crypto/test_main.cpp b/test/test_crypto/test_main.cpp index 36dc37b9d..a04c823a1 100644 --- a/test/test_crypto/test_main.cpp +++ b/test/test_crypto/test_main.cpp @@ -152,6 +152,31 @@ void test_PKC(void) TEST_ASSERT_EQUAL_MEMORY(expected_decrypted, decrypted, 10); } +void test_XEdDSA(void) +{ + uint8_t private_key[32]; + uint8_t x_public_key[32]; + uint8_t ed_private_key[32]; + uint8_t ed_public_key[32]; + uint8_t ed_public_key2[32]; + meshtastic_UserLite_public_key_t public_key; + uint8_t message[] = "This is a test!"; + uint8_t message2[] = "This is a test."; + uint8_t signature[64]; + for (int times = 0; times < 10; times++) { + printf("Start of time %u\n", times); + crypto->generateKeyPair(x_public_key, private_key); + // crypto->setDHPrivateKey(private_key); + crypto->priv_curve_to_ed_keys(private_key, ed_private_key, ed_public_key); + crypto->curve_to_ed_pub(x_public_key, ed_public_key2); + TEST_ASSERT_EQUAL_MEMORY(ed_public_key, ed_public_key2, 32); + + crypto->xeddsa_sign(private_key, message, sizeof(message), signature); + TEST_ASSERT(crypto->xeddsa_verify(x_public_key, message, sizeof(message), signature)); + TEST_ASSERT_FALSE(crypto->xeddsa_verify(x_public_key, message2, sizeof(message), signature)); + } +} + void test_AES_CTR(void) { uint8_t expected[32]; @@ -192,6 +217,7 @@ void setup() RUN_TEST(test_DH25519); RUN_TEST(test_AES_CTR); RUN_TEST(test_PKC); + RUN_TEST(test_XEdDSA); exit(UNITY_END()); // stop unit testing }