Tip
If you find my projects useful, consider β and why not ... Buy me a coffee π
Micropython package for doing fast rsa and elliptic curve cryptography, specifically digital signatures
Tip
If you find my projects useful, consider β and why not ... Buy me a coffee π
Hi!
Can I use calculations with the secp256k1 curve if I change the source data in the file "ucrypto_ecc_p256.py"?
Hello,
On the Pico W, I've observed ecdsa.sign() consistently producing an incorrect signature or hanging the system under specific conditions. The issue only seems to happen when ecdsa.sign() is invoked in an asyncio task, and only when roughly 85k-100k of the available 180k heap space is allocated. The issue exists with the latest ucrypto and micropython.
Below is a demo program that triggers the behavior. Tweaking the heap usage changes whether a bad signature is produced or the program hangs.
from ufastecdsa import ecdsa, keys, curve
import asyncio
import gc
private_key = 22322313096608720262726022759208549999371313709767561346264284646350673024178
public_key = keys.get_public_key(private_key, curve.P256)
# Buffers to consume heap space. The issue manifests around 85-100 kB allocated.
buf_a = bytearray(55000)
buf_b = bytearray()
async def sign_task():
sign()
def sign():
for i in range(0, 100):
print(f'Test {i}')
gc.collect()
print(f'{gc.mem_alloc()} allocated')
# Sometimes ecdsa.sign() hangs forever and sometimes the verification fails instead
msg = bytearray(500)
r, s = ecdsa.sign(msg, private_key)
print(f'{r=}, {s=}')
v = ecdsa.verify((r, s), msg, public_key)
if not v:
print('Verification failed!')
return
# Increase heap usage in a predicable way
buf_b.extend(bytearray(1000))
# Running the function directly does not appear to cause the issue
# sign()
# Running the function as a task causes the issue
asyncio.run(sign_task())
The output:
Test 0
86400 allocated
r=85138370589888148504419467028945835242182133906801408929085382665177392495649, s=36405879136828887984530789867378534397858885811006898673352558309076209890931
Test 1
88032 allocated
r=85138370589888148504419467028945835242182133906801408929085382665177392495649, s=36405879136828887984530789867378534397858885811006898673352558309076209890931
Test 2
89024 allocated
r=85138370589888148504419467028945835242182133906801408929085382665177392495649, s=36405879136828887984530789867378534397858885811006898673352558309076209890931
Test 3
90032 allocated
r=81005532657339936592853986520470807188817871510725802802965116630864593609458, s=59780292414690978660613437195734621900681328919802338312801725760749994467877
Verification failed!
Thanks!
I copied https://github.com/dmazzella/ucrypto/tree/master/modules/ufastrsa and https://github.com/dmazzella/ucrypto/blob/master/modules/functools.py into lib
and ran a slightly modified version of the example from the README:
from ufastrsa.rsa import RSA, genrsa
def main():
bits = 512
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()
Thank you for the straightforward solution! xref https://github.com/orgs/micropython/discussions/10048#discussioncomment-4202935
Will isupport for SECP128r1 is in the plan? Thank you.
I've been playing around with various RSA libraries and found an oddity in the pow3_
function which uses TFM fp_exptmod
. I'm not sure if what I'm seeing is an error, but it isn't what I'm expecting. Here is the test I'm running on an ESP32-S3:
from _crypto import NUMBER as tfm
from adafruit_rsa.core import fast_pow as adf_pow
from time import ticks_diff, ticks_ms
import random
import sys
tfm_pow = tfm.exptmod
def main():
l = []
for i in range(0, 10):
a = random.randint(0, sys.maxsize)
b = random.randint(0, sys.maxsize)
# b = 65537 # 65537 is standard for reasons
c = random.randint(0, sys.maxsize)
# c = 2048 # 2048 bit max to prevent overflow per TFM_CHECK comment
l.append((a, b, c))
# Test tfm
tfm_results = []
start = ticks_ms()
for a, b, c in l:
tfm_results.append(tfm_pow(a, b, c))
stop = ticks_ms()
print('tfm_pow: ', ticks_diff(stop, start))
# Test adf
adf_results = []
start = ticks_ms()
for a, b, c in l:
adf_results.append(adf_pow(a, b, c))
stop = ticks_ms()
print('adf_pow: ', ticks_diff(stop, start))
# Verify both functions had the same output
print('Results are identical: ', tfm_results == adf_results)
if tfm_results != adf_results:
print('Test inputs:')
print(l)
print()
print('TFM results:')
print(tfm_results)
print()
print('ADF results:')
print(adf_results)
if __name__ == "__main__":
main()
And here is the adafruit fast_pow
function. The output of the function below always matches the output of CPython's pow
function as well:
def fast_pow(x: int, e: int, m: int) -> int:
"""
Performs fast modular exponentiation, saves RAM on small CPUs/micros.
:param int x: Base
:param int e: Exponent
:param int m: Modulo
"""
X = x
E = e
Y = 1
while E > 0:
if E % 2 == 0:
X = (X * X) % m
E = E // 2
else:
Y = (X * Y) % m
E = E - 1
return Y
And here are the results:
MicroPython v1.19.1-709-g0219c40e2-dirty on 2022-12-16; ESP32S3 module with ESP32S3
Type "help()" for more information.
>>> import pow
>>> pow.main()
tfm_pow: 9
adf_pow: 112
Results are identical: False
Test inputs:
[(1965509468, 1387443297, 1605567237), (1871294224, 1902723300, 752900670), (1233710178, 1838389496, 1357457465), (1632487816, 1367755825, 1923817713), (442177334, 385651918, 144762972), (488834613, 74276846, 1063867451), (1029344430, 2060678614, 294479980), (1412723309, 1652848341, 2144438478), (457083566, 747582368, 583126214), (580365312, 1089030014, 32)]
TFM results:
[1132155764, 0, 81381301, 488747596, 0, 681878736, 0, 0, 0, 0]
ADF results:
[1132155764, 278440606, 81381301, 488747596, 28485700, 681878736, 227706460, 238573763, 62767214, 0]
It is unclear to me why the fp_exptmod
output isn't matching other pow
implementations. I have tried disabling TFM_CHECK
and TFM_TIMING_RESISTANT
, but disabling the former doesn't appear to make any difference, and disabling the latter results in a stackoverflow.
As title, found this issue when installing .py files to my pico_w.
I currently comment out the occurrences of hashlib.md5 to make it work.
I'm trying to build a Micropython firmware with this library included. I have an environment set up for building Micropython and can get a firmware.bin file out by running
make -C ports/esp32 BOARD=ESP32_GENERIC_C3
However when I clone down ucrypto and include it in the USER_C_MODULES
argument as instructed, I get quite a lot of errors and the firmware fails to build.
make -j8 -C ports/esp32 V=1 BOARD=ESP32_GENERIC_C3 USER_C_MODULES="$(realpath ../ucrypto/micropython.cmake)"
Here is the last chunk of output, but there are quite a few errors, all seemingly coming from ucrypto/moducrypto.c
/home/jonah/micropython/ucrypto/moducrypto.c:2225:7: error: expected ';' before 'const'
2225 | STATIC MP_DEFINE_CONST_DICT(mp_module_ucrypto_globals, mp_module_ucrypto_globals_table);
| ^
| ;
/home/jonah/micropython/ucrypto/moducrypto.c:302:12: warning: 'fp_pow3' defined but not used [-Wunused-function]
302 | static int fp_pow3(fp_int *X, fp_int *E, fp_int *M, fp_int *Y)
| ^~~~~~~
cc1: some warnings being treated as errors
[96/97] Generating binary image from built executable
esptool.py v4.7.0
Creating esp32c3 image...
Merged 2 ELF sections
Successfully created esp32c3 image.
Generated /home/jonah/micropython/micropython/ports/esp32/build-ESP32_GENERIC_C3/bootloader/bootloader.bin
[97/97] cd /home/jonah/micropython/micropython/ports/esp32...rts/esp32/build-ESP32_GENERIC_C3/bootloader/bootloader.bin
Bootloader binary size 0x4330 bytes. 0x3cd0 bytes (48%) free.
ninja: build stopped: subcommand failed.
ninja failed with exit code 1, output of the command is in the /home/jonah/micropython/micropython/ports/esp32/build-ESP32_GENERIC_C3/log/idf_py_stderr_output_39396 and /home/jonah/micropython/micropython/ports/esp32/build-ESP32_GENERIC_C3/log/idf_py_stdout_output_39396
See https://github.com/micropython/micropython/wiki/Build-Troubleshooting
make: *** [Makefile:66: all] Error 1
make: Leaving directory '/home/jonah/micropython/micropython/ports/esp32'
Here's the full output:
https://paste.sr.ht/~jonahbron/c48f525093b76f9481d9340163c03c66fb289442
Is this a known issue, does ESP32C3 not work? Or am I doing something wrong with my compilation?
Hi, friend!)
What is the right command to make firmware on Pi Pico 2040 board? When i used this -> make -j8 -C mpy-cross && make -j8 -C ports/stm32/ BOARD="PYBD_SF6" USER_C_MODULES="$(pwd)/ports/stm32/boards/PYBD_SF6/cmodules" firmware.elf is not supported. And when i convert this firmware with ./elf2uf2 firmware.elf firmware.uf2 I get an error "ERROR: HARD-FLOAT not supported"
Please help me to understand this
Hi!,
Dear Author this is really good project!, I am interested how I can use it on my boad could you please provide the steps how to install it?
Followed README.md, the build fails with latest MicroPython source:
make -j8 -C mpy-cross && make -j8 -C ports/stm32/ BOARD="PYBD_SF6" USER_C_MODULES="$(pwd)/ports/stm32/boards/PYBD_SF6/cmodules"
Turns out I have to go with :
make -j8 -C mpy-cross && make -j8 -C ports/stm32/ BOARD="PYBD_SF6" USER_C_MODULES="$(pwd)/ports/stm32/boards/PYBD_SF6/cmodules/micropython.cmake"
Hi,
Do you have to change the make file to a cmake file in order for this to compile?
-- Adding linker script /Users/thomasgiles/esp-VS/micropython-3/esp-idf/components/soc/esp32s3/ld/esp32s3.peripherals.ld
Including User C Module(s) from /Users/thomasgiles/esp-VS/micropython-3/ports/esp32/boards/GENERIC_S3_SPIRAM/ucrypto
CMake Error at /Users/thomasgiles/esp-VS/micropython-3/py/usermod.cmake:42 (include):
include requested file is a directory:
/Users/thomasgiles/esp-VS/micropython-3/ports/esp32/boards/GENERIC_S3_SPIRAM/ucrypto
Call Stack (most recent call first):
main/CMakeLists.txt:10 (include)
Many thanks,
Thomas
With latest sources, both micropython and ucrypto. Trying to make a build for pico w board, but it always fails in the last steps :
The building keeps failing with Error
selected processor does not support ***** in Thumb mode
instruction not supported -- '*******'
To the best of my knowledge these kind of asm issues should be automatically solved by compiler, but it seems currently not.
What else can be done to make things work or it's just a unsolvable platform supporting issue?
How do I install it into the esp32 libοΌ
This repo has no micropython.cmake file, so how can we compile?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.