From 9ab3b1d03f734f4aae28364f7a6c7c7c223b30a9 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Tue, 26 Jan 2021 14:45:36 +0300 Subject: [PATCH] gost3410 private key % Q --- README | 2 ++ news.texi | 5 +++++ pygost/__init__.py | 2 +- pygost/gost3410.py | 16 ++++++++++++++++ pygost/stubs/pygost/gost3410.pyi | 3 +++ pygost/test_gost3410.py | 8 +++++--- 6 files changed, 32 insertions(+), 4 deletions(-) diff --git a/README b/README index 5795233..acabfb1 100644 --- a/README +++ b/README @@ -39,7 +39,9 @@ Example 34.10-2012 keypair generation, signing and verifying: >>> from os import urandom >>> prv_raw = urandom(64) >>> from pygost.gost3410 import prv_unmarshal + >>> from pygost.gost3410 import prv_marshal >>> prv = prv_unmarshal(prv_raw) + >>> prv_raw = prv_marshal(curve, prv) >>> from pygost.gost3410 import public_key >>> pub = public_key(curve, prv) >>> from pygost.gost3410 import pub_marshal diff --git a/news.texi b/news.texi index 564df7b..324c05c 100644 --- a/news.texi +++ b/news.texi @@ -3,6 +3,11 @@ @table @strong +@anchor{Release 5.4} +@item 5.4 +@item @code{gost3410.prv_marshal} helper can make private keys that are +in curve's Q field, for better compatibility with some implementations. + @anchor{Release 5.3} @item 5.3 @itemize diff --git a/pygost/__init__.py b/pygost/__init__.py index f1f6ad6..21fbf59 100644 --- a/pygost/__init__.py +++ b/pygost/__init__.py @@ -3,4 +3,4 @@ PyGOST is free software: see the file COPYING for copying conditions. """ -__version__ = "5.3" +__version__ = "5.4" diff --git a/pygost/gost3410.py b/pygost/gost3410.py index 88cbfbe..58a20e0 100644 --- a/pygost/gost3410.py +++ b/pygost/gost3410.py @@ -324,10 +324,26 @@ def prv_unmarshal(prv): :param bytes prv: serialized private key :rtype: long + + It is advisable to use :py:func:`pygost.gost3410.prv_marshal` to + assure that key i in curve's Q field for better compatibility with + some implementations. """ return bytes2long(prv[::-1]) +def prv_marshal(curve, prv): + """Marshal little-endian private key + + :param GOST3410Curve curve: curve to use + :param long prv: serialized private key + :rtype: bytes + + Key is in curve's Q field. + """ + return long2bytes(prv % curve.q, point_size(prv))[::-1] + + def pub_marshal(pub): """Marshal public key diff --git a/pygost/stubs/pygost/gost3410.pyi b/pygost/stubs/pygost/gost3410.pyi index 4be9bbb..345a3e6 100644 --- a/pygost/stubs/pygost/gost3410.pyi +++ b/pygost/stubs/pygost/gost3410.pyi @@ -55,6 +55,9 @@ def verify(curve: GOST3410Curve, pub: PublicKey, digest: bytes, signature: bytes def prv_unmarshal(prv: bytes) -> int: ... +def prv_marshal(curve: GOST3410Curve, prv: int) -> bytes: ... + + def pub_marshal(pub: PublicKey) -> bytes: ... diff --git a/pygost/test_gost3410.py b/pygost/test_gost3410.py index 51624db..677968d 100644 --- a/pygost/test_gost3410.py +++ b/pygost/test_gost3410.py @@ -19,6 +19,8 @@ from unittest import TestCase from pygost.gost3410 import CURVES from pygost.gost3410 import GOST3410Curve +from pygost.gost3410 import prv_marshal +from pygost.gost3410 import prv_unmarshal from pygost.gost3410 import public_key from pygost.gost3410 import sign from pygost.gost3410 import uv2xy @@ -81,8 +83,8 @@ class Test341001(TestCase): def test_sequence(self): c = CURVES["id-GostR3410-2001-TestParamSet"] - prv = bytes2long(urandom(32)) - pubX, pubY = public_key(c, prv) + prv = prv_unmarshal(urandom(32)) + pubX, pubY = public_key(c, prv_unmarshal(prv_marshal(c, prv))) for _ in range(20): digest = urandom(32) s = sign(c, prv, digest) @@ -255,7 +257,7 @@ class Test34102012(TestCase): def test_sequence(self): c = CURVES["id-tc26-gost-3410-12-512-paramSetA"] prv = bytes2long(urandom(64)) - pubX, pubY = public_key(c, prv) + pubX, pubY = public_key(c, prv_unmarshal(prv_marshal(c, prv))) for _ in range(20): digest = urandom(64) s = sign(c, prv, digest) -- 2.44.0