]> Cypherpunks.ru repositories - pygost.git/blobdiff - pygost/gost3410.py
Use curve's cofactor during VKO calculations
[pygost.git] / pygost / gost3410.py
index c9b905e225ed06e63fb70c0c55f4f15b96934121..9f0a11e656689745056b8f7c53cdf5c3779201b3 100644 (file)
@@ -1,11 +1,10 @@
 # coding: utf-8
 # PyGOST -- Pure Python GOST cryptographic functions library
 # coding: utf-8
 # PyGOST -- Pure Python GOST cryptographic functions library
-# Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+# Copyright (C) 2015-2020 Sergey Matveev <stargrave@stargrave.org>
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# the Free Software Foundation, version 3 of the License.
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -23,123 +22,57 @@ key, digest and signature lengths.
 
 from os import urandom
 
 
 from os import urandom
 
-from pygost.gost3411_94 import GOST341194
 from pygost.utils import bytes2long
 from pygost.utils import hexdec
 from pygost.utils import long2bytes
 from pygost.utils import modinvert
 
 
 from pygost.utils import bytes2long
 from pygost.utils import hexdec
 from pygost.utils import long2bytes
 from pygost.utils import modinvert
 
 
-SIZE_3410_2001 = 32
-SIZE_3410_2012 = 64
-
-
-DEFAULT_CURVE = "GostR3410_2001_CryptoPro_A_ParamSet"
-# Curve parameters are the following: p, q, a, b, x, y
-CURVE_PARAMS = {
-    "GostR3410_2001_ParamSet_cc": (
-        "C0000000000000000000000000000000000000000000000000000000000003C7",
-        "5fffffffffffffffffffffffffffffff606117a2f4bde428b7458a54b6e87b85",
-        "C0000000000000000000000000000000000000000000000000000000000003c4",
-        "2d06B4265ebc749ff7d0f1f1f88232e81632e9088fd44b7787d5e407e955080c",
-        "0000000000000000000000000000000000000000000000000000000000000002",
-        "a20e034bf8813ef5c18d01105e726a17eb248b264ae9706f440bedc8ccb6b22c",
-    ),
-    "GostR3410_2001_TestParamSet": (
-        "8000000000000000000000000000000000000000000000000000000000000431",
-        "8000000000000000000000000000000150FE8A1892976154C59CFC193ACCF5B3",
-        "0000000000000000000000000000000000000000000000000000000000000007",
-        "5FBFF498AA938CE739B8E022FBAFEF40563F6E6A3472FC2A514C0CE9DAE23B7E",
-        "0000000000000000000000000000000000000000000000000000000000000002",
-        "08E2A8A0E65147D4BD6316030E16D19C85C97F0A9CA267122B96ABBCEA7E8FC8",
-    ),
-    "GostR3410_2001_CryptoPro_A_ParamSet": (
-        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97",
-        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893",
-        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94",
-        "00000000000000000000000000000000000000000000000000000000000000a6",
-        "0000000000000000000000000000000000000000000000000000000000000001",
-        "8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14",
-    ),
-    "GostR3410_2001_CryptoPro_B_ParamSet": (
-        "8000000000000000000000000000000000000000000000000000000000000C99",
-        "800000000000000000000000000000015F700CFFF1A624E5E497161BCC8A198F",
-        "8000000000000000000000000000000000000000000000000000000000000C96",
-        "3E1AF419A269A5F866A7D3C25C3DF80AE979259373FF2B182F49D4CE7E1BBC8B",
-        "0000000000000000000000000000000000000000000000000000000000000001",
-        "3FA8124359F96680B83D1C3EB2C070E5C545C9858D03ECFB744BF8D717717EFC",
-    ),
-    "GostR3410_2001_CryptoPro_C_ParamSet": (
-        "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D759B",
-        "9B9F605F5A858107AB1EC85E6B41C8AA582CA3511EDDFB74F02F3A6598980BB9",
-        "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598",
-        "000000000000000000000000000000000000000000000000000000000000805a",
-        "0000000000000000000000000000000000000000000000000000000000000000",
-        "41ECE55743711A8C3CBF3783CD08C0EE4D4DC440D4641A8F366E550DFDB3BB67",
-    ),
-    "GostR3410_2001_CryptoPro_XchA_ParamSet": (
-        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97",
-        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893",
-        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94",
-        "00000000000000000000000000000000000000000000000000000000000000a6",
-        "0000000000000000000000000000000000000000000000000000000000000001",
-        "8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14",
-    ),
-    "GostR3410_2001_CryptoPro_XchB_ParamSet": (
-        "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D759B",
-        "9B9F605F5A858107AB1EC85E6B41C8AA582CA3511EDDFB74F02F3A6598980BB9",
-        "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598",
-        "000000000000000000000000000000000000000000000000000000000000805a",
-        "0000000000000000000000000000000000000000000000000000000000000000",
-        "41ECE55743711A8C3CBF3783CD08C0EE4D4DC440D4641A8F366E550DFDB3BB67",
-    ),
-    "GostR3410_2012_TC26_ParamSetA": (
-        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7",
-        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275",
-        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4",
-        "E8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760",
-        "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003",
-        "7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4",
-    ),
-    "GostR3410_2012_TC26_ParamSetB": (
-        "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006F",
-        "800000000000000000000000000000000000000000000000000000000000000149A1EC142565A545ACFDB77BD9D40CFA8B996712101BEA0EC6346C54374F25BD",
-        "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C",
-        "687D1B459DC841457E3E06CF6F5E2517B97C7D614AF138BCBF85DC806C4B289F3E965D2DB1416D217F8B276FAD1AB69C50F78BEE1FA3106EFB8CCBC7C5140116",
-        "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002",
-        "1A8F7EDA389B094C2C071E3647A8940F3C123B697578C213BE6DD9E6C8EC7335DCB228FD1EDF4A39152CBCAAF8C0398828041055F94CEEEC7E21340780FE41BD"
-    ),
+MODE2SIZE = {
+    2001: 32,
+    2012: 64,
 }
 }
-for c, params in CURVE_PARAMS.items():
-    CURVE_PARAMS[c] = [hexdec(param) for param in params]
 
 
 class GOST3410Curve(object):
     """ GOST 34.10 validated curve
 
 
 
 class GOST3410Curve(object):
     """ GOST 34.10 validated curve
 
-    >>> p, q, a, b, x, y = CURVE_PARAMS["GostR3410_2001_TestParamSet"]
-    >>> curve = GOST3410Curve(p, q, a, b, x, y)
-    >>> priv = bytes2long(urandom(32))
-    >>> signature = sign(curve, priv, GOST341194(data).digest())
-    >>> pubX, pubY = public_key(curve, priv)
-    >>> verify(curve, pubX, pubY, GOST341194(data).digest(), signature)
+    >>> curve = CURVES["id-GostR3410-2001-TestParamSet"]
+    >>> prv = prv_unmarshal(urandom(32))
+    >>> signature = sign(curve, prv, GOST341194(data).digest())
+    >>> pub = public_key(curve, prv)
+    >>> verify(curve, pub, GOST341194(data).digest(), signature)
     True
     True
+
+    :param long p: characteristic of the underlying prime field
+    :param long q: elliptic curve subgroup order
+    :param long a, b: coefficients of the equation of the elliptic curve in
+                      the canonical form
+    :param long x, y: the coordinate of the point P (generator of the
+                      subgroup of order q) of the elliptic curve in
+                      the canonical form
+    :param long e, d: coefficients of the equation of the elliptic curve in
+                      the twisted Edwards form
     """
     """
-    def __init__(self, p, q, a, b, x, y):
-        self.p = bytes2long(p)
-        self.q = bytes2long(q)
-        self.a = bytes2long(a)
-        self.b = bytes2long(b)
-        self.x = bytes2long(x)
-        self.y = bytes2long(y)
+    def __init__(self, p, q, a, b, x, y, cofactor=1, e=None, d=None):
+        self.p = p
+        self.q = q
+        self.a = a
+        self.b = b
+        self.x = x
+        self.y = y
+        self.cofactor = cofactor
+        self.e = e
+        self.d = d
         r1 = self.y * self.y % self.p
         r2 = ((self.x * self.x + self.a) * self.x + self.b) % self.p
         r1 = self.y * self.y % self.p
         r2 = ((self.x * self.x + self.a) * self.x + self.b) % self.p
-        if r2 < 0:
-            r2 += self.p
-        if r1 != r2:
+        if r1 != self.pos(r2):
             raise ValueError("Invalid parameters")
             raise ValueError("Invalid parameters")
+        self._st = None
 
 
-    def _pos(self, v):
+    def pos(self, v):
+        """Make positive number
+        """
         if v < 0:
             return v + self.p
         return v
         if v < 0:
             return v + self.p
         return v
@@ -149,11 +82,11 @@ class GOST3410Curve(object):
             # double
             t = ((3 * p1x * p1x + self.a) * modinvert(2 * p1y, self.p)) % self.p
         else:
             # double
             t = ((3 * p1x * p1x + self.a) * modinvert(2 * p1y, self.p)) % self.p
         else:
-            tx = self._pos(p2x - p1x) % self.p
-            ty = self._pos(p2y - p1y) % self.p
+            tx = self.pos(p2x - p1x) % self.p
+            ty = self.pos(p2y - p1y) % self.p
             t = (ty * modinvert(tx, self.p)) % self.p
             t = (ty * modinvert(tx, self.p)) % self.p
-        tx = self._pos(t * t - p1x - p2x) % self.p
-        ty = self._pos(t * (p1x - tx) - p1y) % self.p
+        tx = self.pos(t * t - p1x - p2x) % self.p
+        ty = self.pos(t * (p1x - tx) - p1y) % self.p
         return tx, ty
 
     def exp(self, degree, x=None, y=None):
         return tx, ty
 
     def exp(self, degree, x=None, y=None):
@@ -161,9 +94,9 @@ class GOST3410Curve(object):
         y = y or self.y
         tx = x
         ty = y
         y = y or self.y
         tx = x
         ty = y
-        degree -= 1
         if degree == 0:
             raise ValueError("Bad degree value")
         if degree == 0:
             raise ValueError("Bad degree value")
+        degree -= 1
         while degree != 0:
             if degree & 1 == 1:
                 tx, ty = self._add(tx, ty, x, y)
         while degree != 0:
             if degree & 1 == 1:
                 tx, ty = self._add(tx, ty, x, y)
@@ -171,69 +104,157 @@ class GOST3410Curve(object):
             x, y = self._add(x, y, x, y)
         return tx, ty
 
             x, y = self._add(x, y, x, y)
         return tx, ty
 
+    def st(self):
+        """Compute s/t parameters for twisted Edwards curve points conversion
+        """
+        if self.e is None or self.d is None:
+            raise ValueError("non twisted Edwards curve")
+        if self._st is not None:
+            return self._st
+        self._st = (
+            self.pos(self.e - self.d) * modinvert(4, self.p) % self.p,
+            (self.e + self.d) * modinvert(6, self.p) % self.p,
+        )
+        return self._st
 
 
-def public_key(curve, private_key):
-    """ Generate public key from the private one
 
 
-    :param GOST3410Curve curve: curve to use
-    :param long private_key: private key
-    :return: public key's parts, X and Y
-    :rtype: (long, long)
-    """
-    return curve.exp(private_key)
+CURVES = {
+    "GostR3410_2001_ParamSet_cc": GOST3410Curve(
+        p=bytes2long(hexdec("C0000000000000000000000000000000000000000000000000000000000003C7")),
+        q=bytes2long(hexdec("5fffffffffffffffffffffffffffffff606117a2f4bde428b7458a54b6e87b85")),
+        a=bytes2long(hexdec("C0000000000000000000000000000000000000000000000000000000000003c4")),
+        b=bytes2long(hexdec("2d06B4265ebc749ff7d0f1f1f88232e81632e9088fd44b7787d5e407e955080c")),
+        x=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000002")),
+        y=bytes2long(hexdec("a20e034bf8813ef5c18d01105e726a17eb248b264ae9706f440bedc8ccb6b22c")),
+    ),
+    "id-GostR3410-2001-TestParamSet": GOST3410Curve(
+        p=bytes2long(hexdec("8000000000000000000000000000000000000000000000000000000000000431")),
+        q=bytes2long(hexdec("8000000000000000000000000000000150FE8A1892976154C59CFC193ACCF5B3")),
+        a=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000007")),
+        b=bytes2long(hexdec("5FBFF498AA938CE739B8E022FBAFEF40563F6E6A3472FC2A514C0CE9DAE23B7E")),
+        x=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000002")),
+        y=bytes2long(hexdec("08E2A8A0E65147D4BD6316030E16D19C85C97F0A9CA267122B96ABBCEA7E8FC8")),
+    ),
+    "id-GostR3410-2001-CryptoPro-A-ParamSet": GOST3410Curve(
+        p=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97")),
+        q=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893")),
+        a=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94")),
+        b=bytes2long(hexdec("00000000000000000000000000000000000000000000000000000000000000a6")),
+        x=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000001")),
+        y=bytes2long(hexdec("8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14")),
+    ),
+    "id-GostR3410-2001-CryptoPro-B-ParamSet": GOST3410Curve(
+        p=bytes2long(hexdec("8000000000000000000000000000000000000000000000000000000000000C99")),
+        q=bytes2long(hexdec("800000000000000000000000000000015F700CFFF1A624E5E497161BCC8A198F")),
+        a=bytes2long(hexdec("8000000000000000000000000000000000000000000000000000000000000C96")),
+        b=bytes2long(hexdec("3E1AF419A269A5F866A7D3C25C3DF80AE979259373FF2B182F49D4CE7E1BBC8B")),
+        x=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000001")),
+        y=bytes2long(hexdec("3FA8124359F96680B83D1C3EB2C070E5C545C9858D03ECFB744BF8D717717EFC")),
+    ),
+    "id-GostR3410-2001-CryptoPro-C-ParamSet": GOST3410Curve(
+        p=bytes2long(hexdec("9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D759B")),
+        q=bytes2long(hexdec("9B9F605F5A858107AB1EC85E6B41C8AA582CA3511EDDFB74F02F3A6598980BB9")),
+        a=bytes2long(hexdec("9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598")),
+        b=bytes2long(hexdec("000000000000000000000000000000000000000000000000000000000000805a")),
+        x=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000000")),
+        y=bytes2long(hexdec("41ECE55743711A8C3CBF3783CD08C0EE4D4DC440D4641A8F366E550DFDB3BB67")),
+    ),
+    "id-tc26-gost-3410-2012-256-paramSetA": GOST3410Curve(
+        p=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97")),
+        q=bytes2long(hexdec("400000000000000000000000000000000FD8CDDFC87B6635C115AF556C360C67")),
+        a=bytes2long(hexdec("C2173F1513981673AF4892C23035A27CE25E2013BF95AA33B22C656F277E7335")),
+        b=bytes2long(hexdec("295F9BAE7428ED9CCC20E7C359A9D41A22FCCD9108E17BF7BA9337A6F8AE9513")),
+        x=bytes2long(hexdec("91E38443A5E82C0D880923425712B2BB658B9196932E02C78B2582FE742DAA28")),
+        y=bytes2long(hexdec("32879423AB1A0375895786C4BB46E9565FDE0B5344766740AF268ADB32322E5C")),
+        cofactor=4,
+        e=0x01,
+        d=bytes2long(hexdec("0605F6B7C183FA81578BC39CFAD518132B9DF62897009AF7E522C32D6DC7BFFB")),
+    ),
+    "id-tc26-gost-3410-2012-512-paramSetTest": GOST3410Curve(
+        p=bytes2long(hexdec("4531ACD1FE0023C7550D267B6B2FEE80922B14B2FFB90F04D4EB7C09B5D2D15DF1D852741AF4704A0458047E80E4546D35B8336FAC224DD81664BBF528BE6373")),
+        q=bytes2long(hexdec("4531ACD1FE0023C7550D267B6B2FEE80922B14B2FFB90F04D4EB7C09B5D2D15DA82F2D7ECB1DBAC719905C5EECC423F1D86E25EDBE23C595D644AAF187E6E6DF")),
+        a=7,
+        b=bytes2long(hexdec("1CFF0806A31116DA29D8CFA54E57EB748BC5F377E49400FDD788B649ECA1AC4361834013B2AD7322480A89CA58E0CF74BC9E540C2ADD6897FAD0A3084F302ADC")),
+        x=bytes2long(hexdec("24D19CC64572EE30F396BF6EBBFD7A6C5213B3B3D7057CC825F91093A68CD762FD60611262CD838DC6B60AA7EEE804E28BC849977FAC33B4B530F1B120248A9A")),
+        y=bytes2long(hexdec("2BB312A43BD2CE6E0D020613C857ACDDCFBF061E91E5F2C3F32447C259F39B2C83AB156D77F1496BF7EB3351E1EE4E43DC1A18B91B24640B6DBB92CB1ADD371E")),
+    ),
+    "id-tc26-gost-3410-12-512-paramSetA": GOST3410Curve(
+        p=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7")),
+        q=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275")),
+        a=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4")),
+        b=bytes2long(hexdec("E8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760")),
+        x=bytes2long(hexdec("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003")),
+        y=bytes2long(hexdec("7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4")),
+    ),
+    "id-tc26-gost-3410-12-512-paramSetB": GOST3410Curve(
+        p=bytes2long(hexdec("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006F")),
+        q=bytes2long(hexdec("800000000000000000000000000000000000000000000000000000000000000149A1EC142565A545ACFDB77BD9D40CFA8B996712101BEA0EC6346C54374F25BD")),
+        a=bytes2long(hexdec("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C")),
+        b=bytes2long(hexdec("687D1B459DC841457E3E06CF6F5E2517B97C7D614AF138BCBF85DC806C4B289F3E965D2DB1416D217F8B276FAD1AB69C50F78BEE1FA3106EFB8CCBC7C5140116")),
+        x=bytes2long(hexdec("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002")),
+        y=bytes2long(hexdec("1A8F7EDA389B094C2C071E3647A8940F3C123B697578C213BE6DD9E6C8EC7335DCB228FD1EDF4A39152CBCAAF8C0398828041055F94CEEEC7E21340780FE41BD")),
+    ),
+    "id-tc26-gost-3410-2012-512-paramSetC": GOST3410Curve(
+        p=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7")),
+        q=bytes2long(hexdec("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC98CDBA46506AB004C33A9FF5147502CC8EDA9E7A769A12694623CEF47F023ED")),
+        a=bytes2long(hexdec("DC9203E514A721875485A529D2C722FB187BC8980EB866644DE41C68E143064546E861C0E2C9EDD92ADE71F46FCF50FF2AD97F951FDA9F2A2EB6546F39689BD3")),
+        b=bytes2long(hexdec("B4C4EE28CEBC6C2C8AC12952CF37F16AC7EFB6A9F69F4B57FFDA2E4F0DE5ADE038CBC2FFF719D2C18DE0284B8BFEF3B52B8CC7A5F5BF0A3C8D2319A5312557E1")),
+        x=bytes2long(hexdec("E2E31EDFC23DE7BDEBE241CE593EF5DE2295B7A9CBAEF021D385F7074CEA043AA27272A7AE602BF2A7B9033DB9ED3610C6FB85487EAE97AAC5BC7928C1950148")),
+        y=bytes2long(hexdec("F5CE40D95B5EB899ABBCCFF5911CB8577939804D6527378B8C108C3D2090FF9BE18E2D33E3021ED2EF32D85822423B6304F726AA854BAE07D0396E9A9ADDC40F")),
+        cofactor=4,
+        e=0x01,
+        d=bytes2long(hexdec("9E4F5D8C017D8D9F13A5CF3CDF5BFE4DAB402D54198E31EBDE28A0621050439CA6B39E0A515C06B304E2CE43E79E369E91A0CFC2BC2A22B4CA302DBB33EE7550")),
+    ),
+}
+CURVES["id-GostR3410-2001-CryptoPro-XchA-ParamSet"] = CURVES["id-GostR3410-2001-CryptoPro-A-ParamSet"]
+CURVES["id-GostR3410-2001-CryptoPro-XchB-ParamSet"] = CURVES["id-GostR3410-2001-CryptoPro-C-ParamSet"]
+CURVES["id-tc26-gost-3410-2012-256-paramSetB"] = CURVES["id-GostR3410-2001-CryptoPro-A-ParamSet"]
+CURVES["id-tc26-gost-3410-2012-256-paramSetC"] = CURVES["id-GostR3410-2001-CryptoPro-B-ParamSet"]
+CURVES["id-tc26-gost-3410-2012-256-paramSetD"] = CURVES["id-GostR3410-2001-CryptoPro-C-ParamSet"]
+DEFAULT_CURVE = CURVES["id-GostR3410-2001-CryptoPro-A-ParamSet"]
 
 
 
 
-def kek(curve, private_key, ukm, pubkey):
-    """ Make Diffie-Hellman computation
+def public_key(curve, prv):
+    """ Generate public key from the private one
 
     :param GOST3410Curve curve: curve to use
 
     :param GOST3410Curve curve: curve to use
-    :param long private_key: private key
-    :param ukm: UKM value (VKO-factor)
-    :type ukm: bytes, 8 bytes
-    :param pubkey: public key's part
-    :type pubkey: (long, long)
-    :return: Key Encryption Key (shared key)
-    :rtype: bytes, 32 bytes
-
-    Shared Key Encryption Key computation is based on
-    :rfc:`4357` VKO GOST 34.10-2001 with little-endian
-    hash output.
+    :param long prv: private key
+    :returns: public key's parts, X and Y
+    :rtype: (long, long)
     """
     """
-    key = curve.exp(private_key, pubkey[0], pubkey[1])
-    key = curve.exp(bytes2long(24 * b"\x00" + ukm), key[0], key[1])
-    return GOST341194(
-        (long2bytes(key[1]) + long2bytes(key[0]))[::-1],
-        "GostR3411_94_CryptoProParamSet"
-    ).digest()[::-1]
+    return curve.exp(prv)
 
 
 
 
-def sign(curve, private_key, digest, size=SIZE_3410_2001):
+def sign(curve, prv, digest, rand=None, mode=2001):
     """ Calculate signature for provided digest
 
     :param GOST3410Curve curve: curve to use
     """ Calculate signature for provided digest
 
     :param GOST3410Curve curve: curve to use
-    :param long private_key: private key
+    :param long prv: private key
     :param digest: digest for signing
     :param digest: digest for signing
-    :type digest: bytes, 32 bytes
-    :param size: signature size
-    :type size: 32 (for 34.10-2001) or 64 (for 34.10-2012)
-    :return: signature
-    :rtype: bytes, 64 bytes
+    :type digest: bytes, 32 or 64 bytes
+    :param rand: optional predefined random data used for k/r generation
+    :type rand: bytes, 32 or 64 bytes
+    :returns: signature, BE(S) || BE(R)
+    :rtype: bytes, 64 or 128 bytes
     """
     """
-    if len(digest) != size:
-        raise ValueError("Invalid digest length")
+    size = MODE2SIZE[mode]
     q = curve.q
     e = bytes2long(digest) % q
     if e == 0:
         e = 1
     while True:
     q = curve.q
     e = bytes2long(digest) % q
     if e == 0:
         e = 1
     while True:
-        k = bytes2long(urandom(size)) % q
+        if rand is None:
+            rand = urandom(size)
+        elif len(rand) != size:
+            raise ValueError("rand length != %d" % size)
+        k = bytes2long(rand) % q
         if k == 0:
             continue
         r, _ = curve.exp(k)
         r %= q
         if r == 0:
             continue
         if k == 0:
             continue
         r, _ = curve.exp(k)
         r %= q
         if r == 0:
             continue
-        d = private_key * r
+        d = prv * r
         k *= e
         s = (d + k) % q
         if s == 0:
         k *= e
         s = (d + k) % q
         if s == 0:
@@ -242,22 +263,18 @@ def sign(curve, private_key, digest, size=SIZE_3410_2001):
     return long2bytes(s, size) + long2bytes(r, size)
 
 
     return long2bytes(s, size) + long2bytes(r, size)
 
 
-def verify(curve, pubkeyX, pubkeyY, digest, signature, size=SIZE_3410_2001):
+def verify(curve, pub, digest, signature, mode=2001):
     """ Verify provided digest with the signature
 
     :param GOST3410Curve curve: curve to use
     """ Verify provided digest with the signature
 
     :param GOST3410Curve curve: curve to use
-    :param long pubkeyX: public key's X
-    :param long pubkeyY: public key's Y
+    :type pub: (long, long)
     :param digest: digest needed to check
     :param digest: digest needed to check
-    :type digest: bytes, 32 bytes
+    :type digest: bytes, 32 or 64 bytes
     :param signature: signature to verify with
     :param signature: signature to verify with
-    :type signature: bytes, 64 bytes
-    :param size: signature size
-    :type size: 32 (for 34.10-2001) or 64 (for 34.10-2012)
+    :type signature: bytes, 64 or 128 bytes
     :rtype: bool
     """
     :rtype: bool
     """
-    if len(digest) != size:
-        raise ValueError("Invalid digest length")
+    size = MODE2SIZE[mode]
     if len(signature) != size * 2:
         raise ValueError("Invalid signature length")
     q = curve.q
     if len(signature) != size * 2:
         raise ValueError("Invalid signature length")
     q = curve.q
@@ -273,7 +290,7 @@ def verify(curve, pubkeyX, pubkeyY, digest, signature, size=SIZE_3410_2001):
     z1 = s * v % q
     z2 = q - r * v % q
     p1x, p1y = curve.exp(z1)
     z1 = s * v % q
     z2 = q - r * v % q
     p1x, p1y = curve.exp(z1)
-    q1x, q1y = curve.exp(z2, pubkeyX, pubkeyY)
+    q1x, q1y = curve.exp(z2, pub[0], pub[1])
     lm = q1x - p1x
     if lm < 0:
         lm += p
     lm = q1x - p1x
     if lm < 0:
         lm += p
@@ -288,3 +305,56 @@ def verify(curve, pubkeyX, pubkeyY, digest, signature, size=SIZE_3410_2001):
     lm %= q
     # This is not constant time comparison!
     return lm == r
     lm %= q
     # This is not constant time comparison!
     return lm == r
+
+
+def prv_unmarshal(prv):
+    """Unmarshal little-endian private key
+
+    :param bytes prv: serialized private key
+    :rtype: long
+    """
+    return bytes2long(prv[::-1])
+
+
+def pub_marshal(pub, mode=2001):
+    """Marshal public key
+
+    :type pub: (long, long)
+    :rtype: bytes
+    :returns: LE(X) || LE(Y)
+    """
+    size = MODE2SIZE[mode]
+    return (long2bytes(pub[1], size) + long2bytes(pub[0], size))[::-1]
+
+
+def pub_unmarshal(pub, mode=2001):
+    """Unmarshal public key
+
+    :param pub: LE(X) || LE(Y)
+    :type pub: bytes
+    :rtype: (long, long)
+    """
+    size = MODE2SIZE[mode]
+    pub = pub[::-1]
+    return (bytes2long(pub[size:]), bytes2long(pub[:size]))
+
+
+def uv2xy(curve, u, v):
+    """Convert twisted Edwards curve U,V coordinates to Weierstrass X,Y
+    """
+    s, t = curve.st()
+    k1 = (s * (1 + v)) % curve.p
+    k2 = curve.pos(1 - v)
+    x = t + k1 * modinvert(k2, curve.p)
+    y = k1 * modinvert(u * k2, curve.p)
+    return x % curve.p, y % curve.p
+
+
+def xy2uv(curve, x, y):
+    """Convert Weierstrass X,Y coordinates to twisted Edwards curve U,V
+    """
+    s, t = curve.st()
+    xmt = curve.pos(x - t)
+    u = xmt * modinvert(y, curve.p)
+    v = curve.pos(xmt - s) * modinvert(xmt + s, curve.p)
+    return u % curve.p, v % curve.p