Micropython package for doing fast rsa and elliptic curve cryptography, specifically digital signatures. ECDSA API design inspired from fastecdsa and implementation based on tomsfastmath.
[!TIP] If you find ucrypto useful, consider :star: this project and why not ... Buy me a coffee :smile:
Signing and Verifying ufastrsa
from ufastrsa.rsa import RSA, genrsa
def main():
bits = 1024
print("RSA bits", bits)
r = RSA(*genrsa(bits, e=65537))
if r:
print("RSA OK")
data = b"a message to sign and encrypt via RSA"
print("random data len:", len(data), data)
assert r.pkcs_verify(r.pkcs_sign(data)) == data
print("pkcs_verify OK")
assert r.pkcs_decrypt(r.pkcs_encrypt(data)) == data
print("pkcs_decrypt OK")
if __name__ == "__main__":
main()
Signing and Verifying ufastecdsa
try:
from ufastecdsa import curve, ecdsa, keys, util
get_bit_length = util.get_bit_length
except ImportError:
from fastecdsa import curve, ecdsa, keys, util
get_bit_length = int.bit_length
def main():
# private_key = 82378264402520040413352233063555671940555718680152892238371187003380781159101
# public_key = keys.get_public_key(private_key, curve.P256)
private_key, public_key = keys.gen_keypair(curve.P256)
print("private_key:", private_key)
print("public_key:", public_key.x, public_key.y, public_key.curve.name)
m = "a message to sign via ECDSA"
r, s = ecdsa.sign(m, private_key)
print("R:", r)
print("S:", s)
verified = ecdsa.verify((r, s), m, public_key)
print(verified)
if __name__ == "__main__":
main()
from _crypto import ECC
P256 = ECC.Curve( 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff, -0x3, 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b, 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551, 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296, 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5 )
S = ECC.Point( 0xde2444bebc8d36e682edd27e0f271508617519b3221a8fa0b77cab3989da97c9, 0xc093ae7ff36e5380fc01a5aad1e66659702de80f53cec576b6350b243042a256, P256 )
T = ECC.Point( 0x55a8b00f8da1d44e62f6b3b25316212e39540dc861c89575bb8cf92e35e0986b, 0x5421c3209c2d6c704835d82ac4c3dd90f61a8a52598b9e7ab656e9d8c8b24316, P256 )
print("S==S = ", S == S)
print("S==T = ", S == T)
R = S + T print("S+T = ({:X}, {:X})".format(R.x, R.y))
R = S - T print("S-T = ({:X}, {:X})".format(R.x, R.y))
R = 2 * S print("2S = ({:X}, {:X})".format(R.x, R.y))
d = 0xc51e4753afdec1e6b6c6a5b992f43f8dd0c7a8933072708b6522468b2ffb06fd e = 0xd37f628ece72a462f0145cbefe3f0b355ee8332d37acdd83a358016aea029db7 R = (d S) + (e T) print("dS+eT = ({:X}, {:X})".format(R.x, R.y))
R = S + S print("S+S = ({:X}, {:X})".format(R.x, R.y))
R = S - S print("S-S = ({:X}, {:X})".format(R.x, R.y))
for other examples: tests
#define TFM_NO_ASM
// #define TFM_ECC192
// #define TFM_ECC224
// #define TFM_ECC256
// #define TFM_ECC384
// #define TFM_ECC512
// #define TFM_RSA512
// #define TFM_RSA1024
// #define TFM_RSA2048
To build such a module, compile MicroPython with an extra make flag named USER_C_MODULES
set to the directory containing all modules you want included (not to the module itself).
➜ ~ git clone https://github.com/micropython/micropython.git micropython
➜ ~ cd micropython
➜ micropython (master) ✗ git submodule update --init
➜ micropython (master) ✗ git clone https://github.com/dmazzella/ucrypto.git ports/stm32/boards/PYBD_SF6/cmodules/ucrypto
➜ micropython (master) ✗ make -j8 -C mpy-cross && make -j8 -C ports/stm32/ BOARD="PYBD_SF6" USER_C_MODULES="$(pwd)/ports/stm32/boards/PYBD_SF6/cmodules"
➜ ~ git clone https://github.com/micropython/micropython.git micropython
➜ ~ cd micropython
➜ micropython (master) ✗ git submodule update --init
➜ micropython (master) ✗ git clone https://github.com/dmazzella/ucrypto.git ports/esp32/boards/ESP32_GENERIC/cmodules/ucrypto
➜ micropython (master) ✗ make -j8 -C mpy-cross && make -j8 -C ports/esp32/ BOARD="ESP32_GENERIC" USER_C_MODULES="$(pwd)/ports/esp32/boards/ESP32_GENERIC/cmodules/ucrypto/micropython.cmake"
➜ ~ git clone https://github.com/micropython/micropython.git micropython
➜ ~ cd micropython
➜ micropython (master) ✗ git submodule update --init
➜ micropython (master) ✗ git clone https://github.com/dmazzella/ucrypto.git ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/cmodules/ucrypto
➜ micropython (master) ✗ make -j8 -C mpy-cross && make -j8 -C ports/rp2/ BOARD="ARDUINO_NANO_RP2040_CONNECT" USER_C_MODULES="$(pwd)/ports/rp2/boards/ARDUINO_NANO_RP2040_CONNECT/cmodules/ucrypto/micropython.cmake"
The build size depends on the asm optimizations of the tomsfastmath library that are enabled into ucrypto/tomsfastmath/tfm_mpi.h
#define TFM_ECC192
#define TFM_ECC224
#define TFM_ECC256
#define TFM_ECC384
#define TFM_ECC512
#define TFM_RSA512
#define TFM_RSA1024
#define TFM_RSA2048
LINK build-PYBD_SF6/firmware.elf
text data bss dec hex filename
1012856 328 100576 1113760 10fea0 build-PYBD_SF6/firmware.elf
// #define TFM_ECC192
// #define TFM_ECC224
#define TFM_ECC256
// #define TFM_ECC384
// #define TFM_ECC512
// #define TFM_RSA512
// #define TFM_RSA1024
// #define TFM_RSA2048
LINK build-PYBD_SF6/firmware.elf
text data bss dec hex filename
1034872 452 101600 1136924 11591c build-PYBD_SF6/firmware.elf
#define TFM_ECC192
#define TFM_ECC224
#define TFM_ECC256
#define TFM_ECC384
#define TFM_ECC512
// #define TFM_RSA512
// #define TFM_RSA1024
// #define TFM_RSA2048
LINK build-PYBD_SF6/firmware.elf
text data bss dec hex filename
1042552 452 101600 1144604 11771c build-PYBD_SF6/firmware.elf
LINK build-PYBD_SF6/firmware.elf
text data bss dec hex filename
1209976 452 101600 1312028 14051c build-PYBD_SF6/firmware.elf
To see which optimizations are enabled in the build:
MicroPython v1.19.1-705-gac5934c96-dirty on 2022-11-22; PORTENTA with STM32H747
Type "help()" for more information.
>>> import _crypto
>>> print(_crypto.NUMBER.ident())
TomsFastMath v0.13.1-next
Sizeofs
fp_digit = 4
fp_word = 8
FP_MAX_SIZE = 4352
Defines:
TFM_ARM TFM_ECC192 TFM_ECC224 TFM_ECC256 TFM_ECC384 TFM_ECC512 TFM_RSA512 TFM_RSA1024 TFM_RSA2048 TFM_ASM TFM_MUL6 TFM_SQR6 TFM_MUL7 TFM_SQR7 TFM_MUL8 TFM_SQR8 TFM_MUL12 TFM_SQR12 TFM_SMALL_SET TFM_MUL17 TFM_SQR17 TFM_MUL32 TFM_SQR32 TFM_MUL64 TFM_SQR64
>>>