mirror of
https://github.com/Legrandin/pycryptodome.git
synced 2025-10-19 16:03:45 +00:00
Add Ed25519 keys and EdDSA signatures
This commit is contained in:
parent
db731bb3a7
commit
764c1e81b9
73 changed files with 6840 additions and 629 deletions
|
@ -33,7 +33,10 @@ class MockLib(object):
|
|||
ec_ws_new_context = lambda *x: 0
|
||||
ec_free_context = lambda *x: None
|
||||
ec_ws_new_point = lambda *x: 0
|
||||
ec_free_point = lambda *x: None
|
||||
ec_ws_free_point = lambda *x: None
|
||||
ed25519_new_point = lambda *x: 0
|
||||
ed25519_free_point = lambda *x: None
|
||||
ed25519_new_point = lambda *x: 0
|
||||
|
||||
_raw_api.load_pycryptodome_raw_lib = lambda name, cdec: MockLib()
|
||||
|
||||
|
|
28
Doc/reqs.txt
Normal file
28
Doc/reqs.txt
Normal file
|
@ -0,0 +1,28 @@
|
|||
alabaster==0.7.12
|
||||
Babel==2.9.1
|
||||
certifi==2021.5.30
|
||||
chardet==4.0.0
|
||||
commonmark==0.8.1
|
||||
docutils==0.17.1
|
||||
future==0.18.2
|
||||
idna==2.10
|
||||
imagesize==1.2.0
|
||||
Jinja2==2.11.3
|
||||
MarkupSafe==1.1.1
|
||||
mock==1.0.1
|
||||
packaging==20.9
|
||||
Pillow
|
||||
Pygments==2.5.2
|
||||
pyparsing==2.4.7
|
||||
pytz==2021.1
|
||||
readthedocs-sphinx-ext==2.1.4
|
||||
recommonmark==0.5.0
|
||||
requests==2.26.0
|
||||
six==1.16.0
|
||||
snowballstemmer==2.1.0
|
||||
Sphinx==1.8.5
|
||||
sphinx-rtd-theme==0.4.3
|
||||
sphinxcontrib-websupport==1.1.2
|
||||
#typing==3.10.0.0
|
||||
typing
|
||||
urllib3==1.26.7
|
|
@ -17,7 +17,7 @@ using widely supported formats like PEM or DER.
|
|||
|
||||
.. _curve_names:
|
||||
.. csv-table::
|
||||
:header: Curve, Possible identifiers
|
||||
:header: Curve, Strings accepted for the ``curve`` API parameter
|
||||
:widths: 20, 80
|
||||
|
||||
"NIST P-192", "``'NIST P-192'``, ``'p192'``, ``'P-192'``, ``'prime192v1'``, ``'secp192r1'``"
|
||||
|
@ -25,9 +25,12 @@ using widely supported formats like PEM or DER.
|
|||
"NIST P-256", "``'NIST P-256'``, ``'p256'``, ``'P-256'``, ``'prime256v1'``, ``'secp256r1'``"
|
||||
"NIST P-384", "``'NIST P-384'``, ``'p384'``, ``'P-384'``, ``'prime384v1'``, ``'secp384r1'``"
|
||||
"NIST P-521", "``'NIST P-521'``, ``'p521'``, ``'P-521'``, ``'prime521v1'``, ``'secp521r1'``"
|
||||
"Ed25519", "``'ed25519'``, ``'Ed25519'``"
|
||||
|
||||
For more information about each NIST curve see `FIPS 186-4`_, Section D.1.2.
|
||||
|
||||
The Ed25519 curve is defined in RFC8032_.
|
||||
|
||||
The following example demonstrates how to generate a new ECC key, export it,
|
||||
and subsequently reload it back into the application::
|
||||
|
||||
|
@ -42,11 +45,12 @@ and subsequently reload it back into the application::
|
|||
>>> f = open('myprivatekey.pem','rt')
|
||||
>>> key = ECC.import_key(f.read())
|
||||
|
||||
The ECC key can be used to perform or verify ECDSA signatures, using the module
|
||||
:mod:`Crypto.Signature.DSS`.
|
||||
The ECC key can be used to perform or verify ECDSA signatures, using the modules
|
||||
:mod:`Crypto.Signature.DSS` (NIST curves only) or :mod:`Crypto.Signature.eddsa` (Ed25519 curve only).
|
||||
|
||||
.. _ECC: http://andrea.corbellini.name/2015/05/17/elliptic-curve-cryptography-a-gentle-introduction/
|
||||
.. _`FIPS 186-4`: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
|
||||
.. _RFC8032: https://datatracker.ietf.org/doc/html/rfc8032
|
||||
|
||||
.. automodule:: Crypto.PublicKey.ECC
|
||||
:members:
|
||||
|
|
|
@ -43,5 +43,7 @@ Available mechanisms
|
|||
|
||||
* :doc:`pkcs1_pss`
|
||||
|
||||
* :doc:`eddsa`
|
||||
|
||||
* :doc:`dsa`
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ def wrap(private_key, key_oid, passphrase=None, protection=None,
|
|||
| | value is 1. |
|
||||
+------------------+-----------------------------------------------+
|
||||
|
||||
key_params (DER object):
|
||||
key_params (DER object or Null):
|
||||
The algorithm parameters associated to the private key.
|
||||
It is required for algorithms like DSA, but not for others like RSA.
|
||||
|
||||
|
@ -106,9 +106,6 @@ def wrap(private_key, key_oid, passphrase=None, protection=None,
|
|||
The PKCS#8-wrapped private key (possibly encrypted), as a byte string.
|
||||
"""
|
||||
|
||||
if key_params is None:
|
||||
key_params = DerNull()
|
||||
|
||||
#
|
||||
# PrivateKeyInfo ::= SEQUENCE {
|
||||
# version Version,
|
||||
|
@ -117,12 +114,14 @@ def wrap(private_key, key_oid, passphrase=None, protection=None,
|
|||
# attributes [0] IMPLICIT Attributes OPTIONAL
|
||||
# }
|
||||
#
|
||||
if key_params is None:
|
||||
algorithm = DerSequence([DerObjectId(key_oid)])
|
||||
else:
|
||||
algorithm = DerSequence([DerObjectId(key_oid), key_params])
|
||||
|
||||
pk_info = DerSequence([
|
||||
0,
|
||||
DerSequence([
|
||||
DerObjectId(key_oid),
|
||||
key_params
|
||||
]),
|
||||
algorithm,
|
||||
DerOctetString(private_key)
|
||||
])
|
||||
pk_info_der = pk_info.encode()
|
||||
|
@ -185,11 +184,12 @@ def unwrap(p8_private_key, passphrase=None):
|
|||
if not found:
|
||||
raise ValueError("Error decoding PKCS#8 (%s)" % error_str)
|
||||
|
||||
pk_info = DerSequence().decode(p8_private_key, nr_elements=(2, 3, 4))
|
||||
pk_info = DerSequence().decode(p8_private_key, nr_elements=(2, 3, 4, 5))
|
||||
if len(pk_info) == 2 and not passphrase:
|
||||
raise ValueError("Not a valid clear PKCS#8 structure "
|
||||
"(maybe it is encrypted?)")
|
||||
|
||||
# RFC5208, PKCS#8, version is v1(0)
|
||||
#
|
||||
# PrivateKeyInfo ::= SEQUENCE {
|
||||
# version Version,
|
||||
|
@ -197,22 +197,27 @@ def unwrap(p8_private_key, passphrase=None):
|
|||
# privateKey PrivateKey,
|
||||
# attributes [0] IMPLICIT Attributes OPTIONAL
|
||||
# }
|
||||
# Version ::= INTEGER
|
||||
if pk_info[0] != 0:
|
||||
raise ValueError("Not a valid PrivateKeyInfo SEQUENCE")
|
||||
|
||||
# PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
|
||||
#
|
||||
# EncryptedPrivateKeyInfo ::= SEQUENCE {
|
||||
# encryptionAlgorithm EncryptionAlgorithmIdentifier,
|
||||
# encryptedData EncryptedData
|
||||
# RFC5915, Asymmetric Key Package, version is v2(1)
|
||||
#
|
||||
# OneAsymmetricKey ::= SEQUENCE {
|
||||
# version Version,
|
||||
# privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
|
||||
# privateKey PrivateKey,
|
||||
# attributes [0] Attributes OPTIONAL,
|
||||
# ...,
|
||||
# [[2: publicKey [1] PublicKey OPTIONAL ]],
|
||||
# ...
|
||||
# }
|
||||
# EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
|
||||
|
||||
# AlgorithmIdentifier ::= SEQUENCE {
|
||||
# algorithm OBJECT IDENTIFIER,
|
||||
# parameters ANY DEFINED BY algorithm OPTIONAL
|
||||
# }
|
||||
if pk_info[0] == 0:
|
||||
if len(pk_info) not in (3, 4):
|
||||
raise ValueError("Not a valid PrivateKeyInfo SEQUENCE")
|
||||
elif pk_info[0] == 1:
|
||||
if len(pk_info) not in (3, 4, 5):
|
||||
raise ValueError("Not a valid PrivateKeyInfo SEQUENCE")
|
||||
else:
|
||||
raise ValueError("Not a valid PrivateKeyInfo SEQUENCE")
|
||||
|
||||
algo = DerSequence().decode(pk_info[1], nr_elements=(1, 2))
|
||||
algo_oid = DerObjectId().decode(algo[0]).value
|
||||
|
@ -225,7 +230,9 @@ def unwrap(p8_private_key, passphrase=None):
|
|||
except:
|
||||
algo_params = algo[1]
|
||||
|
||||
# EncryptedData ::= OCTET STRING
|
||||
# PrivateKey ::= OCTET STRING
|
||||
private_key = DerOctetString().decode(pk_info[2]).payload
|
||||
|
||||
# We ignore attributes and (for v2 only) publickey
|
||||
|
||||
return (algo_oid, private_key, algo_params)
|
||||
|
|
|
@ -51,12 +51,12 @@ class IntegerBase(ABC):
|
|||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def to_bytes(self, block_size=0):
|
||||
def to_bytes(self, block_size=0, byteorder='big'):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
@abc.abstractmethod
|
||||
def from_bytes(byte_string):
|
||||
def from_bytes(byte_string, byteorder='big'):
|
||||
pass
|
||||
|
||||
# Relations
|
||||
|
|
|
@ -7,9 +7,9 @@ class IntegerBase:
|
|||
def __int__(self) -> int: ...
|
||||
def __str__(self) -> str: ...
|
||||
def __repr__(self) -> str: ...
|
||||
def to_bytes(self, block_size: Optional[int]=0) -> bytes: ...
|
||||
def to_bytes(self, block_size: Optional[int]=0, byteorder: str= ...) -> bytes: ...
|
||||
@staticmethod
|
||||
def from_bytes(byte_string: bytes) -> IntegerBase: ...
|
||||
def from_bytes(byte_string: bytes, byteorder: Optional[str] = ...) -> IntegerBase: ...
|
||||
def __eq__(self, term: object) -> bool: ...
|
||||
def __ne__(self, term: object) -> bool: ...
|
||||
def __lt__(self, term: Union[IntegerBase, int]) -> bool: ...
|
||||
|
|
|
@ -57,7 +57,14 @@ implementation = {"library": "custom", "api": backend}
|
|||
class IntegerCustom(IntegerNative):
|
||||
|
||||
@staticmethod
|
||||
def from_bytes(byte_string):
|
||||
def from_bytes(byte_string, byteorder='big'):
|
||||
if byteorder == 'big':
|
||||
pass
|
||||
elif byteorder == 'little':
|
||||
byte_string = bytearray(byte_string)
|
||||
byte_string.reverse()
|
||||
else:
|
||||
raise ValueError("Incorrect byteorder")
|
||||
return IntegerCustom(bytes_to_long(byte_string))
|
||||
|
||||
def inplace_pow(self, exponent, modulus=None):
|
||||
|
|
|
@ -35,7 +35,7 @@ from Crypto.Util.py3compat import tobytes, is_native_int
|
|||
from Crypto.Util._raw_api import (backend, load_lib,
|
||||
get_raw_buffer, get_c_string,
|
||||
null_pointer, create_string_buffer,
|
||||
c_ulong, c_size_t)
|
||||
c_ulong, c_size_t, c_uint8_ptr)
|
||||
|
||||
from ._IntegerBase import IntegerBase
|
||||
|
||||
|
@ -225,7 +225,7 @@ class IntegerGMP(IntegerBase):
|
|||
def __index__(self):
|
||||
return int(self)
|
||||
|
||||
def to_bytes(self, block_size=0):
|
||||
def to_bytes(self, block_size=0, byteorder='big'):
|
||||
"""Convert the number into a byte string.
|
||||
|
||||
This method encodes the number in network order and prepends
|
||||
|
@ -236,6 +236,8 @@ class IntegerGMP(IntegerBase):
|
|||
block_size : integer
|
||||
The exact size the output byte string must have.
|
||||
If zero, the string has the minimal length.
|
||||
byteorder : string
|
||||
'big' for big-endian integers (default), 'little' for litte-endian.
|
||||
:Returns:
|
||||
A byte string.
|
||||
:Raise ValueError:
|
||||
|
@ -252,6 +254,7 @@ class IntegerGMP(IntegerBase):
|
|||
" of prescribed length")
|
||||
buf = create_string_buffer(buf_len)
|
||||
|
||||
|
||||
_gmp.mpz_export(
|
||||
buf,
|
||||
null_pointer, # Ignore countp
|
||||
|
@ -261,20 +264,39 @@ class IntegerGMP(IntegerBase):
|
|||
c_size_t(0), # No nails
|
||||
self._mpz_p)
|
||||
|
||||
return b'\x00' * max(0, block_size - buf_len) + get_raw_buffer(buf)
|
||||
result = b'\x00' * max(0, block_size - buf_len) + get_raw_buffer(buf)
|
||||
if byteorder == 'big':
|
||||
pass
|
||||
elif byteorder == 'little':
|
||||
result = bytearray(result)
|
||||
result.reverse()
|
||||
result = bytes(result)
|
||||
else:
|
||||
raise ValueError("Incorrect byteorder")
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def from_bytes(byte_string):
|
||||
def from_bytes(byte_string, byteorder='big'):
|
||||
"""Convert a byte string into a number.
|
||||
|
||||
:Parameters:
|
||||
byte_string : byte string
|
||||
The input number, encoded in network order.
|
||||
It can only be non-negative.
|
||||
byteorder : string
|
||||
'big' for big-endian integers (default), 'little' for litte-endian.
|
||||
|
||||
:Return:
|
||||
The ``Integer`` object carrying the same value as the input.
|
||||
"""
|
||||
result = IntegerGMP(0)
|
||||
if byteorder == 'big':
|
||||
pass
|
||||
elif byteorder == 'little':
|
||||
byte_string = bytearray(byte_string)
|
||||
byte_string.reverse()
|
||||
else:
|
||||
raise ValueError("Incorrect byteorder")
|
||||
_gmp.mpz_import(
|
||||
result._mpz_p,
|
||||
c_size_t(len(byte_string)), # Amount of words to read
|
||||
|
@ -282,7 +304,7 @@ class IntegerGMP(IntegerBase):
|
|||
c_size_t(1), # Each word is 1 byte long
|
||||
0, # Endianess within a word - not relevant
|
||||
c_size_t(0), # No nails
|
||||
byte_string)
|
||||
c_uint8_ptr(byte_string))
|
||||
return result
|
||||
|
||||
# Relations
|
||||
|
|
|
@ -62,16 +62,31 @@ class IntegerNative(IntegerBase):
|
|||
def __index__(self):
|
||||
return int(self._value)
|
||||
|
||||
def to_bytes(self, block_size=0):
|
||||
def to_bytes(self, block_size=0, byteorder='big'):
|
||||
if self._value < 0:
|
||||
raise ValueError("Conversion only valid for non-negative numbers")
|
||||
result = long_to_bytes(self._value, block_size)
|
||||
if len(result) > block_size > 0:
|
||||
raise ValueError("Value too large to encode")
|
||||
if byteorder == 'big':
|
||||
pass
|
||||
elif byteorder == 'little':
|
||||
result = bytearray(result)
|
||||
result.reverse()
|
||||
result = bytes(result)
|
||||
else:
|
||||
raise ValueError("Incorrect byteorder")
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def from_bytes(cls, byte_string):
|
||||
def from_bytes(cls, byte_string, byteorder='big'):
|
||||
if byteorder == 'big':
|
||||
pass
|
||||
elif byteorder == 'little':
|
||||
byte_string = bytearray(byte_string)
|
||||
byte_string.reverse()
|
||||
else:
|
||||
raise ValueError("Incorrect byteorder")
|
||||
return cls(bytes_to_long(byte_string))
|
||||
|
||||
# Relations
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -62,3 +62,4 @@ def construct(**kwargs: Union[str, int]) -> EccKey: ...
|
|||
def import_key(encoded: Union[bytes, str],
|
||||
passphrase: Optional[str]=None,
|
||||
curve_name:Optional[str]=None) -> EccKey: ...
|
||||
def _import_ed25519_public_key(encoded: bytes) -> EccKey: ...
|
||||
|
|
|
@ -37,7 +37,7 @@ import struct
|
|||
|
||||
from Crypto import Random
|
||||
from Crypto.Util.py3compat import tobytes, bord, tostr
|
||||
from Crypto.Util.asn1 import DerSequence
|
||||
from Crypto.Util.asn1 import DerSequence, DerNull
|
||||
|
||||
from Crypto.Math.Numbers import Integer
|
||||
from Crypto.Math.Primality import (test_probable_prime,
|
||||
|
@ -339,19 +339,22 @@ class RsaKey(object):
|
|||
|
||||
if format == 'PEM' and protection is None:
|
||||
key_type = 'PRIVATE KEY'
|
||||
binary_key = PKCS8.wrap(binary_key, oid, None)
|
||||
binary_key = PKCS8.wrap(binary_key, oid, None,
|
||||
key_params=DerNull())
|
||||
else:
|
||||
key_type = 'ENCRYPTED PRIVATE KEY'
|
||||
if not protection:
|
||||
protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC'
|
||||
binary_key = PKCS8.wrap(binary_key, oid,
|
||||
passphrase, protection)
|
||||
passphrase, protection,
|
||||
key_params=DerNull())
|
||||
passphrase = None
|
||||
else:
|
||||
key_type = "PUBLIC KEY"
|
||||
binary_key = _create_subject_public_key_info(oid,
|
||||
DerSequence([self.n,
|
||||
self.e])
|
||||
self.e]),
|
||||
DerNull()
|
||||
)
|
||||
|
||||
if format == 'DER':
|
||||
|
|
|
@ -60,17 +60,16 @@ def _expand_subject_public_key_info(encoded):
|
|||
return algo_oid.value, spk, algo_params
|
||||
|
||||
|
||||
def _create_subject_public_key_info(algo_oid, secret_key, params=None):
|
||||
def _create_subject_public_key_info(algo_oid, public_key, params):
|
||||
|
||||
if params is None:
|
||||
params = DerNull()
|
||||
algorithm = DerSequence([DerObjectId(algo_oid)])
|
||||
else:
|
||||
algorithm = DerSequence([DerObjectId(algo_oid), params])
|
||||
|
||||
spki = DerSequence([
|
||||
DerSequence([
|
||||
DerObjectId(algo_oid),
|
||||
params]),
|
||||
DerBitString(secret_key)
|
||||
])
|
||||
spki = DerSequence([algorithm,
|
||||
DerBitString(public_key)
|
||||
])
|
||||
return spki.encode()
|
||||
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@ from binascii import unhexlify
|
|||
from Crypto.Util.py3compat import *
|
||||
from Crypto.IO import PKCS8
|
||||
|
||||
from Crypto.Util.asn1 import DerNull
|
||||
|
||||
oid_key = '1.2.840.113549.1.1.1'
|
||||
|
||||
# Original RSA key (in DER format)
|
||||
|
@ -407,7 +409,7 @@ class PKCS8_Decrypt(unittest.TestCase):
|
|||
b("TestTest"),
|
||||
protection=t[0],
|
||||
prot_params=params,
|
||||
key_params=None,
|
||||
key_params=DerNull(),
|
||||
randfunc=rng)
|
||||
self.assertEqual(wrapped, t[4])
|
||||
|
||||
|
|
|
@ -114,27 +114,42 @@ class TestIntegerBase(unittest.TestCase):
|
|||
v1 = Integer(0x17)
|
||||
self.assertEqual(b("\x17"), v1.to_bytes())
|
||||
|
||||
v2 = Integer(0xFFFF)
|
||||
self.assertEqual(b("\xFF\xFF"), v2.to_bytes())
|
||||
self.assertEqual(b("\x00\xFF\xFF"), v2.to_bytes(3))
|
||||
v2 = Integer(0xFFFE)
|
||||
self.assertEqual(b("\xFF\xFE"), v2.to_bytes())
|
||||
self.assertEqual(b("\x00\xFF\xFE"), v2.to_bytes(3))
|
||||
self.assertRaises(ValueError, v2.to_bytes, 1)
|
||||
|
||||
self.assertEqual(b("\xFE\xFF"), v2.to_bytes(byteorder='little'))
|
||||
self.assertEqual(b("\xFE\xFF\x00"), v2.to_bytes(3, byteorder='little'))
|
||||
|
||||
v3 = Integer(-90)
|
||||
self.assertRaises(ValueError, v3.to_bytes)
|
||||
self.assertRaises(ValueError, v3.to_bytes, byteorder='bittle')
|
||||
|
||||
def test_conversion_from_bytes(self):
|
||||
Integer = self.Integer
|
||||
|
||||
v1 = Integer.from_bytes(b("\x00"))
|
||||
v1 = Integer.from_bytes(b"\x00")
|
||||
self.assertTrue(isinstance(v1, Integer))
|
||||
self.assertEqual(0, v1)
|
||||
|
||||
v2 = Integer.from_bytes(b("\x00\x00"))
|
||||
self.assertEqual(0, v2)
|
||||
v2 = Integer.from_bytes(b"\x00\x01")
|
||||
self.assertEqual(1, v2)
|
||||
|
||||
v3 = Integer.from_bytes(b("\xFF\xFF"))
|
||||
v3 = Integer.from_bytes(b"\xFF\xFF")
|
||||
self.assertEqual(0xFFFF, v3)
|
||||
|
||||
v4 = Integer.from_bytes(b"\x00\x01", 'big')
|
||||
self.assertEqual(1, v4)
|
||||
|
||||
v5 = Integer.from_bytes(b"\x00\x01", byteorder='big')
|
||||
self.assertEqual(1, v5)
|
||||
|
||||
v6 = Integer.from_bytes(b"\x00\x01", byteorder='little')
|
||||
self.assertEqual(0x0100, v6)
|
||||
|
||||
self.assertRaises(ValueError, Integer.from_bytes, b'\x09', 'bittle')
|
||||
|
||||
def test_inequality(self):
|
||||
# Test Integer!=Integer and Integer!=int
|
||||
v1, v2, v3, v4 = self.Integers(89, 89, 90, -8)
|
||||
|
|
|
@ -24,31 +24,29 @@
|
|||
|
||||
"""Self-test for public-key crypto"""
|
||||
|
||||
__revision__ = "$Id$"
|
||||
import unittest
|
||||
from Crypto.SelfTest.PublicKey import (test_DSA, test_RSA,
|
||||
test_ECC_NIST, test_ECC_25519,
|
||||
test_import_DSA, test_import_RSA,
|
||||
test_import_ECC, test_ElGamal)
|
||||
|
||||
import os
|
||||
|
||||
def get_tests(config={}):
|
||||
tests = []
|
||||
from Crypto.SelfTest.PublicKey import test_DSA; tests += test_DSA.get_tests(config=config)
|
||||
from Crypto.SelfTest.PublicKey import test_RSA; tests += test_RSA.get_tests(config=config)
|
||||
from Crypto.SelfTest.PublicKey import test_ECC; tests += test_ECC.get_tests(config=config)
|
||||
tests += test_DSA.get_tests(config=config)
|
||||
tests += test_RSA.get_tests(config=config)
|
||||
tests += test_ECC_NIST.get_tests(config=config)
|
||||
tests += test_ECC_25519.get_tests(config=config)
|
||||
|
||||
from Crypto.SelfTest.PublicKey import test_import_DSA
|
||||
tests +=test_import_DSA.get_tests(config=config)
|
||||
|
||||
from Crypto.SelfTest.PublicKey import test_import_RSA
|
||||
tests += test_import_DSA.get_tests(config=config)
|
||||
tests += test_import_RSA.get_tests(config=config)
|
||||
|
||||
from Crypto.SelfTest.PublicKey import test_import_ECC
|
||||
tests += test_import_ECC.get_tests(config=config)
|
||||
|
||||
from Crypto.SelfTest.PublicKey import test_ElGamal; tests += test_ElGamal.get_tests(config=config)
|
||||
tests += test_ElGamal.get_tests(config=config)
|
||||
return tests
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
||||
if __name__ == '__main__':
|
||||
def suite():
|
||||
return unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
327
lib/Crypto/SelfTest/PublicKey/test_ECC_25519.py
Normal file
327
lib/Crypto/SelfTest/PublicKey/test_ECC_25519.py
Normal file
|
@ -0,0 +1,327 @@
|
|||
# ===================================================================
|
||||
#
|
||||
# Copyright (c) 2022, Legrandin <helderijs@gmail.com>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
# ===================================================================
|
||||
|
||||
import unittest
|
||||
from binascii import unhexlify
|
||||
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
from Crypto.SelfTest.loader import load_test_vectors
|
||||
|
||||
from Crypto.PublicKey import ECC
|
||||
from Crypto.PublicKey.ECC import EccPoint, _curves, EccKey
|
||||
|
||||
from Crypto.Math.Numbers import Integer
|
||||
|
||||
from Crypto.Hash import SHAKE128
|
||||
|
||||
|
||||
class TestEccPoint_Ed25519(unittest.TestCase):
|
||||
|
||||
Gxy = {"x": 15112221349535400772501151409588531511454012693041857206046113283949847762202,
|
||||
"y": 46316835694926478169428394003475163141307993866256225615783033603165251855960}
|
||||
|
||||
G2xy = {"x": 24727413235106541002554574571675588834622768167397638456726423682521233608206,
|
||||
"y": 15549675580280190176352668710449542251549572066445060580507079593062643049417}
|
||||
|
||||
G3xy = {"x": 46896733464454938657123544595386787789046198280132665686241321779790909858396,
|
||||
"y": 8324843778533443976490377120369201138301417226297555316741202210403726505172}
|
||||
|
||||
pointG = EccPoint(Gxy['x'], Gxy['y'], curve="Ed25519")
|
||||
pointG2 = EccPoint(G2xy['x'], G2xy['y'], curve="Ed25519")
|
||||
pointG3 = EccPoint(G3xy['x'], G3xy['y'], curve="Ed25519")
|
||||
|
||||
def test_init_xy(self):
|
||||
EccPoint(self.Gxy['x'], self.Gxy['y'], curve="Ed25519")
|
||||
|
||||
# Neutral point
|
||||
pai = EccPoint(0, 1, curve="Ed25519")
|
||||
self.assertEqual(pai.x, 0)
|
||||
self.assertEqual(pai.y, 1)
|
||||
self.assertEqual(pai.xy, (0, 1))
|
||||
|
||||
# G
|
||||
bp = self.pointG.copy()
|
||||
self.assertEqual(bp.x, 15112221349535400772501151409588531511454012693041857206046113283949847762202)
|
||||
self.assertEqual(bp.y, 46316835694926478169428394003475163141307993866256225615783033603165251855960)
|
||||
self.assertEqual(bp.xy, (bp.x, bp.y))
|
||||
|
||||
# 2G
|
||||
bp2 = self.pointG2.copy()
|
||||
self.assertEqual(bp2.x, 24727413235106541002554574571675588834622768167397638456726423682521233608206)
|
||||
self.assertEqual(bp2.y, 15549675580280190176352668710449542251549572066445060580507079593062643049417)
|
||||
self.assertEqual(bp2.xy, (bp2.x, bp2.y))
|
||||
|
||||
# 5G
|
||||
EccPoint(x=33467004535436536005251147249499675200073690106659565782908757308821616914995,
|
||||
y=43097193783671926753355113395909008640284023746042808659097434958891230611693,
|
||||
curve="Ed25519")
|
||||
|
||||
# Catch if point is not on the curve
|
||||
self.assertRaises(ValueError, EccPoint, 34, 35, curve="Ed25519")
|
||||
|
||||
def test_set(self):
|
||||
pointW = EccPoint(0, 1, curve="Ed25519")
|
||||
pointW.set(self.pointG)
|
||||
self.assertEqual(pointW.x, self.pointG.x)
|
||||
self.assertEqual(pointW.y, self.pointG.y)
|
||||
|
||||
def test_copy(self):
|
||||
pointW = self.pointG.copy()
|
||||
self.assertEqual(pointW.x, self.pointG.x)
|
||||
self.assertEqual(pointW.y, self.pointG.y)
|
||||
|
||||
def test_equal(self):
|
||||
pointH = self.pointG.copy()
|
||||
pointI = self.pointG2.copy()
|
||||
self.assertEqual(self.pointG, pointH)
|
||||
self.assertNotEqual(self.pointG, pointI)
|
||||
|
||||
def test_pai(self):
|
||||
pai = EccPoint(0, 1, curve="Ed25519")
|
||||
self.failUnless(pai.is_point_at_infinity())
|
||||
self.assertEqual(pai, pai.point_at_infinity())
|
||||
|
||||
def test_negate(self):
|
||||
negG = -self.pointG
|
||||
sum = self.pointG + negG
|
||||
self.failUnless(sum.is_point_at_infinity())
|
||||
|
||||
def test_addition(self):
|
||||
self.assertEqual(self.pointG + self.pointG2, self.pointG3)
|
||||
self.assertEqual(self.pointG2 + self.pointG, self.pointG3)
|
||||
self.assertEqual(self.pointG2 + self.pointG.point_at_infinity(), self.pointG2)
|
||||
self.assertEqual(self.pointG.point_at_infinity() + self.pointG2, self.pointG2)
|
||||
|
||||
G5 = self.pointG2 + self.pointG3
|
||||
self.assertEqual(G5.x, 33467004535436536005251147249499675200073690106659565782908757308821616914995)
|
||||
self.assertEqual(G5.y, 43097193783671926753355113395909008640284023746042808659097434958891230611693)
|
||||
|
||||
def test_inplace_addition(self):
|
||||
pointH = self.pointG.copy()
|
||||
pointH += self.pointG
|
||||
self.assertEqual(pointH, self.pointG2)
|
||||
pointH += self.pointG
|
||||
self.assertEqual(pointH, self.pointG3)
|
||||
pointH += self.pointG.point_at_infinity()
|
||||
self.assertEqual(pointH, self.pointG3)
|
||||
|
||||
def test_doubling(self):
|
||||
pointH = self.pointG.copy()
|
||||
pointH.double()
|
||||
self.assertEqual(pointH.x, self.pointG2.x)
|
||||
self.assertEqual(pointH.y, self.pointG2.y)
|
||||
|
||||
# 2*0
|
||||
pai = self.pointG.point_at_infinity()
|
||||
pointR = pai.copy()
|
||||
pointR.double()
|
||||
self.assertEqual(pointR, pai)
|
||||
|
||||
def test_scalar_multiply(self):
|
||||
d = 0
|
||||
pointH = d * self.pointG
|
||||
self.assertEqual(pointH.x, 0)
|
||||
self.assertEqual(pointH.y, 1)
|
||||
|
||||
d = 1
|
||||
pointH = d * self.pointG
|
||||
self.assertEqual(pointH.x, self.pointG.x)
|
||||
self.assertEqual(pointH.y, self.pointG.y)
|
||||
|
||||
d = 2
|
||||
pointH = d * self.pointG
|
||||
self.assertEqual(pointH.x, self.pointG2.x)
|
||||
self.assertEqual(pointH.y, self.pointG2.y)
|
||||
|
||||
d = 3
|
||||
pointH = d * self.pointG
|
||||
self.assertEqual(pointH.x, self.pointG3.x)
|
||||
self.assertEqual(pointH.y, self.pointG3.y)
|
||||
|
||||
d = 4
|
||||
pointH = d * self.pointG
|
||||
self.assertEqual(pointH.x, 14582954232372986451776170844943001818709880559417862259286374126315108956272)
|
||||
self.assertEqual(pointH.y, 32483318716863467900234833297694612235682047836132991208333042722294373421359)
|
||||
|
||||
d = 5
|
||||
pointH = d * self.pointG
|
||||
self.assertEqual(pointH.x, 33467004535436536005251147249499675200073690106659565782908757308821616914995)
|
||||
self.assertEqual(pointH.y, 43097193783671926753355113395909008640284023746042808659097434958891230611693)
|
||||
|
||||
d = 10
|
||||
pointH = d * self.pointG
|
||||
self.assertEqual(pointH.x, 43500613248243327786121022071801015118933854441360174117148262713429272820047)
|
||||
self.assertEqual(pointH.y, 45005105423099817237495816771148012388779685712352441364231470781391834741548)
|
||||
|
||||
d = 20
|
||||
pointH = d * self.pointG
|
||||
self.assertEqual(pointH.x, 46694936775300686710656303283485882876784402425210400817529601134760286812591)
|
||||
self.assertEqual(pointH.y, 8786390172762935853260670851718824721296437982862763585171334833968259029560)
|
||||
|
||||
d = 255
|
||||
pointH = d * self.pointG
|
||||
self.assertEqual(pointH.x, 36843863416400016952258312492144504209624961884991522125275155377549541182230)
|
||||
self.assertEqual(pointH.y, 22327030283879720808995671630924669697661065034121040761798775626517750047180)
|
||||
|
||||
d = 256
|
||||
pointH = d * self.pointG
|
||||
self.assertEqual(pointH.x, 42740085206947573681423002599456489563927820004573071834350074001818321593686)
|
||||
self.assertEqual(pointH.y, 6935684722522267618220753829624209639984359598320562595061366101608187623111)
|
||||
|
||||
def test_sizes(self):
|
||||
self.assertEqual(self.pointG.size_in_bits(), 255)
|
||||
self.assertEqual(self.pointG.size_in_bytes(), 32)
|
||||
|
||||
|
||||
class TestEccKey_Ed25519(unittest.TestCase):
|
||||
|
||||
def test_private_key(self):
|
||||
seed = unhexlify("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")
|
||||
Px = 38815646466658113194383306759739515082307681141926459231621296960732224964046
|
||||
Py = 11903303657706407974989296177215005343713679411332034699907763981919547054807
|
||||
|
||||
key = EccKey(curve="Ed25519", seed=seed)
|
||||
self.assertEqual(key.seed, seed)
|
||||
self.assertEqual(key.d, 36144925721603087658594284515452164870581325872720374094707712194495455132720)
|
||||
self.assertTrue(key.has_private())
|
||||
self.assertEqual(key.pointQ.x, Px)
|
||||
self.assertEqual(key.pointQ.y, Py)
|
||||
|
||||
point = EccPoint(Px, Py, "ed25519")
|
||||
key = EccKey(curve="Ed25519", seed=seed, point=point)
|
||||
self.assertEqual(key.d, 36144925721603087658594284515452164870581325872720374094707712194495455132720)
|
||||
self.assertTrue(key.has_private())
|
||||
self.assertEqual(key.pointQ, point)
|
||||
|
||||
# Other names
|
||||
key = EccKey(curve="ed25519", seed=seed)
|
||||
|
||||
# Must not accept d parameter
|
||||
self.assertRaises(ValueError, EccKey, curve="ed25519", d=1)
|
||||
|
||||
def test_public_key(self):
|
||||
point = EccPoint(_curves['ed25519'].Gx, _curves['ed25519'].Gy, curve='ed25519')
|
||||
key = EccKey(curve="ed25519", point=point)
|
||||
self.assertFalse(key.has_private())
|
||||
self.assertEqual(key.pointQ, point)
|
||||
|
||||
def test_public_key_derived(self):
|
||||
priv_key = EccKey(curve="ed25519", seed=b'H'*32)
|
||||
pub_key = priv_key.public_key()
|
||||
self.assertFalse(pub_key.has_private())
|
||||
self.assertEqual(priv_key.pointQ, pub_key.pointQ)
|
||||
|
||||
def test_invalid_seed(self):
|
||||
self.assertRaises(ValueError, lambda: EccKey(curve="ed25519", seed=b'H' * 31))
|
||||
|
||||
def test_equality(self):
|
||||
private_key = ECC.construct(seed=b'H'*32, curve="Ed25519")
|
||||
private_key2 = ECC.construct(seed=b'H'*32, curve="ed25519")
|
||||
private_key3 = ECC.construct(seed=b'C'*32, curve="Ed25519")
|
||||
|
||||
public_key = private_key.public_key()
|
||||
public_key2 = private_key2.public_key()
|
||||
public_key3 = private_key3.public_key()
|
||||
|
||||
self.assertEqual(private_key, private_key2)
|
||||
self.assertNotEqual(private_key, private_key3)
|
||||
|
||||
self.assertEqual(public_key, public_key2)
|
||||
self.assertNotEqual(public_key, public_key3)
|
||||
|
||||
self.assertNotEqual(public_key, private_key)
|
||||
|
||||
|
||||
class TestEccModule_Ed25519(unittest.TestCase):
|
||||
|
||||
def test_generate(self):
|
||||
key = ECC.generate(curve="Ed25519")
|
||||
self.assertTrue(key.has_private())
|
||||
point = EccPoint(_curves['Ed25519'].Gx, _curves['Ed25519'].Gy, curve="Ed25519") * key.d
|
||||
self.assertEqual(key.pointQ, point)
|
||||
|
||||
# Always random
|
||||
key2 = ECC.generate(curve="Ed25519")
|
||||
self.assertNotEqual(key, key2)
|
||||
|
||||
# Other names
|
||||
ECC.generate(curve="Ed25519")
|
||||
|
||||
# Random source
|
||||
key1 = ECC.generate(curve="Ed25519", randfunc=SHAKE128.new().read)
|
||||
key2 = ECC.generate(curve="Ed25519", randfunc=SHAKE128.new().read)
|
||||
self.assertEqual(key1, key2)
|
||||
|
||||
def test_construct(self):
|
||||
seed = unhexlify("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")
|
||||
Px = 38815646466658113194383306759739515082307681141926459231621296960732224964046
|
||||
Py = 11903303657706407974989296177215005343713679411332034699907763981919547054807
|
||||
d = 36144925721603087658594284515452164870581325872720374094707712194495455132720
|
||||
point = EccPoint(Px, Py, curve="Ed25519")
|
||||
|
||||
# Private key only
|
||||
key = ECC.construct(curve="Ed25519", seed=seed)
|
||||
self.assertEqual(key.pointQ, point)
|
||||
self.assertTrue(key.has_private())
|
||||
|
||||
# Public key only
|
||||
key = ECC.construct(curve="Ed25519", point_x=Px, point_y=Py)
|
||||
self.assertEqual(key.pointQ, point)
|
||||
self.assertFalse(key.has_private())
|
||||
|
||||
# Private and public key
|
||||
key = ECC.construct(curve="Ed25519", seed=seed, point_x=Px, point_y=Py)
|
||||
self.assertEqual(key.pointQ, point)
|
||||
self.assertTrue(key.has_private())
|
||||
|
||||
# Other names
|
||||
key = ECC.construct(curve="ed25519", seed=seed)
|
||||
|
||||
def test_negative_construct(self):
|
||||
coord = dict(point_x=10, point_y=4)
|
||||
coordG = dict(point_x=_curves['ed25519'].Gx, point_y=_curves['ed25519'].Gy)
|
||||
|
||||
self.assertRaises(ValueError, ECC.construct, curve="Ed25519", **coord)
|
||||
self.assertRaises(ValueError, ECC.construct, curve="Ed25519", d=2, **coordG)
|
||||
self.assertRaises(ValueError, ECC.construct, curve="Ed25519", seed=b'H'*31)
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
tests = []
|
||||
tests += list_test_cases(TestEccPoint_Ed25519)
|
||||
tests += list_test_cases(TestEccKey_Ed25519)
|
||||
tests += list_test_cases(TestEccModule_Ed25519)
|
||||
return tests
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
def suite():
|
||||
return unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
|
@ -29,6 +29,8 @@
|
|||
# ===================================================================
|
||||
|
||||
import unittest
|
||||
from binascii import unhexlify
|
||||
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
from Crypto.SelfTest.loader import load_test_vectors
|
||||
|
||||
|
@ -190,7 +192,7 @@ class TestEccPoint_NIST_P192(unittest.TestCase):
|
|||
self.assertEqual(pointR.x, pointRx)
|
||||
self.assertEqual(pointR.y, pointRy)
|
||||
|
||||
def test_joing_scalar_multiply(self):
|
||||
def test_joint_scalar_multiply(self):
|
||||
d = 0xa78a236d60baec0c5dd41b33a542463a8255391af64c74ee
|
||||
e = 0xc4be3d53ec3089e71e4de8ceab7cce889bc393cd85b972bc
|
||||
pointRx = 0x019f64eed8fa9b72b7dfea82c17c9bfa60ecb9e1778b5bde
|
||||
|
@ -993,6 +995,9 @@ class TestEccKey_P256(unittest.TestCase):
|
|||
key = EccKey(curve="secp256r1", d=1)
|
||||
key = EccKey(curve="prime256v1", d=1)
|
||||
|
||||
# Must not accept d parameter
|
||||
self.assertRaises(ValueError, EccKey, curve="p256", seed=b'H'*32)
|
||||
|
||||
def test_public_key(self):
|
||||
|
||||
point = EccPoint(_curves['p256'].Gx, _curves['p256'].Gy)
|
|
@ -148,6 +148,14 @@ def create_ref_keys_p521():
|
|||
return (ECC.construct(curve="P-521", d=private_key_d),
|
||||
ECC.construct(curve="P-521", point_x=public_key_x, point_y=public_key_y))
|
||||
|
||||
|
||||
def create_ref_keys_ed25519():
|
||||
key_lines = load_file("ecc_ed25519.txt").splitlines()
|
||||
seed = compact(key_lines[5:8])
|
||||
key = ECC.construct(curve="Ed25519", seed=seed)
|
||||
return (key, key.public_key())
|
||||
|
||||
|
||||
# Create reference key pair
|
||||
# ref_private, ref_public = create_ref_keys_p521()
|
||||
|
||||
|
@ -199,10 +207,10 @@ class TestImport_P192(unittest.TestCase):
|
|||
key = ECC.import_key(key_file, curve_name='P192')
|
||||
self.assertEqual(self.ref_public, key)
|
||||
|
||||
def test_import_private_der(self):
|
||||
def test_import_rfc5915_der(self):
|
||||
key_file = load_file("ecc_p192_private.der")
|
||||
|
||||
key = ECC._import_private_der(key_file, None)
|
||||
key = ECC._import_rfc5915_der(key_file, None)
|
||||
self.assertEqual(self.ref_private, key)
|
||||
|
||||
key = ECC._import_der(key_file, None)
|
||||
|
@ -309,10 +317,10 @@ class TestImport_P224(unittest.TestCase):
|
|||
key = ECC.import_key(key_file, curve_name='P224')
|
||||
self.assertEqual(self.ref_public, key)
|
||||
|
||||
def test_import_private_der(self):
|
||||
def test_import_rfc5915_der(self):
|
||||
key_file = load_file("ecc_p224_private.der")
|
||||
|
||||
key = ECC._import_private_der(key_file, None)
|
||||
key = ECC._import_rfc5915_der(key_file, None)
|
||||
self.assertEqual(self.ref_private, key)
|
||||
|
||||
key = ECC._import_der(key_file, None)
|
||||
|
@ -419,10 +427,10 @@ class TestImport_P256(unittest.TestCase):
|
|||
key = ECC.import_key(key_file, curve_name='P256')
|
||||
self.assertEqual(self.ref_public, key)
|
||||
|
||||
def test_import_private_der(self):
|
||||
def test_import_rfc5915_der(self):
|
||||
key_file = load_file("ecc_p256_private.der")
|
||||
|
||||
key = ECC._import_private_der(key_file, None)
|
||||
key = ECC._import_rfc5915_der(key_file, None)
|
||||
self.assertEqual(self.ref_private, key)
|
||||
|
||||
key = ECC._import_der(key_file, None)
|
||||
|
@ -559,10 +567,10 @@ class TestImport_P384(unittest.TestCase):
|
|||
key = ECC.import_key(key_file, curve_name='P384')
|
||||
self.assertEqual(self.ref_public, key)
|
||||
|
||||
def test_import_private_der(self):
|
||||
def test_import_rfc5915_der(self):
|
||||
key_file = load_file("ecc_p384_private.der")
|
||||
|
||||
key = ECC._import_private_der(key_file, None)
|
||||
key = ECC._import_rfc5915_der(key_file, None)
|
||||
self.assertEqual(self.ref_private, key)
|
||||
|
||||
key = ECC._import_der(key_file, None)
|
||||
|
@ -694,10 +702,10 @@ class TestImport_P521(unittest.TestCase):
|
|||
key = ECC.import_key(key_file, curve_name='P521')
|
||||
self.assertEqual(self.ref_public, key)
|
||||
|
||||
def test_import_private_der(self):
|
||||
def test_import_rfc5915_der(self):
|
||||
key_file = load_file("ecc_p521_private.der")
|
||||
|
||||
key = ECC._import_private_der(key_file, None)
|
||||
key = ECC._import_rfc5915_der(key_file, None)
|
||||
self.assertEqual(self.ref_private, key)
|
||||
|
||||
key = ECC._import_der(key_file, None)
|
||||
|
@ -840,10 +848,10 @@ class TestExport_P192(unittest.TestCase):
|
|||
value = extract_bitstring_from_spki(key_file_compressed_ref)
|
||||
self.assertEqual(value, encoded)
|
||||
|
||||
def test_export_private_der(self):
|
||||
def test_export_rfc5915_private_der(self):
|
||||
key_file = load_file("ecc_p192_private.der")
|
||||
|
||||
encoded = self.ref_private._export_private_der()
|
||||
encoded = self.ref_private._export_rfc5915_private_der()
|
||||
self.assertEqual(key_file, encoded)
|
||||
|
||||
# ---
|
||||
|
@ -1094,10 +1102,10 @@ class TestExport_P224(unittest.TestCase):
|
|||
value = extract_bitstring_from_spki(key_file_compressed_ref)
|
||||
self.assertEqual(value, encoded)
|
||||
|
||||
def test_export_private_der(self):
|
||||
def test_export_rfc5915_private_der(self):
|
||||
key_file = load_file("ecc_p224_private.der")
|
||||
|
||||
encoded = self.ref_private._export_private_der()
|
||||
encoded = self.ref_private._export_rfc5915_private_der()
|
||||
self.assertEqual(key_file, encoded)
|
||||
|
||||
# ---
|
||||
|
@ -1348,10 +1356,10 @@ class TestExport_P256(unittest.TestCase):
|
|||
value = extract_bitstring_from_spki(key_file_compressed_ref)
|
||||
self.assertEqual(value, encoded)
|
||||
|
||||
def test_export_private_der(self):
|
||||
def test_export_rfc5915_private_der(self):
|
||||
key_file = load_file("ecc_p256_private.der")
|
||||
|
||||
encoded = self.ref_private._export_private_der()
|
||||
encoded = self.ref_private._export_rfc5915_private_der()
|
||||
self.assertEqual(key_file, encoded)
|
||||
|
||||
# ---
|
||||
|
@ -1627,10 +1635,10 @@ class TestExport_P384(unittest.TestCase):
|
|||
value = extract_bitstring_from_spki(key_file_compressed_ref)
|
||||
self.assertEqual(value, encoded)
|
||||
|
||||
def test_export_private_der(self):
|
||||
def test_export_rfc5915_private_der(self):
|
||||
key_file = load_file("ecc_p384_private.der")
|
||||
|
||||
encoded = self.ref_private._export_private_der()
|
||||
encoded = self.ref_private._export_rfc5915_private_der()
|
||||
self.assertEqual(key_file, encoded)
|
||||
|
||||
# ---
|
||||
|
@ -1911,10 +1919,10 @@ class TestExport_P521(unittest.TestCase):
|
|||
value = extract_bitstring_from_spki(key_file_compressed_ref)
|
||||
self.assertEqual(value, encoded)
|
||||
|
||||
def test_export_private_der(self):
|
||||
def test_export_rfc5915_private_der(self):
|
||||
key_file = load_file("ecc_p521_private.der")
|
||||
|
||||
encoded = self.ref_private._export_private_der()
|
||||
encoded = self.ref_private._export_rfc5915_private_der()
|
||||
self.assertEqual(key_file, encoded)
|
||||
|
||||
# ---
|
||||
|
@ -2156,6 +2164,231 @@ vv6oYkMIIi7r5oQWAiQDrR2mlrrFDL9V7GH/r8SWQw==
|
|||
self.assertEqual(low16, 0x9643)
|
||||
|
||||
|
||||
class TestImport_Ed25519(unittest.TestCase):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(TestImport_Ed25519, self).__init__(*args, **kwargs)
|
||||
self.ref_private, self.ref_public = create_ref_keys_ed25519()
|
||||
|
||||
def test_import_public_der(self):
|
||||
key_file = load_file("ecc_ed25519_public.der")
|
||||
|
||||
key = ECC._import_subjectPublicKeyInfo(key_file)
|
||||
self.assertEqual(self.ref_public, key)
|
||||
|
||||
key = ECC._import_der(key_file, None)
|
||||
self.assertEqual(self.ref_public, key)
|
||||
|
||||
key = ECC.import_key(key_file)
|
||||
self.assertEqual(self.ref_public, key)
|
||||
|
||||
def test_import_pkcs8_der(self):
|
||||
key_file = load_file("ecc_ed25519_private.der")
|
||||
|
||||
key = ECC._import_der(key_file, None)
|
||||
self.assertEqual(self.ref_private, key)
|
||||
|
||||
key = ECC.import_key(key_file)
|
||||
self.assertEqual(self.ref_private, key)
|
||||
|
||||
def test_import_private_pkcs8_encrypted_1(self):
|
||||
key_file = load_file("ecc_ed25519_private_p8.der")
|
||||
|
||||
key = ECC._import_der(key_file, "secret")
|
||||
self.assertEqual(self.ref_private, key)
|
||||
|
||||
key = ECC.import_key(key_file, "secret")
|
||||
self.assertEqual(self.ref_private, key)
|
||||
|
||||
def test_import_private_pkcs8_encrypted_2(self):
|
||||
key_file = load_file("ecc_ed25519_private_p8.pem")
|
||||
|
||||
key = ECC.import_key(key_file, "secret")
|
||||
self.assertEqual(self.ref_private, key)
|
||||
|
||||
def test_import_x509_der(self):
|
||||
key_file = load_file("ecc_ed25519_x509.der")
|
||||
|
||||
key = ECC._import_der(key_file, None)
|
||||
self.assertEqual(self.ref_public, key)
|
||||
|
||||
key = ECC.import_key(key_file)
|
||||
self.assertEqual(self.ref_public, key)
|
||||
|
||||
def test_import_public_pem(self):
|
||||
key_file = load_file("ecc_ed25519_public.pem")
|
||||
|
||||
key = ECC.import_key(key_file)
|
||||
self.assertEqual(self.ref_public, key)
|
||||
|
||||
def test_import_private_pem(self):
|
||||
key_file = load_file("ecc_ed25519_private.pem")
|
||||
|
||||
key = ECC.import_key(key_file)
|
||||
self.assertEqual(self.ref_private, key)
|
||||
|
||||
def test_import_private_pem_encrypted(self):
|
||||
for algo in "des3", "aes128", "aes192", "aes256":
|
||||
key_file = load_file("ecc_ed25519_private_enc_%s.pem" % algo)
|
||||
|
||||
key = ECC.import_key(key_file, "secret")
|
||||
self.assertEqual(self.ref_private, key)
|
||||
|
||||
key = ECC.import_key(tostr(key_file), b"secret")
|
||||
self.assertEqual(self.ref_private, key)
|
||||
|
||||
def test_import_x509_pem(self):
|
||||
key_file = load_file("ecc_ed25519_x509.pem")
|
||||
|
||||
key = ECC.import_key(key_file)
|
||||
self.assertEqual(self.ref_public, key)
|
||||
|
||||
def test_import_openssh_public(self):
|
||||
key_file = load_file("ecc_ed25519_public_openssh.txt")
|
||||
key = ECC._import_openssh_public(key_file)
|
||||
self.failIf(key.has_private())
|
||||
key = ECC.import_key(key_file)
|
||||
self.failIf(key.has_private())
|
||||
|
||||
def test_import_openssh_private_clear(self):
|
||||
key_file = load_file("ecc_ed25519_private_openssh.pem")
|
||||
key = ECC.import_key(key_file)
|
||||
|
||||
def test_import_openssh_private_password(self):
|
||||
key_file = load_file("ecc_p521_private_openssh_pwd.pem")
|
||||
key = ECC.import_key(key_file, b"password")
|
||||
|
||||
|
||||
class TestExport_Ed25519(unittest.TestCase):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(TestExport_Ed25519, self).__init__(*args, **kwargs)
|
||||
self.ref_private, self.ref_public = create_ref_keys_ed25519()
|
||||
|
||||
def test_export_public_der(self):
|
||||
key_file = load_file("ecc_ed25519_public.der")
|
||||
|
||||
encoded = self.ref_public._export_subjectPublicKeyInfo(True)
|
||||
self.assertEqual(key_file, encoded)
|
||||
|
||||
encoded = self.ref_public.export_key(format="DER")
|
||||
self.assertEqual(key_file, encoded)
|
||||
|
||||
encoded = self.ref_public.export_key(format="DER", compress=False)
|
||||
self.assertEqual(key_file, encoded)
|
||||
|
||||
def test_export_public_sec1(self):
|
||||
self.assertRaises(ValueError, self.ref_public.export_key, format="SEC1")
|
||||
|
||||
def test_export_private_pkcs8_clear(self):
|
||||
key_file = load_file("ecc_ed25519_private.der")
|
||||
|
||||
encoded = self.ref_private._export_pkcs8()
|
||||
self.assertEqual(key_file, encoded)
|
||||
|
||||
# ---
|
||||
|
||||
encoded = self.ref_private.export_key(format="DER")
|
||||
self.assertEqual(key_file, encoded)
|
||||
|
||||
self.assertRaises(ValueError, self.ref_private.export_key,
|
||||
format="DER", use_pkcs8=False)
|
||||
|
||||
def test_export_private_pkcs8_encrypted(self):
|
||||
encoded = self.ref_private._export_pkcs8(passphrase="secret",
|
||||
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC")
|
||||
|
||||
# This should prove that the output is password-protected
|
||||
self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None)
|
||||
|
||||
decoded = ECC._import_pkcs8(encoded, "secret")
|
||||
self.assertEqual(self.ref_private, decoded)
|
||||
|
||||
# ---
|
||||
|
||||
encoded = self.ref_private.export_key(format="DER",
|
||||
passphrase="secret",
|
||||
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC")
|
||||
decoded = ECC.import_key(encoded, "secret")
|
||||
self.assertEqual(self.ref_private, decoded)
|
||||
|
||||
def test_export_public_pem(self):
|
||||
key_file_ref = load_file("ecc_ed25519_public.pem", "rt").strip()
|
||||
key_file = self.ref_public.export_key(format="PEM").strip()
|
||||
self.assertEqual(key_file_ref, key_file)
|
||||
|
||||
def test_export_private_pem_clear(self):
|
||||
key_file = load_file("ecc_ed25519_private.pem", "rt").strip()
|
||||
encoded = self.ref_private.export_key(format="PEM").strip()
|
||||
self.assertEqual(key_file, encoded)
|
||||
|
||||
def test_export_private_pem_encrypted(self):
|
||||
encoded = self.ref_private.export_key(format="PEM",
|
||||
passphrase=b"secret",
|
||||
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC")
|
||||
|
||||
# This should prove that the output is password-protected
|
||||
self.assertRaises(ValueError, ECC.import_key, encoded)
|
||||
|
||||
assert "ENCRYPTED PRIVATE KEY" in encoded
|
||||
|
||||
decoded = ECC.import_key(encoded, "secret")
|
||||
self.assertEqual(self.ref_private, decoded)
|
||||
|
||||
def test_export_openssh(self):
|
||||
key_file = load_file("ecc_ed25519_public_openssh.txt", "rt")
|
||||
public_key = ECC.import_key(key_file)
|
||||
key_file = " ".join(key_file.split(' ')[:2]) # remove comment
|
||||
|
||||
encoded = public_key._export_openssh(False)
|
||||
self.assertEqual(key_file, encoded.strip())
|
||||
|
||||
encoded = public_key.export_key(format="OpenSSH")
|
||||
self.assertEqual(key_file, encoded.strip())
|
||||
|
||||
def test_prng(self):
|
||||
# Test that password-protected containers use the provided PRNG
|
||||
encoded1 = self.ref_private.export_key(format="PEM",
|
||||
passphrase="secret",
|
||||
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC",
|
||||
randfunc=get_fixed_prng())
|
||||
encoded2 = self.ref_private.export_key(format="PEM",
|
||||
passphrase="secret",
|
||||
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC",
|
||||
randfunc=get_fixed_prng())
|
||||
self.assertEqual(encoded1, encoded2)
|
||||
|
||||
def test_byte_or_string_passphrase(self):
|
||||
encoded1 = self.ref_private.export_key(format="PEM",
|
||||
passphrase="secret",
|
||||
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC",
|
||||
randfunc=get_fixed_prng())
|
||||
encoded2 = self.ref_private.export_key(format="PEM",
|
||||
passphrase=b"secret",
|
||||
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC",
|
||||
randfunc=get_fixed_prng())
|
||||
self.assertEqual(encoded1, encoded2)
|
||||
|
||||
def test_error_params1(self):
|
||||
# Unknown format
|
||||
self.assertRaises(ValueError, self.ref_private.export_key, format="XXX")
|
||||
|
||||
# Missing 'protection' parameter when PKCS#8 is used
|
||||
self.assertRaises(ValueError, self.ref_private.export_key, format="PEM",
|
||||
passphrase="secret")
|
||||
|
||||
# Empty password
|
||||
self.assertRaises(ValueError, self.ref_private.export_key, format="PEM",
|
||||
passphrase="", use_pkcs8=False)
|
||||
self.assertRaises(ValueError, self.ref_private.export_key, format="PEM",
|
||||
passphrase="",
|
||||
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC")
|
||||
|
||||
# No private keys with OpenSSH
|
||||
self.assertRaises(ValueError, self.ref_private.export_key, format="OpenSSH",
|
||||
passphrase="secret")
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
tests = []
|
||||
tests += list_test_cases(TestImport)
|
||||
|
@ -2165,12 +2398,15 @@ def get_tests(config={}):
|
|||
tests += list_test_cases(TestImport_P256)
|
||||
tests += list_test_cases(TestImport_P384)
|
||||
tests += list_test_cases(TestImport_P521)
|
||||
tests += list_test_cases(TestImport_Ed25519)
|
||||
|
||||
tests += list_test_cases(TestExport_P192)
|
||||
tests += list_test_cases(TestExport_P224)
|
||||
tests += list_test_cases(TestExport_P256)
|
||||
tests += list_test_cases(TestExport_P384)
|
||||
tests += list_test_cases(TestExport_P521)
|
||||
tests += list_test_cases(TestExport_Ed25519)
|
||||
|
||||
except MissingTestVectorException:
|
||||
pass
|
||||
return tests
|
||||
|
|
|
@ -22,18 +22,20 @@
|
|||
|
||||
"""Self-test for signature modules"""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
from . import test_pkcs1_15, test_pss, test_dss, test_eddsa
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
tests = []
|
||||
from . import test_pkcs1_15; tests += test_pkcs1_15.get_tests(config=config)
|
||||
from . import test_pss; tests += test_pss.get_tests(config=config)
|
||||
from . import test_dss; tests += test_dss.get_tests(config=config)
|
||||
tests += test_pkcs1_15.get_tests(config=config)
|
||||
tests += test_pss.get_tests(config=config)
|
||||
tests += test_dss.get_tests(config=config)
|
||||
tests += test_eddsa.get_tests(config=config)
|
||||
return tests
|
||||
|
||||
if __name__ == '__main__':
|
||||
import unittest
|
||||
suite = lambda: unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
|
||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
||||
if __name__ == '__main__':
|
||||
def suite():
|
||||
return unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
||||
|
|
|
@ -251,6 +251,10 @@ class FIPS_ECDSA_Tests(unittest.TestCase):
|
|||
self.assertRaises(ValueError, signer.sign, hash_obj)
|
||||
self.assertRaises(ValueError, signer.verify, hash_obj, b"\x00" * 40)
|
||||
|
||||
def test_negative_eddsa_key(self):
|
||||
key = ECC.generate(curve="ed25519")
|
||||
self.assertRaises(ValueError, DSS.new, key, 'fips-186-3')
|
||||
|
||||
def test_sign_verify(self):
|
||||
"""Verify public/private method"""
|
||||
|
||||
|
|
355
lib/Crypto/SelfTest/Signature/test_eddsa.py
Normal file
355
lib/Crypto/SelfTest/Signature/test_eddsa.py
Normal file
|
@ -0,0 +1,355 @@
|
|||
#
|
||||
# Copyright (c) 2022, Legrandin <helderijs@gmail.com>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
# ===================================================================
|
||||
|
||||
import unittest
|
||||
from binascii import unhexlify
|
||||
|
||||
from Crypto.PublicKey import ECC
|
||||
from Crypto.Signature import eddsa
|
||||
from Crypto.Hash import SHA512
|
||||
from Crypto.SelfTest.st_common import list_test_cases
|
||||
from Crypto.SelfTest.loader import load_test_vectors_wycheproof
|
||||
from Crypto.Util.number import bytes_to_long
|
||||
|
||||
rfc8032_tv_str = (
|
||||
# 7.1 Ed25519
|
||||
(
|
||||
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
|
||||
"d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a",
|
||||
"",
|
||||
None,
|
||||
"",
|
||||
"e5564300c360ac729086e2cc806e828a"
|
||||
"84877f1eb8e5d974d873e06522490155"
|
||||
"5fb8821590a33bacc61e39701cf9b46b"
|
||||
"d25bf5f0595bbe24655141438e7a100b"
|
||||
),
|
||||
(
|
||||
"4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb",
|
||||
"3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c",
|
||||
"72",
|
||||
None,
|
||||
"",
|
||||
"92a009a9f0d4cab8720e820b5f642540"
|
||||
"a2b27b5416503f8fb3762223ebdb69da"
|
||||
"085ac1e43e15996e458f3613d0f11d8c"
|
||||
"387b2eaeb4302aeeb00d291612bb0c00"
|
||||
),
|
||||
(
|
||||
"c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7",
|
||||
"fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025",
|
||||
"af82",
|
||||
None,
|
||||
"",
|
||||
"6291d657deec24024827e69c3abe01a3"
|
||||
"0ce548a284743a445e3680d7db5ac3ac"
|
||||
"18ff9b538d16f290ae67f760984dc659"
|
||||
"4a7c15e9716ed28dc027beceea1ec40a"
|
||||
),
|
||||
(
|
||||
"f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5",
|
||||
"278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e",
|
||||
"08b8b2b733424243760fe426a4b54908"
|
||||
"632110a66c2f6591eabd3345e3e4eb98"
|
||||
"fa6e264bf09efe12ee50f8f54e9f77b1"
|
||||
"e355f6c50544e23fb1433ddf73be84d8"
|
||||
"79de7c0046dc4996d9e773f4bc9efe57"
|
||||
"38829adb26c81b37c93a1b270b20329d"
|
||||
"658675fc6ea534e0810a4432826bf58c"
|
||||
"941efb65d57a338bbd2e26640f89ffbc"
|
||||
"1a858efcb8550ee3a5e1998bd177e93a"
|
||||
"7363c344fe6b199ee5d02e82d522c4fe"
|
||||
"ba15452f80288a821a579116ec6dad2b"
|
||||
"3b310da903401aa62100ab5d1a36553e"
|
||||
"06203b33890cc9b832f79ef80560ccb9"
|
||||
"a39ce767967ed628c6ad573cb116dbef"
|
||||
"efd75499da96bd68a8a97b928a8bbc10"
|
||||
"3b6621fcde2beca1231d206be6cd9ec7"
|
||||
"aff6f6c94fcd7204ed3455c68c83f4a4"
|
||||
"1da4af2b74ef5c53f1d8ac70bdcb7ed1"
|
||||
"85ce81bd84359d44254d95629e9855a9"
|
||||
"4a7c1958d1f8ada5d0532ed8a5aa3fb2"
|
||||
"d17ba70eb6248e594e1a2297acbbb39d"
|
||||
"502f1a8c6eb6f1ce22b3de1a1f40cc24"
|
||||
"554119a831a9aad6079cad88425de6bd"
|
||||
"e1a9187ebb6092cf67bf2b13fd65f270"
|
||||
"88d78b7e883c8759d2c4f5c65adb7553"
|
||||
"878ad575f9fad878e80a0c9ba63bcbcc"
|
||||
"2732e69485bbc9c90bfbd62481d9089b"
|
||||
"eccf80cfe2df16a2cf65bd92dd597b07"
|
||||
"07e0917af48bbb75fed413d238f5555a"
|
||||
"7a569d80c3414a8d0859dc65a46128ba"
|
||||
"b27af87a71314f318c782b23ebfe808b"
|
||||
"82b0ce26401d2e22f04d83d1255dc51a"
|
||||
"ddd3b75a2b1ae0784504df543af8969b"
|
||||
"e3ea7082ff7fc9888c144da2af58429e"
|
||||
"c96031dbcad3dad9af0dcbaaaf268cb8"
|
||||
"fcffead94f3c7ca495e056a9b47acdb7"
|
||||
"51fb73e666c6c655ade8297297d07ad1"
|
||||
"ba5e43f1bca32301651339e22904cc8c"
|
||||
"42f58c30c04aafdb038dda0847dd988d"
|
||||
"cda6f3bfd15c4b4c4525004aa06eeff8"
|
||||
"ca61783aacec57fb3d1f92b0fe2fd1a8"
|
||||
"5f6724517b65e614ad6808d6f6ee34df"
|
||||
"f7310fdc82aebfd904b01e1dc54b2927"
|
||||
"094b2db68d6f903b68401adebf5a7e08"
|
||||
"d78ff4ef5d63653a65040cf9bfd4aca7"
|
||||
"984a74d37145986780fc0b16ac451649"
|
||||
"de6188a7dbdf191f64b5fc5e2ab47b57"
|
||||
"f7f7276cd419c17a3ca8e1b939ae49e4"
|
||||
"88acba6b965610b5480109c8b17b80e1"
|
||||
"b7b750dfc7598d5d5011fd2dcc5600a3"
|
||||
"2ef5b52a1ecc820e308aa342721aac09"
|
||||
"43bf6686b64b2579376504ccc493d97e"
|
||||
"6aed3fb0f9cd71a43dd497f01f17c0e2"
|
||||
"cb3797aa2a2f256656168e6c496afc5f"
|
||||
"b93246f6b1116398a346f1a641f3b041"
|
||||
"e989f7914f90cc2c7fff357876e506b5"
|
||||
"0d334ba77c225bc307ba537152f3f161"
|
||||
"0e4eafe595f6d9d90d11faa933a15ef1"
|
||||
"369546868a7f3a45a96768d40fd9d034"
|
||||
"12c091c6315cf4fde7cb68606937380d"
|
||||
"b2eaaa707b4c4185c32eddcdd306705e"
|
||||
"4dc1ffc872eeee475a64dfac86aba41c"
|
||||
"0618983f8741c5ef68d3a101e8a3b8ca"
|
||||
"c60c905c15fc910840b94c00a0b9d0",
|
||||
None,
|
||||
"",
|
||||
"0aab4c900501b3e24d7cdf4663326a3a"
|
||||
"87df5e4843b2cbdb67cbf6e460fec350"
|
||||
"aa5371b1508f9f4528ecea23c436d94b"
|
||||
"5e8fcd4f681e30a6ac00a9704a188a03"
|
||||
),
|
||||
# 7.2 Ed25519ctx
|
||||
(
|
||||
"0305334e381af78f141cb666f6199f57"
|
||||
"bc3495335a256a95bd2a55bf546663f6",
|
||||
"dfc9425e4f968f7f0c29f0259cf5f9ae"
|
||||
"d6851c2bb4ad8bfb860cfee0ab248292",
|
||||
"f726936d19c800494e3fdaff20b276a8",
|
||||
None,
|
||||
"666f6f",
|
||||
"55a4cc2f70a54e04288c5f4cd1e45a7b"
|
||||
"b520b36292911876cada7323198dd87a"
|
||||
"8b36950b95130022907a7fb7c4e9b2d5"
|
||||
"f6cca685a587b4b21f4b888e4e7edb0d"
|
||||
),
|
||||
(
|
||||
"0305334e381af78f141cb666f6199f57"
|
||||
"bc3495335a256a95bd2a55bf546663f6",
|
||||
"dfc9425e4f968f7f0c29f0259cf5f9ae"
|
||||
"d6851c2bb4ad8bfb860cfee0ab248292",
|
||||
"f726936d19c800494e3fdaff20b276a8",
|
||||
None,
|
||||
"626172",
|
||||
"fc60d5872fc46b3aa69f8b5b4351d580"
|
||||
"8f92bcc044606db097abab6dbcb1aee3"
|
||||
"216c48e8b3b66431b5b186d1d28f8ee1"
|
||||
"5a5ca2df6668346291c2043d4eb3e90d"
|
||||
),
|
||||
(
|
||||
"0305334e381af78f141cb666f6199f57"
|
||||
"bc3495335a256a95bd2a55bf546663f6",
|
||||
"dfc9425e4f968f7f0c29f0259cf5f9ae"
|
||||
"d6851c2bb4ad8bfb860cfee0ab248292",
|
||||
"508e9e6882b979fea900f62adceaca35",
|
||||
None,
|
||||
"666f6f",
|
||||
"8b70c1cc8310e1de20ac53ce28ae6e72"
|
||||
"07f33c3295e03bb5c0732a1d20dc6490"
|
||||
"8922a8b052cf99b7c4fe107a5abb5b2c"
|
||||
"4085ae75890d02df26269d8945f84b0b"
|
||||
),
|
||||
(
|
||||
"ab9c2853ce297ddab85c993b3ae14bca"
|
||||
"d39b2c682beabc27d6d4eb20711d6560",
|
||||
"0f1d1274943b91415889152e893d80e9"
|
||||
"3275a1fc0b65fd71b4b0dda10ad7d772",
|
||||
"f726936d19c800494e3fdaff20b276a8",
|
||||
None,
|
||||
"666f6f",
|
||||
"21655b5f1aa965996b3f97b3c849eafb"
|
||||
"a922a0a62992f73b3d1b73106a84ad85"
|
||||
"e9b86a7b6005ea868337ff2d20a7f5fb"
|
||||
"d4cd10b0be49a68da2b2e0dc0ad8960f"
|
||||
),
|
||||
# 7.3 Ed25519ph
|
||||
(
|
||||
"833fe62409237b9d62ec77587520911e"
|
||||
"9a759cec1d19755b7da901b96dca3d42",
|
||||
"ec172b93ad5e563bf4932c70e1245034"
|
||||
"c35467ef2efd4d64ebf819683467e2bf",
|
||||
"616263",
|
||||
SHA512,
|
||||
"",
|
||||
"98a70222f0b8121aa9d30f813d683f80"
|
||||
"9e462b469c7ff87639499bb94e6dae41"
|
||||
"31f85042463c2a355a2003d062adf5aa"
|
||||
"a10b8c61e636062aaad11c2a26083406"
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
rfc8032_tv_bytes = []
|
||||
for tv_str in rfc8032_tv_str:
|
||||
rfc8032_tv_bytes.append([unhexlify(i) if isinstance(i, str) else i for i in tv_str])
|
||||
|
||||
|
||||
class TestEdDSA(unittest.TestCase):
|
||||
|
||||
def test_sign(self):
|
||||
for sk, _, msg, hashmod, ctx, exp_signature in rfc8032_tv_bytes:
|
||||
key = eddsa.import_private_key(sk)
|
||||
signer = eddsa.new(key, 'rfc8032', context=ctx)
|
||||
if hashmod is None:
|
||||
# PureEdDSA
|
||||
signature = signer.sign(msg)
|
||||
else:
|
||||
# HashEdDSA
|
||||
hashobj = hashmod.new(msg)
|
||||
signature = signer.sign(hashobj)
|
||||
self.assertEqual(exp_signature, signature)
|
||||
|
||||
def test_verify(self):
|
||||
for _, pk, msg, hashmod, ctx, exp_signature in rfc8032_tv_bytes:
|
||||
key = eddsa.import_public_key(pk)
|
||||
verifier = eddsa.new(key, 'rfc8032', context=ctx)
|
||||
if hashmod is None:
|
||||
# PureEdDSA
|
||||
verifier.verify(msg, exp_signature)
|
||||
else:
|
||||
# HashEdDSA
|
||||
hashobj = hashmod.new(msg)
|
||||
verifier.verify(hashobj, exp_signature)
|
||||
|
||||
def test_negative(self):
|
||||
key = ECC.generate(curve="ed25519")
|
||||
self.assertRaises(ValueError, eddsa.new, key, 'rfc9999')
|
||||
|
||||
nist_key = ECC.generate(curve="p256")
|
||||
self.assertRaises(ValueError, eddsa.new, nist_key, 'rfc8032')
|
||||
|
||||
|
||||
class TestExport_Ed25519(unittest.TestCase):
|
||||
|
||||
def test_raw(self):
|
||||
key = ECC.generate(curve="Ed25519")
|
||||
x, y = key.pointQ.xy
|
||||
raw = bytearray(key._export_ed25519())
|
||||
sign_x = raw[31] >> 7
|
||||
raw[31] &= 0x7F
|
||||
yt = bytes_to_long(raw[::-1])
|
||||
self.assertEqual(y, yt)
|
||||
self.assertEqual(x & 1, sign_x)
|
||||
|
||||
key = ECC.construct(point_x=0, point_y=1, curve="Ed25519")
|
||||
out = key._export_ed25519()
|
||||
self.assertEqual(b'\x01' + b'\x00' * 31, out)
|
||||
|
||||
|
||||
class TestImport_Ed25519(unittest.TestCase):
|
||||
|
||||
def test_raw(self):
|
||||
Px = 24407857220263921307776619664228778204996144802740950419837658238229122415920
|
||||
Py = 56480760040633817885061096979765646085062883740629155052073094891081309750690
|
||||
encoded = b'\xa2\x05\xd6\x00\xe1 \xe1\xc0\xff\x96\xee?V\x8e\xba/\xd3\x89\x06\xd7\xc4c\xe8$\xc2d\xd7a1\xfa\xde|'
|
||||
key = eddsa.import_public_key(encoded)
|
||||
self.assertEqual(Py, key.pointQ.y)
|
||||
self.assertEqual(Px, key.pointQ.x)
|
||||
|
||||
encoded = b'\x01' + b'\x00' * 31
|
||||
key = eddsa.import_public_key(encoded)
|
||||
self.assertEqual(1, key.pointQ.y)
|
||||
self.assertEqual(0, key.pointQ.x)
|
||||
|
||||
|
||||
class TestVectorsEdDSAWycheproof(unittest.TestCase):
|
||||
|
||||
def add_tests(self, filename):
|
||||
|
||||
def pk(group):
|
||||
elem = group['key']['pk']
|
||||
return unhexlify(elem)
|
||||
|
||||
def sk(group):
|
||||
elem = group['key']['sk']
|
||||
return unhexlify(elem)
|
||||
|
||||
result = load_test_vectors_wycheproof(("Signature", "wycheproof"),
|
||||
filename,
|
||||
"Wycheproof ECDSA signature (%s)"
|
||||
% filename,
|
||||
group_tag={'pk': pk, 'sk': sk})
|
||||
self.tv += result
|
||||
|
||||
def setUp(self):
|
||||
self.tv = []
|
||||
self.add_tests("eddsa_test.json")
|
||||
|
||||
def test_sign(self, tv):
|
||||
if not tv.valid:
|
||||
return
|
||||
|
||||
self._id = "Wycheproof EdDSA Sign Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename)
|
||||
key = eddsa.import_private_key(tv.sk)
|
||||
signer = eddsa.new(key, 'rfc8032')
|
||||
signature = signer.sign(tv.msg)
|
||||
self.assertEqual(signature, tv.sig)
|
||||
|
||||
def test_verify(self, tv):
|
||||
self._id = "Wycheproof EdDSA Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename)
|
||||
key = eddsa.import_public_key(tv.pk)
|
||||
verifier = eddsa.new(key, 'rfc8032')
|
||||
try:
|
||||
verifier.verify(tv.msg, tv.sig)
|
||||
except ValueError:
|
||||
assert not tv.valid
|
||||
else:
|
||||
assert tv.valid
|
||||
|
||||
def runTest(self):
|
||||
for tv in self.tv:
|
||||
self.test_sign(tv)
|
||||
self.test_verify(tv)
|
||||
|
||||
|
||||
def get_tests(config={}):
|
||||
|
||||
tests = []
|
||||
tests += list_test_cases(TestExport_Ed25519)
|
||||
tests += list_test_cases(TestImport_Ed25519)
|
||||
tests += list_test_cases(TestEdDSA)
|
||||
tests += [TestVectorsEdDSAWycheproof()]
|
||||
return tests
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
def suite():
|
||||
return unittest.TestSuite(get_tests())
|
||||
unittest.main(defaultTest='suite')
|
|
@ -379,6 +379,8 @@ def new(key, mode, encoding='binary', randfunc=None):
|
|||
if isinstance(key, EccKey):
|
||||
order = key._curve.order
|
||||
private_key_attr = 'd'
|
||||
if key._curve.name == "ed25519":
|
||||
raise ValueError("ECC key is not on a NIST P curve")
|
||||
elif isinstance(key, DsaKey):
|
||||
order = Integer(key.q)
|
||||
private_key_attr = 'x'
|
||||
|
|
|
@ -33,4 +33,4 @@
|
|||
A collection of standardized protocols to carry out digital signatures.
|
||||
"""
|
||||
|
||||
__all__ = ['PKCS1_v1_5', 'PKCS1_PSS', 'DSS', 'pkcs1_15', 'pss']
|
||||
__all__ = ['PKCS1_v1_5', 'PKCS1_PSS', 'DSS', 'pkcs1_15', 'pss', 'eddsa']
|
||||
|
|
229
lib/Crypto/Signature/eddsa.py
Normal file
229
lib/Crypto/Signature/eddsa.py
Normal file
|
@ -0,0 +1,229 @@
|
|||
# ===================================================================
|
||||
#
|
||||
# Copyright (c) 2022, Legrandin <helderijs@gmail.com>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
# ===================================================================
|
||||
|
||||
from Crypto.Math.Numbers import Integer
|
||||
|
||||
from Crypto.Hash import SHA512
|
||||
from Crypto.Util.py3compat import bchr, is_bytes
|
||||
from Crypto.PublicKey.ECC import EccKey, construct, _import_ed25519_public_key
|
||||
|
||||
|
||||
def import_public_key(encoded):
|
||||
"""Import an EdDSA ECC public key, when encoded as raw ``bytes`` as described
|
||||
in RFC8032.
|
||||
|
||||
Args:
|
||||
encoded (bytes):
|
||||
The EdDSA public key to import.
|
||||
It must be 32 bytes long for Ed25519.
|
||||
|
||||
Returns:
|
||||
:class:`Crypto.PublicKey.EccKey` : a new ECC key object.
|
||||
|
||||
Raises:
|
||||
ValueError: when the given key cannot be parsed.
|
||||
"""
|
||||
|
||||
x, y = _import_ed25519_public_key(encoded)
|
||||
return construct(curve="Ed25519", point_x=x, point_y=y)
|
||||
|
||||
|
||||
def import_private_key(encoded):
|
||||
"""Import an EdDSA ECC private key, when encoded as raw ``bytes`` as described
|
||||
in RFC8032.
|
||||
|
||||
Args:
|
||||
encoded (bytes):
|
||||
The EdDSA private key to import. It must be 32 bytes long for Ed25519.
|
||||
|
||||
Returns:
|
||||
:class:`Crypto.PublicKey.EccKey` : a new ECC key object.
|
||||
|
||||
Raises:
|
||||
ValueError: when the given key cannot be parsed.
|
||||
"""
|
||||
|
||||
if len(encoded) != 32:
|
||||
raise ValueError("Incorrect length. Only Ed25519 private keys are supported.")
|
||||
|
||||
# Note that the private key is truly a sequence of random bytes,
|
||||
# so we cannot check its correctness in any way.
|
||||
|
||||
return construct(seed=encoded, curve="ed25519")
|
||||
|
||||
|
||||
class EdDSASigScheme(object):
|
||||
"""An EdDSA signature object.
|
||||
Do not instantiate directly.
|
||||
Use :func:`Crypto.Signature.eddsa.new`.
|
||||
"""
|
||||
|
||||
def __init__(self, key, context):
|
||||
"""Create a new EdDSA object.
|
||||
|
||||
Do not instantiate this object directly,
|
||||
use `Crypto.Signature.DSS.new` instead.
|
||||
"""
|
||||
|
||||
self._key = key
|
||||
self._context = context
|
||||
self._A = key._export_ed25519()
|
||||
self._order = key._curve.order
|
||||
|
||||
def can_sign(self):
|
||||
"""Return ``True`` if this signature object can be used
|
||||
for signing messages."""
|
||||
|
||||
return self._key.has_private()
|
||||
|
||||
def sign(self, msg_or_hash):
|
||||
"""Compute the EdDSA signature of a message.
|
||||
|
||||
Args:
|
||||
msg_or_hash (bytes or a :class:`Crypto.Hash.SHA512` object):
|
||||
The message to verify (*PureEdDSA*) or
|
||||
the hash that was carried out over the message (*HashEdDSA*).
|
||||
|
||||
:return: The signature as ``bytes``
|
||||
:raise TypeError: if the EdDSA key has no private half
|
||||
"""
|
||||
|
||||
if not self._key.has_private():
|
||||
raise TypeError("Private key is needed to sign")
|
||||
|
||||
ph = isinstance(msg_or_hash, SHA512.SHA512Hash)
|
||||
if not (ph or is_bytes(msg_or_hash)):
|
||||
raise TypeError("'msg_or_hash' must be bytes of a SHA-512 hash")
|
||||
|
||||
if self._context or ph:
|
||||
flag = int(ph)
|
||||
dom2 = b'SigEd25519 no Ed25519 collisions' + bchr(flag) + \
|
||||
bchr(len(self._context)) + self._context
|
||||
else:
|
||||
dom2 = b''
|
||||
|
||||
PHM = msg_or_hash.digest() if ph else msg_or_hash
|
||||
|
||||
# See RFC 8032, section 5.1.6
|
||||
|
||||
# Step 2
|
||||
r_hash = SHA512.new(dom2 + self._key._prefix + PHM).digest()
|
||||
r = Integer.from_bytes(r_hash, 'little') % self._order
|
||||
# Step 3
|
||||
R_pk = EccKey(point=r * self._key._curve.G)._export_ed25519()
|
||||
# Step 4
|
||||
k_hash = SHA512.new(dom2 + R_pk + self._A + PHM).digest()
|
||||
k = Integer.from_bytes(k_hash, 'little') % self._order
|
||||
# Step 5
|
||||
s = (r + k * self._key.d) % self._order
|
||||
|
||||
return R_pk + s.to_bytes(32, 'little')
|
||||
|
||||
def verify(self, msg_or_hash, signature):
|
||||
"""Check if an EdDSA signature is authentic.
|
||||
|
||||
Args:
|
||||
msg_or_hash (bytes or a :class:`Crypto.Hash.SHA512` object):
|
||||
The message to verify (*PureEdDSA*) or
|
||||
the hash that was carried out over the message (*HashEdDSA*).
|
||||
|
||||
signature (``bytes``):
|
||||
The signature that needs to be validated.
|
||||
|
||||
:raise ValueError: if the signature is not authentic
|
||||
"""
|
||||
|
||||
if len(signature) != 64:
|
||||
raise ValueError("The signature is not authentic (length)")
|
||||
|
||||
ph = isinstance(msg_or_hash, SHA512.SHA512Hash)
|
||||
if not (ph or is_bytes(msg_or_hash)):
|
||||
raise TypeError("'msg_or_hash' must be bytes of a SHA-512 hash")
|
||||
|
||||
if self._context or ph:
|
||||
flag = int(ph)
|
||||
dom2 = b'SigEd25519 no Ed25519 collisions' + bchr(flag) + \
|
||||
bchr(len(self._context)) + self._context
|
||||
else:
|
||||
dom2 = b''
|
||||
|
||||
PHM = msg_or_hash.digest() if ph else msg_or_hash
|
||||
|
||||
# Step 1
|
||||
try:
|
||||
R = import_public_key(signature[:32]).pointQ
|
||||
except ValueError:
|
||||
raise ValueError("The signature is not authentic (R)")
|
||||
s = Integer.from_bytes(signature[32:], 'little')
|
||||
if s > self._order:
|
||||
raise ValueError("The signature is not authentic (S)")
|
||||
# Step 2
|
||||
k_hash = SHA512.new(dom2 + signature[:32] + self._A + PHM).digest()
|
||||
k = Integer.from_bytes(k_hash, 'little') % self._order
|
||||
# Step 3
|
||||
point1 = s * 8 * self._key._curve.G
|
||||
# OPTIMIZE: with double-scalar multiplication, with no SCA
|
||||
# countermeasures because it is public values
|
||||
point2 = 8 * R + k * 8 * self._key.pointQ
|
||||
if point1 != point2:
|
||||
raise ValueError("The signature is not authentic")
|
||||
|
||||
|
||||
def new(key, mode, context=None):
|
||||
"""Create a signature object :class:`EdDSASigScheme` that
|
||||
can perform or verify an EdDSA signature.
|
||||
|
||||
Args:
|
||||
key (:class:`Crypto.PublicKey.ECC` on curve ``Ed25519``):
|
||||
The key to use for computing the signature (*private* keys only)
|
||||
or for verifying one.
|
||||
|
||||
mode (string):
|
||||
This parameter must be ``'rfc8032'``.
|
||||
|
||||
context (bytes):
|
||||
Up to 255 bytes of `context <https://datatracker.ietf.org/doc/html/rfc8032#page-41>`_,
|
||||
which is a constant byte string to segregate different protocols or
|
||||
uses of the same key.
|
||||
Do not specify a context, if you want a pure Ed25519 signature.
|
||||
"""
|
||||
|
||||
if not isinstance(key, EccKey) or key._curve.name != 'ed25519':
|
||||
raise ValueError("EdDSA can only be used with Ed25519 keys")
|
||||
|
||||
if mode != 'rfc8032':
|
||||
raise ValueError("Mode must be 'rfc8032'")
|
||||
|
||||
if context is None:
|
||||
context = b''
|
||||
elif len(context) > 255:
|
||||
raise ValueError("Context for EdDSA must not be longer than 255 bytes")
|
||||
|
||||
return EdDSASigScheme(key, context)
|
18
lib/Crypto/Signature/eddsa.pyi
Normal file
18
lib/Crypto/Signature/eddsa.pyi
Normal file
|
@ -0,0 +1,18 @@
|
|||
from typing import Union, Optional
|
||||
from typing_extensions import Protocol
|
||||
from Crypto.PublicKey.ECC import EccKey
|
||||
|
||||
class Hash(Protocol):
|
||||
def digest(self) -> bytes: ...
|
||||
|
||||
def import_public_key(encoded: bytes) -> EccKey: ...
|
||||
def import_private_key(encoded: bytes) -> EccKey: ...
|
||||
|
||||
class EdDSASigScheme(object):
|
||||
|
||||
def __init__(self, key: EccKey, context: bytes) -> None: ...
|
||||
def can_sign(self) -> bool: ...
|
||||
def sign(self, msg_or_hash: Union[bytes, Hash]) -> bytes: ...
|
||||
def verify(self, msg_or_hash: Union[bytes, Hash], signature: bytes) -> None: ...
|
||||
|
||||
def new(key: EccKey, mode: bytes, context: Optional[bytes]=None) -> EdDSASigScheme: ...
|
|
@ -13,6 +13,7 @@ def bytestring(x: Any) -> bool: ...
|
|||
|
||||
def is_native_int(s: Any) -> bool: ...
|
||||
def is_string(x: Any) -> bool: ...
|
||||
def is_bytes(x: Any) -> bool: ...
|
||||
|
||||
def BytesIO(b: bytes) -> IO[bytes]: ...
|
||||
def StringIO(s: str) -> IO[str]: ...
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
__all__ = ['Cipher', 'Hash', 'Protocol', 'PublicKey', 'Util', 'Signature',
|
||||
'IO', 'Math']
|
||||
|
||||
version_info = (3, 15, '0', 'dev')
|
||||
version_info = (3, 15, '0dev')
|
||||
|
||||
__version__ = ".".join([str(x) for x in version_info])
|
||||
|
|
8
setup.py
8
setup.py
|
@ -443,6 +443,14 @@ ext_modules = [
|
|||
'src/p521_table.c'],
|
||||
py_limited_api=True,
|
||||
),
|
||||
Extension("Crypto.PublicKey._x255219",
|
||||
include_dirs=['src/'],
|
||||
sources=['src/x25519.c']
|
||||
),
|
||||
Extension("Crypto.PublicKey._ed25519",
|
||||
include_dirs=['src/'],
|
||||
sources=['src/ed25519.c']
|
||||
),
|
||||
|
||||
# Math
|
||||
Extension("Crypto.Math._modexp",
|
||||
|
|
|
@ -28,5 +28,8 @@ p384_table.c: make_ecc_table.py
|
|||
p521_table.c: make_ecc_table.py
|
||||
python make_ecc_table.py p521 4 p521_table
|
||||
|
||||
x25519: x25519.c multiply_64.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^ -DSYS_BITS=64 -DPROFILE
|
||||
|
||||
clean::
|
||||
rm -f ec_ws_p256 ec_ws_p384 ec_ws_p521 mont.o modexp
|
||||
rm -f ec_ws_p256 ec_ws_p384 ec_ws_p521 mont.o modexp x25519
|
||||
|
|
282
src/bignum.c
Normal file
282
src/bignum.c
Normal file
|
@ -0,0 +1,282 @@
|
|||
#ifndef __BIGNUM_C
|
||||
#define __BIGNUM_C
|
||||
|
||||
#include "common.h"
|
||||
#include "multiply.h"
|
||||
|
||||
#if defined(USE_SSE2)
|
||||
#if defined(HAVE_INTRIN_H)
|
||||
#include <intrin.h>
|
||||
#elif defined(HAVE_X86INTRIN_H)
|
||||
#include <x86intrin.h>
|
||||
#elif defined(HAVE_EMMINTRIN_H)
|
||||
#include <xmmintrin.h>
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static inline unsigned is_odd(uint64_t x)
|
||||
{
|
||||
return 1 == (x & 1);
|
||||
}
|
||||
|
||||
static inline unsigned is_even(uint64_t x)
|
||||
{
|
||||
return !is_odd(x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a multi-word integer x is greater than or equal to y.
|
||||
*
|
||||
* @param x The first term
|
||||
* @param y The second term
|
||||
* @param nw The number of words that make up x and y
|
||||
* @return 1 if x>=y, 0 if x<y
|
||||
*/
|
||||
STATIC int ge(const uint64_t *x, const uint64_t *y, size_t nw)
|
||||
{
|
||||
unsigned mask = (unsigned)-1;
|
||||
unsigned result = 0;
|
||||
size_t i, j;
|
||||
|
||||
i = nw - 1;
|
||||
for (j=0; j<nw; j++, i--) {
|
||||
unsigned greater, lower;
|
||||
|
||||
greater = x[i] > y[i];
|
||||
lower = x[i] < y[i];
|
||||
result |= mask & (greater | (lower << 1));
|
||||
mask &= (greater ^ lower) - 1;
|
||||
}
|
||||
|
||||
return result<2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Subtract a multi-word integer b from a.
|
||||
*
|
||||
* @param out The location where the multi-word result is stored
|
||||
* @param a Number to subtract from
|
||||
* @param b Number to subtract
|
||||
* @param nw The number of words of both a and b
|
||||
* @result 0 if there is no borrow, 1 otherwise
|
||||
*/
|
||||
STATIC unsigned sub(uint64_t *out, const uint64_t *a, const uint64_t *b, size_t nw)
|
||||
{
|
||||
size_t i;
|
||||
unsigned borrow1 , borrow2;
|
||||
|
||||
borrow2 = 0;
|
||||
for (i=0; i<nw; i++) {
|
||||
borrow1 = b[i] > a[i];
|
||||
out[i] = a[i] - b[i];
|
||||
|
||||
borrow1 |= borrow2 > out[i];
|
||||
out[i] -= borrow2;
|
||||
|
||||
borrow2 = borrow1;
|
||||
}
|
||||
|
||||
return borrow2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Multiply a multi-word integer a by a 64-bit scalar k and
|
||||
* then add the result to the multi-word integer t.
|
||||
*
|
||||
* @param t The multi-word integer accumulator
|
||||
* @param tw The number of words of t
|
||||
* @param a The multi-word integer to multiply with the scalar
|
||||
* @param aw The number of words of a
|
||||
* @param k The 64-bit scalar multiplier
|
||||
*/
|
||||
STATIC void addmul(uint64_t *t, size_t tw, const uint64_t *a, size_t aw, uint64_t k)
|
||||
{
|
||||
size_t i;
|
||||
uint64_t carry;
|
||||
|
||||
carry = 0;
|
||||
for (i=0; i<aw; i++) {
|
||||
uint64_t prod_lo, prod_hi;
|
||||
|
||||
DP_MULT(a[i], k, prod_lo, prod_hi);
|
||||
|
||||
prod_lo += carry;
|
||||
prod_hi += prod_lo < carry;
|
||||
|
||||
t[i] += prod_lo;
|
||||
prod_hi += t[i] < prod_lo;
|
||||
|
||||
carry = prod_hi;
|
||||
}
|
||||
|
||||
for (; carry; i++) {
|
||||
t[i] += carry;
|
||||
carry = t[i] < carry;
|
||||
}
|
||||
|
||||
assert(i <= tw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply two multi-word integers.
|
||||
*
|
||||
* @param t The location where the result is stored. It is twice as big as
|
||||
* either a (or b). It is an array of 2*nw words).
|
||||
* @param scratchpad Temporary area. It is an array of 3*nw words.
|
||||
* @param a The first term, array of nw words.
|
||||
* @param b The second term, array of nw words.
|
||||
* @param nw The number of words of both a and b.
|
||||
*
|
||||
*/
|
||||
STATIC void product(uint64_t *t, uint64_t *scratchpad, const uint64_t *a, const uint64_t *b, size_t nw)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
memset(t, 0, 2*sizeof(uint64_t)*nw);
|
||||
|
||||
for (i=0; i<(nw ^ (nw & 1)); i+=2) {
|
||||
addmul128(&t[i], scratchpad, a, b[i], b[i+1], 2*nw-i, nw);
|
||||
}
|
||||
|
||||
if (is_odd(nw)) {
|
||||
addmul(&t[nw-1], nw+2, a, nw, b[nw-1]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Select a number out of two, in constant time.
|
||||
*
|
||||
* @param out The location where the multi-word result is stored
|
||||
* @param a The first choice, selected if cond is true (non-zero)
|
||||
* @param b The second choice, selected if cond is false (zero)
|
||||
* @param cond The flag that drives the selection
|
||||
* @param words The number of words of a, b, and out
|
||||
* @return 0 for success, the appropriate code otherwise.
|
||||
*/
|
||||
STATIC FUNC_SSE2 int mod_select(uint64_t *out, const uint64_t *a, const uint64_t *b, unsigned cond, size_t words)
|
||||
{
|
||||
uint64_t mask;
|
||||
#if defined(USE_SSE2)
|
||||
unsigned pairs, i;
|
||||
__m128i r0, r1, r2, r3, r4, r5;
|
||||
|
||||
pairs = (unsigned)words / 2;
|
||||
mask = (uint64_t)((cond != 0) - 1); /* 0 for a, 1s for b */
|
||||
|
||||
#if SYSBITS == 64
|
||||
r0 = _mm_set1_epi64x(mask);
|
||||
#else
|
||||
r0 = _mm_loadl_epi64((__m128i*)&mask);
|
||||
r0 = _mm_unpacklo_epi64(r0, r0);
|
||||
#endif
|
||||
for (i=0; i<pairs; i++, a+=2, b+=2, out+=2) {
|
||||
r1 = _mm_loadu_si128((__m128i const*)b);
|
||||
r2 = _mm_loadu_si128((__m128i const*)a);
|
||||
r3 = _mm_and_si128(r0, r1);
|
||||
r4 = _mm_andnot_si128(r0, r2);
|
||||
r5 = _mm_or_si128(r3, r4);
|
||||
_mm_storeu_si128((__m128i*)out, r5);
|
||||
}
|
||||
|
||||
if (words & 1) {
|
||||
*out = (*b & mask) ^ (*a & ~mask);
|
||||
}
|
||||
#else
|
||||
unsigned i;
|
||||
|
||||
mask = (uint64_t)((cond != 0) - 1);
|
||||
for (i=0; i<words; i++) {
|
||||
*out++ = (*b++ & mask) ^ (*a++ & ~mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add two multi-word numbers with modulo arithmetic.
|
||||
*
|
||||
* @param out The locaton where the multi-word result (nw words) is stored
|
||||
* @param a The first term (nw words)
|
||||
* @param b The second term (nw words)
|
||||
* @param modulus The modulus (nw words)
|
||||
* @param tmp1 A temporary area (nw words)
|
||||
* @param tmp2 A temporary area (nw words)
|
||||
* @param nw The number of 64-bit words in all parameters
|
||||
*/
|
||||
STATIC void add_mod(uint64_t* out, const uint64_t* a, const uint64_t* b, const uint64_t *modulus, uint64_t *tmp1, uint64_t *tmp2, size_t nw)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned carry, borrow1, borrow2;
|
||||
|
||||
/*
|
||||
* Compute sum in tmp1[], and subtract modulus[]
|
||||
* from tmp1[] into tmp2[].
|
||||
*/
|
||||
borrow2 = 0;
|
||||
for (i=0, carry=0; i<nw; i++) {
|
||||
tmp1[i] = a[i] + carry;
|
||||
carry = tmp1[i] < carry;
|
||||
tmp1[i] += b[i];
|
||||
carry += tmp1[i] < b[i];
|
||||
|
||||
borrow1 = modulus[i] > tmp1[i];
|
||||
tmp2[i] = tmp1[i] - modulus[i];
|
||||
borrow1 |= borrow2 > tmp2[i];
|
||||
tmp2[i] -= borrow2;
|
||||
borrow2 = borrow1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is no borrow or if there is carry,
|
||||
* tmp1[] is larger than modulus, so we must return tmp2[].
|
||||
*/
|
||||
mod_select(out, tmp2, tmp1, carry | (borrow2 ^ 1), nw);
|
||||
}
|
||||
|
||||
/*
|
||||
* Subtract two multi-word numbers with modulo arithmetic.
|
||||
*
|
||||
* @param out The locaton where the multi-word result (nw words) is stored
|
||||
* @param a The number it will be subtracted from (nw words)
|
||||
* @param b The number to subtract (nw wordS)
|
||||
* @param modulus The modulus (nw words)
|
||||
* @param tmp1 A temporary area (nw words)
|
||||
* @param tmp2 A temporary area (nw words)
|
||||
* @param nw The number of 64-bit words in all parameters
|
||||
* @return 0 for success, the relevant error code otherwise
|
||||
*/
|
||||
int sub_mod(uint64_t *out, const uint64_t *a, const uint64_t *b, const uint64_t *modulus, uint64_t *tmp1, uint64_t *tmp2, size_t nw)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned carry, borrow1 , borrow2;
|
||||
|
||||
/*
|
||||
* Compute difference in tmp1[], and add modulus[]
|
||||
* to tmp1[] into tmp2[].
|
||||
*/
|
||||
borrow2 = 0;
|
||||
carry = 0;
|
||||
for (i=0; i<nw; i++) {
|
||||
borrow1 = b[i] > a[i];
|
||||
tmp1[i] = a[i] - b[i];
|
||||
borrow1 |= borrow2 > tmp1[i];
|
||||
tmp1[i] -= borrow2;
|
||||
borrow2 = borrow1;
|
||||
|
||||
tmp2[i] = tmp1[i] + carry;
|
||||
carry = tmp2[i] < carry;
|
||||
tmp2[i] += modulus[i];
|
||||
carry += tmp2[i] < modulus[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is no borrow, tmp[] is smaller than modulus.
|
||||
*/
|
||||
mod_select(out, tmp2, tmp1, borrow2, nw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __BIGNUM_C **/
|
2
src/ec.h
2
src/ec.h
|
@ -42,7 +42,7 @@ EXPORT_SYM int ec_ws_new_point(EcPoint **pecp,
|
|||
const uint8_t *y,
|
||||
size_t len,
|
||||
const EcContext *ec_ctx);
|
||||
EXPORT_SYM void ec_free_point(EcPoint *ecp);
|
||||
EXPORT_SYM void ec_ws_free_point(EcPoint *ecp);
|
||||
EXPORT_SYM int ec_ws_get_xy(uint8_t *x,
|
||||
uint8_t *y,
|
||||
size_t len,
|
||||
|
|
74
src/ec_ws.c
74
src/ec_ws.c
|
@ -36,6 +36,9 @@
|
|||
#include "multiply.h"
|
||||
#include "mont.h"
|
||||
#include "ec.h"
|
||||
#include "p256_table.h"
|
||||
#include "p384_table.h"
|
||||
#include "p521_table.h"
|
||||
|
||||
#include "p256_table.h"
|
||||
#include "p384_table.h"
|
||||
|
@ -986,7 +989,7 @@ EXPORT_SYM void ec_free_context(EcContext *ec_ctx)
|
|||
* Create a new EC point on the given EC curve.
|
||||
*
|
||||
* @param pecp The memory area where the pointer to the newly allocated EC
|
||||
* point will be stored. Use ec_free_point() for deallocating it.
|
||||
* point will be stored. Use ec_ws_free_point() for deallocating it.
|
||||
* @param x The X-coordinate (affine, big-endian)
|
||||
* @param y The Y-coordinate (affine, big-endian)
|
||||
* @param len The length of x and y in bytes
|
||||
|
@ -1062,7 +1065,7 @@ cleanup:
|
|||
return res;
|
||||
}
|
||||
|
||||
EXPORT_SYM void ec_free_point(EcPoint *ecp)
|
||||
EXPORT_SYM void ec_ws_free_point(EcPoint *ecp)
|
||||
{
|
||||
if (NULL == ecp)
|
||||
return;
|
||||
|
@ -1172,42 +1175,6 @@ EXPORT_SYM int ec_ws_add(EcPoint *ecpa, EcPoint *ecpb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Normalize the projective representation of a point
|
||||
* so that Z=1 or Z=0.
|
||||
*/
|
||||
EXPORT_SYM int ec_ws_normalize(EcPoint *ecp)
|
||||
{
|
||||
MontContext *ctx;
|
||||
Workplace *wp = NULL;
|
||||
|
||||
if (NULL == ecp)
|
||||
return ERR_NULL;
|
||||
ctx = ecp->ec_ctx->mont_ctx;
|
||||
|
||||
wp = new_workplace(ctx);
|
||||
if (NULL == wp)
|
||||
return ERR_MEMORY;
|
||||
|
||||
if (!mont_is_zero(ecp->z, ctx)) {
|
||||
ec_projective_to_affine(ecp->x, ecp->y,
|
||||
ecp->x, ecp->y, ecp->z,
|
||||
wp, ctx);
|
||||
mont_set(ecp->z, 1, ctx);
|
||||
}
|
||||
|
||||
free_workplace(wp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYM int ec_ws_is_pai(EcPoint *ecp)
|
||||
{
|
||||
if (NULL == ecp)
|
||||
return FALSE;
|
||||
|
||||
return mont_is_zero(ecp->z, ecp->ec_ctx->mont_ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Blind the scalar factor to be used in an EC multiplication
|
||||
*
|
||||
|
@ -1473,22 +1440,6 @@ cleanup:
|
|||
return res;
|
||||
}
|
||||
|
||||
EXPORT_SYM int ec_ws_copy(EcPoint *ecp1, const EcPoint *ecp2)
|
||||
{
|
||||
MontContext *ctx;
|
||||
|
||||
if (NULL == ecp1 || NULL == ecp2)
|
||||
return ERR_NULL;
|
||||
ctx = ecp2->ec_ctx->mont_ctx;
|
||||
|
||||
ecp1->ec_ctx = ecp2->ec_ctx;
|
||||
mont_copy(ecp1->x, ecp2->x, ctx);
|
||||
mont_copy(ecp1->y, ecp2->y, ctx);
|
||||
mont_copy(ecp1->z, ecp2->z, ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare two EC points and return 0 if they match
|
||||
*/
|
||||
|
@ -1550,3 +1501,18 @@ EXPORT_SYM int ec_ws_neg(EcPoint *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYM int ec_ws_copy(EcPoint *ecp1, const EcPoint *ecp2)
|
||||
{
|
||||
MontContext *ctx;
|
||||
|
||||
if (NULL == ecp1 || NULL == ecp2)
|
||||
return ERR_NULL;
|
||||
ctx = ecp2->ec_ctx->mont_ctx;
|
||||
|
||||
ecp1->ec_ctx = ecp2->ec_ctx;
|
||||
mont_copy(ecp1->x, ecp2->x, ctx);
|
||||
mont_copy(ecp1->y, ecp2->y, ctx);
|
||||
mont_copy(ecp1->z, ecp2->z, ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -116,8 +116,8 @@ int main(void)
|
|||
printf("\n");
|
||||
#endif
|
||||
|
||||
ec_free_point(gp);
|
||||
ec_free_point(ecp);
|
||||
ec_ws_free_point(gp);
|
||||
ec_ws_free_point(ecp);
|
||||
ec_free_context(ec_ctx);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -118,8 +118,8 @@ int main(void)
|
|||
printf("\n");
|
||||
#endif
|
||||
|
||||
ec_free_point(gp);
|
||||
ec_free_point(ecp);
|
||||
ec_ws_free_point(gp);
|
||||
ec_ws_free_point(ecp);
|
||||
ec_free_context(ec_ctx);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -122,8 +122,8 @@ int main(void)
|
|||
printf("\n");
|
||||
#endif
|
||||
|
||||
ec_free_point(gp);
|
||||
ec_free_point(ecp);
|
||||
ec_ws_free_point(gp);
|
||||
ec_ws_free_point(ecp);
|
||||
ec_free_context(ec_ctx);
|
||||
|
||||
return 0;
|
||||
|
|
308
src/ed25519.c
Normal file
308
src/ed25519.c
Normal file
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* Twisted Edward curve with equation:
|
||||
*
|
||||
* ax² + y² = 1 + dx²y²
|
||||
*
|
||||
* where a = -1 and d = - 121665/121666 over the prime field 2²⁵⁵ - 19.
|
||||
*
|
||||
* Points (x, y) can be represented as extended homogeneous coordinates
|
||||
* (X, Y, Z, T) with x = X/Z, y = Y/Z, and x*y = T/Z for a non-zero Z.
|
||||
*
|
||||
* The PAI (or neutral point) is (0, Z, Z, 0) or equivalently (0, 1).
|
||||
* The point (x, y) can be obtained by normalizing to (x, y, 1, x*y).
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "endianess.h"
|
||||
|
||||
#include "mod25519.c"
|
||||
|
||||
typedef struct Point {
|
||||
uint32_t X[10];
|
||||
uint32_t Y[10];
|
||||
uint32_t Z[10];
|
||||
uint32_t T[10];
|
||||
} Point;
|
||||
|
||||
/*
|
||||
* P3 can be P1 or P2
|
||||
*/
|
||||
STATIC void ed25519_add_internal(Point *P3, const Point *P1, const Point *P2)
|
||||
{
|
||||
uint32_t A[10], B[10], C[10], D[10];
|
||||
/* d = 37095705934669439343138083508754565189542113879843219016388785533085940283555 */
|
||||
/* k = 2 * d (mod 2²⁵⁵ - 19) */
|
||||
static const uint32_t k[10] = { 0x2B2F159, 0x1A6E509, 0x22ADD7A, 0xD4141D, 0x38052,
|
||||
0xF3D130, 0x3407977, 0x19CE331, 0x1C56DFF, 0x901B67 };
|
||||
|
||||
/* https://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3 */
|
||||
|
||||
sub32(A, P1->Y, P1->X); /* (Y1-X1) each limb < 2²⁷ */
|
||||
sub32(B, P2->Y, P2->X); /* (Y2-X2) < 2²⁷ */
|
||||
mul_25519(A, A, B); /* A < 2²⁶ */
|
||||
add32(B, P1->Y, P1->X); /* (Y1+X1) < 2²⁷ */
|
||||
add32(C, P2->Y, P2->X); /* (Y2+X2) < 2²⁷ */
|
||||
mul_25519(B, B, C); /* B < 2²⁶ */
|
||||
mul_25519(C, P1->T, P2->T); /* T1*T2 < 2²⁶ */
|
||||
mul_25519(C, C, k); /* C < 2²⁶ */
|
||||
mul_25519(D, P1->Z, P2->Z); /* Z1*Z2 < 2²⁶ */
|
||||
add_25519(D, D, D); /* D < 2²⁶ */
|
||||
sub32(P3->T, B, A); /* E=B-A < 2²⁷ */
|
||||
sub32(P3->Z, D, C); /* F=D-C < 2²⁷ */
|
||||
add32(D, D, C); /* G=D+C < 2²⁷ */
|
||||
add32(B, B, A); /* H=B+A < 2²⁷ */
|
||||
mul_25519(P3->X, P3->T, P3->Z); /* X3=E*F < 2²⁶ */
|
||||
mul_25519(P3->Y, D, B); /* Y3=G*H < 2²⁶ */
|
||||
mul_25519(P3->T, P3->T, B); /* T3=E*H < 2²⁶ */
|
||||
mul_25519(P3->Z, P3->Z, D); /* Z3=F*G < 2²⁶ */
|
||||
}
|
||||
|
||||
STATIC void ed25519_double_internal(Point *P3, const Point *P1)
|
||||
{
|
||||
uint32_t A[10], B[10], C[10], D[10];
|
||||
|
||||
mul_25519(A, P1->X, P1->X); /* X1^2 each limb < 2²⁶ */
|
||||
mul_25519(B, P1->Y, P1->Y); /* Y1^2 < 2²⁶ */
|
||||
mul_25519(C, P1->Z, P1->Z); /* Z1^2 < 2²⁶ */
|
||||
add_25519(C, C, C); /* C=2*Z1^2 < 2²⁶ */
|
||||
add32(D, A, B); /* H=A+B < 2²⁷ */
|
||||
add32(P3->T, P1->X, P1->Y); /* X1+Y1 < 2²⁷ */
|
||||
mul_25519(P3->T, P3->T, P3->T); /* (X1+Y1)^2 < 2²⁶ */
|
||||
sub32(P3->T, D, P3->T); /* E=H-(X1+Y1)^2 < 2²⁷ */
|
||||
sub32(P3->Z, A, B); /* G=A-B < 2²⁷ */
|
||||
add_25519(A, C, P3->Z); /* F=C+G < 2²⁶ */
|
||||
mul_25519(P3->X, P3->T, A); /* X3=E*F < 2²⁶ */
|
||||
mul_25519(P3->Y, P3->Z, D); /* Y3=G*H < 2²⁶ */
|
||||
mul_25519(P3->T, P3->T, D); /* T3=E*H < 2²⁶ */
|
||||
mul_25519(P3->Z, A, P3->Z); /* Z3=F*G < 2²⁶ */
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void print_point_le8(const Point *p)
|
||||
{
|
||||
uint8_t bin[32];
|
||||
unsigned i;
|
||||
uint32_t tmp[32];
|
||||
uint32_t invz[32];
|
||||
|
||||
invert_25519(invz, p->Z);
|
||||
mul_25519(tmp, p->X, invz);
|
||||
convert_le25p5_to_le8(bin, tmp);
|
||||
printf("X=");
|
||||
for (i=0; i<32; i++)
|
||||
printf("%02X", bin[i]);
|
||||
printf("\n");
|
||||
|
||||
invert_25519(invz, p->Z);
|
||||
mul_25519(tmp, p->Y, invz);
|
||||
convert_le25p5_to_le8(bin, tmp);
|
||||
printf("Y=");
|
||||
for (i=0; i<32; i++)
|
||||
printf("%02X", bin[i]);
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Scalar multiplication Q = k*B
|
||||
*
|
||||
* @param[out] xout The X-coordinate of the resulting point Q.
|
||||
* @param[out] yout The Y-coordinate of the resulting point Q.
|
||||
* @param[in] k The scalar encoded in little-endian mode.
|
||||
* @param[in] len Length of the scalar in bytes.
|
||||
* @param[in] xin The X-coordinate of the input point B.
|
||||
* @param[in] yin The Y-coordinate of the input point B.
|
||||
*/
|
||||
|
||||
STATIC void ed25519_scalar_internal(Point *Pout,
|
||||
const uint8_t *k, size_t len,
|
||||
const Point *Pin)
|
||||
{
|
||||
Point R0, R1;
|
||||
unsigned bit_idx, swap;
|
||||
size_t scan;
|
||||
|
||||
/* Point R0 */
|
||||
memset(&R0, 0, sizeof R0);
|
||||
R0.Y[0] = R0.Z[0] = 1;
|
||||
|
||||
/* Point R1 */
|
||||
R1 = *Pin;
|
||||
|
||||
/* https://eprint.iacr.org/2020/956.pdf */
|
||||
|
||||
/* OPTIMIZE: with pre-computed tables in case of fixed-point multiplication */
|
||||
|
||||
/* Scan all bits from MSB to LSB */
|
||||
bit_idx = 7;
|
||||
swap = 0;
|
||||
scan = 0;
|
||||
while (scan<len) {
|
||||
unsigned bit;
|
||||
|
||||
bit = (k[scan] >> bit_idx) & 1;
|
||||
swap ^= bit;
|
||||
|
||||
cswap(R0.X, R0.Y, R1.X, R1.Y, swap);
|
||||
cswap(R0.Z, R0.T, R1.Z, R1.T, swap);
|
||||
|
||||
ed25519_add_internal(&R1, &R0, &R1); /* R1 <-- R0 + R1 */
|
||||
ed25519_double_internal(&R0, &R0); /* R0 <-- 2R0 */
|
||||
|
||||
swap = bit;
|
||||
if (bit_idx-- == 0) {
|
||||
bit_idx = 7;
|
||||
scan++;
|
||||
}
|
||||
}
|
||||
cswap(R0.X, R0.Y, R1.X, R1.Y, swap);
|
||||
cswap(R0.Z, R0.T, R1.Z, R1.T, swap);
|
||||
|
||||
*Pout = R0;
|
||||
}
|
||||
|
||||
/* ---- */
|
||||
|
||||
int ed25519_new_point(Point **out,
|
||||
uint8_t x[32], uint8_t y[32],
|
||||
size_t modsize, void *context)
|
||||
{
|
||||
uint32_t A[10], B[10], C[10];
|
||||
const char d[] = "52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3";
|
||||
|
||||
if ((NULL == out) || (NULL == x) || (NULL == y))
|
||||
return ERR_NULL;
|
||||
|
||||
if (modsize != 32)
|
||||
return ERR_MODULUS;
|
||||
|
||||
*out = calloc(1, sizeof(Point));
|
||||
if (NULL == *out)
|
||||
return ERR_MEMORY;
|
||||
|
||||
convert_be8_to_le25p5((*out)->X, x);
|
||||
convert_be8_to_le25p5((*out)->Y, y);
|
||||
(*out)->Z[0] = 1;
|
||||
mul_25519((*out)->T, (*out)->X, (*out)->Y);
|
||||
|
||||
/** Verify that the point is on the Ed25519 curve **/
|
||||
mul_25519(A, (*out)->X, (*out)->X); /* x² */
|
||||
mul_25519(B, (*out)->Y, (*out)->Y); /* y² */
|
||||
|
||||
convert_behex_to_le25p5(C, d); /* d */
|
||||
mul_25519(C, C, B); /* dy² */
|
||||
mul_25519(C, C, A); /* dx²y² */
|
||||
add_25519(C, C, A); /* dx²y² - ax² */
|
||||
|
||||
memset(A, 0, sizeof A);
|
||||
A[0] = 1;
|
||||
add_25519(C, C, A); /* 1 + dx²y² - ax² */
|
||||
|
||||
reduce_25519_le25p5(B);
|
||||
reduce_25519_le25p5(C);
|
||||
if (0 != memcmp(B, C, sizeof B)) {
|
||||
free(*out);
|
||||
*out = NULL;
|
||||
return ERR_EC_POINT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ed25519_clone(Point **P, const Point *Q)
|
||||
{
|
||||
if ((NULL == P) || (NULL == Q))
|
||||
return ERR_NULL;
|
||||
|
||||
*P = calloc(1, sizeof(Point));
|
||||
if (NULL == *P)
|
||||
return ERR_MEMORY;
|
||||
|
||||
**P = *Q;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ed25519_free_point(Point *p)
|
||||
{
|
||||
if (p)
|
||||
free(p);
|
||||
}
|
||||
|
||||
int ed25519_cmp(const Point *p1, const Point *p2)
|
||||
{
|
||||
uint32_t tmp[10];
|
||||
uint8_t bin1[32], bin2[32];
|
||||
int res = 0;
|
||||
|
||||
mul_25519(tmp, p1->X, p2->Z);
|
||||
convert_le25p5_to_le8(bin1, tmp);
|
||||
mul_25519(tmp, p2->X, p1->Z);
|
||||
convert_le25p5_to_le8(bin2, tmp);
|
||||
for (unsigned i=0; i<sizeof bin1; i++) {
|
||||
res |= bin1[i] != bin2[i];
|
||||
}
|
||||
|
||||
mul_25519(tmp, p1->Y, p2->Z);
|
||||
convert_le25p5_to_le8(bin1, tmp);
|
||||
mul_25519(tmp, p2->Y, p1->Z);
|
||||
convert_le25p5_to_le8(bin2, tmp);
|
||||
for (unsigned i=0; i<sizeof bin1; i++) {
|
||||
res |= bin1[i] != bin2[i];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int ed25519_neg(Point *p)
|
||||
{
|
||||
const uint32_t zero[10] = { 0 };
|
||||
|
||||
sub32(p->X, zero, p->X);
|
||||
reduce_25519_le25p5(p->X);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ed25519_get_xy(uint8_t *xb, uint8_t *yb, size_t modsize, Point *p)
|
||||
{
|
||||
uint32_t invz[10], tmp[10];
|
||||
|
||||
if ((NULL == xb) || (NULL == yb) || (NULL == p))
|
||||
return ERR_NULL;
|
||||
if (modsize != 32)
|
||||
return ERR_MODULUS;
|
||||
|
||||
invert_25519(invz, p->Z);
|
||||
mul_25519(tmp, p->X, invz);
|
||||
convert_le25p5_to_be8(xb, tmp);
|
||||
mul_25519(tmp, p->Y, invz);
|
||||
convert_le25p5_to_be8(yb, tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ed25519_double(Point *p)
|
||||
{
|
||||
if (NULL == p)
|
||||
return ERR_NULL;
|
||||
ed25519_double_internal(p, p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ed25519_add(Point *P1, const Point *P2)
|
||||
{
|
||||
if ((NULL == P1) || (NULL == P2))
|
||||
return ERR_NULL;
|
||||
ed25519_add_internal(P1, P1, P2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ed25519_scalar(Point *P, uint8_t *scalar, size_t scalar_len, uint64_t seed)
|
||||
{
|
||||
if ((NULL == P) || (NULL == scalar))
|
||||
return ERR_NULL;
|
||||
|
||||
ed25519_scalar_internal(P, scalar, scalar_len, P);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
111
src/make_p256_table.c
Normal file
111
src/make_p256_table.c
Normal file
|
@ -0,0 +1,111 @@
|
|||
#include "common.h"
|
||||
#include "ec.h"
|
||||
#include "endianess.h"
|
||||
|
||||
#define BITS 256
|
||||
#define BYTES BITS/8
|
||||
#define WORDS BITS/64
|
||||
|
||||
static void print_64bit_array(uint64_t *x, unsigned len)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
printf("0x");
|
||||
for (j=0; j<8; j++) {
|
||||
printf("%02X", (uint8_t)(x[i] >> ((7-j)*8)));
|
||||
}
|
||||
printf("ULL");
|
||||
if (i!=(len-1))
|
||||
printf(",");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const uint8_t p256_mod[32] = "\xff\xff\xff\xff\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
|
||||
const uint8_t b[32] = "\x5a\xc6\x35\xd8\xaa\x3a\x93\xe7\xb3\xeb\xbd\x55\x76\x98\x86\xbc\x65\x1d\x06\xb0\xcc\x53\xb0\xf6\x3b\xce\x3c\x3e\x27\xd2\x60\x4b";
|
||||
const uint8_t order[32] = "\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xbc\xe6\xfa\xad\xa7\x17\x9e\x84\xf3\xb9\xca\xc2\xfc\x63\x25\x51";
|
||||
const uint8_t p256_Gx[32] = "\x6b\x17\xd1\xf2\xe1\x2c\x42\x47\xf8\xbc\xe6\xe5\x63\xa4\x40\xf2\x77\x03\x7d\x81\x2d\xeb\x33\xa0\xf4\xa1\x39\x45\xd8\x98\xc2\x96";
|
||||
const uint8_t p256_Gy[32] = "\x4f\xe3\x42\xe2\xfe\x1a\x7f\x9b\x8e\xe7\xeb\x4a\x7c\x0f\x9e\x16\x2b\xce\x33\x57\x6b\x31\x5e\xce\xcb\xb6\x40\x68\x37\xbf\x51\xf5";
|
||||
uint8_t xz[32] = { 0 }, yz[32] = { 0 };
|
||||
EcContext *ec_ctx;
|
||||
EcPoint *g = NULL;
|
||||
EcPoint **window = NULL;
|
||||
int i, j;
|
||||
unsigned n_tables, points_per_table, window_size;
|
||||
|
||||
ec_ws_new_context(&ec_ctx, p256_mod, b, order, 32, 0);
|
||||
ec_ws_new_point(&g, p256_Gx, p256_Gy, 32, ec_ctx);
|
||||
|
||||
/** TODO: accept this as input **/
|
||||
window_size = 5;
|
||||
|
||||
points_per_table = 1U << window_size;
|
||||
n_tables = (256+window_size-1)/window_size;
|
||||
|
||||
/** Create table with points 0, G, 2G, 3G, .. (2**window_size-1)G **/
|
||||
window = (EcPoint**)calloc(points_per_table, sizeof(EcPoint*));
|
||||
ec_ws_new_point(&window[0], xz, yz, 32, ec_ctx);
|
||||
for (i=1; i<points_per_table; i++) {
|
||||
ec_ws_clone(&window[i], window[i-1]);
|
||||
ec_ws_add(window[i], g);
|
||||
}
|
||||
|
||||
printf("/* This file was automatically generated, do not edit */\n");
|
||||
printf("#include \"common.h\"\n");
|
||||
printf("#include \"p256_table.h\"\n");
|
||||
printf("const unsigned p256_n_tables = %d;\n", n_tables);
|
||||
printf("const unsigned p256_window_size = %d;\n", window_size);
|
||||
printf("const unsigned p256_points_per_table = %d;\n", points_per_table);
|
||||
printf("/* Affine coordinates in Montgomery form */\n");
|
||||
printf("/* Table size: %u kbytes */\n", (unsigned)(n_tables*points_per_table*2*WORDS*sizeof(uint64_t)));
|
||||
printf("const uint64_t p256_tables[%d][%d][2][4] = {\n", n_tables, points_per_table);
|
||||
|
||||
for (i=0; i<n_tables; i++) {
|
||||
|
||||
printf(" { /* Table #%u */\n", i);
|
||||
for (j=0; j<points_per_table; j++) {
|
||||
uint64_t xw[4], yw[4];
|
||||
|
||||
if (j == 0) {
|
||||
memcpy(xw, xz, sizeof xw);
|
||||
memcpy(yw, yz, sizeof yw);
|
||||
} else {
|
||||
ec_ws_normalize(window[j]);
|
||||
memcpy(xw, window[j]->x, sizeof xw);
|
||||
memcpy(yw, window[j]->y, sizeof yw);
|
||||
}
|
||||
|
||||
printf(" { /* Point #%d */\n", j);
|
||||
printf(" { ");
|
||||
print_64bit_array(xw, 4);
|
||||
printf(" },\n");
|
||||
printf(" { ");
|
||||
print_64bit_array(yw, 4);
|
||||
printf(" }\n");
|
||||
printf(" }%s\n", j==points_per_table-1 ? "" : ",");
|
||||
}
|
||||
printf(" }%s\n", i==n_tables-1 ? "" : ",");
|
||||
|
||||
/* Move from G to G*2^{w} */
|
||||
for (j=0; j<window_size; j++)
|
||||
ec_ws_double(g);
|
||||
|
||||
for (j=1; j<points_per_table; j++) {
|
||||
ec_ws_copy(window[j], window[j-1]);
|
||||
ec_ws_add(window[j], g);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
|
||||
for (i=0; i<points_per_table; i++) {
|
||||
ec_ws_free_point(window[i]);
|
||||
}
|
||||
free(window);
|
||||
ec_ws_free_point(g);
|
||||
ec_free_context(ec_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
111
src/make_p384_table.c
Normal file
111
src/make_p384_table.c
Normal file
|
@ -0,0 +1,111 @@
|
|||
#include "common.h"
|
||||
#include "ec.h"
|
||||
#include "endianess.h"
|
||||
|
||||
#define BITS 384
|
||||
#define BYTES BITS/8
|
||||
#define WORDS BITS/64
|
||||
|
||||
static void print_64bit_array(uint64_t *x, unsigned len)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
printf("0x");
|
||||
for (j=0; j<8; j++) {
|
||||
printf("%02X", (uint8_t)(x[i] >> ((7-j)*8)));
|
||||
}
|
||||
printf("ULL");
|
||||
if (i!=(len-1))
|
||||
printf(",");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const uint8_t p384_mod[BYTES] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff";
|
||||
const uint8_t b[BYTES] = "\xb3\x31\x2f\xa7\xe2\x3e\xe7\xe4\x98\x8e\x05\x6b\xe3\xf8\x2d\x19\x18\x1d\x9c\x6e\xfe\x81\x41\x12\x03\x14\x08\x8f\x50\x13\x87\x5a\xc6\x56\x39\x8d\x8a\x2e\xd1\x9d\x2a\x85\xc8\xed\xd3\xec\x2a\xef";
|
||||
const uint8_t order[BYTES] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc7\x63\x4d\x81\xf4\x37\x2d\xdf\x58\x1a\x0d\xb2\x48\xb0\xa7\x7a\xec\xec\x19\x6a\xcc\xc5\x29\x73";
|
||||
const uint8_t p384_Gx[BYTES] = "\xaa\x87\xca\x22\xbe\x8b\x05\x37\x8e\xb1\xc7\x1e\xf3\x20\xad\x74\x6e\x1d\x3b\x62\x8b\xa7\x9b\x98\x59\xf7\x41\xe0\x82\x54\x2a\x38\x55\x02\xf2\x5d\xbf\x55\x29\x6c\x3a\x54\x5e\x38\x72\x76\x0a\xb7";
|
||||
const uint8_t p384_Gy[BYTES] = "\x36\x17\xde\x4a\x96\x26\x2c\x6f\x5d\x9e\x98\xbf\x92\x92\xdc\x29\xf8\xf4\x1d\xbd\x28\x9a\x14\x7c\xe9\xda\x31\x13\xb5\xf0\xb8\xc0\x0a\x60\xb1\xce\x1d\x7e\x81\x9d\x7a\x43\x1d\x7c\x90\xea\x0e\x5f";
|
||||
uint8_t xz[BYTES] = { 0 }, yz[BYTES] = { 0 };
|
||||
EcContext *ec_ctx;
|
||||
EcPoint *g = NULL;
|
||||
EcPoint **window = NULL;
|
||||
int i, j;
|
||||
unsigned n_tables, points_per_table, window_size;
|
||||
|
||||
ec_ws_new_context(&ec_ctx, p384_mod, b, order, BYTES, 0);
|
||||
ec_ws_new_point(&g, p384_Gx, p384_Gy, BYTES, ec_ctx);
|
||||
|
||||
/** TODO: accept this as input **/
|
||||
window_size = 5;
|
||||
|
||||
points_per_table = 1U << window_size;
|
||||
n_tables = (BITS+window_size-1)/window_size;
|
||||
|
||||
/** Create table with points 0, G, 2G, 3G, .. (2**window_size-1)G **/
|
||||
window = (EcPoint**)calloc(points_per_table, sizeof(EcPoint*));
|
||||
ec_ws_new_point(&window[0], xz, yz, BYTES, ec_ctx);
|
||||
for (i=1; i<points_per_table; i++) {
|
||||
ec_ws_clone(&window[i], window[i-1]);
|
||||
ec_ws_add(window[i], g);
|
||||
}
|
||||
|
||||
printf("/* This file was automatically generated, do not edit */\n");
|
||||
printf("#include \"common.h\"\n");
|
||||
printf("#include \"p384_table.h\"\n");
|
||||
printf("const unsigned p384_n_tables = %d;\n", n_tables);
|
||||
printf("const unsigned p384_window_size = %d;\n", window_size);
|
||||
printf("const unsigned p384_points_per_table = %d;\n", points_per_table);
|
||||
printf("/* Affine coordinates in Montgomery form */\n");
|
||||
printf("/* Table size: %u kbytes */\n", (unsigned)(n_tables*points_per_table*2*WORDS*sizeof(uint64_t)));
|
||||
printf("const uint64_t p384_tables[%d][%d][2][%d] = {\n", n_tables, points_per_table, WORDS);
|
||||
|
||||
for (i=0; i<n_tables; i++) {
|
||||
|
||||
printf(" { /* Table #%u */\n", i);
|
||||
for (j=0; j<points_per_table; j++) {
|
||||
uint64_t xw[WORDS], yw[WORDS];
|
||||
|
||||
if (j == 0) {
|
||||
memcpy(xw, xz, sizeof xw);
|
||||
memcpy(yw, yz, sizeof yw);
|
||||
} else {
|
||||
ec_ws_normalize(window[j]);
|
||||
memcpy(xw, window[j]->x, sizeof xw);
|
||||
memcpy(yw, window[j]->y, sizeof yw);
|
||||
}
|
||||
|
||||
printf(" { /* Point #%d */\n", j);
|
||||
printf(" { ");
|
||||
print_64bit_array(xw, 6);
|
||||
printf(" },\n");
|
||||
printf(" { ");
|
||||
print_64bit_array(yw, 6);
|
||||
printf(" }\n");
|
||||
printf(" }%s\n", j==points_per_table-1 ? "" : ",");
|
||||
}
|
||||
printf(" }%s\n", i==n_tables-1 ? "" : ",");
|
||||
|
||||
/* Move from G to G*2^{w} */
|
||||
for (j=0; j<window_size; j++)
|
||||
ec_ws_double(g);
|
||||
|
||||
for (j=1; j<points_per_table; j++) {
|
||||
ec_ws_copy(window[j], window[j-1]);
|
||||
ec_ws_add(window[j], g);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
|
||||
for (i=0; i<points_per_table; i++) {
|
||||
ec_ws_free_point(window[i]);
|
||||
}
|
||||
free(window);
|
||||
ec_ws_free_point(g);
|
||||
ec_free_context(ec_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
111
src/make_p521_table.c
Normal file
111
src/make_p521_table.c
Normal file
|
@ -0,0 +1,111 @@
|
|||
#include "common.h"
|
||||
#include "ec.h"
|
||||
#include "endianess.h"
|
||||
|
||||
#define BITS 521
|
||||
#define BYTES 66
|
||||
#define WORDS 9
|
||||
|
||||
static void print_64bit_array(uint64_t *x, unsigned len)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
printf("0x");
|
||||
for (j=0; j<8; j++) {
|
||||
printf("%02X", (uint8_t)(x[i] >> ((7-j)*8)));
|
||||
}
|
||||
printf("ULL");
|
||||
if (i!=(len-1))
|
||||
printf(",");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const uint8_t p521_mod[BYTES] = "\x01\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
|
||||
const uint8_t b[BYTES] = "\x00\x51\x95\x3e\xb9\x61\x8e\x1c\x9a\x1f\x92\x9a\x21\xa0\xb6\x85\x40\xee\xa2\xda\x72\x5b\x99\xb3\x15\xf3\xb8\xb4\x89\x91\x8e\xf1\x09\xe1\x56\x19\x39\x51\xec\x7e\x93\x7b\x16\x52\xc0\xbd\x3b\xb1\xbf\x07\x35\x73\xdf\x88\x3d\x2c\x34\xf1\xef\x45\x1f\xd4\x6b\x50\x3f\x00";
|
||||
const uint8_t order[BYTES] = "\x01\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfa\x51\x86\x87\x83\xbf\x2f\x96\x6b\x7f\xcc\x01\x48\xf7\x09\xa5\xd0\x3b\xb5\xc9\xb8\x89\x9c\x47\xae\xbb\x6f\xb7\x1e\x91\x38\x64\x09";
|
||||
const uint8_t p521_Gx[BYTES] = "\x00\xc6\x85\x8e\x06\xb7\x04\x04\xe9\xcd\x9e\x3e\xcb\x66\x23\x95\xb4\x42\x9c\x64\x81\x39\x05\x3f\xb5\x21\xf8\x28\xaf\x60\x6b\x4d\x3d\xba\xa1\x4b\x5e\x77\xef\xe7\x59\x28\xfe\x1d\xc1\x27\xa2\xff\xa8\xde\x33\x48\xb3\xc1\x85\x6a\x42\x9b\xf9\x7e\x7e\x31\xc2\xe5\xbd\x66";
|
||||
const uint8_t p521_Gy[BYTES] = "\x01\x18\x39\x29\x6a\x78\x9a\x3b\xc0\x04\x5c\x8a\x5f\xb4\x2c\x7d\x1b\xd9\x98\xf5\x44\x49\x57\x9b\x44\x68\x17\xaf\xbd\x17\x27\x3e\x66\x2c\x97\xee\x72\x99\x5e\xf4\x26\x40\xc5\x50\xb9\x01\x3f\xad\x07\x61\x35\x3c\x70\x86\xa2\x72\xc2\x40\x88\xbe\x94\x76\x9f\xd1\x66\x50";
|
||||
uint8_t xz[WORDS*8] = { 0 }, yz[WORDS*8] = { 0 };
|
||||
EcContext *ec_ctx;
|
||||
EcPoint *g = NULL;
|
||||
EcPoint **window = NULL;
|
||||
int i, j;
|
||||
unsigned n_tables, points_per_table, window_size;
|
||||
|
||||
ec_ws_new_context(&ec_ctx, p521_mod, b, order, BYTES, 0);
|
||||
ec_ws_new_point(&g, p521_Gx, p521_Gy, BYTES, ec_ctx);
|
||||
|
||||
/** TODO: accept this as input **/
|
||||
window_size = 4;
|
||||
|
||||
points_per_table = 1U << window_size;
|
||||
n_tables = (BITS+window_size-1)/window_size;
|
||||
|
||||
/** Create table with points 0, G, 2G, 3G, .. (2**window_size-1)G **/
|
||||
window = (EcPoint**)calloc(points_per_table, sizeof(EcPoint*));
|
||||
ec_ws_new_point(&window[0], xz, yz, sizeof xz, ec_ctx);
|
||||
for (i=1; i<points_per_table; i++) {
|
||||
ec_ws_clone(&window[i], window[i-1]);
|
||||
ec_ws_add(window[i], g);
|
||||
}
|
||||
|
||||
printf("/* This file was automatically generated, do not edit */\n");
|
||||
printf("#include \"common.h\"\n");
|
||||
printf("#include \"p521_table.h\"\n");
|
||||
printf("const unsigned p521_n_tables = %d;\n", n_tables);
|
||||
printf("const unsigned p521_window_size = %d;\n", window_size);
|
||||
printf("const unsigned p521_points_per_table = %d;\n", points_per_table);
|
||||
printf("/* Affine coordinates in plain form (not Montgomery) */\n");
|
||||
printf("/* Table size: %u kbytes */\n", (unsigned)(n_tables*points_per_table*2*WORDS*sizeof(uint64_t)));
|
||||
printf("const uint64_t p521_tables[%d][%d][2][%d] = {\n", n_tables, points_per_table, WORDS);
|
||||
|
||||
for (i=0; i<n_tables; i++) {
|
||||
|
||||
printf(" { /* Table #%u */\n", i);
|
||||
for (j=0; j<points_per_table; j++) {
|
||||
uint64_t xw[WORDS], yw[WORDS];
|
||||
|
||||
if (j == 0) {
|
||||
memcpy(xw, xz, sizeof xw);
|
||||
memcpy(yw, yz, sizeof yw);
|
||||
} else {
|
||||
ec_ws_normalize(window[j]);
|
||||
memcpy(xw, window[j]->x, sizeof xw);
|
||||
memcpy(yw, window[j]->y, sizeof yw);
|
||||
}
|
||||
|
||||
printf(" { /* Point #%d */\n", j);
|
||||
printf(" { ");
|
||||
print_64bit_array(xw, WORDS);
|
||||
printf(" },\n");
|
||||
printf(" { ");
|
||||
print_64bit_array(yw, WORDS);
|
||||
printf(" }\n");
|
||||
printf(" }%s\n", j==points_per_table-1 ? "" : ",");
|
||||
}
|
||||
printf(" }%s\n", i==n_tables-1 ? "" : ",");
|
||||
|
||||
/* Move from G to G*2^{w} */
|
||||
for (j=0; j<window_size; j++)
|
||||
ec_ws_double(g);
|
||||
|
||||
for (j=1; j<points_per_table; j++) {
|
||||
ec_ws_copy(window[j], window[j-1]);
|
||||
ec_ws_add(window[j], g);
|
||||
}
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
|
||||
for (i=0; i<points_per_table; i++) {
|
||||
ec_ws_free_point(window[i]);
|
||||
}
|
||||
free(window);
|
||||
ec_ws_free_point(g);
|
||||
ec_free_context(ec_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
581
src/mod25519.c
Normal file
581
src/mod25519.c
Normal file
|
@ -0,0 +1,581 @@
|
|||
#ifndef __MOD25519_C
|
||||
#define __MOD25519_C
|
||||
|
||||
#include "common.h"
|
||||
#include "endianess.h"
|
||||
#include "bignum.c"
|
||||
|
||||
/*
|
||||
* Operations over the field of integers modulo 2²⁵⁵ - 19
|
||||
*/
|
||||
|
||||
#if defined(MASK26) || defined(MASK25) || defined(MASK13) || defined(MASK12)
|
||||
#error Necessary macros are already defined
|
||||
#endif
|
||||
|
||||
#define MASK26 ((1ULL<<26)-1)
|
||||
#define MASK25 ((1ULL<<25)-1)
|
||||
#define MASK13 ((1ULL<<13)-1)
|
||||
#define MASK12 ((1ULL<<12)-1)
|
||||
|
||||
STATIC void reduce_25519_le64(uint64_t x[4]);
|
||||
|
||||
/*
|
||||
* Convert a 256-bit number in radix 2⁶⁴ and little-endian mode,
|
||||
* to mixed radix 2²⁵/2²⁶, also little-endian.
|
||||
*/
|
||||
STATIC void convert_le64_to_le25p5(uint32_t out[10], const uint64_t in[4])
|
||||
{
|
||||
/** MSB of in[3] will be ignored */
|
||||
out[0] = in[0] & MASK26; /* Fill 26 bits: 38 bits left in in[0] */
|
||||
out[1] = (in[0] >> 26) & MASK25; /* Fill 25 bits: 13 bits left in in[0] */
|
||||
out[2] = (uint32_t)((in[0] >> 51) | (in[1] & MASK13) << 13); /* Fill 26 bits: 51 bits left in in[1] */
|
||||
out[3] = (in[1] >> 13) & MASK25; /* Fill 25 bits: 26 bits left in in[1] */
|
||||
out[4] = (uint32_t)(in[1] >> 38); /* Fill 26 bits: no bits left in in[1] */
|
||||
out[5] = in[2] & MASK25; /* Fill 25 bits: 39 bits left in in[2] */
|
||||
out[6] = (in[2] >> 25) & MASK26; /* Fill 26 bits: 13 bits left in in[2] */
|
||||
out[7] = (uint32_t)((in[2] >> 51) | (in[3] & MASK12) << 13); /* Fill 25 bits: 52 bits left in in[3] */
|
||||
out[8] = (in[3] >> 12) & MASK26; /* Fill 26 bits: 26 bits left in in[3] */
|
||||
out[9] = (uint32_t)(in[3] >> 38); /* Fill 26 bits in theory, 25 in practice */
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a 256-bit number in mixed radix 2²⁵/2²⁶ and little-endian mode,
|
||||
* to radix 2⁶⁴, also little-endian mode.
|
||||
*
|
||||
* The input limbs must fulfill the conditions:
|
||||
* in[i] < 2²⁶ for even i (0, 2, 4, etc)
|
||||
* in[j] < 2²⁵ for odd j<9 (1, 3, 5, etc)
|
||||
* in[9] < 2²⁶
|
||||
*/
|
||||
STATIC void convert_le25p5_to_le64(uint64_t out[4], const uint32_t in[10])
|
||||
{
|
||||
/** We assume that the 6 or 7 upper bits of in[] words is set to 0 */
|
||||
assert(in[0] >> 26 == 0);
|
||||
assert(in[1] >> 25 == 0);
|
||||
assert(in[2] >> 26 == 0);
|
||||
assert(in[3] >> 25 == 0);
|
||||
assert(in[4] >> 26 == 0);
|
||||
assert(in[5] >> 25 == 0);
|
||||
assert(in[6] >> 26 == 0);
|
||||
assert(in[7] >> 25 == 0);
|
||||
assert(in[8] >> 26 == 0);
|
||||
assert(in[9] >> 26 == 0);
|
||||
|
||||
out[0] = in[0] | (uint64_t)in[1] << 26 | ((uint64_t)in[2] & MASK13) << 51; /* 64 = 26 + 25 + 13: 13 bits left in in[2] */
|
||||
out[1] = in[2] >> 13 | (uint64_t)in[3] << 13 | (uint64_t)in[4] << 38; /* 64 = 13 + 25 + 26: no bits left in[4] */
|
||||
out[2] = in[5] | (uint64_t)in[6] << 25 | ((uint64_t)in[7] & MASK13) << 51; /* 64 = 25 + 26 + 13: 12 bits left in in[7] */
|
||||
out[3] = in[7] >> 13 | (uint64_t)in[8] << 12 | (uint64_t)in[9] << 38; /* 64 = 12 + 26 + 26(!) */
|
||||
}
|
||||
|
||||
/*
|
||||
* Deserialize a 255-bit little-endian integer
|
||||
* to mixed radix 2²⁶/2²⁵, also little-endian.
|
||||
*/
|
||||
STATIC void convert_le8_to_le25p5(uint32_t out[10], const uint8_t in[32])
|
||||
{
|
||||
uint64_t in64[4];
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<4; i++) {
|
||||
in64[i] = LOAD_U64_LITTLE(&in[i*8]);
|
||||
}
|
||||
convert_le64_to_le25p5(out, in64);
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialize a 256-bit mixed-radix 2²⁶/2²⁵ little-endian integer
|
||||
* into a little-endian byte string.
|
||||
*
|
||||
* The input limbs must fulfill the conditions:
|
||||
* in[i] < 2²⁶ for even i (0, 2, 4, etc)
|
||||
* in[j] < 2²⁵ for odd j<9 (1, 3, 5, etc)
|
||||
* in[9] < 2²⁶
|
||||
*/
|
||||
STATIC void convert_le25p5_to_le8(uint8_t out[32], const uint32_t in[10])
|
||||
{
|
||||
uint64_t out64[4];
|
||||
unsigned i;
|
||||
|
||||
convert_le25p5_to_le64(out64, in);
|
||||
reduce_25519_le64(out64);
|
||||
for (i=0; i<4; i++) {
|
||||
STORE_U64_LITTLE(&out[i*8], out64[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Deserialize a 255-bit big-endian integer
|
||||
* to mixed radix 2²⁶/2²⁵ little-endian.
|
||||
*/
|
||||
STATIC void convert_be8_to_le25p5(uint32_t out[10], const uint8_t in[32])
|
||||
{
|
||||
uint64_t in64[4];
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<4; i++) {
|
||||
in64[3-i] = LOAD_U64_BIG(&in[i*8]);
|
||||
}
|
||||
convert_le64_to_le25p5(out, in64);
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialize a 256-bit mixed-radix 2²⁶/2²⁵ little-endian integer
|
||||
* into a big-endian byte string.
|
||||
*
|
||||
* The input limbs must fulfill the conditions:
|
||||
* in[i] < 2²⁶ for even i (0, 2, 4, etc)
|
||||
* in[j] < 2²⁵ for odd j<9 (1, 3, 5, etc)
|
||||
* in[9] < 2²⁶
|
||||
*/
|
||||
STATIC void convert_le25p5_to_be8(uint8_t out[32], const uint32_t in[10])
|
||||
{
|
||||
uint64_t out64[4];
|
||||
unsigned i;
|
||||
|
||||
convert_le25p5_to_le64(out64, in);
|
||||
reduce_25519_le64(out64);
|
||||
for (i=0; i<4; i++) {
|
||||
STORE_U64_BIG(&out[i*8], out64[3-i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int hex2bin(char in)
|
||||
{
|
||||
if ((in >= '0') && (in <= '9'))
|
||||
return in - '0';
|
||||
if ((in >= 'A') && (in <= 'F'))
|
||||
return in - 'A' + 10;
|
||||
if ((in >= 'a') && (in <= 'f'))
|
||||
return in - 'a' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char bin2hex(uint8_t b)
|
||||
{
|
||||
if (b < 10)
|
||||
return '0' + b;
|
||||
return 'a' + b - 10;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a big-endian hexadecimal number (up to 256 bits, and as a zero-terminated ASCII string)
|
||||
* to mixed radix 2²⁶/2²⁵, also little-endian.
|
||||
*/
|
||||
STATIC int convert_behex_to_le25p5(uint32_t out[10], const char *in)
|
||||
{
|
||||
size_t len;
|
||||
uint8_t bin[32];
|
||||
unsigned i;
|
||||
|
||||
if (in == NULL)
|
||||
return ERR_NULL;
|
||||
len = strlen(in);
|
||||
if (len > 64)
|
||||
return ERR_MAX_DATA;
|
||||
if (len & 1)
|
||||
return ERR_BLOCK_SIZE;
|
||||
|
||||
memset(bin, 0, sizeof bin);
|
||||
|
||||
for (i=0; i<len; i+=2) {
|
||||
int c1, c2;
|
||||
|
||||
c1 = hex2bin(in[len-1-i]);
|
||||
c2 = hex2bin(in[len-1-i-1]);
|
||||
if ((c1 < 0) || (c2 < 0))
|
||||
return ERR_VALUE;
|
||||
|
||||
bin[i/2] = c2 * 16 + c1;
|
||||
}
|
||||
|
||||
convert_le8_to_le25p5(out, bin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a number in mixed radix 2²⁶/2²⁵, little-endian form
|
||||
* into a new ASCII hex, zero-terminated string. The caller
|
||||
* is responsible for deallocating the string.
|
||||
*/
|
||||
STATIC int convert_le25p5_to_behex(char **out, uint32_t in[10])
|
||||
{
|
||||
uint8_t bin[32];
|
||||
unsigned i;
|
||||
|
||||
if (NULL == out)
|
||||
return ERR_NULL;
|
||||
|
||||
convert_le25p5_to_le8(bin, in);
|
||||
*out = calloc(64 + 1, 1);
|
||||
|
||||
for (i=0; i<32; i++) {
|
||||
*(*out+64-1-i*2) = bin2hex(bin[i] & 0xF);
|
||||
*(*out+64-2-i*2) = bin2hex(bin[i] >> 4);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void print_le25p5(char *str, const uint32_t n[10])
|
||||
{
|
||||
uint8_t bin[32];
|
||||
|
||||
convert_le25p5_to_le8(bin, n);
|
||||
printf("%s", str);
|
||||
for (unsigned i=0; i<32; i++) {
|
||||
printf("%02X", bin[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Reduce a 256-bit number (2⁶⁴ radix, litte-endian) modulo 2²⁵⁵ - 19.
|
||||
*/
|
||||
STATIC void reduce_25519_le64(uint64_t x[4])
|
||||
{
|
||||
unsigned borrow;
|
||||
uint64_t tmp1[4], tmp2[4];
|
||||
static const uint64_t modulus[4] = { 0xffffffffffffffedULL, 0xffffffffffffffffULL, 0xffffffffffffffffULL, 0x7fffffffffffffffULL };
|
||||
|
||||
borrow = sub(tmp1, x, modulus, 4);
|
||||
mod_select(tmp2, x, tmp1, borrow, 4);
|
||||
|
||||
borrow = sub(tmp1, tmp2, modulus, 4);
|
||||
mod_select(x, tmp2, tmp1, borrow, 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Multiply f[] and g[] modulo 2²⁵⁵ - 19.
|
||||
*
|
||||
* The inputs f[] and g[] are encoded in mixed radix 2²⁶/2²⁵ with limbs < 2²⁷.
|
||||
*
|
||||
* The result out[] is encoded in also mixed radix 2²⁶/2²⁵ such that:
|
||||
* f[i] < 2²⁶ for even i
|
||||
* f[j] < 2²⁵ for odd j<9
|
||||
* f[9] < 2²⁶
|
||||
*/
|
||||
STATIC void mul_25519(uint32_t out[10], const uint32_t f[10], const uint32_t g[10])
|
||||
{
|
||||
uint64_t h0, h1, h2, h3, h4, h5, h6, h7, h8, h9;
|
||||
uint64_t f0, f1, f2, f3, f4, f5, f6, f7, f8, f9;
|
||||
uint64_t f1_38, f2_19, f3_19, f4_19, f5_19, f6_19, f7_19, f8_19, f9_19;
|
||||
uint64_t g0, g1, g2, g3, g4, g5, g6, g7, g8, g9;
|
||||
uint64_t carry;
|
||||
|
||||
f0 = f[0]; f1 = f[1]; f2 = f[2]; f3 = f[3]; f4 = f[4]; f5 = f[5]; f6 = f[6]; f7 = f[7]; f8 = f[8]; f9 = f[9];
|
||||
g0 = g[0]; g1 = g[1]; g2 = g[2]; g3 = g[3]; g4 = g[4]; g5 = g[5]; g6 = g[6]; g7 = g[7]; g8 = g[8]; g9 = g[9];
|
||||
|
||||
f1_38 = (uint64_t)38*f[1];
|
||||
f2_19 = (uint64_t)19*f[2];
|
||||
f3_19 = (uint64_t)19*f[3];
|
||||
f4_19 = (uint64_t)19*f[4];
|
||||
f5_19 = (uint64_t)19*f[5];
|
||||
f6_19 = (uint64_t)19*f[6];
|
||||
f7_19 = (uint64_t)19*f[7];
|
||||
f8_19 = (uint64_t)19*f[8];
|
||||
f9_19 = (uint64_t)19*f[9];
|
||||
|
||||
/** input terms can the result of at most 4 additions **/
|
||||
|
||||
h0 = f0*g0 + f1_38*g9 + f2_19*g8 + 2*f3_19*g7 + f4_19*g6 +
|
||||
2*f5_19*g5 + f6_19*g4 + 2*f7_19*g3 + f8_19*g2 + 2*f9_19*g1;
|
||||
h1 = f0*g1 + f1*g0 + f2_19*g9 + f3_19*g8 + f4_19*g7 +
|
||||
f5_19*g6 + f6_19*g5 + f7_19*g4 + f8_19*g3 + f9_19*g2;
|
||||
h2 = f0*g2 + 2*f1*g1 + f2*g0 + 2*f3_19*g9 + f4_19*g8 +
|
||||
2*f5_19*g7 + f6_19*g6 + 2*f7_19*g5 + f8_19*g4 + 2*f9_19*g3;
|
||||
h3 = f0*g3 + f1*g2 + f2*g1 + f3*g0 + f4_19*g9 +
|
||||
f5_19*g8 + f6_19*g7 + f7_19*g6 + f8_19*g5 + f9_19*g4;
|
||||
h4 = f0*g4 + 2*f1*g3 + f2*g2 + 2*f3*g1 + f4*g0 +
|
||||
2*f5_19*g9 + f6_19*g8 + 2*f7_19*g7 + f8_19*g6 + 2*f9_19*g5;
|
||||
h5 = f0*g5 + f1*g4 + f2*g3 + f3*g2 + f4*g1 +
|
||||
f5*g0 + f6_19*g9 + f7_19*g8 + f8_19*g7 + f9_19*g6;
|
||||
h6 = f0*g6 + 2*f1*g5 + f2*g4 + 2*f3*g3 + f4*g2 +
|
||||
2*f5*g1 + f6*g0 + 2*f7_19*g9 + f8_19*g8 + 2*f9_19*g7;
|
||||
h7 = f0*g7 + f1*g6 + f2*g5 + f3*g4 + f4*g3 +
|
||||
f5*g2 + f6*g1 + f7*g0 + f8_19*g9 + f9_19*g8;
|
||||
h8 = f0*g8 + 2*f1*g7 + f2*g6 + 2*f3*g5 + f4*g4 +
|
||||
2*f5*g3 + f6*g2 + 2*f7*g1 + f8*g0 + 2*f9_19*g9;
|
||||
h9 = f0*g9 + f1*g8 + f2*g7 + f3*g6 + f4*g5 +
|
||||
f5*g4 + f6*g3 + f7*g2 + f8*g1 + f9*g0;
|
||||
|
||||
/* h0..h9 < 2⁶³ */
|
||||
carry = h8 >> 26;
|
||||
h8 &= MASK26;
|
||||
/* carry < 2³⁷ */
|
||||
h9 += carry;
|
||||
carry = (h9 >> 25)*19;
|
||||
h9 &= MASK25;
|
||||
/* carry < 2⁴⁴ */
|
||||
h0 += carry;
|
||||
carry = h0 >> 26;
|
||||
h0 &= MASK26;
|
||||
/* carry < 2³⁸ */
|
||||
h1 += carry;
|
||||
carry = h1 >> 25;
|
||||
h1 &= MASK25;
|
||||
/* carry < 2³⁹ */
|
||||
h2 += carry;
|
||||
carry = h2 >> 26;
|
||||
h2 &= MASK26;
|
||||
/* carry < 2³⁸ */
|
||||
h3 += carry;
|
||||
carry = h3 >> 25;
|
||||
h3 &= MASK25;
|
||||
/* carry < 2³⁹ */
|
||||
h4 += carry;
|
||||
carry = h4 >> 26;
|
||||
h4 &= MASK26;
|
||||
/* carry < 2³⁸ */
|
||||
h5 += carry;
|
||||
carry = h5 >> 25;
|
||||
h5 &= MASK25;
|
||||
/* carry < 2³⁹ */
|
||||
h6 += carry;
|
||||
carry = h6 >> 26;
|
||||
h6 &= MASK26;
|
||||
/* carry < 2³⁸ */
|
||||
h7 += carry;
|
||||
carry = h7 >> 25;
|
||||
h7 &= MASK25;
|
||||
/* carry < 2³⁹ */
|
||||
h8 += carry;
|
||||
carry = h8 >> 26;
|
||||
h8 &= MASK26;
|
||||
/* carry < 2¹⁴ */
|
||||
h9 += carry;
|
||||
/* h9 < 2²⁶ */
|
||||
|
||||
out[0] = (uint32_t)h0;
|
||||
out[1] = (uint32_t)h1;
|
||||
out[2] = (uint32_t)h2;
|
||||
out[3] = (uint32_t)h3;
|
||||
out[4] = (uint32_t)h4;
|
||||
out[5] = (uint32_t)h5;
|
||||
out[6] = (uint32_t)h6;
|
||||
out[7] = (uint32_t)h7;
|
||||
out[8] = (uint32_t)h8;
|
||||
out[9] = (uint32_t)h9;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute addition for mixed-radix 2²⁶/2²⁵.
|
||||
* If the biggest input limb fits into x bits (x<32), the biggest output limb will fit into (x+1) bits.
|
||||
*/
|
||||
STATIC void add32(uint32_t out[10], const uint32_t a[10], const uint32_t b[10])
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<10; i++) {
|
||||
out[i] = a[i] + b[i];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Carry out subtraction a[] - b[] for mixed-radix 2²⁶/2²⁵ where all limbs are < 2²⁶.
|
||||
* Output limbs are < 2²⁷.
|
||||
*/
|
||||
STATIC void sub32(uint32_t out[10], const uint32_t a[10], const uint32_t b[10])
|
||||
{
|
||||
/*
|
||||
* We pre-sum a number which is >= 2²⁶-1 for each limb, and which is congruent to zero modulo 2²⁵⁵-19
|
||||
*/
|
||||
static const uint32_t modulus_32[10] = { 0x7ffffda, 0x3fffffe, 0x7fffffe, 0x3fffffe, 0x7fffffe, 0x3fffffe, 0x7fffffe, 0x3fffffe, 0x7fffffe, 0x3fffffe };
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<10; i++) {
|
||||
out[i] = modulus_32[i] + a[i] - b[i];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Swap arguments a/c and b/d when condition is NOT ZERO.
|
||||
* If the condition IS ZERO, no swapping takes place.
|
||||
*/
|
||||
STATIC void cswap(uint32_t a[10], uint32_t b[10], uint32_t c[10], uint32_t d[10], unsigned swap)
|
||||
{
|
||||
uint32_t mask, i, e, f;
|
||||
|
||||
mask = (uint32_t)(0 - (swap!=0)); /* 0 if swap is 0, all 1s if swap is !=0 */
|
||||
for (i=0; i<10; i++) {
|
||||
e = mask & (a[i] ^ c[i]);
|
||||
a[i] ^= e;
|
||||
c[i] ^= e;
|
||||
f = mask & (b[i] ^ d[i]);
|
||||
b[i] ^= f;
|
||||
d[i] ^= f;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute x⁻¹ in prime field 2²⁵⁵ - 19
|
||||
*
|
||||
* The input x[] is encoded in mixed radix 2²⁶/2²⁵ with limbs < 2²⁷.
|
||||
*
|
||||
* The result out[] is encoded in also mixed radix 2²⁶/2²⁵ such that:
|
||||
* out[i] < 2²⁶ for even i
|
||||
* out[j] < 2²⁵ for odd j<9
|
||||
* out[9] < 2²⁶
|
||||
*/
|
||||
STATIC void invert_25519(uint32_t out[10], const uint32_t x[10])
|
||||
{
|
||||
uint32_t a[10], x1[10], x3p0[10], x3p1p0[10], x5m0[10];
|
||||
uint32_t x10m0[10], x20m0[10], x50m0[10], x100m0[10];
|
||||
unsigned i;
|
||||
|
||||
#define sqr_25519(a,b) mul_25519(a,b,b)
|
||||
|
||||
sqr_25519(x1, x); /* 2¹ */
|
||||
sqr_25519(a, x1); /* 2² */
|
||||
sqr_25519(a, a); /* 2³ */
|
||||
mul_25519(x3p0, a, x); /* 2³ + 2⁰ */
|
||||
mul_25519(x3p1p0, x3p0, x1);/* 2³ + 2¹ + 2⁰ = 11 */
|
||||
sqr_25519(a, x3p1p0); /* 2⁴ + 2² + 2¹ */
|
||||
mul_25519(x5m0, a, x3p0); /* 2⁴ + 2³ + 2² + 2¹ + 2⁰ = 2⁵ - 2⁰ */
|
||||
sqr_25519(a, x5m0); /* 2⁶ - 2¹ */
|
||||
sqr_25519(a, a); /* 2⁷ - 2² */
|
||||
sqr_25519(a, a); /* 2⁸ - 2³ */
|
||||
sqr_25519(a, a); /* 2⁹ - 2⁴ */
|
||||
sqr_25519(a, a); /* 2¹⁰ - 2⁵ */
|
||||
mul_25519(a, a, x5m0); /* 2¹⁰ - 2⁰ */
|
||||
memcpy(x10m0, a, sizeof a);
|
||||
for (i=0; i<10; i++) {
|
||||
sqr_25519(a, a);
|
||||
} /* 2²⁰ - 2¹⁰ */
|
||||
mul_25519(a, a, x10m0); /* 2²⁰ - 2⁰ */
|
||||
memcpy(x20m0, a, sizeof a);
|
||||
for (i=0; i<20; i++) {
|
||||
sqr_25519(a, a);
|
||||
} /* 2⁴⁰ - 2²⁰ */
|
||||
mul_25519(a, a, x20m0); /* 2⁴⁰ - 2⁰ */
|
||||
for (i=0; i<10; i++) {
|
||||
sqr_25519(a, a);
|
||||
} /* 2⁵⁰ - 2¹⁰ */
|
||||
mul_25519(a, a, x10m0); /* 2⁵⁰ - 2⁰ */
|
||||
memcpy(x50m0, a, sizeof a);
|
||||
for (i=0; i<50; i++) {
|
||||
sqr_25519(a, a);
|
||||
} /* 2¹⁰⁰ - 2⁵⁰ */
|
||||
mul_25519(a, a, x50m0); /* 2¹⁰⁰ - 2⁰ */
|
||||
memcpy(x100m0, a, sizeof a);
|
||||
for (i=0; i<100; i++) {
|
||||
sqr_25519(a, a);
|
||||
} /* 2²⁰⁰ - 2¹⁰⁰ */
|
||||
mul_25519(a, a, x100m0); /* 2²⁰⁰ - 2⁰ */
|
||||
for (i=0; i<50; i++) {
|
||||
sqr_25519(a, a);
|
||||
} /* 2²⁵⁰ - 2⁵⁰ */
|
||||
mul_25519(a, a, x50m0); /* 2²⁵⁰ - 2⁰ */
|
||||
sqr_25519(a, a); /* 2²⁵¹ - 2¹ */
|
||||
sqr_25519(a, a); /* 2²⁵² - 2² */
|
||||
sqr_25519(a, a); /* 2²⁵³ - 2³ */
|
||||
sqr_25519(a, a); /* 2²⁵⁴ - 2⁴ */
|
||||
sqr_25519(a, a); /* 2²⁵⁵ - 2⁵ = 2²⁵⁵ - 32 */
|
||||
mul_25519(out, a, x3p1p0); /* 2²⁵⁵ - 21 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Add f[] and g[] modulo 2²⁵⁵ - 19.
|
||||
*
|
||||
* f[] and g[] are encoded in radix 2²⁶/2²⁵ and each limb is < 2²⁷.
|
||||
*
|
||||
* The result out[] is encoded in also radix 2²⁶/2²⁵ such that:
|
||||
* out[i] < 2²⁶ for even i
|
||||
* out[j] < 2²⁵ for odd j<9
|
||||
* out[9] < 2²⁶
|
||||
*/
|
||||
STATIC void add_25519(uint32_t out[10], const uint32_t f[10], const uint32_t g[10])
|
||||
{
|
||||
uint64_t h0, h1, h2, h3, h4, h5, h6, h7, h8, h9;
|
||||
uint64_t carry;
|
||||
|
||||
h0 = f[0] + g[0];
|
||||
h1 = f[1] + g[1];
|
||||
h2 = f[2] + g[2];
|
||||
h3 = f[3] + g[3];
|
||||
h4 = f[4] + g[4];
|
||||
h5 = f[5] + g[5];
|
||||
h6 = f[6] + g[6];
|
||||
h7 = f[7] + g[7];
|
||||
h8 = f[8] + g[8];
|
||||
h9 = f[9] + g[9];
|
||||
|
||||
/* h0..h9 < 2²⁸ */
|
||||
carry = h8 >> 26;
|
||||
h8 &= MASK26;
|
||||
/* carry < 2² */
|
||||
h9 += carry;
|
||||
carry = (h9 >> 25)*19;
|
||||
h9 &= MASK25;
|
||||
/* carry < 2⁹ */
|
||||
h0 += carry;
|
||||
carry = h0 >> 26;
|
||||
h0 &= MASK26;
|
||||
/* carry < 2³ */
|
||||
h1 += carry;
|
||||
carry = h1 >> 25;
|
||||
h1 &= MASK25;
|
||||
/* carry < 2⁴ */
|
||||
h2 += carry;
|
||||
carry = h2 >> 26;
|
||||
h2 &= MASK26;
|
||||
/* carry < 2³ */
|
||||
h3 += carry;
|
||||
carry = h3 >> 25;
|
||||
h3 &= MASK25;
|
||||
/* carry < 2⁴ */
|
||||
h4 += carry;
|
||||
carry = h4 >> 26;
|
||||
h4 &= MASK26;
|
||||
/* carry < 2³ */
|
||||
h5 += carry;
|
||||
carry = h5 >> 25;
|
||||
h5 &= MASK25;
|
||||
/* carry < 2⁴ */
|
||||
h6 += carry;
|
||||
carry = h6 >> 26;
|
||||
h6 &= MASK26;
|
||||
/* carry < 2³ */
|
||||
h7 += carry;
|
||||
carry = h7 >> 25;
|
||||
h7 &= MASK25;
|
||||
/* carry < 2⁴ */
|
||||
h8 += carry;
|
||||
carry = h8 >> 26;
|
||||
h8 &= MASK26;
|
||||
/* carry < 2¹ */
|
||||
h9 += carry;
|
||||
/* h9 < 2²⁶ */
|
||||
|
||||
out[0] = (uint32_t)h0;
|
||||
out[1] = (uint32_t)h1;
|
||||
out[2] = (uint32_t)h2;
|
||||
out[3] = (uint32_t)h3;
|
||||
out[4] = (uint32_t)h4;
|
||||
out[5] = (uint32_t)h5;
|
||||
out[6] = (uint32_t)h6;
|
||||
out[7] = (uint32_t)h7;
|
||||
out[8] = (uint32_t)h8;
|
||||
out[9] = (uint32_t)h9;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reduce a 256-bit number (mixed radix 2²⁶/²⁵, litte-endian) modulo 2²⁵⁵ - 19.
|
||||
*
|
||||
* Each limb of x[] in input is < 2²⁷ (for instance, as result of sub32).
|
||||
*
|
||||
* The result x[] in output is such that:
|
||||
* x[i] < 2²⁶ for even i
|
||||
* x[j] < 2²⁵ for odd j<9
|
||||
* x[9] < 2²⁶
|
||||
*/
|
||||
STATIC void reduce_25519_le25p5(uint32_t x[10])
|
||||
{
|
||||
uint32_t zero[10] = { 0 };
|
||||
add_25519(x, x, zero);
|
||||
assert((x[0] >> 26) == 0);
|
||||
}
|
||||
|
||||
#endif /* __MOD25519_C */
|
258
src/mont.c
258
src/mont.c
|
@ -58,15 +58,7 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
static inline unsigned is_odd(uint64_t x)
|
||||
{
|
||||
return 1 == (x & 1);
|
||||
}
|
||||
|
||||
static inline unsigned is_even(uint64_t x)
|
||||
{
|
||||
return !is_odd(x);
|
||||
}
|
||||
#include "bignum.c"
|
||||
|
||||
/**
|
||||
* Compute the inverse modulo 2⁶⁴ of a 64-bit odd integer.
|
||||
|
@ -88,61 +80,6 @@ STATIC uint64_t inverse64(uint64_t a)
|
|||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a multi-word integer x is greater than or equal to y.
|
||||
*
|
||||
* @param x The first term
|
||||
* @param y The second term
|
||||
* @param nw The number of words that make up x and y
|
||||
* @return 1 if x>=y, 0 if x<y
|
||||
*/
|
||||
STATIC int ge(const uint64_t *x, const uint64_t *y, size_t nw)
|
||||
{
|
||||
unsigned mask = (unsigned)-1;
|
||||
unsigned result = 0;
|
||||
size_t i, j;
|
||||
|
||||
i = nw - 1;
|
||||
for (j=0; j<nw; j++, i--) {
|
||||
unsigned greater, lower;
|
||||
|
||||
greater = x[i] > y[i];
|
||||
lower = x[i] < y[i];
|
||||
result |= mask & (greater | (lower << 1));
|
||||
mask &= (greater ^ lower) - 1;
|
||||
}
|
||||
|
||||
return result<2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Subtract a multi-word integer b from a.
|
||||
*
|
||||
* @param out The location where the multi-word result is stored
|
||||
* @param a Number to subtract from
|
||||
* @param b Number to subtract
|
||||
* @param nw The number of words of both a and b
|
||||
* @result 0 if there is no borrow, 1 otherwise
|
||||
*/
|
||||
STATIC unsigned sub(uint64_t *out, const uint64_t *a, const uint64_t *b, size_t nw)
|
||||
{
|
||||
size_t i;
|
||||
unsigned borrow1 , borrow2;
|
||||
|
||||
borrow2 = 0;
|
||||
for (i=0; i<nw; i++) {
|
||||
borrow1 = b[i] > a[i];
|
||||
out[i] = a[i] - b[i];
|
||||
|
||||
borrow1 |= borrow2 > out[i];
|
||||
out[i] -= borrow2;
|
||||
|
||||
borrow2 = borrow1;
|
||||
}
|
||||
|
||||
return borrow2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute R² mod N, where R is the smallest power of 2⁶⁴ larger than N.
|
||||
*
|
||||
|
@ -183,161 +120,6 @@ STATIC void rsquare(uint64_t *r2_mod_n, uint64_t *n, size_t nw)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Multiply a multi-word integer a by a 64-bit scalar k and
|
||||
* then add the result to the multi-word integer t.
|
||||
*
|
||||
* @param t The multi-word integer accumulator
|
||||
* @param tw The number of words of t
|
||||
* @param a The multi-word integer to multiply with the scalar
|
||||
* @param aw The number of words of a
|
||||
* @param k The 64-bit scalar multiplier
|
||||
*/
|
||||
STATIC void addmul(uint64_t *t, size_t tw, const uint64_t *a, size_t aw, uint64_t k)
|
||||
{
|
||||
size_t i;
|
||||
uint64_t carry;
|
||||
|
||||
carry = 0;
|
||||
for (i=0; i<aw; i++) {
|
||||
uint64_t prod_lo, prod_hi;
|
||||
|
||||
DP_MULT(a[i], k, prod_lo, prod_hi);
|
||||
|
||||
prod_lo += carry;
|
||||
prod_hi += prod_lo < carry;
|
||||
|
||||
t[i] += prod_lo;
|
||||
prod_hi += t[i] < prod_lo;
|
||||
|
||||
carry = prod_hi;
|
||||
}
|
||||
|
||||
for (; carry; i++) {
|
||||
t[i] += carry;
|
||||
carry = t[i] < carry;
|
||||
}
|
||||
|
||||
assert(i <= tw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply two multi-word integers.
|
||||
*
|
||||
* @param t The location where the result is stored. It is twice as big as
|
||||
* either a (or b). It is an array of 2*nw words).
|
||||
* @param scratchpad Temporary area. It is an array of 3*nw words.
|
||||
* @param a The first term, array of nw words.
|
||||
* @param b The second term, array of nw words.
|
||||
* @param nw The number of words of both a and b.
|
||||
*
|
||||
*/
|
||||
STATIC void product(uint64_t *t, uint64_t *scratchpad, const uint64_t *a, const uint64_t *b, size_t nw)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
memset(t, 0, 2*sizeof(uint64_t)*nw);
|
||||
|
||||
for (i=0; i<(nw ^ (nw & 1)); i+=2) {
|
||||
addmul128(&t[i], scratchpad, a, b[i], b[i+1], 2*nw-i, nw);
|
||||
}
|
||||
|
||||
if (is_odd(nw)) {
|
||||
addmul(&t[nw-1], nw+2, a, nw, b[nw-1]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Select a number out of two, in constant time.
|
||||
*
|
||||
* @param out The location where the multi-word result is stored
|
||||
* @param a The first choice, selected if cond is true (non-zero)
|
||||
* @param b The second choice, selected if cond is false (zero)
|
||||
* @param cond The flag that drives the selection
|
||||
* @param words The number of words of a, b, and out
|
||||
* @return 0 for success, the appropriate code otherwise.
|
||||
*/
|
||||
STATIC FUNC_SSE2 int mont_select(uint64_t *out, const uint64_t *a, const uint64_t *b, unsigned cond, size_t words)
|
||||
{
|
||||
uint64_t mask;
|
||||
#if defined(USE_SSE2)
|
||||
unsigned pairs, i;
|
||||
__m128i r0, r1, r2, r3, r4, r5;
|
||||
|
||||
pairs = (unsigned)words / 2;
|
||||
mask = (uint64_t)((cond != 0) - 1); /* 0 for a, 1s for b */
|
||||
|
||||
#if SYSBITS == 64
|
||||
r0 = _mm_set1_epi64x(mask);
|
||||
#else
|
||||
r0 = _mm_loadl_epi64((__m128i*)&mask);
|
||||
r0 = _mm_unpacklo_epi64(r0, r0);
|
||||
#endif
|
||||
for (i=0; i<pairs; i++, a+=2, b+=2, out+=2) {
|
||||
r1 = _mm_loadu_si128((__m128i const*)b);
|
||||
r2 = _mm_loadu_si128((__m128i const*)a);
|
||||
r3 = _mm_and_si128(r0, r1);
|
||||
r4 = _mm_andnot_si128(r0, r2);
|
||||
r5 = _mm_or_si128(r3, r4);
|
||||
_mm_storeu_si128((__m128i*)out, r5);
|
||||
}
|
||||
|
||||
if (words & 1) {
|
||||
*out = (*b & mask) ^ (*a & ~mask);
|
||||
}
|
||||
#else
|
||||
unsigned i;
|
||||
|
||||
mask = (uint64_t)((cond != 0) - 1);
|
||||
for (i=0; i<words; i++) {
|
||||
*out++ = (*b++ & mask) ^ (*a++ & ~mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add two multi-word numbers with modulo arithmetic.
|
||||
*
|
||||
* @param out The locaton where the multi-word result (nw words) is stored
|
||||
* @param a The first term (nw words)
|
||||
* @param b The second term (nw words)
|
||||
* @param modulus The modulus (nw words)
|
||||
* @param tmp1 A temporary area (nw words)
|
||||
* @param tmp2 A temporary area (nw words)
|
||||
* @param nw The number of 64-bit words in all parameters
|
||||
*/
|
||||
void add_mod(uint64_t* out, const uint64_t* a, const uint64_t* b, const uint64_t *modulus, uint64_t *tmp1, uint64_t *tmp2, size_t nw)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned carry, borrow1, borrow2;
|
||||
|
||||
/*
|
||||
* Compute sum in tmp1[], and subtract modulus[]
|
||||
* from tmp1[] into tmp2[].
|
||||
*/
|
||||
borrow2 = 0;
|
||||
for (i=0, carry=0; i<nw; i++) {
|
||||
tmp1[i] = a[i] + carry;
|
||||
carry = tmp1[i] < carry;
|
||||
tmp1[i] += b[i];
|
||||
carry += tmp1[i] < b[i];
|
||||
|
||||
borrow1 = modulus[i] > tmp1[i];
|
||||
tmp2[i] = tmp1[i] - modulus[i];
|
||||
borrow1 |= borrow2 > tmp2[i];
|
||||
tmp2[i] -= borrow2;
|
||||
borrow2 = borrow1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is no borrow or if there is carry,
|
||||
* tmp1[] is larger than modulus, so we must return tmp2[].
|
||||
*/
|
||||
mont_select(out, tmp2, tmp1, carry | (borrow2 ^ 1), nw);
|
||||
}
|
||||
|
||||
/*
|
||||
* Montgomery modular multiplication, that is a*b*R mod N.
|
||||
*
|
||||
|
@ -413,7 +195,7 @@ STATIC void mont_mult_generic(uint64_t *out, const uint64_t *a, const uint64_t *
|
|||
/** Divide by R and possibly subtract n **/
|
||||
sub(t2, &t[nw], n, nw);
|
||||
cond = (unsigned)(t[2*nw] | (uint64_t)ge(&t[nw], n, nw));
|
||||
mont_select(out, t2, &t[nw], cond, (unsigned)nw);
|
||||
mod_select(out, t2, &t[nw], cond, (unsigned)nw);
|
||||
}
|
||||
|
||||
STATIC void mont_mult_p256(uint64_t *out, const uint64_t *a, const uint64_t *b, const uint64_t *n, uint64_t m0, uint64_t *tmp, size_t nw)
|
||||
|
@ -552,7 +334,7 @@ STATIC void mont_mult_p256(uint64_t *out, const uint64_t *a, const uint64_t *b,
|
|||
/** Divide by R and possibly subtract n **/
|
||||
sub(t2, &t[nw], n, WORDS_64);
|
||||
cond = (unsigned)(t[PREDIV_WORDS_64-1] | (uint64_t)ge(&t[WORDS_64], n, WORDS_64));
|
||||
mont_select(out, t2, &t[WORDS_64], cond, WORDS_64);
|
||||
mod_select(out, t2, &t[WORDS_64], cond, WORDS_64);
|
||||
|
||||
#undef WORDS_64
|
||||
#undef PREDIV_WORDS_64
|
||||
|
@ -735,7 +517,7 @@ STATIC void mont_mult_p384(uint64_t *out, const uint64_t *a, const uint64_t *b,
|
|||
/** Divide by R and possibly subtract n **/
|
||||
sub(t2, &t[WORDS_64], n, WORDS_64);
|
||||
cond = (unsigned)(t[PREDIV_WORDS_64-1] | (uint64_t)ge(&t[WORDS_64], n, WORDS_64));
|
||||
mont_select(out, t2, &t[WORDS_64], cond, WORDS_64);
|
||||
mod_select(out, t2, &t[WORDS_64], cond, WORDS_64);
|
||||
|
||||
#undef WORDS_64
|
||||
#undef PREDIV_WORDS_64
|
||||
|
@ -1044,40 +826,10 @@ int mont_mult(uint64_t* out, const uint64_t* a, const uint64_t *b, uint64_t *tmp
|
|||
*/
|
||||
int mont_sub(uint64_t *out, const uint64_t *a, const uint64_t *b, uint64_t *tmp, const MontContext *ctx)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned carry, borrow1 , borrow2;
|
||||
uint64_t *scratchpad;
|
||||
|
||||
if (NULL == out || NULL == a || NULL == b || NULL == tmp || NULL == ctx)
|
||||
return ERR_NULL;
|
||||
|
||||
scratchpad = tmp + ctx->words;
|
||||
|
||||
/*
|
||||
* Compute difference in tmp[], and add modulus[]
|
||||
* to tmp[] into scratchpad[].
|
||||
*/
|
||||
borrow2 = 0;
|
||||
carry = 0;
|
||||
for (i=0; i<ctx->words; i++) {
|
||||
borrow1 = b[i] > a[i];
|
||||
tmp[i] = a[i] - b[i];
|
||||
borrow1 |= borrow2 > tmp[i];
|
||||
tmp[i] -= borrow2;
|
||||
borrow2 = borrow1;
|
||||
|
||||
scratchpad[i] = tmp[i] + carry;
|
||||
carry = scratchpad[i] < carry;
|
||||
scratchpad[i] += ctx->modulus[i];
|
||||
carry += scratchpad[i] < ctx->modulus[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is no borrow, tmp[] is smaller than modulus.
|
||||
*/
|
||||
mont_select(out, scratchpad, tmp, borrow2, ctx->words);
|
||||
|
||||
return 0;
|
||||
return sub_mod(out, a, b, ctx->modulus, tmp, tmp + ctx->words, ctx->words);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -6,7 +6,8 @@ CFLAGS += -O3 -g -fstrict-aliasing -Wall -Werror
|
|||
|
||||
TAPPS:=tests_addmul128_32 tests_addmul128_64 tests_square_32 tests_square_64 tests_product tests_addmul test_endianess\
|
||||
test_poly1305_reduce test_poly1305_load_r test_poly1305_load_m test_poly1305_multiply test_poly1305_accumulate\
|
||||
test_mont tests_mont_mult tests_ec_ws_64 tests_ec_ws_32 test_pkcs1
|
||||
test_mont tests_mont_mult tests_ec_ws_64 tests_ec_ws_32 test_pkcs1\
|
||||
test_mod25519 test_x25519 tests_mul_25519 tests_ladder_step test_ed25519
|
||||
|
||||
ifneq (,$(filter $(shell uname -m),x86_64 i386 i686))
|
||||
CPPFLAGS += -DHAVE_X86INTRIN_H -DUSE_SSE2 -DHAVE_WMMINTRIN_H -DHAVE_TMMINTRIN_H
|
||||
|
@ -33,7 +34,7 @@ build:
|
|||
all: ${$TGTS}
|
||||
|
||||
clean:
|
||||
rm -fr build common.pyc
|
||||
rm -fr build common.pyc __pycache__
|
||||
|
||||
# utils
|
||||
|
||||
|
@ -44,7 +45,6 @@ build/modexp_utils.o: ../modexp_utils.c
|
|||
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $^
|
||||
|
||||
# ECC
|
||||
|
||||
TABLES = build/p256_table.o build/p384_table.o build/p521_table.o
|
||||
|
||||
build/p256_table.o: ../p256_table.c
|
||||
|
@ -164,3 +164,25 @@ build/tests_mont_mult: build/tests_mont_mult.c build/mont_32.o $(UTILS)
|
|||
# pkcs1
|
||||
build/test_pkcs1: test_pkcs1.c ../common.h ../pkcs1_decode.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $^
|
||||
|
||||
# Curve25519
|
||||
build/test_mod25519: test_mod25519.c ../mod25519.c ../multiply_32.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^
|
||||
|
||||
build/tests_mul_25519.c: make_tests_mul_25519.py
|
||||
$(PYTHON) $^ > $@
|
||||
|
||||
build/tests_mul_25519: build/tests_mul_25519.c ../mod25519.c ../multiply_32.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^
|
||||
|
||||
build/test_x25519: test_x25519.c ../x25519.c ../multiply_32.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^
|
||||
|
||||
build/tests_ladder_step.c: make_tests_ladder_step.py
|
||||
$(PYTHON) $^ > $@
|
||||
|
||||
build/tests_ladder_step: build/tests_ladder_step.c ../x25519.c ../multiply_32.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^
|
||||
|
||||
build/test_ed25519: test_ed25519.c ../ed25519.c ../multiply_32.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^
|
||||
|
|
182
src/test/make_tests_ladder_step.py
Normal file
182
src/test/make_tests_ladder_step.py
Normal file
|
@ -0,0 +1,182 @@
|
|||
"""Make unit test for ladder_step() in x25519.c"""
|
||||
|
||||
from common import counter, make_main, split64, bin2int
|
||||
from hashlib import sha256
|
||||
import struct
|
||||
|
||||
|
||||
def ref(x2, z2, x3, z3, x1):
|
||||
mod = 2**255 - 19
|
||||
|
||||
x4 = (x2**2 - z2**2)**2
|
||||
z4 = 4*x2*z2*(x2**2 + 486662*x2*z2 + z2**2)
|
||||
x5 = 4*((x2*x3 - z2*z3)**2)
|
||||
z5 = 4*((x2*z3 - z2*x3)**2)*x1
|
||||
|
||||
return x4 % mod, z4 % mod, x5 % mod, z5 % mod
|
||||
|
||||
|
||||
def make_test_max():
|
||||
|
||||
v = ["0x%08X" % (2**26-1)] * 10
|
||||
|
||||
modulus = 2**255 - 19
|
||||
base = [0, 26, 51, 77, 102, 128, 153, 179, 204, 230]
|
||||
n = 0
|
||||
for i in range(10):
|
||||
n += (2**26 - 1) * (2**(base[i]))
|
||||
n %= modulus
|
||||
x2_out, z2_out, x3_out, z3_out = ref(n, n, n, n, n)
|
||||
|
||||
# Output
|
||||
words = split64(x2_out)
|
||||
x2outx = words + ["0"] * (4 - len(words))
|
||||
words = split64(z2_out)
|
||||
z2outx = words + ["0"] * (4 - len(words))
|
||||
words = split64(x3_out)
|
||||
x3outx = words + ["0"] * (4 - len(words))
|
||||
words = split64(z3_out)
|
||||
z3outx = words + ["0"] * (4 - len(words))
|
||||
|
||||
print("")
|
||||
print("void test_%d() {" % next(counter))
|
||||
print(" uint32_t x2[10] = { " + ",".join(v) + " };")
|
||||
print(" uint32_t z2[10] = { " + ",".join(v) + " };")
|
||||
print(" uint32_t x3[10] = { " + ",".join(v) + " };")
|
||||
print(" uint32_t z3[10] = { " + ",".join(v) + " };")
|
||||
print(" uint32_t xp[10] = { " + ",".join(v) + " };")
|
||||
print(" const uint64_t x2_out_ref[4] = {" + ", ".join(x2outx) + "};")
|
||||
print(" const uint64_t z2_out_ref[4] = {" + ", ".join(z2outx) + "};")
|
||||
print(" const uint64_t x3_out_ref[4] = {" + ", ".join(x3outx) + "};")
|
||||
print(" const uint64_t z3_out_ref[4] = {" + ", ".join(z3outx) + "};")
|
||||
print(" uint64_t x2_out[4] = { 0 };")
|
||||
print(" uint64_t z2_out[4] = { 0 };")
|
||||
print(" uint64_t x3_out[4] = { 0 };")
|
||||
print(" uint64_t z3_out[4] = { 0 };")
|
||||
|
||||
print("")
|
||||
|
||||
print(" ladder_step(x2, z2, x3, z3, xp);")
|
||||
print(" convert_le25p5_to_le64(x2_out, x2);")
|
||||
print(" convert_le25p5_to_le64(z2_out, z2);")
|
||||
print(" convert_le25p5_to_le64(x3_out, x3);")
|
||||
print(" convert_le25p5_to_le64(z3_out, z3);")
|
||||
print(" reduce_25519_le64(x2_out);")
|
||||
print(" reduce_25519_le64(z2_out);")
|
||||
print(" reduce_25519_le64(x3_out);")
|
||||
print(" reduce_25519_le64(z3_out);")
|
||||
|
||||
print("")
|
||||
|
||||
print(" assert(0 == memcmp(x2_out, x2_out_ref, sizeof x2_out));")
|
||||
print(" assert(0 == memcmp(z2_out, z2_out_ref, sizeof z2_out));")
|
||||
print(" assert(0 == memcmp(x3_out, x3_out_ref, sizeof x3_out));")
|
||||
print(" assert(0 == memcmp(z3_out, z3_out_ref, sizeof z3_out));")
|
||||
print("}")
|
||||
|
||||
|
||||
def make_test(x2, z2, x3, z3, xp):
|
||||
|
||||
x2_out, z2_out, x3_out, z3_out = ref(x2, z2, x3, z3, xp)
|
||||
|
||||
# Input
|
||||
words = split64(x2)
|
||||
x2x = words + ["0"] * (4 - len(words))
|
||||
words = split64(z2)
|
||||
z2x = words + ["0"] * (4 - len(words))
|
||||
words = split64(x3)
|
||||
x3x = words + ["0"] * (4 - len(words))
|
||||
words = split64(z3)
|
||||
z3x = words + ["0"] * (4 - len(words))
|
||||
words = split64(xp)
|
||||
xpx = words + ["0"] * (4 - len(words))
|
||||
|
||||
# Output
|
||||
words = split64(x2_out)
|
||||
x2outx = words + ["0"] * (4 - len(words))
|
||||
words = split64(z2_out)
|
||||
z2outx = words + ["0"] * (4 - len(words))
|
||||
words = split64(x3_out)
|
||||
x3outx = words + ["0"] * (4 - len(words))
|
||||
words = split64(z3_out)
|
||||
z3outx = words + ["0"] * (4 - len(words))
|
||||
|
||||
print("")
|
||||
print("void test_%d() {" % next(counter))
|
||||
print(" const uint64_t x2_in[4] = {" + ", ".join(x2x) + "};")
|
||||
print(" const uint64_t z2_in[4] = {" + ", ".join(z2x) + "};")
|
||||
print(" const uint64_t x3_in[4] = {" + ", ".join(x3x) + "};")
|
||||
print(" const uint64_t z3_in[4] = {" + ", ".join(z3x) + "};")
|
||||
print(" const uint64_t xp_in[4] = {" + ", ".join(xpx) + "};")
|
||||
|
||||
print(" const uint64_t x2_out_ref[4] = {" + ", ".join(x2outx) + "};")
|
||||
print(" const uint64_t z2_out_ref[4] = {" + ", ".join(z2outx) + "};")
|
||||
print(" const uint64_t x3_out_ref[4] = {" + ", ".join(x3outx) + "};")
|
||||
print(" const uint64_t z3_out_ref[4] = {" + ", ".join(z3outx) + "};")
|
||||
|
||||
print(" uint32_t x2[10] = { 0 };")
|
||||
print(" uint32_t z2[10] = { 0 };")
|
||||
print(" uint32_t x3[10] = { 0 };")
|
||||
print(" uint32_t z3[10] = { 0 };")
|
||||
print(" uint32_t xp[10] = { 0 };")
|
||||
|
||||
print(" uint64_t x2_out[4] = { 0 };")
|
||||
print(" uint64_t z2_out[4] = { 0 };")
|
||||
print(" uint64_t x3_out[4] = { 0 };")
|
||||
print(" uint64_t z3_out[4] = { 0 };")
|
||||
|
||||
print("")
|
||||
|
||||
print(" convert_le64_to_le25p5(x2, x2_in);")
|
||||
print(" convert_le64_to_le25p5(z2, z2_in);")
|
||||
print(" convert_le64_to_le25p5(x3, x3_in);")
|
||||
print(" convert_le64_to_le25p5(z3, z3_in);")
|
||||
print(" convert_le64_to_le25p5(xp, xp_in);")
|
||||
|
||||
print(" ladder_step(x2, z2, x3, z3, xp);")
|
||||
|
||||
print(" convert_le25p5_to_le64(x2_out, x2);")
|
||||
print(" convert_le25p5_to_le64(z2_out, z2);")
|
||||
print(" convert_le25p5_to_le64(x3_out, x3);")
|
||||
print(" convert_le25p5_to_le64(z3_out, z3);")
|
||||
print(" reduce_25519_le64(x2_out);")
|
||||
print(" reduce_25519_le64(z2_out);")
|
||||
print(" reduce_25519_le64(x3_out);")
|
||||
print(" reduce_25519_le64(z3_out);")
|
||||
|
||||
print("")
|
||||
print(" assert(0 == memcmp(x2_out, x2_out_ref, sizeof x2_out));")
|
||||
print(" assert(0 == memcmp(z2_out, z2_out_ref, sizeof z2_out));")
|
||||
print(" assert(0 == memcmp(x3_out, x3_out_ref, sizeof x3_out));")
|
||||
print(" assert(0 == memcmp(z3_out, z3_out_ref, sizeof z3_out));")
|
||||
print("}")
|
||||
|
||||
|
||||
def make_limb(seed):
|
||||
result = bin2int(sha256(struct.pack(">I", seed)).digest()) & ((2**255)-1)
|
||||
return result
|
||||
|
||||
|
||||
print("#include <assert.h>")
|
||||
print("#include <string.h>")
|
||||
print("#include <stdint.h>")
|
||||
print("#include <stdio.h>")
|
||||
print("void convert_le25p5_to_le64(uint64_t out[4], const uint32_t in[10]);")
|
||||
print("void convert_le64_to_le25p5(uint32_t out[10], const uint64_t in[4]);")
|
||||
print("void reduce_25519_le64(uint64_t x[4]);")
|
||||
print("void ladder_step(uint32_t x2[10], uint32_t z2[10], uint32_t x3[10], uint32_t z3[10], const uint32_t xp[10]);")
|
||||
|
||||
make_test_max()
|
||||
make_test(0, 0, 0, 0, 0)
|
||||
make_test(1, 1, 1, 1, 1)
|
||||
make_test(6000, 10, 1000, 19999, 18888)
|
||||
|
||||
for x in range(50):
|
||||
x2 = make_limb(1000 + x)
|
||||
z2 = make_limb(2000 + x)
|
||||
x3 = make_limb(3000 + x)
|
||||
z3 = make_limb(4000 + x)
|
||||
xp = make_limb(5000 + x)
|
||||
make_test(x2, z2, x3, z3, xp)
|
||||
|
||||
make_main()
|
107
src/test/make_tests_mul_25519.py
Normal file
107
src/test/make_tests_mul_25519.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
"""Make unit test for mul_25519() in x25519.c"""
|
||||
|
||||
from common import counter, make_main, split64, bin2int
|
||||
from hashlib import sha256
|
||||
import struct
|
||||
|
||||
|
||||
def make_test(f, g):
|
||||
|
||||
assert(len(f) == 10)
|
||||
assert(len(g) == 10)
|
||||
for i in range(10):
|
||||
assert(f[i] < 2**27)
|
||||
assert(g[i] < 2**27)
|
||||
fx = ["0x%08X" % x for x in f]
|
||||
gx = ["0x%08X" % x for x in g]
|
||||
max26 = hex(2**26 - 1)
|
||||
max25 = hex(2**25 - 1)
|
||||
|
||||
modulus = 2**255 - 19
|
||||
base = [0, 26, 51, 77, 102, 128, 153, 179, 204, 230]
|
||||
fv = 0
|
||||
gv = 0
|
||||
for i in range(10):
|
||||
fv += f[i] * (2**(base[i]))
|
||||
gv += g[i] * (2**(base[i]))
|
||||
|
||||
canonical = (fv * gv) % modulus
|
||||
results = [canonical, canonical + modulus]
|
||||
if canonical < 38:
|
||||
results.append(canonical + modulus * 2)
|
||||
|
||||
# Turn results[] into arrays of 64-bit words
|
||||
results_hex = []
|
||||
for result in results:
|
||||
words = split64(result)
|
||||
words = words + ["0"] * (4 - len(words))
|
||||
results_hex.append(words)
|
||||
|
||||
print("")
|
||||
print("void test_%d() {" % next(counter))
|
||||
print(" const uint32_t f[10] = {" + ", ".join(fx) + "};")
|
||||
print(" const uint32_t g[10] = {" + ", ".join(gx) + "};")
|
||||
print(" uint32_t out[10];")
|
||||
print(" uint64_t out64[4];")
|
||||
print(" uint64_t exp[%d][4] = {" % len(results))
|
||||
print(" { " + ",".join(results_hex[0]) + " },")
|
||||
print(" { " + ",".join(results_hex[1]) + " }")
|
||||
if len(results_hex) == 3:
|
||||
print(" ,{ " + ",".join(results_hex[2]) + " }")
|
||||
print(" };")
|
||||
print(" unsigned match;")
|
||||
print("")
|
||||
print(" mul_25519(out, f, g);")
|
||||
print(" assert(out[0] <= " + max26 + ");")
|
||||
print(" assert(out[1] <= " + max25 + ");")
|
||||
print(" assert(out[2] <= " + max26 + ");")
|
||||
print(" assert(out[3] <= " + max25 + ");")
|
||||
print(" assert(out[4] <= " + max26 + ");")
|
||||
print(" assert(out[5] <= " + max25 + ");")
|
||||
print(" assert(out[6] <= " + max26 + ");")
|
||||
print(" assert(out[7] <= " + max25 + ");")
|
||||
print(" assert(out[8] <= " + max26 + ");")
|
||||
print(" assert(out[9] <= " + max26 + ");")
|
||||
print(" convert_le25p5_to_le64(out64, out);")
|
||||
print(" match = 0;")
|
||||
print(" match |= !memcmp(exp[0], out64, 32);")
|
||||
print(" match |= !memcmp(exp[1], out64, 32);")
|
||||
if len(results_hex) == 3:
|
||||
print(" match |= !memcmp(exp[2], out64, 32);")
|
||||
print(" assert(match);")
|
||||
print("}")
|
||||
|
||||
|
||||
def make_limb(seed):
|
||||
result = bin2int(sha256(struct.pack(">I", seed)).digest()) & ((2**27)-1)
|
||||
return result
|
||||
|
||||
|
||||
print("#include <assert.h>")
|
||||
print("#include <string.h>")
|
||||
print("#include <stdint.h>")
|
||||
print("#include <stdio.h>")
|
||||
print("void convert_le25p5_to_le64(uint64_t out[4], const uint32_t in[10]);")
|
||||
print("void mul_25519(uint32_t out[10], const uint32_t f[10], const uint32_t g[10]);")
|
||||
|
||||
modulus = [0x3ffffed, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff]
|
||||
modulus_m1 = [0x3ffffec, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff]
|
||||
modulus_m2 = [0x3ffffeb, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff]
|
||||
modulus_m40 = [0x3ffffc5, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff]
|
||||
|
||||
make_test([0]*10, [0]*10)
|
||||
make_test([1] + [0]*9, [1] + [0]*9)
|
||||
make_test([30] + [0]*9, [30] + [0]*9)
|
||||
make_test([0x7ffffed] + [0]*9, [0x7ffffed] + [0]*9)
|
||||
make_test(modulus, modulus)
|
||||
make_test(modulus_m1, modulus_m1)
|
||||
make_test(modulus_m2, modulus_m2)
|
||||
make_test(modulus, modulus_m2)
|
||||
make_test(modulus_m40, modulus_m40)
|
||||
|
||||
for x in range(100):
|
||||
f = [make_limb(1000*x + y) for y in range(10)]
|
||||
g = [make_limb(2000*x + y) for y in range(10)]
|
||||
make_test(f, g)
|
||||
|
||||
make_main()
|
|
@ -572,11 +572,11 @@ void test_ec_ws_new_point(void)
|
|||
res = ec_ws_new_point(&ecp, Gx, Gy, 32, ec_ctx);
|
||||
assert(res == 0);
|
||||
|
||||
ec_free_point(ecp);
|
||||
ec_ws_free_point(ecp);
|
||||
res = ec_ws_new_point(&ecp, zero, zero, 32, ec_ctx);
|
||||
assert(res == 0);
|
||||
|
||||
ec_free_point(ecp);
|
||||
ec_ws_free_point(ecp);
|
||||
ec_free_context(ec_ctx);
|
||||
}
|
||||
|
||||
|
@ -614,7 +614,7 @@ void test_ec_ws_get_xy(void)
|
|||
assert(0 == memcmp(bufx, Gx, 32));
|
||||
assert(0 == memcmp(bufy, Gy, 32));
|
||||
|
||||
ec_free_point(ecp);
|
||||
ec_ws_free_point(ecp);
|
||||
ec_free_context(ec_ctx);
|
||||
}
|
||||
|
||||
|
@ -642,7 +642,7 @@ void test_ec_ws_double_p256(void)
|
|||
assert(0 == memcmp(bufx, "\x7c\xf2\x7b\x18\x8d\x03\x4f\x7e\x8a\x52\x38\x03\x04\xb5\x1a\xc3\xc0\x89\x69\xe2\x77\xf2\x1b\x35\xa6\x0b\x48\xfc\x47\x66\x99\x78", 32));
|
||||
assert(0 == memcmp(bufy, "\x07\x77\x55\x10\xdb\x8e\xd0\x40\x29\x3d\x9a\xc6\x9f\x74\x30\xdb\xba\x7d\xad\xe6\x3c\xe9\x82\x29\x9e\x04\xb7\x9d\x22\x78\x73\xd1", 32));
|
||||
|
||||
ec_free_point(ecp);
|
||||
ec_ws_free_point(ecp);
|
||||
ec_free_context(ec_ctx);
|
||||
}
|
||||
|
||||
|
@ -670,7 +670,7 @@ void test_ec_ws_double_p521(void)
|
|||
assert(0 == memcmp(bufx, "\x01\x28\x79\x44\x2F\x24\x50\xC1\x19\xE7\x11\x9A\x5F\x73\x8B\xE1\xF1\xEB\xA9\xE9\xD7\xC6\xCF\x41\xB3\x25\xD9\xCE\x6D\x64\x31\x06\xE9\xD6\x11\x24\xA9\x1A\x96\xBC\xF2\x01\x30\x5A\x9D\xEE\x55\xFA\x79\x13\x6D\xC7\x00\x83\x1E\x54\xC3\xCA\x4F\xF2\x64\x6B\xD3\xC3\x6B\xC6", 66));
|
||||
assert(0 == memcmp(bufy, "\x01\x98\x64\xA8\xB8\x85\x5C\x24\x79\xCB\xEF\xE3\x75\xAE\x55\x3E\x23\x93\x27\x1E\xD3\x6F\xAD\xFC\x44\x94\xFC\x05\x83\xF6\xBD\x03\x59\x88\x96\xF3\x98\x54\xAB\xEA\xE5\xF9\xA6\x51\x5A\x02\x1E\x2C\x0E\xEF\x13\x9E\x71\xDE\x61\x01\x43\xF5\x33\x82\xF4\x10\x4D\xCC\xB5\x43", 66));
|
||||
|
||||
ec_free_point(ecp);
|
||||
ec_ws_free_point(ecp);
|
||||
ec_free_context(ec_ctx);
|
||||
}
|
||||
|
||||
|
@ -702,8 +702,8 @@ void test_ec_ws_add(void)
|
|||
assert(0 == memcmp(bufx, "\x5e\xcb\xe4\xd1\xa6\x33\x0a\x44\xc8\xf7\xef\x95\x1d\x4b\xf1\x65\xe6\xc6\xb7\x21\xef\xad\xa9\x85\xfb\x41\x66\x1b\xc6\xe7\xfd\x6c", 32));
|
||||
assert(0 == memcmp(bufy, "\x87\x34\x64\x0c\x49\x98\xff\x7e\x37\x4b\x06\xce\x1a\x64\xa2\xec\xd8\x2a\xb0\x36\x38\x4f\xb8\x3d\x9a\x79\xb1\x27\xa2\x7d\x50\x32", 32));
|
||||
|
||||
ec_free_point(ecp);
|
||||
ec_free_point(ecp2);
|
||||
ec_ws_free_point(ecp);
|
||||
ec_ws_free_point(ecp2);
|
||||
ec_free_context(ec_ctx);
|
||||
}
|
||||
|
||||
|
@ -733,7 +733,7 @@ void test_ec_ws_scalar(void)
|
|||
assert(0 == memcmp(bufx, "\xf2\x49\x10\x4d\x0e\x6f\x8f\x29\xe6\x01\x62\x77\x78\x0c\xda\x84\xdc\x84\xb8\x3b\xc3\xd8\x99\xdf\xb7\x36\xca\x08\x31\xfb\xe8\xcf", 32));
|
||||
assert(0 == memcmp(bufy, "\xb5\x7e\x12\xfc\xdb\x03\x1f\x59\xca\xb8\x1b\x1c\x6b\x1e\x1c\x07\xe4\x51\x2e\x52\xce\x83\x2f\x1a\x0c\xed\xef\xff\x8b\x43\x40\xe9", 32));
|
||||
|
||||
ec_free_point(ecp);
|
||||
ec_ws_free_point(ecp);
|
||||
ec_free_context(ec_ctx);
|
||||
}
|
||||
|
||||
|
@ -761,7 +761,7 @@ void test_ec_ws_neg(void)
|
|||
assert(0 == memcmp(bufx, "\x6b\x17\xd1\xf2\xe1\x2c\x42\x47\xf8\xbc\xe6\xe5\x63\xa4\x40\xf2\x77\x03\x7d\x81\x2d\xeb\x33\xa0\xf4\xa1\x39\x45\xd8\x98\xc2\x96", 32));
|
||||
assert(0 == memcmp(bufy, "\xb0\x1c\xbd\x1c\x01\xe5\x80\x65\x71\x18\x14\xb5\x83\xf0\x61\xe9\xd4\x31\xcc\xa9\x94\xce\xa1\x31\x34\x49\xbf\x97\xc8\x40\xae\x0a", 32));
|
||||
|
||||
ec_free_point(ecp);
|
||||
ec_ws_free_point(ecp);
|
||||
ec_free_context(ec_ctx);
|
||||
}
|
||||
|
||||
|
|
169
src/test/test_ed25519.c
Normal file
169
src/test/test_ed25519.c
Normal file
|
@ -0,0 +1,169 @@
|
|||
#include "endianess.h"
|
||||
#include <assert.h>
|
||||
|
||||
typedef struct Point {
|
||||
uint32_t X[10];
|
||||
uint32_t Y[10];
|
||||
uint32_t Z[10];
|
||||
uint32_t T[10];
|
||||
} Point;
|
||||
|
||||
void ed25519_add_internal(Point *P3, const Point *P1, const Point *P2);
|
||||
void ed25519_double_internal(Point *P3, const Point *P1);
|
||||
void mul_25519(uint32_t out[10], const uint32_t f[10], const uint32_t g[10]);
|
||||
void invert_25519(uint32_t out[10], const uint32_t x[10]);
|
||||
int convert_behex_to_le25p5(uint32_t out[10], const char *in);
|
||||
int convert_le25p5_to_behex(char **out, uint32_t in[10]);
|
||||
void convert_le25p5_to_le8(uint8_t out[32], const uint32_t in[10]);
|
||||
void convert_le8_to_le25p5(uint32_t out[10], const uint8_t in[32]);
|
||||
void ed25519_scalar_internal(Point *Pout,
|
||||
const uint8_t *k, size_t len,
|
||||
const Point *Pin);
|
||||
|
||||
void test_point_add(void)
|
||||
{
|
||||
char Gx_hex[] = "216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a";
|
||||
char Gy_hex[] = "6666666666666666666666666666666666666666666666666666666666666658";
|
||||
char G2x_hex[] = "36ab384c9f5a046c3d043b7d1833e7ac080d8e4515d7a45f83c5a14e2843ce0e";
|
||||
char G2y_hex[] = "2260cdf3092329c21da25ee8c9a21f5697390f51643851560e5f46ae6af8a3c9";
|
||||
|
||||
Point G, G2;
|
||||
uint32_t invz[10];
|
||||
char *c;
|
||||
|
||||
memset(&G, 0, sizeof G);
|
||||
|
||||
convert_behex_to_le25p5(G.X, Gx_hex);
|
||||
convert_behex_to_le25p5(G.Y, Gy_hex);
|
||||
G.Z[0] = 1;
|
||||
mul_25519(G.T, G.X, G.Y);
|
||||
|
||||
ed25519_add_internal(&G2, &G, &G);
|
||||
invert_25519(invz, G2.Z);
|
||||
|
||||
/* Check X */
|
||||
mul_25519(G2.X, G2.X, invz);
|
||||
convert_le25p5_to_behex(&c, G2.X);
|
||||
assert(0 == strcmp(c, G2x_hex));
|
||||
free(c);
|
||||
|
||||
/* Check Y */
|
||||
mul_25519(G2.Y, G2.Y, invz);
|
||||
convert_le25p5_to_behex(&c, G2.Y);
|
||||
assert(0 == strcmp(c, G2y_hex));
|
||||
free(c);
|
||||
}
|
||||
|
||||
void test_point_double(void)
|
||||
{
|
||||
char Gx_hex[] = "216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a";
|
||||
char Gy_hex[] = "6666666666666666666666666666666666666666666666666666666666666658";
|
||||
char G2x_hex[] = "36ab384c9f5a046c3d043b7d1833e7ac080d8e4515d7a45f83c5a14e2843ce0e";
|
||||
char G2y_hex[] = "2260cdf3092329c21da25ee8c9a21f5697390f51643851560e5f46ae6af8a3c9";
|
||||
|
||||
Point G, G2;
|
||||
uint32_t invz[10];
|
||||
char *c;
|
||||
|
||||
memset(&G, 0, sizeof G);
|
||||
|
||||
convert_behex_to_le25p5(G.X, Gx_hex);
|
||||
convert_behex_to_le25p5(G.Y, Gy_hex);
|
||||
G.Z[0] = 1;
|
||||
mul_25519(G.T, G.X, G.Y);
|
||||
|
||||
ed25519_double_internal(&G2, &G);
|
||||
invert_25519(invz, G2.Z);
|
||||
|
||||
/* Check X */
|
||||
mul_25519(G2.X, G2.X, invz);
|
||||
convert_le25p5_to_behex(&c, G2.X);
|
||||
assert(0 == strcmp(c, G2x_hex));
|
||||
free(c);
|
||||
|
||||
/* Check Y */
|
||||
mul_25519(G2.Y, G2.Y, invz);
|
||||
convert_le25p5_to_behex(&c, G2.Y);
|
||||
assert(0 == strcmp(c, G2y_hex));
|
||||
free(c);
|
||||
}
|
||||
|
||||
void from_affine(Point *P, const uint8_t x[32], const uint8_t y[32])
|
||||
{
|
||||
memset(P, 0, sizeof *P);
|
||||
convert_le8_to_le25p5(P->X, x);
|
||||
convert_le8_to_le25p5(P->Y, y);
|
||||
P->Z[0] = 1;
|
||||
mul_25519(P->T, P->X, P->Y);
|
||||
}
|
||||
|
||||
void to_affine(uint8_t x[32], uint8_t y[32], const Point *P)
|
||||
{
|
||||
uint32_t invz[10];
|
||||
uint32_t tmp[10];
|
||||
|
||||
invert_25519(invz, P->Z);
|
||||
mul_25519(tmp, P->X, invz);
|
||||
convert_le25p5_to_le8(x, tmp);
|
||||
mul_25519(tmp, P->Y, invz);
|
||||
convert_le25p5_to_le8(y, tmp);
|
||||
}
|
||||
|
||||
void test_scalar_mult(void)
|
||||
{
|
||||
uint8_t xout[32], yout[32];
|
||||
|
||||
uint8_t G0x[32] = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||
uint8_t G0y[32] = "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||
uint8_t Gx[32] = "\x1a\xd5\x25\x8f\x60\x2d\x56\xc9\xb2\xa7\x25\x95\x60\xc7\x2c\x69\x5c\xdc\xd6\xfd\x31\xe2\xa4\xc0\xfe\x53\x6e\xcd\xd3\x36\x69\x21";
|
||||
uint8_t Gy[32] = "\x58\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66";
|
||||
uint8_t G2x[32] = "\x0e\xce\x43\x28\x4e\xa1\xc5\x83\x5f\xa4\xd7\x15\x45\x8e\x0d\x08\xac\xe7\x33\x18\x7d\x3b\x04\x3d\x6c\x04\x5a\x9f\x4c\x38\xab\x36";
|
||||
uint8_t G2y[32] = "\xc9\xa3\xf8\x6a\xae\x46\x5f\x0e\x56\x51\x38\x64\x51\x0f\x39\x97\x56\x1f\xa2\xc9\xe8\x5e\xa2\x1d\xc2\x29\x23\x09\xf3\xcd\x60\x22";
|
||||
uint8_t G5y[32] = "\xED\xC8\x76\xD6\x83\x1F\xD2\x10\x5D\x0B\x43\x89\xCA\x2E\x28\x31\x66\x46\x92\x89\x14\x6E\x2C\xE0\x6F\xAE\xFE\x98\xB2\x25\x48\x5F";
|
||||
uint8_t Gry[32] = "\xC9\x72\x8D\x51\x1D\xF5\xB3\x05\x12\xD4\x81\xCC\x41\xDE\x72\x0E\x73\x90\xF1\x53\xFE\xF6\xF0\x59\xDC\xF4\xB8\xAF\xEE\x92\x77\x16";
|
||||
|
||||
Point P, Q;
|
||||
|
||||
/* 0 */
|
||||
from_affine(&P, Gx, Gy);
|
||||
ed25519_scalar_internal(&Q, (uint8_t*)"\x00", 1, &P);
|
||||
to_affine(xout, yout, &Q);
|
||||
assert(0 == memcmp(G0x, xout, sizeof G0x));
|
||||
assert(0 == memcmp(G0y, yout, sizeof G0y));
|
||||
|
||||
/* 1 */
|
||||
from_affine(&P, Gx, Gy);
|
||||
ed25519_scalar_internal(&Q, (uint8_t*)"\x01", 1, &P);
|
||||
to_affine(xout, yout, &Q);
|
||||
assert(0 == memcmp(Gx, xout, sizeof Gx));
|
||||
assert(0 == memcmp(Gy, yout, sizeof Gy));
|
||||
|
||||
/* 2 */
|
||||
from_affine(&P, Gx, Gy);
|
||||
ed25519_scalar_internal(&Q, (uint8_t*)"\x02", 1, &P);
|
||||
to_affine(xout, yout, &Q);
|
||||
assert(0 == memcmp(G2x, xout, sizeof G2x));
|
||||
assert(0 == memcmp(G2y, yout, sizeof G2y));
|
||||
|
||||
/* 5 */
|
||||
from_affine(&P, Gx, Gy);
|
||||
ed25519_scalar_internal(&Q, (uint8_t*)"\x05", 1, &P);
|
||||
to_affine(xout, yout, &Q);
|
||||
assert(0 == memcmp(G5y, yout, sizeof G5y));
|
||||
|
||||
/* random */
|
||||
uint8_t r[32] = "\x08\x68\xba\x7a\x34\x73\x4f\x3e\x93\xdd\x24\x26\x32\x7f\x0f\x34\x14\x5c\xd9\x43\x02\xe4\xd5\xdd\x95\x00\xee\x1b\x57\x11\x39\xdd";
|
||||
|
||||
from_affine(&P, Gx, Gy);
|
||||
ed25519_scalar_internal(&Q, r, 32, &P);
|
||||
to_affine(xout, yout, &Q);
|
||||
assert(0 == memcmp(Gry, yout, sizeof Gry));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_point_add();
|
||||
test_point_double();
|
||||
test_scalar_mult();
|
||||
return 0;
|
||||
}
|
374
src/test/test_mod25519.c
Normal file
374
src/test/test_mod25519.c
Normal file
|
@ -0,0 +1,374 @@
|
|||
#include "endianess.h"
|
||||
#include <assert.h>
|
||||
|
||||
/** Test for multiplication are in a separate unit **/
|
||||
|
||||
void convert_le64_to_le25p5(uint32_t out[9], const uint64_t in[4]);
|
||||
void convert_le25p5_to_le64(uint64_t out[4], const uint32_t in[9]);
|
||||
int convert_behex_to_le25p5(uint32_t out[10], const char *in);
|
||||
int convert_le25p5_to_behex(char **out, uint32_t in[10]);
|
||||
void reduce_25519_le64(uint64_t x[4]);
|
||||
void cswap(uint32_t a[10], uint32_t b[10], uint32_t c[10], uint32_t d[10], unsigned cond);
|
||||
void invert_25519(uint32_t out[10], const uint32_t x[10]);
|
||||
void add_25519(uint32_t out[10], const uint32_t f[10], const uint32_t g[10]);
|
||||
|
||||
static const uint64_t modulus[4] = { 0xffffffffffffffedULL, 0xffffffffffffffffULL, 0xffffffffffffffffULL, 0x7fffffffffffffffULL };
|
||||
static const uint64_t modulus2[4] = { 0xffffffffffffffdaULL, 0xffffffffffffffffULL, 0xffffffffffffffffULL, 0xffffffffffffffffULL };
|
||||
static const uint64_t hundhund[4] = { 0xe08063f1e8753fb4ULL, 0x29e492f797f6605cULL, 0x1f6de7b30d1327efULL, 0x534a930de945ebf3ULL };
|
||||
|
||||
static const uint32_t modulus_32[10] = { 0x3ffffed, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff };
|
||||
static const uint32_t hundhund_32[10] = { 0x753fb4, 0x18fc7a, 0xb9c10, 0x1bcbfb3, 0xa7924b, 0x11327ef, 0x2f3d986, 0x17e63ed, 0xde945e, 0x14d2a4c };
|
||||
|
||||
void test_le64_tole25p5(void)
|
||||
{
|
||||
uint32_t out[10];
|
||||
uint64_t in[4];
|
||||
|
||||
memset(out, 0xAA, sizeof out);
|
||||
memcpy(in, modulus, sizeof modulus);
|
||||
convert_le64_to_le25p5(out, in);
|
||||
|
||||
assert(out[0] == 0x3ffffed);
|
||||
assert(out[1] == 0x1ffffff);
|
||||
assert(out[2] == 0x3ffffff);
|
||||
assert(out[3] == 0x1ffffff);
|
||||
assert(out[4] == 0x3ffffff);
|
||||
assert(out[5] == 0x1ffffff);
|
||||
assert(out[6] == 0x3ffffff);
|
||||
assert(out[7] == 0x1ffffff);
|
||||
assert(out[8] == 0x3ffffff);
|
||||
assert(out[9] == 0x1ffffff);
|
||||
|
||||
memset(out, 0xAA, sizeof out);
|
||||
memcpy(in, hundhund, sizeof hundhund);
|
||||
convert_le64_to_le25p5(out, in);
|
||||
|
||||
assert(out[0] == 0x753fb4);
|
||||
assert(out[1] == 0x18fc7a);
|
||||
assert(out[2] == 0xb9c10);
|
||||
assert(out[3] == 0x1bcbfb3);
|
||||
assert(out[4] == 0xa7924b);
|
||||
assert(out[5] == 0x11327ef);
|
||||
assert(out[6] == 0x2f3d986);
|
||||
assert(out[7] == 0x17e63ed);
|
||||
assert(out[8] == 0xde945e);
|
||||
assert(out[9] == 0x14d2a4c);
|
||||
|
||||
in[0] = 0xAAAAAAAAAAAAAAAA;
|
||||
in[1] = 0xBBBBBBBBBBBBBBBB;
|
||||
in[2] = 0xCCCCCCCCCCCCCCCC;
|
||||
in[3] = 0xDDDDDDDDDDDDDDDD;
|
||||
convert_le64_to_le25p5(out, in);
|
||||
assert(out[0] == 0x2aaaaaa);
|
||||
assert(out[1] == 0xaaaaaa);
|
||||
assert(out[2] == 0x3777555);
|
||||
assert(out[3] == 0x1dddddd);
|
||||
assert(out[4] == 0x2eeeeee);
|
||||
assert(out[5] == 0xcccccc);
|
||||
assert(out[6] == 0x2666666);
|
||||
assert(out[7] == 0x1bbb999);
|
||||
assert(out[8] == 0x1dddddd);
|
||||
assert(out[9] == 0x3777777);
|
||||
}
|
||||
|
||||
void test_le25p5_to_le64(void)
|
||||
{
|
||||
uint64_t out[4];
|
||||
|
||||
memset(out, 0xAA, sizeof out);
|
||||
convert_le25p5_to_le64(out, modulus_32);
|
||||
|
||||
assert(out[0] == modulus[0]);
|
||||
assert(out[1] == modulus[1]);
|
||||
assert(out[2] == modulus[2]);
|
||||
assert(out[3] == modulus[3]);
|
||||
|
||||
memset(out, 0xAA, sizeof out);
|
||||
convert_le25p5_to_le64(out, hundhund_32);
|
||||
|
||||
assert(out[0] == hundhund[0]);
|
||||
assert(out[1] == hundhund[1]);
|
||||
assert(out[2] == hundhund[2]);
|
||||
}
|
||||
|
||||
void test_behex_tole25p5(void)
|
||||
{
|
||||
uint32_t out[10];
|
||||
char in1[] = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed";
|
||||
char in2[] = "534a930de945ebf31f6de7b30d1327ef29e492f797f6605ce08063f1e8753fb4";
|
||||
char in3[] = "DDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA";
|
||||
char in4[] = "AA";
|
||||
int ret;
|
||||
|
||||
memset(out, 0xAA, sizeof out);
|
||||
ret = convert_behex_to_le25p5(out, in1);
|
||||
assert(ret == 0);
|
||||
|
||||
assert(out[0] == 0x3ffffed);
|
||||
assert(out[1] == 0x1ffffff);
|
||||
assert(out[2] == 0x3ffffff);
|
||||
assert(out[3] == 0x1ffffff);
|
||||
assert(out[4] == 0x3ffffff);
|
||||
assert(out[5] == 0x1ffffff);
|
||||
assert(out[6] == 0x3ffffff);
|
||||
assert(out[7] == 0x1ffffff);
|
||||
assert(out[8] == 0x3ffffff);
|
||||
assert(out[9] == 0x1ffffff);
|
||||
|
||||
memset(out, 0xAA, sizeof out);
|
||||
ret = convert_behex_to_le25p5(out, in2);
|
||||
assert(ret == 0);
|
||||
|
||||
assert(out[0] == 0x753fb4);
|
||||
assert(out[1] == 0x18fc7a);
|
||||
assert(out[2] == 0xb9c10);
|
||||
assert(out[3] == 0x1bcbfb3);
|
||||
assert(out[4] == 0xa7924b);
|
||||
assert(out[5] == 0x11327ef);
|
||||
assert(out[6] == 0x2f3d986);
|
||||
assert(out[7] == 0x17e63ed);
|
||||
assert(out[8] == 0xde945e);
|
||||
assert(out[9] == 0x14d2a4c);
|
||||
|
||||
memset(out, 0xAA, sizeof out);
|
||||
ret = convert_behex_to_le25p5(out, in3);
|
||||
assert(ret == 0);
|
||||
|
||||
assert(out[0] == 0x2aaaaaa);
|
||||
assert(out[1] == 0xaaaaaa);
|
||||
assert(out[2] == 0x3777555);
|
||||
assert(out[3] == 0x1dddddd);
|
||||
assert(out[4] == 0x2eeeeee);
|
||||
assert(out[5] == 0xcccccc);
|
||||
assert(out[6] == 0x2666666);
|
||||
assert(out[7] == 0x1bbb999);
|
||||
assert(out[8] == 0x1dddddd);
|
||||
assert(out[9] == 0x3777777);
|
||||
|
||||
memset(out, 0xAA, sizeof out);
|
||||
ret = convert_behex_to_le25p5(out, in4);
|
||||
assert(ret == 0);
|
||||
|
||||
assert(out[0] == 0xaa);
|
||||
assert(out[1] == 0);
|
||||
assert(out[2] == 0);
|
||||
assert(out[3] == 0);
|
||||
assert(out[4] == 0);
|
||||
assert(out[5] == 0);
|
||||
assert(out[6] == 0);
|
||||
assert(out[7] == 0);
|
||||
assert(out[8] == 0);
|
||||
|
||||
/* Negative test cases */
|
||||
ret = convert_behex_to_le25p5(out, "A");
|
||||
assert(ret != 0);
|
||||
ret = convert_behex_to_le25p5(out, NULL);
|
||||
assert(ret != 0);
|
||||
ret = convert_behex_to_le25p5(out, "te");
|
||||
assert(ret != 0);
|
||||
}
|
||||
|
||||
void test_tole25p5_to_behex(void)
|
||||
{
|
||||
char *out;
|
||||
uint32_t in[10];
|
||||
int res;
|
||||
|
||||
in[0] = 0x3ffffed;
|
||||
in[1] = 0x1ffffff;
|
||||
in[2] = 0x3ffffff;
|
||||
in[3] = 0x1ffffff;
|
||||
in[4] = 0x3ffffff;
|
||||
in[5] = 0x1ffffff;
|
||||
in[6] = 0x3ffffff;
|
||||
in[7] = 0x1ffffff;
|
||||
in[8] = 0x3ffffff;
|
||||
in[9] = 0x1ffffff;
|
||||
|
||||
convert_le25p5_to_behex(&out, in);
|
||||
res = strcmp(out, "0000000000000000000000000000000000000000000000000000000000000000");
|
||||
assert(res == 0);
|
||||
}
|
||||
|
||||
void test_reduce(void)
|
||||
{
|
||||
uint64_t x[4];
|
||||
|
||||
/** 0 **/
|
||||
|
||||
x[0] = x[1] = x[2] = x[3] = 0;
|
||||
reduce_25519_le64(x);
|
||||
assert(x[0] == 0);
|
||||
assert(x[1] == 0);
|
||||
assert(x[2] == 0);
|
||||
assert(x[3] == 0);
|
||||
|
||||
memcpy(x, modulus, sizeof x);
|
||||
reduce_25519_le64(x);
|
||||
assert(x[0] == 0);
|
||||
assert(x[1] == 0);
|
||||
assert(x[2] == 0);
|
||||
assert(x[3] == 0);
|
||||
|
||||
memcpy(x, modulus2, sizeof x);
|
||||
reduce_25519_le64(x);
|
||||
assert(x[0] == 0);
|
||||
assert(x[1] == 0);
|
||||
assert(x[2] == 0);
|
||||
assert(x[3] == 0);
|
||||
|
||||
/** 1 **/
|
||||
|
||||
x[0] = 1;
|
||||
x[1] = x[2] = x[3] = 0;
|
||||
reduce_25519_le64(x);
|
||||
assert(x[0] == 1);
|
||||
assert(x[1] == 0);
|
||||
assert(x[2] == 0);
|
||||
assert(x[3] == 0);
|
||||
|
||||
memcpy(x, modulus, sizeof x);
|
||||
x[0]++;
|
||||
reduce_25519_le64(x);
|
||||
assert(x[0] == 1);
|
||||
assert(x[1] == 0);
|
||||
assert(x[2] == 0);
|
||||
assert(x[3] == 0);
|
||||
|
||||
memcpy(x, modulus2, sizeof x);
|
||||
x[0]++;
|
||||
reduce_25519_le64(x);
|
||||
assert(x[0] == 1);
|
||||
assert(x[1] == 0);
|
||||
assert(x[2] == 0);
|
||||
assert(x[3] == 0);
|
||||
|
||||
/** 38 **/
|
||||
|
||||
x[0] = 38;
|
||||
x[1] = x[2] = x[3] = 0;
|
||||
reduce_25519_le64(x);
|
||||
assert(x[0] == 38);
|
||||
assert(x[1] == 0);
|
||||
assert(x[2] == 0);
|
||||
assert(x[3] == 0);
|
||||
|
||||
x[0] = 0x13;
|
||||
x[1] = x[2] = 0;
|
||||
x[3] = 0x8000000000000000ULL;
|
||||
reduce_25519_le64(x);
|
||||
assert(x[0] == 38);
|
||||
assert(x[1] == 0);
|
||||
assert(x[2] == 0);
|
||||
assert(x[3] == 0);
|
||||
}
|
||||
|
||||
int check(uint32_t x[10], uint32_t s)
|
||||
{
|
||||
unsigned i;
|
||||
for (i=0; i<10; i++)
|
||||
if (x[i] != s) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void test_cswap(void)
|
||||
{
|
||||
uint32_t a[10];
|
||||
uint32_t b[10];
|
||||
uint32_t c[10];
|
||||
uint32_t d[10];
|
||||
|
||||
memset(a, 0xAA, sizeof a);
|
||||
memset(b, 0x55, sizeof b);
|
||||
memset(c, 0x77, sizeof c);
|
||||
memset(d, 0x11, sizeof d);
|
||||
cswap(a, b, c, d, 0);
|
||||
|
||||
assert(check(a, 0xAAAAAAAA));
|
||||
assert(check(b, 0x55555555));
|
||||
assert(check(c, 0x77777777));
|
||||
assert(check(d, 0x11111111));
|
||||
|
||||
cswap(a, b, c, d, 1);
|
||||
assert(check(a, 0x77777777));
|
||||
assert(check(b, 0x11111111));
|
||||
assert(check(c, 0xAAAAAAAA));
|
||||
assert(check(d, 0x55555555));
|
||||
}
|
||||
|
||||
void test_invert(void)
|
||||
{
|
||||
uint64_t in[4];
|
||||
uint32_t x[10];
|
||||
uint64_t out[4];
|
||||
|
||||
in[0] = 1;
|
||||
in[1] = in[2] = in[3] = 0;
|
||||
convert_le64_to_le25p5(x, in);
|
||||
invert_25519(x, x);
|
||||
convert_le25p5_to_le64(out, x);
|
||||
reduce_25519_le64(out);
|
||||
assert(out[0] == 1);
|
||||
assert(out[1] == 0);
|
||||
assert(out[2] == 0);
|
||||
assert(out[3] == 0);
|
||||
|
||||
in[0] = 2;
|
||||
in[1] = in[2] = in[3] = 0;
|
||||
convert_le64_to_le25p5(x, in);
|
||||
invert_25519(x, x);
|
||||
convert_le25p5_to_le64(out, x);
|
||||
reduce_25519_le64(out);
|
||||
assert(out[0] == 0xfffffffffffffff7);
|
||||
assert(out[1] == 0xffffffffffffffff);
|
||||
assert(out[2] == 0xffffffffffffffff);
|
||||
assert(out[3] == 0x3fffffffffffffff);
|
||||
|
||||
in[0] = 0xAAAAAAAAAAAAAAAA;
|
||||
in[1] = 0xBBBBBBBBBBBBBBBB;
|
||||
in[2] = 0xCCCCCCCCCCCCCCCC;
|
||||
in[3] = 0xDDDDDDDDDDDDDDDD;
|
||||
convert_le64_to_le25p5(x, in);
|
||||
invert_25519(x, x);
|
||||
convert_le25p5_to_le64(out, x);
|
||||
reduce_25519_le64(out);
|
||||
assert(out[0] == 0x6cf8847ba332c4c7);
|
||||
assert(out[1] == 0x984028b39c0b5e92);
|
||||
assert(out[2] == 0x2404af2276fdd005);
|
||||
assert(out[3] == 0x22336ebc77628108);
|
||||
}
|
||||
|
||||
void test_add(void)
|
||||
{
|
||||
uint64_t in[4];
|
||||
uint32_t x[10];
|
||||
uint64_t out[4];
|
||||
|
||||
in[0] = 0xFFFFFFFFFFFFFFFF;
|
||||
in[1] = 0xFFFFFFFFFFFFFFFF;
|
||||
in[2] = 0xFFFFFFFFFFFFFFFF;
|
||||
in[3] = 0xFFFFFFFFFFFFFFFF;
|
||||
convert_le64_to_le25p5(x, in);
|
||||
/* x[8] and x[9] have 26 bits set */
|
||||
add_25519(x, x, x);
|
||||
convert_le25p5_to_le64(out, x);
|
||||
assert(out[0] == 0x0000000000000037);
|
||||
assert(out[1] == 0x0000000000000000);
|
||||
assert(out[2] == 0x0000000000000000);
|
||||
assert(out[3] == 0x8000000000000000);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_le64_tole25p5();
|
||||
test_le25p5_to_le64();
|
||||
test_behex_tole25p5();
|
||||
test_tole25p5_to_behex();
|
||||
test_reduce();
|
||||
test_cswap();
|
||||
test_invert();
|
||||
test_add();
|
||||
return 0;
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
int ge(const uint64_t *x, const uint64_t *y, size_t nw);
|
||||
unsigned sub(uint64_t *out, const uint64_t *a, const uint64_t *b, size_t nw);
|
||||
void rsquare(uint64_t *r2, uint64_t *n, size_t nw);
|
||||
int mont_select(uint64_t *out, const uint64_t *a, const uint64_t *b, unsigned cond, size_t words);
|
||||
int mod_select(uint64_t *out, const uint64_t *a, const uint64_t *b, unsigned cond, unsigned words);
|
||||
|
||||
void test_ge(void)
|
||||
{
|
||||
|
@ -371,7 +371,7 @@ void test_mont_set(void)
|
|||
mont_context_free(ctx);
|
||||
}
|
||||
|
||||
void test_mont_select()
|
||||
void test_mod_select()
|
||||
{
|
||||
int res;
|
||||
MontContext *ctx;
|
||||
|
@ -387,17 +387,17 @@ void test_mont_select()
|
|||
mont_context_init(&ctx, modulusA, 16);
|
||||
|
||||
memset(c, 0, sizeof c);
|
||||
res = mont_select(c, a, b, 1, ctx->words);
|
||||
res = mod_select(c, a, b, 1, ctx->words);
|
||||
assert(res == 0);
|
||||
assert(memcmp(a, c, sizeof c) == 0);
|
||||
|
||||
memset(c, 0, sizeof c);
|
||||
res = mont_select(c, a, b, 10, ctx->words);
|
||||
res = mod_select(c, a, b, 10, ctx->words);
|
||||
assert(res == 0);
|
||||
assert(memcmp(a, c, sizeof c) == 0);
|
||||
|
||||
memset(c, 0, sizeof c);
|
||||
res = mont_select(c, a, b, 0, ctx->words);
|
||||
res = mod_select(c, a, b, 0, ctx->words);
|
||||
assert(res == 0);
|
||||
assert(memcmp(b, c, sizeof c) == 0);
|
||||
|
||||
|
@ -408,12 +408,12 @@ void test_mont_select()
|
|||
mont_context_init(&ctx, modulusB, 17);
|
||||
|
||||
memset(f, 0, sizeof f);
|
||||
res = mont_select(f, d, e, 1, ctx->words);
|
||||
res = mod_select(f, d, e, 1, ctx->words);
|
||||
assert(res == 0);
|
||||
assert(memcmp(d, f, sizeof f) == 0);
|
||||
|
||||
memset(f, 0, sizeof f);
|
||||
res = mont_select(f, d, e, 0, ctx->words);
|
||||
res = mod_select(f, d, e, 0, ctx->words);
|
||||
assert(res == 0);
|
||||
assert(memcmp(e, f, sizeof f) == 0);
|
||||
}
|
||||
|
@ -429,6 +429,6 @@ int main(void) {
|
|||
test_mont_sub();
|
||||
test_mont_inv_prime();
|
||||
test_mont_set();
|
||||
test_mont_select();
|
||||
test_mod_select();
|
||||
return 0;
|
||||
}
|
||||
|
|
24
src/test/test_x25519.c
Normal file
24
src/test/test_x25519.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include "endianess.h"
|
||||
#include <assert.h>
|
||||
|
||||
void ladder(uint8_t shared_secret[32], const uint8_t *k, size_t len, const uint8_t pubkey[32]);
|
||||
|
||||
void test_ladder(void)
|
||||
{
|
||||
uint8_t scalar[32] = "\xa5\x46\xe3\x6b\xf0\x52\x7c\x9d\x3b\x16\x15\x4b\x82\x46\x5e\xdd\x62\x14\x4c\x0a\xc1\xfc\x5a\x18\x50\x6a\x22\x44\xba\x44\x9a\xc4";
|
||||
uint8_t pubkey[32] = "\xe6\xdb\x68\x67\x58\x30\x30\xdb\x35\x94\xc1\xa4\x24\xb1\x5f\x7c\x72\x66\x24\xec\x26\xb3\x35\x3b\x10\xa9\x03\xa6\xd0\xab\x1c\x4c";
|
||||
uint8_t expout[32] = "\xc3\xda\x55\x37\x9d\xe9\xc6\x90\x8e\x94\xea\x4d\xf2\x8d\x08\x4f\x32\xec\xcf\x03\x49\x1c\x71\xf7\x54\xb4\x07\x55\x77\xa2\x85\x52";
|
||||
uint8_t out[32];
|
||||
|
||||
scalar[0] &= 248;
|
||||
scalar[31] &= 127;
|
||||
scalar[31] |= 64;
|
||||
ladder(out, scalar, 32, pubkey);
|
||||
assert(0 == memcmp(out, expout, 32));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_ladder();
|
||||
return 0;
|
||||
}
|
133
src/x25519.c
Normal file
133
src/x25519.c
Normal file
|
@ -0,0 +1,133 @@
|
|||
#include "common.h"
|
||||
#include "endianess.h"
|
||||
|
||||
FAKE_INIT(x25519)
|
||||
|
||||
/*
|
||||
* Fast variable-base scalar multiplication for the Montgomery curve Curve25519
|
||||
*
|
||||
* y² = x³ + 486662x² + x
|
||||
*
|
||||
* over the prime field 2²⁵⁵ - 19.
|
||||
*/
|
||||
|
||||
#include "mod25519.c"
|
||||
|
||||
/*
|
||||
* Execute the step in the Montgomery ladder.
|
||||
*
|
||||
* x2/z2 is updated with the doubling of P₂
|
||||
* x3/z3 is updated with the sum P₂+P₃
|
||||
*
|
||||
* @param[in,out] x2 The projective X-coordinate of P₂ (< 2²⁶)
|
||||
* @param[in,out] z2 The projective Z-coordinate of P₂ (< 2²⁶)
|
||||
* @param[in,out] x3 The projective X-coordinate of P₃ (< 2²⁶)
|
||||
* @param[in,out] z3 The projective Z-coordinate of P₃ (< 2²⁶)
|
||||
* @param[in] xp The affine X-coordinate of P₃-P₂ (< 2²⁶)
|
||||
*/
|
||||
STATIC void ladder_step(uint32_t x2[10], uint32_t z2[10], uint32_t x3[10], uint32_t z3[10], const uint32_t xp[10])
|
||||
{
|
||||
uint32_t t0[10], t1[10];
|
||||
static const uint32_t nr_121666[10] = { 121666 };
|
||||
|
||||
/* https://www.hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#ladder-mladd-1987-m */
|
||||
|
||||
sub32(t0, x3, z3); /* t0 = D < 2^28 */
|
||||
sub32(t1, x2, z2); /* t1 = B < 2^28 */
|
||||
add32(x2, x2, z2); /* x2 = A < 2^27 */
|
||||
add32(z2, x3, z3); /* z2 = C < 2^27 */
|
||||
mul_25519(z3, t0, x2); /* z3 = DA < 2^26 */
|
||||
mul_25519(z2, z2, t1); /* z2 = CB < 2^26 */
|
||||
add32(x3, z3, z2); /* x3 = DA+CB < 2^27 */
|
||||
sub32(z2, z3, z2); /* z2 = DA-CB < 2^28 */
|
||||
mul_25519(x3, x3, x3); /* x3 = X5 < 2^26 */
|
||||
mul_25519(z2, z2, z2); /* z2 = (DA-CB)² < 2^26 */
|
||||
mul_25519(t0, t1, t1); /* t0 = BB < 2^26 */
|
||||
mul_25519(t1, x2, x2); /* t1 = AA < 2^26 */
|
||||
sub32(x2, t1, t0); /* x2 = E < 2^28 */
|
||||
mul_25519(z3, xp, z2); /* z3 = Z5 < 2^26 */
|
||||
mul_25519(z2, x2, nr_121666); /* z2 = a24*E < 2^26 */
|
||||
add32(z2, t0, z2); /* z2 = BB+a24*E < 2^27 */
|
||||
mul_25519(z2, x2, z2); /* z2 = Z4 < 2^26 */
|
||||
mul_25519(x2, t1, t0); /* x2 = X4 < 2^26 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Variable-base scalar multiplication on Curve25519.
|
||||
*
|
||||
* @param[out] ssecret The X-coordinate of the resulting point.
|
||||
* @param[in] k The scalar encoded in little-endian mode.
|
||||
* It must have been already clamped.
|
||||
* @param[in] len Length of the scalar in bytes.
|
||||
* @param[in] pubkey The X-coordinate of the point to multiply, encoded in
|
||||
* little-endian mode.
|
||||
*/
|
||||
void ladder(uint8_t ssecret[32], const uint8_t *k, size_t len, const uint8_t pubkey[32])
|
||||
{
|
||||
uint32_t R0x[10] = { 1 };
|
||||
uint32_t R0z[10] = { 0 };
|
||||
uint32_t R1x[10];
|
||||
uint32_t R1z[10] = { 1 };
|
||||
uint32_t xp[10];
|
||||
uint32_t invz[10];
|
||||
uint32_t affx[10];
|
||||
uint64_t tmp_64[4];
|
||||
unsigned bit_idx, swap;
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<4; i++) {
|
||||
tmp_64[i] = LOAD_U64_LITTLE(&pubkey[i*8]);
|
||||
}
|
||||
convert_le64_to_le25p5(xp, tmp_64);
|
||||
|
||||
memcpy(R1x, xp, sizeof R1x);
|
||||
bit_idx = 7;
|
||||
swap = 0;
|
||||
|
||||
/* https://eprint.iacr.org/2020/956.pdf */
|
||||
|
||||
while (len>0) {
|
||||
unsigned bit;
|
||||
|
||||
bit = (k[len-1] >> bit_idx) & 1;
|
||||
swap ^= bit;
|
||||
|
||||
cswap(R0x, R0z, R1x, R1z, swap);
|
||||
ladder_step(R0x, R0z, R1x, R1z, xp);
|
||||
swap = bit;
|
||||
|
||||
if (bit_idx-- == 0) {
|
||||
bit_idx = 7;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
cswap(R0x, R0z, R1x, R1z, swap);
|
||||
|
||||
invert_25519(invz, R0z);
|
||||
mul_25519(affx, R0x, invz);
|
||||
convert_le25p5_to_le64(tmp_64, affx);
|
||||
reduce_25519_le64(tmp_64);
|
||||
|
||||
for (i=0; i<4; i++) {
|
||||
STORE_U64_LITTLE(&ssecret[i*8], tmp_64[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PROFILE
|
||||
int main(void)
|
||||
{
|
||||
uint8_t pubkey[32];
|
||||
uint8_t secret[32];
|
||||
uint8_t out[32];
|
||||
unsigned i;
|
||||
|
||||
secret[0] = pubkey[0] = 0xAA;
|
||||
for (i=1; i<32; i++) {
|
||||
secret[i] = pubkey[i] = (uint8_t)((secret[i-1] << 1) | (secret[i-1] >> 7));
|
||||
}
|
||||
|
||||
for (i=0; i<10000; i++) {
|
||||
ladder(out, secret, sizeof secret, pubkey);
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,12 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MC4CAQAwBQYDK2VwBCIEIAX0BvLDTI71TpzUoZ+rzXFdgm0WVN+ndcu2UuG4lz47
|
||||
-----END PRIVATE KEY-----
|
||||
ED25519 Private-Key:
|
||||
priv:
|
||||
05:f4:06:f2:c3:4c:8e:f5:4e:9c:d4:a1:9f:ab:cd:
|
||||
71:5d:82:6d:16:54:df:a7:75:cb:b6:52:e1:b8:97:
|
||||
3e:3b
|
||||
pub:
|
||||
bc:85:b8:cf:58:5d:20:a4:de:47:e8:4d:1c:b6:18:
|
||||
3f:63:d9:ba:96:22:3f:cb:c8:86:e3:63:ff:de:a2:
|
||||
0c:ff
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MC4CAQAwBQYDK2VwBCIEIAX0BvLDTI71TpzUoZ+rzXFdgm0WVN+ndcu2UuG4lz47
|
||||
-----END PRIVATE KEY-----
|
|
@ -0,0 +1,6 @@
|
|||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAiwCrCpOhjU8wICCAAw
|
||||
DAYIKoZIhvcNAgkFADAdBglghkgBZQMEAQIEEOk0cNotyf4edYcdUnl6GNAEQFEf
|
||||
NUiZ3jfT8HYD0FqIjwZ9UL5T5rUmM34LCqipAuSPu+f23i2OuFlWIvfXtF4Qy79v
|
||||
ysv4OQa6DTDGopAHaL4=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
|
@ -0,0 +1,6 @@
|
|||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAiX7Eh6OAEHXAICCAAw
|
||||
DAYIKoZIhvcNAgkFADAdBglghkgBZQMEARYEEJpUDxSZpCzf7OI60qPsYU0EQG0u
|
||||
aMz2AkSXtRU3+ATTEDtb4slSdtivYBkUCfcAw8/d0PZN56wjPStu585VgRTlGTXW
|
||||
Ty3Qe6eABSTTtEfBAhU=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
|
@ -0,0 +1,6 @@
|
|||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAh8KD2HGLrgSAICCAAw
|
||||
DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEENKrZJ2LKxhTgbSfXCWBKuMEQFiS
|
||||
O8+y8UlvtuAAHhDd0TBu7sGVG2M4tzpvhnMV82QXfCRDkJAUqQNtXQBLWjdO44Ui
|
||||
EaYvk2g9GUDQVDfx25E=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
|
@ -0,0 +1,5 @@
|
|||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIGKME4GCSqGSIb3DQEFDTBBMCkGCSqGSIb3DQEFDDAcBAjS0vLA/pEM8AICCAAw
|
||||
DAYIKoZIhvcNAgkFADAUBggqhkiG9w0DBwQIdHVzfnJXMDwEOFN1knabShDOAvnI
|
||||
M8NhzBnlqPf0YK3HeJ4JZY0jAfLBGyKafLPA94+KbGBGRLB+bFIrVRpBrkN4
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
|
@ -0,0 +1,7 @@
|
|||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
QyNTUxOQAAACB5VzUBr/gix80anEf1muNYHTnCByK7eInlDM5QrqilUAAAAIiXPO6Alzzu
|
||||
gAAAAAtzc2gtZWQyNTUxOQAAACB5VzUBr/gix80anEf1muNYHTnCByK7eInlDM5QrqilUA
|
||||
AAAEBjRlj3swElydFqbfy2FD2dgmwGMDLyhkPJ6HesGcJC4XlXNQGv+CLHzRqcR/Wa41gd
|
||||
OcIHIrt4ieUMzlCuqKVQAAAABHRlc3QB
|
||||
-----END OPENSSH PRIVATE KEY-----
|
|
@ -0,0 +1,8 @@
|
|||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABDjWCfp8z
|
||||
xIlHc7MwYdCIthAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAICHNC69L0IPdGK1V
|
||||
hVBpRNoxcBOoDKZpGZ98pFEBo1wNAAAAkKTQjCRhdNO9Zv027lR5uG3cGePQK+98oRA6Wy
|
||||
wcrAmwahxGoBo8y49yPMCIt0e9KmDY7+Utw0FBfdldKuYzRV732kd7bQgr0z13sc+70oix
|
||||
rT8S6ufYMZHyT5sRvjaM8jlM6nuyBix4xLc7pjyNqojZfLnoELNWQ9hrN6DK8C4yQ2rUwU
|
||||
UtOxazNEKJBnmLqg==
|
||||
-----END OPENSSH PRIVATE KEY-----
|
Binary file not shown.
|
@ -0,0 +1,6 @@
|
|||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAh2gZRW4+DZnQICCAAw
|
||||
DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEENs1bbPFWltnsWl6mwI1bf8EQH0K
|
||||
0QOWF+Y2c24tojkepMuuKq3JRht2vCY/bxaJO74lk0p0DLsa8kIxUfd6oDA0+Mf2
|
||||
K8LxR/qXZCIMRYzRyjA=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
|||
-----BEGIN PUBLIC KEY-----
|
||||
MCowBQYDK2VwAyEAvIW4z1hdIKTeR+hNHLYYP2PZupYiP8vIhuNj/96iDP8=
|
||||
-----END PUBLIC KEY-----
|
|
@ -0,0 +1 @@
|
|||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHlXNQGv+CLHzRqcR/Wa41gdOcIHIrt4ieUMzlCuqKVQ test
|
Binary file not shown.
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIBWzCCAQ2gAwIBAgIUCvoAagsRlhJ+PYMH2nrNafycn1UwBQYDK2VwMCMxCzAJ
|
||||
BgNVBAYTAkdCMRQwEgYDVQQDDAtleGFtcGxlLmNvbTAeFw0yMjA1MDcxODMxMzFa
|
||||
Fw0yMzA1MDcxODMxMzFaMCMxCzAJBgNVBAYTAkdCMRQwEgYDVQQDDAtleGFtcGxl
|
||||
LmNvbTAqMAUGAytlcAMhALyFuM9YXSCk3kfoTRy2GD9j2bqWIj/LyIbjY//eogz/
|
||||
o1MwUTAdBgNVHQ4EFgQU8Yevx2AVIt0UoJy8mJSdH7lBHF0wHwYDVR0jBBgwFoAU
|
||||
8Yevx2AVIt0UoJy8mJSdH7lBHF0wDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXADQQB/
|
||||
vYInhoHQyJYoNuPWHQt0AkZwHTZNNFBSz/+Vty2SfkTZgsyKtqNdeVlc1VfVDjU7
|
||||
Sa3zerNfRQGz/qMLtKkP
|
||||
-----END CERTIFICATE-----
|
39
test_vectors/pycryptodome_test_vectors/PublicKey/ECC/gen_ed22519.sh
Executable file
39
test_vectors/pycryptodome_test_vectors/PublicKey/ECC/gen_ed22519.sh
Executable file
|
@ -0,0 +1,39 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Note that openssl's ec command does not support ed25519; you must use the (gen)pkey command
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
openssl version | tee openssl_version_ed25519.txt
|
||||
|
||||
# Private key (PKCS#8)
|
||||
openssl genpkey -algorithm ed25519 -outform PEM -out ecc_ed25519_private.pem
|
||||
openssl pkey -inform PEM -in ecc_ed25519_private.pem -outform DER -out ecc_ed25519_private.der
|
||||
openssl pkey -in ecc_ed25519_private.pem -text -out ecc_ed25519.txt
|
||||
|
||||
# Encrypted private key
|
||||
# Traditional format (PEM enveloped) is unsupported for ed25519, so we only use encrypted PKCS#8
|
||||
openssl pkcs8 -in ecc_ed25519_private.der -inform DER -passout 'pass:secret' -out ecc_ed25519_private_p8.der -outform DER -topk8
|
||||
openssl pkcs8 -in ecc_ed25519_private.der -inform DER -passout 'pass:secret' -out ecc_ed25519_private_p8.pem -outform PEM -topk8
|
||||
openssl pkey -in ecc_ed25519_private.pem -des3 -out ecc_ed25519_private_enc_des3.pem -passout 'pass:secret' -outform PEM
|
||||
openssl pkey -in ecc_ed25519_private.pem -aes128 -out ecc_ed25519_private_enc_aes128.pem -passout 'pass:secret' -outform PEM
|
||||
openssl pkey -in ecc_ed25519_private.pem -aes192 -out ecc_ed25519_private_enc_aes192.pem -passout 'pass:secret' -outform PEM
|
||||
openssl pkey -in ecc_ed25519_private.pem -aes256 -out ecc_ed25519_private_enc_aes256.pem -passout 'pass:secret' -outform PEM
|
||||
# GCM is not supported by openssl in this case...
|
||||
#openssl pkey -in ecc_ed25519_private.pem -aes-256-gcm -out ecc_ed25519_private_enc_aes256_gcm.pem -passout 'pass:secret' -outform PEM
|
||||
|
||||
# Public key
|
||||
openssl pkey -in ecc_ed25519_private.pem -pubout -out ecc_ed25519_public.pem
|
||||
openssl pkey -pubin -in ecc_ed25519_public.pem -outform DER -out ecc_ed25519_public.der
|
||||
|
||||
# X.509 cert
|
||||
openssl req -new -key ecc_ed25519_private.pem -days 365 -x509 -out ecc_ed25519_x509.pem -subj '/C=GB/CN=example.com'
|
||||
openssl x509 -in ecc_ed25519_x509.pem -out ecc_ed25519_x509.der -outform DER
|
||||
|
||||
# OpenSSH - also the .pem.pub files are created
|
||||
# Unfortunately, it does not seem possible to reuse ecc_ed25519_private.pem, we need to regenerate
|
||||
ssh-keygen -t ed25519 -f ecc_ed25519_private_openssh.pem -P "" -C test
|
||||
mv ecc_ed25519_private_openssh.pem.pub ecc_ed25519_public_openssh.txt
|
||||
ssh-keygen -t ed25519 -f ecc_ed25519_private_openssh_pwd.pem -P "password" -C test
|
||||
rm ecc_ed25519_private_openssh_pwd.pem.pub
|
|
@ -0,0 +1 @@
|
|||
OpenSSL 1.1.1n FIPS 15 Mar 2022
|
File diff suppressed because it is too large
Load diff
|
@ -1 +1 @@
|
|||
__version__ = "1.0.7"
|
||||
__version__ = "1.0.8"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue