Replaced system SQLite with SQLCipher to support encrypted database

This commit is contained in:
Oleksii Zghurskyi
2025-06-07 18:11:17 +03:00
parent f4198d62a7
commit 177d74700f
534 changed files with 362771 additions and 21 deletions

View File

@@ -0,0 +1,435 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file ecc.c
ECC Crypto, Tom St Denis
*/
#ifdef LTC_MECC
/* This array holds the curve parameters.
* Curves (prime field only) are taken from:
* - http://www.secg.org/collateral/sec2_final.pdf (named: SECP*)
* - http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf (named: NISTP*)
* - ANS X9.62 (named: PRIMEP*)
* - http://www.ecc-brainpool.org/download/Domain-parameters.pdf (named: BRAINPOOLP*)
*/
const ltc_ecc_curve ltc_ecc_curves[] = {
#ifdef LTC_ECC_SECP112R1
{
/* prime */ "DB7C2ABF62E35E668076BEAD208B",
/* A */ "DB7C2ABF62E35E668076BEAD2088",
/* B */ "659EF8BA043916EEDE8911702B22",
/* order */ "DB7C2ABF62E35E7628DFAC6561C5",
/* Gx */ "09487239995A5EE76B55F9C2F098",
/* Gy */ "A89CE5AF8724C0A23E0E0FF77500",
/* cofactor */ 1,
/* OID */ "1.3.132.0.6"
},
#endif
#ifdef LTC_ECC_SECP112R2
{
/* prime */ "DB7C2ABF62E35E668076BEAD208B",
/* A */ "6127C24C05F38A0AAAF65C0EF02C",
/* B */ "51DEF1815DB5ED74FCC34C85D709",
/* order */ "36DF0AAFD8B8D7597CA10520D04B",
/* Gx */ "4BA30AB5E892B4E1649DD0928643",
/* Gy */ "ADCD46F5882E3747DEF36E956E97",
/* cofactor */ 4,
/* OID */ "1.3.132.0.7"
},
#endif
#ifdef LTC_ECC_SECP128R1
{
/* prime */ "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF",
/* A */ "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC",
/* B */ "E87579C11079F43DD824993C2CEE5ED3",
/* order */ "FFFFFFFE0000000075A30D1B9038A115",
/* Gx */ "161FF7528B899B2D0C28607CA52C5B86",
/* Gy */ "CF5AC8395BAFEB13C02DA292DDED7A83",
/* cofactor */ 1,
/* OID */ "1.3.132.0.28"
},
#endif
#ifdef LTC_ECC_SECP128R2
{
/* prime */ "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF",
/* A */ "D6031998D1B3BBFEBF59CC9BBFF9AEE1",
/* B */ "5EEEFCA380D02919DC2C6558BB6D8A5D",
/* order */ "3FFFFFFF7FFFFFFFBE0024720613B5A3",
/* Gx */ "7B6AA5D85E572983E6FB32A7CDEBC140",
/* Gy */ "27B6916A894D3AEE7106FE805FC34B44",
/* cofactor */ 4,
/* OID */ "1.3.132.0.29"
},
#endif
#ifdef LTC_ECC_SECP160R1
{
/* prime */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF",
/* A */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC",
/* B */ "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45",
/* order */ "0100000000000000000001F4C8F927AED3CA752257",
/* Gx */ "4A96B5688EF573284664698968C38BB913CBFC82",
/* Gy */ "23A628553168947D59DCC912042351377AC5FB32",
/* cofactor */ 1,
/* OID */ "1.3.132.0.8"
},
#endif
#ifdef LTC_ECC_SECP160R2
{
/* prime */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73",
/* A */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70",
/* B */ "B4E134D3FB59EB8BAB57274904664D5AF50388BA",
/* order */ "0100000000000000000000351EE786A818F3A1A16B",
/* Gx */ "52DCB034293A117E1F4FF11B30F7199D3144CE6D",
/* Gy */ "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E",
/* cofactor */ 1,
/* OID */ "1.3.132.0.30"
},
#endif
#ifdef LTC_ECC_SECP160K1
{
/* prime */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73",
/* A */ "0000000000000000000000000000000000000000",
/* B */ "0000000000000000000000000000000000000007",
/* order */ "0100000000000000000001B8FA16DFAB9ACA16B6B3",
/* Gx */ "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB",
/* Gy */ "938CF935318FDCED6BC28286531733C3F03C4FEE",
/* cofactor */ 1,
/* OID */ "1.3.132.0.9"
},
#endif
#ifdef LTC_ECC_SECP192R1
{
/* prime */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",
/* A */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC",
/* B */ "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1",
/* order */ "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831",
/* Gx */ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",
/* Gy */ "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
/* cofactor */ 1,
/* OID */ "1.2.840.10045.3.1.1"
},
#endif
#ifdef LTC_ECC_PRIME192V2
{
/* prime */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",
/* A */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC",
/* B */ "CC22D6DFB95C6B25E49C0D6364A4E5980C393AA21668D953",
/* order */ "FFFFFFFFFFFFFFFFFFFFFFFE5FB1A724DC80418648D8DD31",
/* Gx */ "EEA2BAE7E1497842F2DE7769CFE9C989C072AD696F48034A",
/* Gy */ "6574D11D69B6EC7A672BB82A083DF2F2B0847DE970B2DE15",
/* cofactor */ 1,
/* OID */ "1.2.840.10045.3.1.2"
},
#endif
#ifdef LTC_ECC_PRIME192V3
{
/* prime */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",
/* A */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC",
/* B */ "22123DC2395A05CAA7423DAECCC94760A7D462256BD56916",
/* order */ "FFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13",
/* Gx */ "7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896",
/* Gy */ "38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0",
/* cofactor */ 1,
/* OID */ "1.2.840.10045.3.1.3"
},
#endif
#ifdef LTC_ECC_SECP192K1
{
/* prime */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37",
/* A */ "000000000000000000000000000000000000000000000000",
/* B */ "000000000000000000000000000000000000000000000003",
/* order */ "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D",
/* Gx */ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D",
/* Gy */ "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D",
/* cofactor */ 1,
/* OID */ "1.3.132.0.31"
},
#endif
#ifdef LTC_ECC_SECP224R1
{
/* prime */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001",
/* A */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE",
/* B */ "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4",
/* order */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D",
/* Gx */ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21",
/* Gy */ "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34",
/* cofactor */ 1,
/* OID */ "1.3.132.0.33"
},
#endif
#ifdef LTC_ECC_SECP224K1
{
/* prime */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D",
/* A */ "00000000000000000000000000000000000000000000000000000000",
/* B */ "00000000000000000000000000000000000000000000000000000005",
/* order */ "010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7",
/* Gx */ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C",
/* Gy */ "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5",
/* cofactor */ 1,
/* OID */ "1.3.132.0.32"
},
#endif
#ifdef LTC_ECC_SECP256R1
{
/* prime */ "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
/* A */ "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
/* B */ "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
/* order */ "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
/* Gx */ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
/* Gy */ "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
/* cofactor */ 1,
/* OID */ "1.2.840.10045.3.1.7"
},
#endif
#ifdef LTC_ECC_SECP256K1
{
/* prime */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",
/* A */ "0000000000000000000000000000000000000000000000000000000000000000",
/* B */ "0000000000000000000000000000000000000000000000000000000000000007",
/* order */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
/* Gx */ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
/* Gy */ "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",
/* cofactor */ 1,
/* OID */ "1.3.132.0.10"
},
#endif
#ifdef LTC_ECC_SECP384R1
{
/* prime */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
/* A */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
/* B */ "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
/* order */ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
/* Gx */ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
/* Gy */ "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
/* cofactor */ 1,
/* OID */ "1.3.132.0.34"
},
#endif
#ifdef LTC_ECC_SECP521R1
{
/* prime */ "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
/* A */ "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
/* B */ "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
/* order */ "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
/* Gx */ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
/* Gy */ "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
/* cofactor */ 1,
/* OID */ "1.3.132.0.35"
},
#endif
#ifdef LTC_ECC_PRIME239V1
{
/* prime */ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF",
/* A */ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC",
/* B */ "6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A",
/* order */ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E5E9A9F5D9071FBD1522688909D0B",
/* Gx */ "0FFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF",
/* Gy */ "7DEBE8E4E90A5DAE6E4054CA530BA04654B36818CE226B39FCCB7B02F1AE",
/* cofactor */ 1,
/* OID */ "1.2.840.10045.3.1.4"
},
#endif
#ifdef LTC_ECC_PRIME239V2
{
/* prime */ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF",
/* A */ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC",
/* B */ "617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C",
/* order */ "7FFFFFFFFFFFFFFFFFFFFFFF800000CFA7E8594377D414C03821BC582063",
/* Gx */ "38AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7",
/* Gy */ "5B0125E4DBEA0EC7206DA0FC01D9B081329FB555DE6EF460237DFF8BE4BA",
/* cofactor */ 1,
/* OID */ "1.2.840.10045.3.1.5"
},
#endif
#ifdef LTC_ECC_PRIME239V3
{
/* prime */ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF",
/* A */ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC",
/* B */ "255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E",
/* order */ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF975DEB41B3A6057C3C432146526551",
/* Gx */ "6768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A",
/* Gy */ "1607E6898F390C06BC1D552BAD226F3B6FCFE48B6E818499AF18E3ED6CF3",
/* cofactor */ 1,
/* OID */ "1.2.840.10045.3.1.6"
},
#endif
#ifdef LTC_ECC_BRAINPOOLP160R1
{
/* prime */ "E95E4A5F737059DC60DFC7AD95B3D8139515620F",
/* A */ "340E7BE2A280EB74E2BE61BADA745D97E8F7C300",
/* B */ "1E589A8595423412134FAA2DBDEC95C8D8675E58",
/* order */ "E95E4A5F737059DC60DF5991D45029409E60FC09",
/* Gx */ "BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3",
/* Gy */ "1667CB477A1A8EC338F94741669C976316DA6321",
/* cofactor */ 1,
/* OID */ "1.3.36.3.3.2.8.1.1.1"
},
#endif
#ifdef LTC_ECC_BRAINPOOLP192R1
{
/* prime */ "C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297",
/* A */ "6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF",
/* B */ "469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9",
/* order */ "C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1",
/* Gx */ "C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD6",
/* Gy */ "14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F",
/* cofactor */ 1,
/* OID */ "1.3.36.3.3.2.8.1.1.3"
},
#endif
#ifdef LTC_ECC_BRAINPOOLP224R1
{
/* prime */ "D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF",
/* A */ "68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43",
/* B */ "2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B",
/* order */ "D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F",
/* Gx */ "0D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D",
/* Gy */ "58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD",
/* cofactor */ 1,
/* OID */ "1.3.36.3.3.2.8.1.1.5"
},
#endif
#ifdef LTC_ECC_BRAINPOOLP256R1
{
/* prime */ "A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377",
/* A */ "7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9",
/* B */ "26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6",
/* order */ "A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7",
/* Gx */ "8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262",
/* Gy */ "547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997",
/* cofactor */ 1,
/* OID */ "1.3.36.3.3.2.8.1.1.7"
},
#endif
#ifdef LTC_ECC_BRAINPOOLP320R1
{
/* prime */ "D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27",
/* A */ "3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4",
/* B */ "520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6",
/* order */ "D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311",
/* Gx */ "43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E20611",
/* Gy */ "14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1",
/* cofactor */ 1,
/* OID */ "1.3.36.3.3.2.8.1.1.9"
},
#endif
#ifdef LTC_ECC_BRAINPOOLP384R1
{
/* prime */ "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53",
/* A */ "7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826",
/* B */ "04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11",
/* order */ "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565",
/* Gx */ "1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E",
/* Gy */ "8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315",
/* cofactor */ 1,
/* OID */ "1.3.36.3.3.2.8.1.1.11"
},
#endif
#ifdef LTC_ECC_BRAINPOOLP512R1
{
/* prime */ "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3",
/* A */ "7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA",
/* B */ "3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723",
/* order */ "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069",
/* Gx */ "81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822",
/* Gy */ "7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892",
/* cofactor */ 1,
/* OID */ "1.3.36.3.3.2.8.1.1.13"
},
#endif
#ifdef LTC_ECC_BRAINPOOLP160T1
{
/* prime */ "E95E4A5F737059DC60DFC7AD95B3D8139515620F",
/* A */ "E95E4A5F737059DC60DFC7AD95B3D8139515620C",
/* B */ "7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380",
/* order */ "E95E4A5F737059DC60DF5991D45029409E60FC09",
/* Gx */ "B199B13B9B34EFC1397E64BAEB05ACC265FF2378",
/* Gy */ "ADD6718B7C7C1961F0991B842443772152C9E0AD",
/* cofactor */ 1,
/* OID */ "1.3.36.3.3.2.8.1.1.2"
},
#endif
#ifdef LTC_ECC_BRAINPOOLP192T1
{
/* prime */ "C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297",
/* A */ "C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294",
/* B */ "13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79",
/* order */ "C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1",
/* Gx */ "3AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129",
/* Gy */ "097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9",
/* cofactor */ 1,
/* OID */ "1.3.36.3.3.2.8.1.1.4"
},
#endif
#ifdef LTC_ECC_BRAINPOOLP224T1
{
/* prime */ "D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF",
/* A */ "D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC",
/* B */ "4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D",
/* order */ "D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F",
/* Gx */ "6AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D580",
/* Gy */ "0374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C",
/* cofactor */ 1,
/* OID */ "1.3.36.3.3.2.8.1.1.6"
},
#endif
#ifdef LTC_ECC_BRAINPOOLP256T1
{
/* prime */ "A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377",
/* A */ "A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374",
/* B */ "662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04",
/* order */ "A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7",
/* Gx */ "A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F4",
/* Gy */ "2D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE",
/* cofactor */ 1,
/* OID */ "1.3.36.3.3.2.8.1.1.8"
},
#endif
#ifdef LTC_ECC_BRAINPOOLP320T1
{
/* prime */ "D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27",
/* A */ "D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E24",
/* B */ "A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547CEB5B4FEF422340353",
/* order */ "D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311",
/* Gx */ "925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED52",
/* Gy */ "63BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3",
/* cofactor */ 1,
/* OID */ "1.3.36.3.3.2.8.1.1.10"
},
#endif
#ifdef LTC_ECC_BRAINPOOLP384T1
{
/* prime */ "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53",
/* A */ "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC50",
/* B */ "7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE",
/* order */ "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565",
/* Gx */ "18DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC",
/* Gy */ "25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928",
/* cofactor */ 1,
/* OID */ "1.3.36.3.3.2.8.1.1.12"
},
#endif
#ifdef LTC_ECC_BRAINPOOLP512T1
{
/* prime */ "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3",
/* A */ "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0",
/* B */ "7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E",
/* order */ "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069",
/* Gx */ "640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA",
/* Gy */ "5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332",
/* cofactor */ 1,
/* OID */ "1.3.36.3.3.2.8.1.1.14"
},
#endif
{
NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL
}
};
#endif

View File

@@ -0,0 +1,24 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file ecc_ansi_x963_export.c
ECC Crypto, Tom St Denis
*/
#ifdef LTC_MECC
/** ECC X9.63 (Sec. 4.3.6) uncompressed export
@param key Key to export
@param out [out] destination of export
@param outlen [in/out] Length of destination and final output size
Return CRYPT_OK on success
*/
int ecc_ansi_x963_export(const ecc_key *key, unsigned char *out, unsigned long *outlen)
{
return ecc_get_key(out, outlen, PK_PUBLIC, key);
}
#endif

View File

@@ -0,0 +1,58 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
/**
@file ecc_ansi_x963_import.c
ECC Crypto, Tom St Denis
*/
#ifdef LTC_MECC
/** Import an ANSI X9.63 format public key
@param in The input data to read
@param inlen The length of the input data
@param key [out] destination to store imported key \
*/
int ecc_ansi_x963_import(const unsigned char *in, unsigned long inlen, ecc_key *key)
{
return ecc_ansi_x963_import_ex(in, inlen, key, NULL);
}
int ecc_ansi_x963_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, const ltc_ecc_curve *cu)
{
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(key != NULL);
/* must be odd */
if ((inlen & 1) == 0) {
return CRYPT_INVALID_ARG;
}
/* initialize key->dp */
if (cu == NULL) {
/* this case works only for uncompressed public keys */
if ((err = ecc_set_curve_by_size((inlen-1)>>1, key)) != CRYPT_OK) { return err; }
}
else {
/* this one works for both compressed / uncompressed pubkeys */
if ((err = ecc_set_curve(cu, key)) != CRYPT_OK) { return err; }
}
/* load public key */
if ((err = ecc_set_key(in, inlen, PK_PUBLIC, key)) != CRYPT_OK) { return err; }
/* we're done */
return CRYPT_OK;
}
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,133 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file ecc_decrypt_key.c
ECC Crypto, Tom St Denis
*/
#if defined(LTC_MECC) && defined(LTC_DER)
/**
Decrypt an ECC encrypted key
@param in The ciphertext
@param inlen The length of the ciphertext (octets)
@param out [out] The plaintext
@param outlen [in/out] The max size and resulting size of the plaintext
@param key The corresponding private ECC key
@return CRYPT_OK if successful
*/
int ecc_decrypt_key(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
const ecc_key *key)
{
unsigned char *ecc_shared, *skey, *pub_expt;
unsigned long x, y;
unsigned long hashOID[32] = { 0 };
int hash, err;
ecc_key pubkey;
ltc_asn1_list decode[3];
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(key != NULL);
/* right key type? */
if (key->type != PK_PRIVATE) {
return CRYPT_PK_NOT_PRIVATE;
}
/* decode to find out hash */
LTC_SET_ASN1(decode, 0, LTC_ASN1_OBJECT_IDENTIFIER, hashOID, sizeof(hashOID)/sizeof(hashOID[0]));
err = der_decode_sequence(in, inlen, decode, 1);
if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) {
return err;
}
hash = find_hash_oid(hashOID, decode[0].size);
if (hash_is_valid(hash) != CRYPT_OK) {
return CRYPT_INVALID_PACKET;
}
/* we now have the hash! */
/* allocate memory */
pub_expt = XMALLOC(ECC_BUF_SIZE);
ecc_shared = XMALLOC(ECC_BUF_SIZE);
skey = XMALLOC(MAXBLOCKSIZE);
if (pub_expt == NULL || ecc_shared == NULL || skey == NULL) {
if (pub_expt != NULL) {
XFREE(pub_expt);
}
if (ecc_shared != NULL) {
XFREE(ecc_shared);
}
if (skey != NULL) {
XFREE(skey);
}
return CRYPT_MEM;
}
LTC_SET_ASN1(decode, 1, LTC_ASN1_OCTET_STRING, pub_expt, ECC_BUF_SIZE);
LTC_SET_ASN1(decode, 2, LTC_ASN1_OCTET_STRING, skey, MAXBLOCKSIZE);
/* read the structure in now */
if ((err = der_decode_sequence(in, inlen, decode, 3)) != CRYPT_OK) {
goto LBL_ERR;
}
/* import ECC key from packet */
if ((err = ecc_copy_curve(key, &pubkey)) != CRYPT_OK) { goto LBL_ERR; }
if ((err = ecc_set_key(decode[1].data, decode[1].size, PK_PUBLIC, &pubkey)) != CRYPT_OK) { goto LBL_ERR; }
/* make shared key */
x = ECC_BUF_SIZE;
if ((err = ecc_shared_secret(key, &pubkey, ecc_shared, &x)) != CRYPT_OK) {
ecc_free(&pubkey);
goto LBL_ERR;
}
ecc_free(&pubkey);
y = MIN(ECC_BUF_SIZE, MAXBLOCKSIZE);
if ((err = hash_memory(hash, ecc_shared, x, ecc_shared, &y)) != CRYPT_OK) {
goto LBL_ERR;
}
/* ensure the hash of the shared secret is at least as big as the encrypt itself */
if (decode[2].size > y) {
err = CRYPT_INVALID_PACKET;
goto LBL_ERR;
}
/* avoid buffer overflow */
if (*outlen < decode[2].size) {
*outlen = decode[2].size;
err = CRYPT_BUFFER_OVERFLOW;
goto LBL_ERR;
}
/* Decrypt the key */
for (x = 0; x < decode[2].size; x++) {
out[x] = skey[x] ^ ecc_shared[x];
}
*outlen = x;
err = CRYPT_OK;
LBL_ERR:
#ifdef LTC_CLEAN_STACK
zeromem(pub_expt, ECC_BUF_SIZE);
zeromem(ecc_shared, ECC_BUF_SIZE);
zeromem(skey, MAXBLOCKSIZE);
#endif
XFREE(pub_expt);
XFREE(ecc_shared);
XFREE(skey);
return err;
}
#endif

View File

@@ -0,0 +1,120 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file ecc_encrypt_key.c
ECC Crypto, Tom St Denis
*/
#if defined(LTC_MECC) && defined(LTC_DER)
/**
Encrypt a symmetric key with ECC
@param in The symmetric key you want to encrypt
@param inlen The length of the key to encrypt (octets)
@param out [out] The destination for the ciphertext
@param outlen [in/out] The max size and resulting size of the ciphertext
@param prng An active PRNG state
@param wprng The index of the PRNG you wish to use
@param hash The index of the hash you want to use
@param key The ECC key you want to encrypt to
@return CRYPT_OK if successful
*/
int ecc_encrypt_key(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, int hash,
const ecc_key *key)
{
unsigned char *pub_expt, *ecc_shared, *skey;
ecc_key pubkey;
unsigned long x, y, pubkeysize;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(key != NULL);
if ((err = hash_is_valid(hash)) != CRYPT_OK) {
return err;
}
if (inlen > hash_descriptor[hash].hashsize) {
return CRYPT_INVALID_HASH;
}
/* make a random key and export the public copy */
if ((err = ecc_copy_curve(key, &pubkey)) != CRYPT_OK) { return err; }
if ((err = ecc_generate_key(prng, wprng, &pubkey)) != CRYPT_OK) { return err; }
pub_expt = XMALLOC(ECC_BUF_SIZE);
ecc_shared = XMALLOC(ECC_BUF_SIZE);
skey = XMALLOC(MAXBLOCKSIZE);
if (pub_expt == NULL || ecc_shared == NULL || skey == NULL) {
if (pub_expt != NULL) {
XFREE(pub_expt);
}
if (ecc_shared != NULL) {
XFREE(ecc_shared);
}
if (skey != NULL) {
XFREE(skey);
}
ecc_free(&pubkey);
return CRYPT_MEM;
}
pubkeysize = ECC_BUF_SIZE;
if (ltc_mp.sqrtmod_prime != NULL) {
/* PK_COMPRESSED requires sqrtmod_prime */
err = ecc_get_key(pub_expt, &pubkeysize, PK_PUBLIC|PK_COMPRESSED, &pubkey);
}
else {
err = ecc_get_key(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey);
}
if (err != CRYPT_OK) {
ecc_free(&pubkey);
goto LBL_ERR;
}
/* make random key */
x = ECC_BUF_SIZE;
if ((err = ecc_shared_secret(&pubkey, key, ecc_shared, &x)) != CRYPT_OK) {
ecc_free(&pubkey);
goto LBL_ERR;
}
ecc_free(&pubkey);
y = MAXBLOCKSIZE;
if ((err = hash_memory(hash, ecc_shared, x, skey, &y)) != CRYPT_OK) {
goto LBL_ERR;
}
/* Encrypt key */
for (x = 0; x < inlen; x++) {
skey[x] ^= in[x];
}
err = der_encode_sequence_multi(out, outlen,
LTC_ASN1_OBJECT_IDENTIFIER, hash_descriptor[hash].OIDlen, hash_descriptor[hash].OID,
LTC_ASN1_OCTET_STRING, pubkeysize, pub_expt,
LTC_ASN1_OCTET_STRING, inlen, skey,
LTC_ASN1_EOL, 0UL, NULL);
LBL_ERR:
#ifdef LTC_CLEAN_STACK
/* clean up */
zeromem(pub_expt, ECC_BUF_SIZE);
zeromem(ecc_shared, ECC_BUF_SIZE);
zeromem(skey, MAXBLOCKSIZE);
#endif
XFREE(skey);
XFREE(ecc_shared);
XFREE(pub_expt);
return err;
}
#endif

View File

@@ -0,0 +1,61 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file ecc_export.c
ECC Crypto, Tom St Denis
*/
#if defined(LTC_MECC) && defined(LTC_DER)
/**
Export an ECC key as a binary packet
@param out [out] Destination for the key
@param outlen [in/out] Max size and resulting size of the exported key
@param type The type of key you want to export (PK_PRIVATE or PK_PUBLIC)
@param key The key to export
@return CRYPT_OK if successful
*/
int ecc_export(unsigned char *out, unsigned long *outlen, int type, const ecc_key *key)
{
int err;
unsigned char flags[1];
unsigned long key_size;
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(key != NULL);
/* type valid? */
if (key->type != PK_PRIVATE && type == PK_PRIVATE) {
return CRYPT_PK_TYPE_MISMATCH;
}
/* we store the NIST byte size */
key_size = key->dp.size;
if (type == PK_PRIVATE) {
flags[0] = 1;
err = der_encode_sequence_multi(out, outlen,
LTC_ASN1_BIT_STRING, 1UL, flags,
LTC_ASN1_SHORT_INTEGER, 1UL, &key_size,
LTC_ASN1_INTEGER, 1UL, key->pubkey.x,
LTC_ASN1_INTEGER, 1UL, key->pubkey.y,
LTC_ASN1_INTEGER, 1UL, key->k,
LTC_ASN1_EOL, 0UL, NULL);
} else {
flags[0] = 0;
err = der_encode_sequence_multi(out, outlen,
LTC_ASN1_BIT_STRING, 1UL, flags,
LTC_ASN1_SHORT_INTEGER, 1UL, &key_size,
LTC_ASN1_INTEGER, 1UL, key->pubkey.x,
LTC_ASN1_INTEGER, 1UL, key->pubkey.y,
LTC_ASN1_EOL, 0UL, NULL);
}
return err;
}
#endif

View File

@@ -0,0 +1,167 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#if defined(LTC_MECC) && defined(LTC_DER)
/**
Export an ECC key as a binary packet
@param out [out] Destination for the key
@param outlen [in/out] Max size and resulting size of the exported key
@param type The type of key you want to export (PK_PRIVATE or PK_PUBLIC)
@param key The key to export
@return CRYPT_OK if successful
*/
int ecc_export_openssl(unsigned char *out, unsigned long *outlen, int type, const ecc_key *key)
{
int err;
void *prime, *order, *a, *b, *gx, *gy;
unsigned char bin_a[256], bin_b[256], bin_k[256], bin_g[512], bin_xy[512];
unsigned long len_a, len_b, len_k, len_g, len_xy;
unsigned long cofactor, one = 1;
const char *OID;
unsigned long oid[16], oidlen;
ltc_asn1_list seq_fieldid[2], seq_curve[2], seq_ecparams[6], seq_priv[4], pub_xy, ecparams;
int flag_oid = type & PK_CURVEOID ? 1 : 0;
int flag_com = type & PK_COMPRESSED ? 1 : 0;
int flag_pri = type & PK_PRIVATE ? 1 : 0;
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(key != NULL);
if (key->type != PK_PRIVATE && flag_pri) return CRYPT_PK_TYPE_MISMATCH;
if (flag_oid) {
/* http://tools.ietf.org/html/rfc5912
ECParameters ::= CHOICE {
namedCurve CURVE.&id({NamedCurve}) # OBJECT
}
*/
if (key->dp.oidlen == 0) { err = CRYPT_INVALID_ARG; goto error; }
LTC_SET_ASN1(&ecparams, 0, LTC_ASN1_OBJECT_IDENTIFIER, key->dp.oid, key->dp.oidlen);
}
else {
prime = key->dp.prime;
order = key->dp.order;
a = key->dp.A;
b = key->dp.B;
gx = key->dp.base.x;
gy = key->dp.base.y;
cofactor = key->dp.cofactor;
/* curve param a */
len_a = ltc_mp_unsigned_bin_size(a);
if (len_a > sizeof(bin_a)) { err = CRYPT_BUFFER_OVERFLOW; goto error; }
if ((err = ltc_mp_to_unsigned_bin(a, bin_a)) != CRYPT_OK) { goto error; }
if (len_a == 0) { len_a = 1; bin_a[0] = 0; } /* handle case a == 0 */
/* curve param b */
len_b = ltc_mp_unsigned_bin_size(b);
if (len_b > sizeof(bin_b)) { err = CRYPT_BUFFER_OVERFLOW; goto error; }
if ((err = ltc_mp_to_unsigned_bin(b, bin_b)) != CRYPT_OK) { goto error; }
if (len_b == 0) { len_b = 1; bin_b[0] = 0; } /* handle case b == 0 */
/* base point - (un)compressed based on flag_com */
len_g = sizeof(bin_g);
err = ltc_ecc_export_point(bin_g, &len_g, gx, gy, key->dp.size, flag_com);
if (err != CRYPT_OK) { goto error; }
/* we support only prime-field EC */
if ((err = pk_get_oid(LTC_OID_EC_PRIMEF, &OID)) != CRYPT_OK) { goto error; }
/* http://tools.ietf.org/html/rfc3279
ECParameters ::= SEQUENCE { # SEQUENCE
version INTEGER { ecpVer1(1) } (ecpVer1) # INTEGER :01
FieldID ::= SEQUENCE { # SEQUENCE
fieldType FIELD-ID.&id({IOSet}), # OBJECT :prime-field
parameters FIELD-ID.&Type({IOSet}{@fieldType}) # INTEGER
}
Curve ::= SEQUENCE { # SEQUENCE
a FieldElement ::= OCTET STRING # OCTET STRING
b FieldElement ::= OCTET STRING # OCTET STRING
seed BIT STRING OPTIONAL
}
base ECPoint ::= OCTET STRING # OCTET STRING
order INTEGER, # INTEGER
cofactor INTEGER OPTIONAL # INTEGER
}
*/
oidlen = sizeof(oid)/sizeof(oid[0]);
if ((err = pk_oid_str_to_num(OID, oid, &oidlen)) != CRYPT_OK) {
goto error;
}
/* FieldID SEQUENCE */
LTC_SET_ASN1(seq_fieldid, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid, oidlen);
LTC_SET_ASN1(seq_fieldid, 1, LTC_ASN1_INTEGER, prime, 1UL);
/* Curve SEQUENCE */
LTC_SET_ASN1(seq_curve, 0, LTC_ASN1_OCTET_STRING, bin_a, len_a);
LTC_SET_ASN1(seq_curve, 1, LTC_ASN1_OCTET_STRING, bin_b, len_b);
/* ECParameters SEQUENCE */
LTC_SET_ASN1(seq_ecparams, 0, LTC_ASN1_SHORT_INTEGER, &one, 1UL);
LTC_SET_ASN1(seq_ecparams, 1, LTC_ASN1_SEQUENCE, seq_fieldid, 2UL);
LTC_SET_ASN1(seq_ecparams, 2, LTC_ASN1_SEQUENCE, seq_curve, 2UL);
LTC_SET_ASN1(seq_ecparams, 3, LTC_ASN1_OCTET_STRING, bin_g, len_g);
LTC_SET_ASN1(seq_ecparams, 4, LTC_ASN1_INTEGER, order, 1UL);
LTC_SET_ASN1(seq_ecparams, 5, LTC_ASN1_SHORT_INTEGER, &cofactor, 1UL);
/* ECParameters used by ECPrivateKey or SubjectPublicKeyInfo below */
LTC_SET_ASN1(&ecparams, 0, LTC_ASN1_SEQUENCE, seq_ecparams, 6UL);
}
/* public key - (un)compressed based on flag_com */
len_xy = sizeof(bin_xy);
err = ltc_ecc_export_point(bin_xy, &len_xy, key->pubkey.x, key->pubkey.y, key->dp.size, flag_com);
if (err != CRYPT_OK) {
goto error;
}
if (flag_pri) {
/* http://tools.ietf.org/html/rfc5915
ECPrivateKey ::= SEQUENCE { # SEQUENCE
version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1) # INTEGER :01
privateKey OCTET STRING, # OCTET STRING
[0] ECParameters # see above
[1] publicKey # BIT STRING
}
*/
/* private key */
len_k = ltc_mp_unsigned_bin_size(key->k);
if (len_k > sizeof(bin_k)) { err = CRYPT_BUFFER_OVERFLOW; goto error; }
if ((err = ltc_mp_to_unsigned_bin(key->k, bin_k)) != CRYPT_OK) { goto error; }
LTC_SET_ASN1(&pub_xy, 0, LTC_ASN1_RAW_BIT_STRING, bin_xy, 8*len_xy);
LTC_SET_ASN1(seq_priv, 0, LTC_ASN1_SHORT_INTEGER, &one, 1);
LTC_SET_ASN1(seq_priv, 1, LTC_ASN1_OCTET_STRING, bin_k, len_k);
LTC_SET_ASN1_CUSTOM_CONSTRUCTED(seq_priv, 2, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0, &ecparams); /* context specific 0 */
LTC_SET_ASN1_CUSTOM_CONSTRUCTED(seq_priv, 3, LTC_ASN1_CL_CONTEXT_SPECIFIC, 1, &pub_xy); /* context specific 1 */
err = der_encode_sequence(seq_priv, 4, out, outlen);
}
else {
/* http://tools.ietf.org/html/rfc5480
SubjectPublicKeyInfo ::= SEQUENCE { # SEQUENCE
AlgorithmIdentifier ::= SEQUENCE { # SEQUENCE
algorithm OBJECT IDENTIFIER # OBJECT :id-ecPublicKey
ECParameters # see above
}
subjectPublicKey BIT STRING # BIT STRING
}
*/
err = x509_encode_subject_public_key_info( out, outlen, LTC_OID_EC, bin_xy, len_xy,
ecparams.type, ecparams.data, ecparams.size );
}
error:
return err;
}
#endif

View File

@@ -0,0 +1,241 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_MECC
static const struct {
const char *OID;
const char *names[6];
} s_curve_names[] = {
#ifdef LTC_ECC_SECP112R1
{
"1.3.132.0.6", { "SECP112R1", "ECC-112", NULL }
},
#endif
#ifdef LTC_ECC_SECP112R2
{
"1.3.132.0.7", { "SECP112R2", NULL }
},
#endif
#ifdef LTC_ECC_SECP128R1
{
"1.3.132.0.28", { "SECP128R1", "ECC-128", NULL }
},
#endif
#ifdef LTC_ECC_SECP128R2
{
"1.3.132.0.29", { "SECP128R2", NULL }
},
#endif
#ifdef LTC_ECC_SECP160R1
{
"1.3.132.0.8", { "SECP160R1", "ECC-160", NULL }
},
#endif
#ifdef LTC_ECC_SECP160R2
{
"1.3.132.0.30", { "SECP160R2", NULL }
},
#endif
#ifdef LTC_ECC_SECP160K1
{
"1.3.132.0.9", { "SECP160K1", NULL }
},
#endif
#ifdef LTC_ECC_SECP192R1
{
"1.2.840.10045.3.1.1", { "SECP192R1", "NISTP192", "PRIME192V1", "ECC-192", "P-192", NULL }
},
#endif
#ifdef LTC_ECC_PRIME192V2
{
"1.2.840.10045.3.1.2", { "PRIME192V2", NULL }
},
#endif
#ifdef LTC_ECC_PRIME192V3
{
"1.2.840.10045.3.1.3", { "PRIME192V3", NULL }
},
#endif
#ifdef LTC_ECC_SECP192K1
{
"1.3.132.0.31", { "SECP192K1", NULL }
},
#endif
#ifdef LTC_ECC_SECP224R1
{
"1.3.132.0.33", { "SECP224R1", "NISTP224", "ECC-224", "P-224", NULL }
},
#endif
#ifdef LTC_ECC_SECP224K1
{
"1.3.132.0.32", { "SECP224K1", NULL }
},
#endif
#ifdef LTC_ECC_SECP256R1
{
"1.2.840.10045.3.1.7", { "SECP256R1", "NISTP256", "PRIME256V1", "ECC-256", "P-256", NULL }
},
#endif
#ifdef LTC_ECC_SECP256K1
{
"1.3.132.0.10", { "SECP256K1", NULL }
},
#endif
#ifdef LTC_ECC_SECP384R1
{
"1.3.132.0.34", { "SECP384R1", "NISTP384", "ECC-384", "P-384", NULL }
},
#endif
#ifdef LTC_ECC_SECP521R1
{
"1.3.132.0.35", { "SECP521R1", "NISTP521", "ECC-521", "P-521", NULL }
},
#endif
#ifdef LTC_ECC_PRIME239V1
{
"1.2.840.10045.3.1.4", { "PRIME239V1", NULL }
},
#endif
#ifdef LTC_ECC_PRIME239V2
{
"1.2.840.10045.3.1.5", { "PRIME239V2", NULL }
},
#endif
#ifdef LTC_ECC_PRIME239V3
{
"1.2.840.10045.3.1.6", { "PRIME239V3", NULL }
},
#endif
#ifdef LTC_ECC_BRAINPOOLP160R1
{
"1.3.36.3.3.2.8.1.1.1", { "BRAINPOOLP160R1", NULL }
},
#endif
#ifdef LTC_ECC_BRAINPOOLP192R1
{
"1.3.36.3.3.2.8.1.1.3", { "BRAINPOOLP192R1", NULL }
},
#endif
#ifdef LTC_ECC_BRAINPOOLP224R1
{
"1.3.36.3.3.2.8.1.1.5", { "BRAINPOOLP224R1", NULL }
},
#endif
#ifdef LTC_ECC_BRAINPOOLP256R1
{
"1.3.36.3.3.2.8.1.1.7", { "BRAINPOOLP256R1", NULL }
},
#endif
#ifdef LTC_ECC_BRAINPOOLP320R1
{
"1.3.36.3.3.2.8.1.1.9", { "BRAINPOOLP320R1", NULL }
},
#endif
#ifdef LTC_ECC_BRAINPOOLP384R1
{
"1.3.36.3.3.2.8.1.1.11", { "BRAINPOOLP384R1", NULL }
},
#endif
#ifdef LTC_ECC_BRAINPOOLP512R1
{
"1.3.36.3.3.2.8.1.1.13", { "BRAINPOOLP512R1", NULL }
},
#endif
#ifdef LTC_ECC_BRAINPOOLP160T1
{
"1.3.36.3.3.2.8.1.1.2", { "BRAINPOOLP160T1", NULL }
},
#endif
#ifdef LTC_ECC_BRAINPOOLP192T1
{
"1.3.36.3.3.2.8.1.1.4", { "BRAINPOOLP192T1", NULL }
},
#endif
#ifdef LTC_ECC_BRAINPOOLP224T1
{
"1.3.36.3.3.2.8.1.1.6", { "BRAINPOOLP224T1", NULL }
},
#endif
#ifdef LTC_ECC_BRAINPOOLP256T1
{
"1.3.36.3.3.2.8.1.1.8", { "BRAINPOOLP256T1", NULL }
},
#endif
#ifdef LTC_ECC_BRAINPOOLP320T1
{
"1.3.36.3.3.2.8.1.1.10", { "BRAINPOOLP320T1", NULL }
},
#endif
#ifdef LTC_ECC_BRAINPOOLP384T1
{
"1.3.36.3.3.2.8.1.1.12", { "BRAINPOOLP384T1", NULL }
},
#endif
#ifdef LTC_ECC_BRAINPOOLP512T1
{
"1.3.36.3.3.2.8.1.1.14", { "BRAINPOOLP512T1", NULL }
},
#endif
{
NULL, { NULL }
}
};
/* case-insensitive match + ignore '-', '_', ' ' */
static int s_name_match(const char *left, const char *right)
{
char lc_r, lc_l;
while ((*left != '\0') && (*right != '\0')) {
while ((*left == ' ') || (*left == '-') || (*left == '_')) left++;
while ((*right == ' ') || (*right == '-') || (*right == '_')) right++;
if (*left == '\0' || *right == '\0') break;
lc_r = *right;
lc_l = *left;
if ((lc_r >= 'A') && (lc_r <= 'Z')) lc_r += 32;
if ((lc_l >= 'A') && (lc_l <= 'Z')) lc_l += 32;
if (lc_l != lc_r) return 0;
left++;
right++;
}
if ((*left == '\0') && (*right == '\0')) return 1;
return 0;
}
int ecc_find_curve(const char *name_or_oid, const ltc_ecc_curve **cu)
{
int i, j;
const char *OID = NULL;
LTC_ARGCHK(name_or_oid != NULL);
if (cu) *cu = NULL;
for (i = 0; s_curve_names[i].OID != NULL && !OID; i++) {
if (XSTRCMP(s_curve_names[i].OID, name_or_oid) == 0) {
OID = s_curve_names[i].OID;
}
for (j = 0; s_curve_names[i].names[j] != NULL && !OID; j++) {
if (s_name_match(s_curve_names[i].names[j], name_or_oid)) {
OID = s_curve_names[i].OID;
}
}
}
if (OID != NULL) {
for (i = 0; ltc_ecc_curves[i].prime != NULL; i++) {
if (XSTRCMP(ltc_ecc_curves[i].OID, OID) == 0) {
if (cu) *cu = &ltc_ecc_curves[i];
return CRYPT_OK;
}
}
}
return CRYPT_INVALID_ARG; /* not found */
}
#endif

View File

@@ -0,0 +1,28 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file ecc_free.c
ECC Crypto, Tom St Denis
*/
#ifdef LTC_MECC
/**
Free an ECC key from memory
@param key The key you wish to free
*/
void ecc_free(ecc_key *key)
{
LTC_ARGCHKVD(key != NULL);
ltc_mp_cleanup_multi(&key->dp.prime, &key->dp.order,
&key->dp.A, &key->dp.B,
&key->dp.base.x, &key->dp.base.y, &key->dp.base.z,
&key->pubkey.x, &key->pubkey.y, &key->pubkey.z,
&key->k, NULL);
}
#endif

View File

@@ -0,0 +1,53 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_MECC
/** Export raw public or private key (public keys = ANS X9.63 compressed or uncompressed; private keys = raw bytes)
@param out [out] destination of export
@param outlen [in/out] Length of destination and final output size
@param type PK_PRIVATE, PK_PUBLIC or PK_PUBLIC|PK_COMPRESSED
@param key Key to export
Return CRYPT_OK on success
*/
int ecc_get_key(unsigned char *out, unsigned long *outlen, int type, const ecc_key *key)
{
unsigned long size, ksize;
int err, compressed;
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
size = key->dp.size;
compressed = type & PK_COMPRESSED ? 1 : 0;
type &= ~PK_COMPRESSED;
if (type == PK_PUBLIC) {
if ((err = ltc_ecc_export_point(out, outlen, key->pubkey.x, key->pubkey.y, size, compressed)) != CRYPT_OK) {
return err;
}
}
else if (type == PK_PRIVATE) {
if (key->type != PK_PRIVATE) return CRYPT_PK_TYPE_MISMATCH;
if (size > *outlen) {
*outlen = size;
return CRYPT_BUFFER_OVERFLOW;
}
*outlen = size;
if ((ksize = ltc_mp_unsigned_bin_size(key->k)) > size) return CRYPT_BUFFER_OVERFLOW;
/* pad and store k */
if ((err = ltc_mp_to_unsigned_bin(key->k, out + (size - ksize))) != CRYPT_OK) return err;
zeromem(out, size - ksize);
}
else {
return CRYPT_INVALID_ARG;
}
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,22 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_MECC
/** Extract OID as a string from ECC key
@param out [out] destination buffer
@param outlen [in/out] Length of destination buffer and final output size (without terminating NUL byte)
@param key The ECC key
Return CRYPT_OK on success
*/
int ecc_get_oid_str(char *out, unsigned long *outlen, const ecc_key *key)
{
LTC_ARGCHK(key != NULL);
return pk_oid_num_to_str(key->dp.oid, key->dp.oidlen, out, outlen);
}
#endif

View File

@@ -0,0 +1,26 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file ecc_get_size.c
ECC Crypto, Tom St Denis
*/
#ifdef LTC_MECC
/**
Get the size of an ECC key
@param key The key to get the size of
@return The size (octets) of the key or INT_MAX on error
*/
int ecc_get_size(const ecc_key *key)
{
if (key == NULL) {
return INT_MAX;
}
return key->dp.size;
}
#endif

View File

@@ -0,0 +1,106 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
/**
@file ecc_import.c
ECC Crypto, Tom St Denis
*/
#if defined(LTC_MECC) && defined(LTC_DER)
/**
Import an ECC key from a binary packet
@param in The packet to import
@param inlen The length of the packet
@param key [out] The destination of the import
@return CRYPT_OK if successful, upon error all allocated memory will be freed
*/
int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key)
{
return ecc_import_ex(in, inlen, key, NULL);
}
/**
Import an ECC key from a binary packet, using user supplied domain params rather than one of the NIST ones
@param in The packet to import
@param inlen The length of the packet
@param key [out] The destination of the import
@param cu pointer to user supplied params; must be the same as the params used when exporting
@return CRYPT_OK if successful, upon error all allocated memory will be freed
*/
int ecc_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, const ltc_ecc_curve *cu)
{
unsigned long key_size;
unsigned char flags[1];
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(ltc_mp.name != NULL);
/* find out what type of key it is */
err = der_decode_sequence_multi(in, inlen, LTC_ASN1_BIT_STRING, 1UL, flags,
LTC_ASN1_SHORT_INTEGER, 1UL, &key_size,
LTC_ASN1_EOL, 0UL, NULL);
if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) {
return err;
}
/* allocate & initialize the key */
if (cu == NULL) {
if ((err = ecc_set_curve_by_size(key_size, key)) != CRYPT_OK) { goto done; }
} else {
if ((err = ecc_set_curve(cu, key)) != CRYPT_OK) { goto done; }
}
if (flags[0] == 1) {
/* private key */
key->type = PK_PRIVATE;
if ((err = der_decode_sequence_multi(in, inlen,
LTC_ASN1_BIT_STRING, 1UL, flags,
LTC_ASN1_SHORT_INTEGER, 1UL, &key_size,
LTC_ASN1_INTEGER, 1UL, key->pubkey.x,
LTC_ASN1_INTEGER, 1UL, key->pubkey.y,
LTC_ASN1_INTEGER, 1UL, key->k,
LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) {
goto done;
}
} else if (flags[0] == 0) {
/* public key */
key->type = PK_PUBLIC;
if ((err = der_decode_sequence_multi(in, inlen,
LTC_ASN1_BIT_STRING, 1UL, flags,
LTC_ASN1_SHORT_INTEGER, 1UL, &key_size,
LTC_ASN1_INTEGER, 1UL, key->pubkey.x,
LTC_ASN1_INTEGER, 1UL, key->pubkey.y,
LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) {
goto done;
}
}
else {
err = CRYPT_INVALID_PACKET;
goto done;
}
/* set z */
if ((err = ltc_mp_set(key->pubkey.z, 1)) != CRYPT_OK) { goto done; }
/* point on the curve + other checks */
if ((err = ltc_ecc_verify_key(key)) != CRYPT_OK) { goto done; }
/* we're good */
return CRYPT_OK;
done:
ecc_free(key);
return err;
}
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,142 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#if defined(LTC_MECC) && defined(LTC_DER)
static int s_ecc_import_private_with_oid(const unsigned char *in, unsigned long inlen, ecc_key *key)
{
ltc_asn1_list seq_priv[4], custom[2];
unsigned char bin_xy[2*ECC_MAXSIZE+2], bin_k[ECC_MAXSIZE];
unsigned long pkver = 0, curveoid[16];
int err;
/* ### try to load private key - no curve parameters just curve OID */
/* ECPrivateKey SEQUENCE */
LTC_SET_ASN1(custom, 0, LTC_ASN1_OBJECT_IDENTIFIER, curveoid, 16UL);
LTC_SET_ASN1(custom, 1, LTC_ASN1_RAW_BIT_STRING, bin_xy, 8UL*sizeof(bin_xy));
LTC_SET_ASN1(seq_priv, 0, LTC_ASN1_SHORT_INTEGER, &pkver, 1UL);
LTC_SET_ASN1(seq_priv, 1, LTC_ASN1_OCTET_STRING, bin_k, sizeof(bin_k));
LTC_SET_ASN1_CUSTOM_CONSTRUCTED(seq_priv, 2, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0, custom); /* context specific 0 */
LTC_SET_ASN1_CUSTOM_CONSTRUCTED(seq_priv, 3, LTC_ASN1_CL_CONTEXT_SPECIFIC, 1, custom + 1); /* context specific 1 */
/* try to load private key */
err = der_decode_sequence(in, inlen, seq_priv, 4);
if (err != CRYPT_OK) { goto error; }
err = ecc_import_with_oid(bin_k, seq_priv[1].size, curveoid, custom[0].size, PK_PRIVATE, key);
error:
return err;
}
int ecc_import_with_oid(const unsigned char *in, unsigned long inlen, unsigned long *oid, unsigned long oid_len, int type, ecc_key *key)
{
char OID[256];
unsigned long len;
const ltc_ecc_curve *curve;
int err;
/* load curve parameters for given curve OID */
len = sizeof(OID);
if ((err = pk_oid_num_to_str(oid, oid_len, OID, &len)) != CRYPT_OK) { goto error; }
if ((err = ecc_find_curve(OID, &curve)) != CRYPT_OK) { goto error; }
if ((err = ecc_set_curve(curve, key)) != CRYPT_OK) { goto error; }
/* load public key */
err = ecc_set_key(in, inlen, type, key);
error:
return err;
}
int ecc_import_with_curve(const unsigned char *in, unsigned long inlen, int type, ecc_key *key)
{
void *prime, *order, *a, *b, *gx, *gy;
ltc_asn1_list seq_fieldid[2], seq_curve[3], seq_ecparams[6], seq_priv[4], custom[2];
unsigned char bin_a[ECC_MAXSIZE], bin_b[ECC_MAXSIZE], bin_k[ECC_MAXSIZE];
unsigned char bin_g[2*ECC_MAXSIZE+1], bin_xy[2*ECC_MAXSIZE+2], bin_seed[128];
unsigned long len_a, len_b, len_k, len_g, len_xy, len;
unsigned long cofactor = 0, ecver = 0, pkver = 0, tmpoid[16];
int err;
if ((err = ltc_mp_init_multi(&prime, &order, &a, &b, &gx, &gy, LTC_NULL)) != CRYPT_OK) {
return err;
}
/* FieldID SEQUENCE */
LTC_SET_ASN1(seq_fieldid, 0, LTC_ASN1_OBJECT_IDENTIFIER, tmpoid, 16UL);
LTC_SET_ASN1(seq_fieldid, 1, LTC_ASN1_INTEGER, prime, 1UL);
/* Curve SEQUENCE */
LTC_SET_ASN1(seq_curve, 0, LTC_ASN1_OCTET_STRING, bin_a, sizeof(bin_a));
LTC_SET_ASN1(seq_curve, 1, LTC_ASN1_OCTET_STRING, bin_b, sizeof(bin_b));
LTC_SET_ASN1(seq_curve, 2, LTC_ASN1_RAW_BIT_STRING, bin_seed, 8UL*sizeof(bin_seed));
seq_curve[2].optional = 1;
/* ECParameters SEQUENCE */
LTC_SET_ASN1(seq_ecparams, 0, LTC_ASN1_SHORT_INTEGER, &ecver, 1UL);
LTC_SET_ASN1(seq_ecparams, 1, LTC_ASN1_SEQUENCE, seq_fieldid, 2UL);
LTC_SET_ASN1(seq_ecparams, 2, LTC_ASN1_SEQUENCE, seq_curve, 3UL);
LTC_SET_ASN1(seq_ecparams, 3, LTC_ASN1_OCTET_STRING, bin_g, sizeof(bin_g));
LTC_SET_ASN1(seq_ecparams, 4, LTC_ASN1_INTEGER, order, 1UL);
LTC_SET_ASN1(seq_ecparams, 5, LTC_ASN1_SHORT_INTEGER, &cofactor, 1UL);
seq_ecparams[5].optional = 1;
if (type == PK_PRIVATE) {
/* ECPrivateKey SEQUENCE */
LTC_SET_ASN1(custom, 0, LTC_ASN1_SEQUENCE, seq_ecparams, 6UL);
LTC_SET_ASN1(custom, 1, LTC_ASN1_RAW_BIT_STRING, bin_xy, 8UL*sizeof(bin_xy));
LTC_SET_ASN1(seq_priv, 0, LTC_ASN1_SHORT_INTEGER, &pkver, 1UL);
LTC_SET_ASN1(seq_priv, 1, LTC_ASN1_OCTET_STRING, bin_k, sizeof(bin_k));
LTC_SET_ASN1_CUSTOM_CONSTRUCTED(seq_priv, 2, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0, custom); /* context specific 0 */
LTC_SET_ASN1_CUSTOM_CONSTRUCTED(seq_priv, 3, LTC_ASN1_CL_CONTEXT_SPECIFIC, 1, custom + 1); /* context specific 1 */
/* try to load private key */
err = der_decode_sequence(in, inlen, seq_priv, 4);
} else if (type == PK_PUBLIC) {
/* try to load public key */
len_xy = sizeof(bin_xy);
len = 6;
err = x509_decode_subject_public_key_info(in, inlen, LTC_OID_EC, bin_xy, &len_xy, LTC_ASN1_SEQUENCE, seq_ecparams, &len);
} else {
err = CRYPT_PK_INVALID_TYPE;
}
if (err == CRYPT_OK) {
len_a = seq_curve[0].size;
len_b = seq_curve[1].size;
len_g = seq_ecparams[3].size;
/* create bignums */
if ((err = ltc_mp_read_unsigned_bin(a, bin_a, len_a)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_read_unsigned_bin(b, bin_b, len_b)) != CRYPT_OK) { goto error; }
if ((err = ltc_ecc_import_point(bin_g, len_g, prime, a, b, gx, gy)) != CRYPT_OK) { goto error; }
/* load curve parameters */
if ((err = ecc_set_curve_from_mpis(a, b, prime, order, gx, gy, cofactor, key)) != CRYPT_OK) { goto error; }
if (type == PK_PRIVATE) {
len_k = seq_priv[1].size;
/* load private+public key */
err = ecc_set_key(bin_k, len_k, PK_PRIVATE, key);
} else {
/* load public key */
err = ecc_set_key(bin_xy, len_xy, PK_PUBLIC, key);
}
}
error:
ltc_mp_deinit_multi(prime, order, a, b, gx, gy, LTC_NULL);
return err;
}
int ecc_import_openssl(const unsigned char *in, unsigned long inlen, ecc_key *key)
{
int err;
if ((err = ecc_import_subject_public_key_info(in, inlen, key)) == CRYPT_OK) {
goto success;
}
if ((err = s_ecc_import_private_with_oid(in, inlen, key)) == CRYPT_OK) {
goto success;
}
err = ecc_import_with_curve(in, inlen, PK_PRIVATE, key);
success:
return err;
}
#endif

View File

@@ -0,0 +1,173 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#if defined(LTC_MECC) && defined(LTC_DER)
int ecc_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, ecc_key *key)
{
void *a, *b, *gx, *gy;
unsigned long len, cofactor, n;
int err;
char OID[256];
const ltc_ecc_curve *curve;
ltc_asn1_list *p = NULL;
der_flexi_check case2_should[7];
ltc_asn1_list *version, *field, *point, *point_g, *order, *p_cofactor;
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(ltc_mp.name != NULL);
/* init key */
err = ltc_mp_init_multi(&a, &b, &gx, &gy, LTC_NULL);
if (err != CRYPT_OK) goto LBL_DER_FREE;
/* Setup for CASE 2 */
n=0;
LTC_SET_DER_FLEXI_CHECK(case2_should, n++, LTC_ASN1_INTEGER, &version);
LTC_SET_DER_FLEXI_CHECK(case2_should, n++, LTC_ASN1_SEQUENCE, &field);
LTC_SET_DER_FLEXI_CHECK(case2_should, n++, LTC_ASN1_SEQUENCE, &point);
LTC_SET_DER_FLEXI_CHECK(case2_should, n++, LTC_ASN1_OCTET_STRING, &point_g);
LTC_SET_DER_FLEXI_CHECK(case2_should, n++, LTC_ASN1_INTEGER, &order);
LTC_SET_DER_FLEXI_CHECK(case2_should, n++, LTC_ASN1_INTEGER, &p_cofactor);
LTC_SET_DER_FLEXI_CHECK(case2_should, n, LTC_ASN1_EOL, NULL);
if (LTC_ASN1_IS_TYPE(alg_id->child->next, LTC_ASN1_OBJECT_IDENTIFIER)) {
/* CASE 1: curve by OID (AKA short variant):
* 0:d=0 hl=2 l= 100 cons: SEQUENCE
* 2:d=1 hl=2 l= 1 prim: INTEGER :00
* 5:d=1 hl=2 l= 16 cons: SEQUENCE (== *seq)
* 7:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey
* 16:d=2 hl=2 l= 5 prim: OBJECT :(== *curve_oid (e.g. secp256k1 (== 1.3.132.0.10)))
* 23:d=1 hl=2 l= 77 prim: OCTET STRING :bytes (== *priv_key)
*/
ltc_asn1_list *curve_oid = alg_id->child->next;
len = sizeof(OID);
if ((err = pk_oid_num_to_str(curve_oid->data, curve_oid->size, OID, &len)) != CRYPT_OK) { goto LBL_DONE; }
if ((err = ecc_find_curve(OID, &curve)) != CRYPT_OK) { goto LBL_DONE; }
if ((err = ecc_set_curve(curve, key)) != CRYPT_OK) { goto LBL_DONE; }
} else if (der_flexi_sequence_cmp(alg_id->child->next, case2_should) == CRYPT_OK) {
/* CASE 2: explicit curve parameters (AKA long variant):
* 0:d=0 hl=3 l= 227 cons: SEQUENCE
* 3:d=1 hl=2 l= 1 prim: INTEGER :00
* 6:d=1 hl=3 l= 142 cons: SEQUENCE (== *seq)
* 9:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey
* 18:d=2 hl=3 l= 130 cons: SEQUENCE
* 21:d=3 hl=2 l= 1 prim: INTEGER :01
* 24:d=3 hl=2 l= 44 cons: SEQUENCE (== *field)
* 26:d=4 hl=2 l= 7 prim: OBJECT :prime-field
* 35:d=4 hl=2 l= 33 prim: INTEGER :(== *prime / curve.prime)
* 70:d=3 hl=2 l= 6 cons: SEQUENCE (== *point)
* 72:d=4 hl=2 l= 1 prim: OCTET STRING :bytes (== curve.A)
* 75:d=4 hl=2 l= 1 prim: OCTET STRING :bytes (== curve.B)
* 78:d=3 hl=2 l= 33 prim: OCTET STRING :bytes (== *g_point / curve.G-point)
* 113:d=3 hl=2 l= 33 prim: INTEGER :(== *order / curve.order)
* 148:d=3 hl=2 l= 1 prim: INTEGER :(== curve.cofactor)
* 151:d=1 hl=2 l= 77 prim: OCTET STRING :bytes (== *priv_key)
*/
if (ltc_mp_cmp_d(version->data, 1) != LTC_MP_EQ) {
goto LBL_DONE;
}
cofactor = ltc_mp_get_int(p_cofactor->data);
if (LTC_ASN1_IS_TYPE(field->child, LTC_ASN1_OBJECT_IDENTIFIER) &&
LTC_ASN1_IS_TYPE(field->child->next, LTC_ASN1_INTEGER) &&
LTC_ASN1_IS_TYPE(point->child, LTC_ASN1_OCTET_STRING) &&
LTC_ASN1_IS_TYPE(point->child->next, LTC_ASN1_OCTET_STRING)) {
ltc_asn1_list *prime = field->child->next;
if ((err = ltc_mp_read_unsigned_bin(a, point->child->data, point->child->size)) != CRYPT_OK) {
goto LBL_DONE;
}
if ((err = ltc_mp_read_unsigned_bin(b, point->child->next->data, point->child->next->size)) != CRYPT_OK) {
goto LBL_DONE;
}
if ((err = ltc_ecc_import_point(point_g->data, point_g->size, prime->data, a, b, gx, gy)) != CRYPT_OK) {
goto LBL_DONE;
}
if ((err = ecc_set_curve_from_mpis(a, b, prime->data, order->data, gx, gy, cofactor, key)) != CRYPT_OK) {
goto LBL_DONE;
}
}
} else {
err = CRYPT_INVALID_PACKET;
goto LBL_DONE;
}
/* load private key value 'k' */
len = priv_key->size;
if (der_decode_sequence_flexi(priv_key->data, &len, &p) == CRYPT_OK) {
if (p->type == LTC_ASN1_SEQUENCE &&
LTC_ASN1_IS_TYPE(p->child, LTC_ASN1_INTEGER) &&
LTC_ASN1_IS_TYPE(p->child->next, LTC_ASN1_OCTET_STRING)) {
ltc_asn1_list *lk = p->child->next;
if (ltc_mp_cmp_d(p->child->data, 1) != LTC_MP_EQ) {
err = CRYPT_INVALID_PACKET;
goto LBL_ECCFREE;
}
if ((err = ecc_set_key(lk->data, lk->size, PK_PRIVATE, key)) != CRYPT_OK) {
goto LBL_ECCFREE;
}
goto LBL_DONE; /* success */
}
}
err = CRYPT_INVALID_PACKET;
goto LBL_DONE;
LBL_ECCFREE:
ecc_free(key);
LBL_DONE:
ltc_mp_deinit_multi(a, b, gx, gy, LTC_NULL);
LBL_DER_FREE:
if (p) der_free_sequence_flexi(p);
return err;
}
/**
Import an ECC private from in PKCS#8 format
@param in The packet to import from
@param inlen It's length (octets)
@param pw_ctx The password context when decrypting the private key
@param key [out] Destination for newly imported key
@return CRYPT_OK if successful, upon error allocated memory is freed
*/
int ecc_import_pkcs8(const unsigned char *in, unsigned long inlen,
const password_ctx *pw_ctx,
ecc_key *key)
{
int err;
ltc_asn1_list *l = NULL;
ltc_asn1_list *alg_id, *priv_key;
enum ltc_oid_id pka;
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(ltc_mp.name != NULL);
err = pkcs8_decode_flexi(in, inlen, pw_ctx, &l);
if (err != CRYPT_OK) return err;
if ((err = pkcs8_get_children(l, &pka, &alg_id, &priv_key)) != CRYPT_OK) {
goto LBL_DER_FREE;
}
if (pka != LTC_OID_EC) {
err = CRYPT_INVALID_PACKET;
goto LBL_DER_FREE;
}
err = ecc_import_pkcs8_asn1(alg_id, priv_key, key);
LBL_DER_FREE:
der_free_sequence_flexi(l);
return err;
}
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,54 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#if defined(LTC_MECC) && defined(LTC_DER)
static int s_ecc_import_x509_with_oid(const unsigned char *in, unsigned long inlen, ecc_key *key)
{
unsigned char bin_xy[2*ECC_MAXSIZE+2];
unsigned long curveoid[16];
unsigned long len_xy, len_oid;
int err;
len_xy = sizeof(bin_xy);
len_oid = 16;
err = x509_decode_subject_public_key_info(in, inlen, LTC_OID_EC, bin_xy, &len_xy,
LTC_ASN1_OBJECT_IDENTIFIER, (void *)curveoid, &len_oid);
if (err != CRYPT_OK) { goto error; }
err = ecc_import_with_oid(bin_xy, len_xy, curveoid, len_oid, PK_PUBLIC, key);
error:
return err;
}
int ecc_import_subject_public_key_info(const unsigned char *in, unsigned long inlen, ecc_key *key)
{
int err;
if ((err = s_ecc_import_x509_with_oid(in, inlen, key)) == CRYPT_OK) {
goto success;
}
err = ecc_import_with_curve(in, inlen, PK_PUBLIC, key);
success:
return err;
}
/**
Import an ECC key from a X.509 certificate
@param in The packet to import from
@param inlen It's length (octets)
@param key [out] Destination for newly imported key
@return CRYPT_OK if successful, upon error allocated memory is freed
*/
int ecc_import_x509(const unsigned char *in, unsigned long inlen, ecc_key *key)
{
return x509_decode_public_key_from_certificate(in, inlen,
LTC_OID_EC,
LTC_ASN1_EOL, NULL, NULL,
(public_key_decode_cb)ecc_import_subject_public_key_info, key);
}
#endif /* LTC_MECC */

View File

@@ -0,0 +1,73 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file ecc_make_key.c
ECC Crypto, Tom St Denis
*/
#ifdef LTC_MECC
/**
Make a new ECC key
@param prng An active PRNG state
@param wprng The index of the PRNG you wish to use
@param keysize The keysize for the new key (in octets from 20 to 65 bytes)
@param key [out] Destination of the newly created key
@return CRYPT_OK if successful, upon error all allocated memory will be freed
*/
int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key)
{
int err;
if ((err = ecc_set_curve_by_size(keysize, key)) != CRYPT_OK) { return err; }
if ((err = ecc_generate_key(prng, wprng, key)) != CRYPT_OK) { return err; }
return CRYPT_OK;
}
int ecc_make_key_ex(prng_state *prng, int wprng, ecc_key *key, const ltc_ecc_curve *cu)
{
int err;
if ((err = ecc_set_curve(cu, key)) != CRYPT_OK) { return err; }
if ((err = ecc_generate_key(prng, wprng, key)) != CRYPT_OK) { return err; }
return CRYPT_OK;
}
int ecc_generate_key(prng_state *prng, int wprng, ecc_key *key)
{
int err;
LTC_ARGCHK(ltc_mp.name != NULL);
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(key->dp.size > 0);
/* ECC key pair generation according to FIPS-186-4 (B.4.2 Key Pair Generation by Testing Candidates):
* the generated private key k should be the range [1, order-1]
* a/ N = bitlen(order)
* b/ generate N random bits and convert them into big integer k
* c/ if k not in [1, order-1] go to b/
* e/ Q = k*G
*/
if ((err = rand_bn_upto(key->k, key->dp.order, prng, wprng)) != CRYPT_OK) {
goto error;
}
/* make the public key */
if ((err = ltc_mp.ecc_ptmul(key->k, &key->dp.base, &key->pubkey, key->dp.A, key->dp.prime, 1)) != CRYPT_OK) {
goto error;
}
key->type = PK_PRIVATE;
/* success */
err = CRYPT_OK;
goto cleanup;
error:
ecc_free(key);
cleanup:
return err;
}
#endif

View File

@@ -0,0 +1,265 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#if defined(LTC_MECC) && defined(LTC_ECC_SHAMIR)
/**
@file ecc_recover_key.c
ECC Crypto, Russ Williams
*/
/**
Recover ECC public key from signature and hash
@param sig The signature to verify
@param siglen The length of the signature (octets)
@param hash The hash (message digest) that was signed
@param hashlen The length of the hash (octets)
@param recid The recovery ID ("v"), can be -1 if signature contains it
@param sigformat The format of the signature (ecc_signature_type)
@param key The recovered public ECC key
@return CRYPT_OK if successful (even if the signature is not valid)
*/
int ecc_recover_key(const unsigned char *sig, unsigned long siglen,
const unsigned char *hash, unsigned long hashlen,
int recid, ecc_signature_type sigformat, ecc_key *key)
{
ecc_point *mG = NULL, *mQ = NULL, *mR = NULL;
void *p, *m, *a, *b;
void *r, *s, *v, *w, *t1, *t2, *u1, *u2, *v1, *v2, *e, *x, *y, *a_plus3;
void *mu = NULL, *ma = NULL;
void *mp = NULL;
int err;
unsigned long pbits, pbytes, i, shift_right;
unsigned char ch, buf[MAXBLOCKSIZE];
LTC_ARGCHK(sig != NULL);
LTC_ARGCHK(hash != NULL);
LTC_ARGCHK(key != NULL);
/* BEWARE: requires sqrtmod_prime */
if (ltc_mp.sqrtmod_prime == NULL) {
return CRYPT_ERROR;
}
/* allocate ints */
if ((err = ltc_mp_init_multi(&r, &s, &v, &w, &t1, &t2, &u1, &u2, &v1, &v2, &e, &x, &y, &a_plus3, LTC_NULL)) != CRYPT_OK) {
return err;
}
p = key->dp.order;
m = key->dp.prime;
a = key->dp.A;
b = key->dp.B;
if ((err = ltc_mp_add_d(a, 3, a_plus3)) != CRYPT_OK) {
goto error;
}
/* allocate points */
mG = ltc_ecc_new_point();
mQ = ltc_ecc_new_point();
mR = ltc_ecc_new_point();
if (mR == NULL || mQ == NULL || mG == NULL) {
err = CRYPT_MEM;
goto error;
}
if (sigformat == LTC_ECCSIG_RFC7518) {
/* RFC7518 format - raw (r,s) */
i = ltc_mp_unsigned_bin_size(key->dp.order);
if (siglen != (2*i)) {
err = CRYPT_INVALID_PACKET;
goto error;
}
if ((err = ltc_mp_read_unsigned_bin(r, sig, i)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_read_unsigned_bin(s, sig+i, i)) != CRYPT_OK) { goto error; }
}
else if (sigformat == LTC_ECCSIG_ETH27) {
/* Ethereum (v,r,s) format */
if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
/* Only valid for secp256k1 - OID 1.3.132.0.10 */
err = CRYPT_ERROR; goto error;
}
if (siglen != 65) { /* Only secp256k1 curves use this format, so must be 65 bytes long */
err = CRYPT_INVALID_PACKET;
goto error;
}
i = (unsigned long)sig[64];
if ((i>=27) && (i<31)) i -= 27; /* Ethereum adds 27 to recovery ID */
if (recid >= 0 && ((unsigned long)recid != i)) {
/* Recovery ID specified, but doesn't match signature */
err = CRYPT_INVALID_PACKET;
goto error;
}
recid = i;
if ((err = ltc_mp_read_unsigned_bin(r, sig, 32)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_read_unsigned_bin(s, sig+32, 32)) != CRYPT_OK) { goto error; }
}
#ifdef LTC_DER
else if (sigformat == LTC_ECCSIG_ANSIX962) {
/* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) } */
if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
LTC_ASN1_INTEGER, 1UL, r,
LTC_ASN1_INTEGER, 1UL, s,
LTC_ASN1_EOL, 0UL, LTC_NULL)) != CRYPT_OK) { goto error; }
}
#endif
#ifdef LTC_SSH
else if (sigformat == LTC_ECCSIG_RFC5656) {
char name[64], name2[64];
unsigned long namelen = sizeof(name);
unsigned long name2len = sizeof(name2);
/* Decode as SSH data sequence, per RFC4251 */
if ((err = ssh_decode_sequence_multi(sig, &siglen,
LTC_SSHDATA_STRING, name, &namelen,
LTC_SSHDATA_MPINT, r,
LTC_SSHDATA_MPINT, s,
LTC_SSHDATA_EOL, LTC_NULL)) != CRYPT_OK) { goto error; }
/* Check curve matches identifier string */
if ((err = ecc_ssh_ecdsa_encode_name(name2, &name2len, key)) != CRYPT_OK) { goto error; }
if ((namelen != name2len) || (XSTRCMP(name, name2) != 0)) {
err = CRYPT_INVALID_ARG;
goto error;
}
}
#endif
else {
/* Unknown signature format */
err = CRYPT_ERROR;
goto error;
}
if (recid < 0 || (unsigned long)recid >= 2*(key->dp.cofactor+1)) {
/* Recovery ID is out of range, reject it */
err = CRYPT_INVALID_ARG;
goto error;
}
/* check for zero */
if (ltc_mp_cmp_d(r, 0) != LTC_MP_GT || ltc_mp_cmp_d(s, 0) != LTC_MP_GT ||
ltc_mp_cmp(r, p) != LTC_MP_LT || ltc_mp_cmp(s, p) != LTC_MP_LT) {
err = CRYPT_INVALID_PACKET;
goto error;
}
/* read hash - truncate if needed */
pbits = ltc_mp_count_bits(p);
pbytes = (pbits+7) >> 3;
if (pbits > hashlen*8) {
if ((err = ltc_mp_read_unsigned_bin(e, hash, hashlen)) != CRYPT_OK) { goto error; }
}
else if (pbits % 8 == 0) {
if ((err = ltc_mp_read_unsigned_bin(e, hash, pbytes)) != CRYPT_OK) { goto error; }
}
else {
shift_right = 8 - pbits % 8;
for (i=0, ch=0; i<pbytes; i++) {
buf[i] = ch;
ch = (hash[i] << (8-shift_right));
buf[i] = buf[i] ^ (hash[i] >> shift_right);
}
if ((err = ltc_mp_read_unsigned_bin(e, buf, pbytes)) != CRYPT_OK) { goto error; }
}
/* decompress point from r=(x mod p) - BEWARE: requires sqrtmod_prime */
/* x = r + p*(recid/2) */
if ((err = ltc_mp_set(x, recid/2)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_mulmod(p, x, m, x)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_add(x, r, x)) != CRYPT_OK) { goto error; }
/* compute x^3 */
if ((err = ltc_mp_sqr(x, t1)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_mulmod(t1, x, m, t1)) != CRYPT_OK) { goto error; }
/* compute x^3 + a*x */
if ((err = ltc_mp_mulmod(a, x, m, t2)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_add(t1, t2, t1)) != CRYPT_OK) { goto error; }
/* compute x^3 + a*x + b */
if ((err = ltc_mp_add(t1, b, t1)) != CRYPT_OK) { goto error; }
/* compute sqrt(x^3 + a*x + b) */
if ((err = ltc_mp_sqrtmod_prime(t1, m, t2)) != CRYPT_OK) { goto error; }
/* fill in mR */
if ((err = ltc_mp_copy(x, mR->x)) != CRYPT_OK) { goto error; }
if ((ltc_mp_isodd(t2) && (recid%2)) || (!ltc_mp_isodd(t2) && !(recid%2))) {
if ((err = ltc_mp_mod(t2, m, mR->y)) != CRYPT_OK) { goto error; }
}
else {
if ((err = ltc_mp_submod(m, t2, m, mR->y)) != CRYPT_OK) { goto error; }
}
if ((err = ltc_mp_set(mR->z, 1)) != CRYPT_OK) { goto error; }
/* w = r^-1 mod n */
if ((err = ltc_mp_invmod(r, p, w)) != CRYPT_OK) { goto error; }
/* v1 = sw */
if ((err = ltc_mp_mulmod(s, w, p, v1)) != CRYPT_OK) { goto error; }
/* v2 = -ew */
if ((err = ltc_mp_mulmod(e, w, p, v2)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_submod(p, v2, p, v2)) != CRYPT_OK) { goto error; }
/* w = s^-1 mod n */
if ((err = ltc_mp_invmod(s, p, w)) != CRYPT_OK) { goto error; }
/* u1 = ew */
if ((err = ltc_mp_mulmod(e, w, p, u1)) != CRYPT_OK) { goto error; }
/* u2 = rw */
if ((err = ltc_mp_mulmod(r, w, p, u2)) != CRYPT_OK) { goto error; }
/* find mG */
if ((err = ltc_ecc_copy_point(&key->dp.base, mG)) != CRYPT_OK) { goto error; }
/* find the montgomery mp */
if ((err = ltc_mp_montgomery_setup(m, &mp)) != CRYPT_OK) { goto error; }
/* for curves with a == -3 keep ma == NULL */
if (ltc_mp_cmp(a_plus3, m) != LTC_MP_EQ) {
if ((err = ltc_mp_init_multi(&mu, &ma, LTC_NULL)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_montgomery_normalization(mu, m)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_mulmod(a, mu, m, ma)) != CRYPT_OK) { goto error; }
}
/* recover mQ from mR */
/* compute v1*mR + v2*mG = mQ using Shamir's trick */
if ((err = ltc_mp.ecc_mul2add(mR, v1, mG, v2, mQ, ma, m)) != CRYPT_OK) { goto error; }
/* compute u1*mG + u2*mQ = mG using Shamir's trick */
if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, ma, m)) != CRYPT_OK) { goto error; }
/* v = X_x1 mod n */
if ((err = ltc_mp_mod(mG->x, p, v)) != CRYPT_OK) { goto error; }
/* does v == r */
if (ltc_mp_cmp(v, r) == LTC_MP_EQ) {
/* found public key which verifies signature */
if ((err = ltc_ecc_copy_point(mQ, &key->pubkey)) != CRYPT_OK) { goto error; }
/* point on the curve + other checks */
if ((err = ltc_ecc_verify_key(key)) != CRYPT_OK) { goto error; }
key->type = PK_PUBLIC;
err = CRYPT_OK;
}
else {
/* not found - recid is wrong or we're unable to calculate public key for some other reason */
err = CRYPT_INVALID_ARG;
}
error:
if (ma != NULL) ltc_mp_clear(ma);
if (mu != NULL) ltc_mp_clear(mu);
if (mp != NULL) ltc_mp_montgomery_free(mp);
if (mR != NULL) ltc_ecc_del_point(mR);
if (mQ != NULL) ltc_ecc_del_point(mQ);
if (mG != NULL) ltc_ecc_del_point(mG);
ltc_mp_deinit_multi(a_plus3, y, x, e, v2, v1, u2, u1, t2, t1, w, v, s, r, LTC_NULL);
return err;
}
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,86 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#ifdef LTC_MECC
int ecc_set_curve(const ltc_ecc_curve *cu, ecc_key *key)
{
int err;
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(cu != NULL);
if ((err = ltc_mp_init_multi(&key->dp.prime, &key->dp.order, &key->dp.A, &key->dp.B,
&key->dp.base.x, &key->dp.base.y, &key->dp.base.z,
&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k,
NULL)) != CRYPT_OK) {
return err;
}
/* A, B, order, prime, Gx, Gy */
if ((err = ltc_mp_read_radix(key->dp.prime, cu->prime, 16)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_read_radix(key->dp.order, cu->order, 16)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_read_radix(key->dp.A, cu->A, 16)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_read_radix(key->dp.B, cu->B, 16)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_read_radix(key->dp.base.x, cu->Gx, 16)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_read_radix(key->dp.base.y, cu->Gy, 16)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_set(key->dp.base.z, 1)) != CRYPT_OK) { goto error; }
/* cofactor & size */
key->dp.cofactor = cu->cofactor;
key->dp.size = ltc_mp_unsigned_bin_size(key->dp.prime);
/* OID string >> unsigned long oid[16] + oidlen */
key->dp.oidlen = 16;
if ((err = pk_oid_str_to_num(cu->OID, key->dp.oid, &key->dp.oidlen)) != CRYPT_OK) { goto error; }
/* success */
return CRYPT_OK;
error:
ecc_free(key);
return err;
}
int ecc_set_curve_by_size(int size, ecc_key *key)
{
const ltc_ecc_curve *cu = NULL;
int err = CRYPT_ERROR;
/* for compatibility with libtomcrypt-1.17 the sizes below must match the specific curves */
if (size <= 14) {
err = ecc_find_curve("SECP112R1", &cu);
}
else if (size <= 16) {
err = ecc_find_curve("SECP128R1", &cu);
}
else if (size <= 20) {
err = ecc_find_curve("SECP160R1", &cu);
}
else if (size <= 24) {
err = ecc_find_curve("SECP192R1", &cu);
}
else if (size <= 28) {
err = ecc_find_curve("SECP224R1", &cu);
}
else if (size <= 32) {
err = ecc_find_curve("SECP256R1", &cu);
}
else if (size <= 48) {
err = ecc_find_curve("SECP384R1", &cu);
}
else if (size <= 66) {
err = ecc_find_curve("SECP521R1", &cu);
}
if (err == CRYPT_OK && cu != NULL) return ecc_set_curve(cu, key);
return CRYPT_INVALID_ARG;
}
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,125 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#ifdef LTC_MECC
static int s_ecc_cmp_hex_bn(const char *left_hex, void *right_bn, void *tmp_bn)
{
if (ltc_mp_read_radix(tmp_bn, left_hex, 16) != CRYPT_OK) return 0;
if (ltc_mp_cmp(tmp_bn, right_bn) != LTC_MP_EQ) return 0;
return 1;
}
static void s_ecc_oid_lookup(ecc_key *key)
{
void *bn;
const ltc_ecc_curve *curve;
key->dp.oidlen = 0;
if (ltc_mp_init(&bn) != CRYPT_OK) return;
for (curve = ltc_ecc_curves; curve->prime != NULL; curve++) {
if (s_ecc_cmp_hex_bn(curve->prime, key->dp.prime, bn) != 1) continue;
if (s_ecc_cmp_hex_bn(curve->order, key->dp.order, bn) != 1) continue;
if (s_ecc_cmp_hex_bn(curve->A, key->dp.A, bn) != 1) continue;
if (s_ecc_cmp_hex_bn(curve->B, key->dp.B, bn) != 1) continue;
if (s_ecc_cmp_hex_bn(curve->Gx, key->dp.base.x, bn) != 1) continue;
if (s_ecc_cmp_hex_bn(curve->Gy, key->dp.base.y, bn) != 1) continue;
if (key->dp.cofactor != curve->cofactor) continue;
break; /* found */
}
ltc_mp_clear(bn);
if (curve->prime && curve->OID) {
key->dp.oidlen = 16; /* size of key->dp.oid */
pk_oid_str_to_num(curve->OID, key->dp.oid, &key->dp.oidlen);
}
}
int ecc_copy_curve(const ecc_key *srckey, ecc_key *key)
{
unsigned long i;
int err;
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(srckey != NULL);
if ((err = ltc_mp_init_multi(&key->dp.prime, &key->dp.order, &key->dp.A, &key->dp.B,
&key->dp.base.x, &key->dp.base.y, &key->dp.base.z,
&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k,
NULL)) != CRYPT_OK) {
return err;
}
/* A, B, order, prime, Gx, Gy */
if ((err = ltc_mp_copy(srckey->dp.prime, key->dp.prime )) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_copy(srckey->dp.order, key->dp.order )) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_copy(srckey->dp.A, key->dp.A )) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_copy(srckey->dp.B, key->dp.B )) != CRYPT_OK) { goto error; }
if ((err = ltc_ecc_copy_point(&srckey->dp.base, &key->dp.base)) != CRYPT_OK) { goto error; }
/* cofactor & size */
key->dp.cofactor = srckey->dp.cofactor;
key->dp.size = srckey->dp.size;
/* OID */
if (srckey->dp.oidlen > 0) {
key->dp.oidlen = srckey->dp.oidlen;
for (i = 0; i < key->dp.oidlen; i++) key->dp.oid[i] = srckey->dp.oid[i];
}
else {
s_ecc_oid_lookup(key); /* try to find OID in ltc_ecc_curves */
}
/* success */
return CRYPT_OK;
error:
ecc_free(key);
return err;
}
int ecc_set_curve_from_mpis(void *a, void *b, void *prime, void *order, void *gx, void *gy, unsigned long cofactor, ecc_key *key)
{
int err;
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(a != NULL);
LTC_ARGCHK(b != NULL);
LTC_ARGCHK(prime != NULL);
LTC_ARGCHK(order != NULL);
LTC_ARGCHK(gx != NULL);
LTC_ARGCHK(gy != NULL);
if ((err = ltc_mp_init_multi(&key->dp.prime, &key->dp.order, &key->dp.A, &key->dp.B,
&key->dp.base.x, &key->dp.base.y, &key->dp.base.z,
&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k,
NULL)) != CRYPT_OK) {
return err;
}
/* A, B, order, prime, Gx, Gy */
if ((err = ltc_mp_copy(prime, key->dp.prime )) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_copy(order, key->dp.order )) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_copy(a, key->dp.A )) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_copy(b, key->dp.B )) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_copy(gx, key->dp.base.x)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_copy(gy, key->dp.base.y)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_set(key->dp.base.z, 1)) != CRYPT_OK) { goto error; }
/* cofactor & size */
key->dp.cofactor = cofactor;
key->dp.size = ltc_mp_unsigned_bin_size(prime);
/* try to find OID in ltc_ecc_curves */
s_ecc_oid_lookup(key);
/* success */
return CRYPT_OK;
error:
ecc_free(key);
return err;
}
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,56 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_MECC
int ecc_set_key(const unsigned char *in, unsigned long inlen, int type, ecc_key *key)
{
int err;
void *prime, *a, *b;
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen > 0);
prime = key->dp.prime;
a = key->dp.A;
b = key->dp.B;
if (type == PK_PRIVATE) {
/* load private key */
if ((err = ltc_mp_read_unsigned_bin(key->k, in, inlen)) != CRYPT_OK) {
goto error;
}
if (ltc_mp_iszero(key->k) || (ltc_mp_cmp(key->k, key->dp.order) != LTC_MP_LT)) {
err = CRYPT_INVALID_PACKET;
goto error;
}
/* compute public key */
if ((err = ltc_mp.ecc_ptmul(key->k, &key->dp.base, &key->pubkey, a, prime, 1)) != CRYPT_OK) { goto error; }
}
else if (type == PK_PUBLIC) {
/* load public key */
if ((err = ltc_ecc_import_point(in, inlen, prime, a, b, key->pubkey.x, key->pubkey.y)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_set(key->pubkey.z, 1)) != CRYPT_OK) { goto error; }
}
else {
err = CRYPT_INVALID_PACKET;
goto error;
}
/* point on the curve + other checks */
if ((err = ltc_ecc_verify_key(key)) != CRYPT_OK) {
goto error;
}
key->type = type;
return CRYPT_OK;
error:
ecc_free(key);
return err;
}
#endif

View File

@@ -0,0 +1,66 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file ecc_shared_secret.c
ECC Crypto, Tom St Denis
*/
#ifdef LTC_MECC
/**
Create an ECC shared secret between two keys
@param private_key The private ECC key
@param public_key The public key
@param out [out] Destination of the shared secret (Conforms to EC-DH from ANSI X9.63)
@param outlen [in/out] The max size and resulting size of the shared secret
@return CRYPT_OK if successful
*/
int ecc_shared_secret(const ecc_key *private_key, const ecc_key *public_key,
unsigned char *out, unsigned long *outlen)
{
unsigned long x;
ecc_point *result;
void *prime, *a;
int err;
LTC_ARGCHK(private_key != NULL);
LTC_ARGCHK(public_key != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* type valid? */
if (private_key->type != PK_PRIVATE) {
return CRYPT_PK_NOT_PRIVATE;
}
/* make new point */
result = ltc_ecc_new_point();
if (result == NULL) {
return CRYPT_MEM;
}
prime = private_key->dp.prime;
a = private_key->dp.A;
if ((err = ltc_mp.ecc_ptmul(private_key->k, &public_key->pubkey, result, a, prime, 1)) != CRYPT_OK) { goto done; }
x = (unsigned long)ltc_mp_unsigned_bin_size(prime);
if (*outlen < x) {
*outlen = x;
err = CRYPT_BUFFER_OVERFLOW;
goto done;
}
zeromem(out, x);
if ((err = ltc_mp_to_unsigned_bin(result->x, out + (x - ltc_mp_unsigned_bin_size(result->x)))) != CRYPT_OK) { goto done; }
err = CRYPT_OK;
*outlen = x;
done:
ltc_ecc_del_point(result);
return err;
}
#endif

View File

@@ -0,0 +1,42 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#if defined(LTC_MECC) && defined(LTC_DER)
/**
Sign a message digest (ANSI X9.62 format)
@param in The message digest to sign
@param inlen The length of the digest
@param out [out] The destination for the signature
@param outlen [in/out] The max size and resulting size of the signature
@param prng An active PRNG state
@param wprng The index of the PRNG you wish to use
@param key A private ECC key
@return CRYPT_OK if successful
*/
int ecc_sign_hash(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, const ecc_key *key)
{
int err;
void *r, *s;
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, NULL, key)) != CRYPT_OK) goto error;
/* store as ASN.1 SEQUENCE { r, s -- integer } */
err = der_encode_sequence_multi(out, outlen,
LTC_ASN1_INTEGER, 1UL, r,
LTC_ASN1_INTEGER, 1UL, s,
LTC_ASN1_EOL, 0UL, NULL);
error:
ltc_mp_deinit_multi(r, s, LTC_NULL);
return err;
}
#endif

View File

@@ -0,0 +1,57 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_MECC
/**
Sign a message digest (Ethereum format with recovery_id+27)
@param in The message digest to sign
@param inlen The length of the digest
@param out [out] The destination for the signature
@param outlen [in/out] The max size and resulting size of the signature
@param prng An active PRNG state
@param wprng The index of the PRNG you wish to use
@param key A private ECC key
@return CRYPT_OK if successful
*/
int ecc_sign_hash_eth27(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, const ecc_key *key)
{
int err, recid;
void *r, *s;
unsigned long i;
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(key != NULL);
/* Only valid for secp256k1 - OID 1.3.132.0.10 */
if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
return CRYPT_ERROR;
}
if (*outlen < 65) {
*outlen = 65;
return CRYPT_BUFFER_OVERFLOW;
}
if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, &recid, key)) != CRYPT_OK) goto error;
zeromem(out, 65);
*outlen = 65;
i = ltc_mp_unsigned_bin_size(r);
if ((err = ltc_mp_to_unsigned_bin(r, out + 32 - i)) != CRYPT_OK) goto error;
i = ltc_mp_unsigned_bin_size(s);
if ((err = ltc_mp_to_unsigned_bin(s, out + 64 - i)) != CRYPT_OK) goto error;
out[64] = (unsigned char)(recid + 27); /* Recovery ID is 27/28 for Ethereum */
err = CRYPT_OK;
error:
ltc_mp_deinit_multi(r, s, LTC_NULL);
return err;
}
#endif

View File

@@ -0,0 +1,111 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_MECC
int ecc_sign_hash_internal(const unsigned char *in, unsigned long inlen,
void *r, void *s, prng_state *prng, int wprng,
int *recid, const ecc_key *key)
{
ecc_key pubkey;
void *e, *p, *b;
int v = 0;
int err, max_iterations = LTC_PK_MAX_RETRIES;
unsigned long pbits, pbytes, i, shift_right;
unsigned char ch, buf[MAXBLOCKSIZE];
LTC_ARGCHK(r != NULL);
LTC_ARGCHK(s != NULL);
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(key != NULL);
/* is this a private key? */
if (key->type != PK_PRIVATE) {
return CRYPT_PK_NOT_PRIVATE;
}
/* init the bignums */
if ((err = ltc_mp_init_multi(&e, &b, LTC_NULL)) != CRYPT_OK) {
return err;
}
/* get the hash and load it as a bignum into 'e' */
p = key->dp.order;
pbits = ltc_mp_count_bits(p);
pbytes = (pbits+7) >> 3;
if (pbits > inlen*8) {
if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)in, inlen)) != CRYPT_OK) { goto errnokey; }
}
else if (pbits % 8 == 0) {
if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)in, pbytes)) != CRYPT_OK) { goto errnokey; }
}
else {
if (pbytes >= MAXBLOCKSIZE) {
err = CRYPT_BUFFER_OVERFLOW;
goto error;
}
shift_right = 8 - pbits % 8;
for (i=0, ch=0; i<pbytes; i++) {
buf[i] = ch;
ch = (in[i] << (8-shift_right));
buf[i] = buf[i] ^ (in[i] >> shift_right);
}
if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)buf, pbytes)) != CRYPT_OK) { goto errnokey; }
}
/* make up a key and export the public copy */
do {
if ((err = ecc_copy_curve(key, &pubkey)) != CRYPT_OK) { goto errnokey; }
if ((err = ecc_generate_key(prng, wprng, &pubkey)) != CRYPT_OK) { goto errnokey; }
/* find r = x1 mod n */
if ((err = ltc_mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK) { goto error; }
if (recid) {
/* find recovery ID (if needed) */
v = 0;
if (ltc_mp_copy(pubkey.pubkey.x, s) != CRYPT_OK) { goto error; }
while (ltc_mp_cmp_d(s, 0) == LTC_MP_GT && ltc_mp_cmp(s, p) != LTC_MP_LT) {
/* Compute x1 div n... this will almost never be reached for curves with order 1 */
v += 2;
if ((err = ltc_mp_sub(s, p, s)) != CRYPT_OK) { goto error; }
}
if (ltc_mp_isodd(pubkey.pubkey.y)) v += 1;
}
if (ltc_mp_iszero(r) == LTC_MP_YES) {
ecc_free(&pubkey);
} else {
if ((err = rand_bn_upto(b, p, prng, wprng)) != CRYPT_OK) { goto error; } /* b = blinding value */
/* find s = (e + xr)/k */
if ((err = ltc_mp_mulmod(pubkey.k, b, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = kb */
if ((err = ltc_mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = 1/kb */
if ((err = ltc_mp_mulmod(key->k, r, p, s)) != CRYPT_OK) { goto error; } /* s = xr */
if ((err = ltc_mp_mulmod(pubkey.k, s, p, s)) != CRYPT_OK) { goto error; } /* s = xr/kb */
if ((err = ltc_mp_mulmod(pubkey.k, e, p, e)) != CRYPT_OK) { goto error; } /* e = e/kb */
if ((err = ltc_mp_add(e, s, s)) != CRYPT_OK) { goto error; } /* s = e/kb + xr/kb */
if ((err = ltc_mp_mulmod(s, b, p, s)) != CRYPT_OK) { goto error; } /* s = b(e/kb + xr/kb) = (e + xr)/k */
ecc_free(&pubkey);
if (ltc_mp_iszero(s) == LTC_MP_NO) {
break;
}
}
} while (--max_iterations > 0);
if (max_iterations == 0) {
goto errnokey;
}
if (recid) *recid = v;
goto errnokey;
error:
ecc_free(&pubkey);
errnokey:
ltc_mp_deinit_multi(e, b, LTC_NULL);
return err;
}
#endif

View File

@@ -0,0 +1,48 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#if defined(LTC_MECC) && defined(LTC_SSH)
/**
Sign a message digest (RFC5656 / SSH format)
@param in The message digest to sign
@param inlen The length of the digest
@param out [out] The destination for the signature
@param outlen [in/out] The max size and resulting size of the signature
@param prng An active PRNG state
@param wprng The index of the PRNG you wish to use
@param key A private ECC key
@return CRYPT_OK if successful
*/
int ecc_sign_hash_rfc5656(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, const ecc_key *key)
{
int err;
void *r, *s;
char name[64];
unsigned long namelen = sizeof(name);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
/* Get identifier string */
if ((err = ecc_ssh_ecdsa_encode_name(name, &namelen, key)) != CRYPT_OK) return err;
if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, NULL, key)) != CRYPT_OK) goto error;
/* Store as SSH data sequence, per RFC4251 */
err = ssh_encode_sequence_multi(out, outlen,
LTC_SSHDATA_STRING, name, namelen,
LTC_SSHDATA_MPINT, r,
LTC_SSHDATA_MPINT, s,
LTC_SSHDATA_EOL, LTC_NULL);
error:
ltc_mp_deinit_multi(r, s, LTC_NULL);
return err;
}
#endif

View File

@@ -0,0 +1,73 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_MECC
/**
Sign a message digest (RFC7518 format + recovery_id)
@param in The message digest to sign
@param inlen The length of the digest
@param out [out] The destination for the signature
@param outlen [in/out] The max size and resulting size of the signature
@param prng An active PRNG state
@param wprng The index of the PRNG you wish to use
@param recid [out] Recovery ID
@param key A private ECC key
@return CRYPT_OK if successful
*/
int ecc_sign_hash_rfc7518_ex(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng,
int *recid, const ecc_key *key)
{
int err;
void *r, *s;
unsigned long pbytes, i;
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(key != NULL);
/* RFC7518 format - raw (r,s) */
pbytes = ltc_mp_unsigned_bin_size(key->dp.order);
if (*outlen < 2 * pbytes) {
*outlen = 2 * pbytes;
return CRYPT_BUFFER_OVERFLOW;
}
if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, recid, key)) != CRYPT_OK) goto error;
zeromem(out, 2 * pbytes);
*outlen = 2 * pbytes;
i = ltc_mp_unsigned_bin_size(r);
if ((err = ltc_mp_to_unsigned_bin(r, out + pbytes - i)) != CRYPT_OK) goto error;
i = ltc_mp_unsigned_bin_size(s);
err = ltc_mp_to_unsigned_bin(s, out + 2 * pbytes - i);
error:
ltc_mp_deinit_multi(r, s, LTC_NULL);
return err;
}
/**
Sign a message digest (RFC7518 format)
@param in The message digest to sign
@param inlen The length of the digest
@param out [out] The destination for the signature
@param outlen [in/out] The max size and resulting size of the signature
@param prng An active PRNG state
@param wprng The index of the PRNG you wish to use
@param key A private ECC key
@return CRYPT_OK if successful
*/
int ecc_sign_hash_rfc7518(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, const ecc_key *key)
{
return ecc_sign_hash_rfc7518_ex(in, inlen, out, outlen, prng, wprng, NULL, key);
}
#endif

View File

@@ -0,0 +1,42 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
/**
@file ecc_sizes.c
ECC Crypto, Tom St Denis
*/
#ifdef LTC_MECC
void ecc_sizes(int *low, int *high)
{
int i, size;
void *prime;
LTC_ARGCHKVD(low != NULL);
LTC_ARGCHKVD(high != NULL);
*low = INT_MAX;
*high = 0;
if (ltc_mp_init(&prime) == CRYPT_OK) {
for (i = 0; ltc_ecc_curves[i].prime != NULL; i++) {
if (ltc_mp_read_radix(prime, ltc_ecc_curves[i].prime, 16) == CRYPT_OK) {
size = ltc_mp_unsigned_bin_size(prime);
if (size < *low) *low = size;
if (size > *high) *high = size;
}
}
ltc_mp_clear(prime);
}
}
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,65 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file ecc_ssh_ecdsa_encode_name.c
Curve/OID to SSH+ECDSA name string mapping per RFC5656
Russ Williams
*/
#ifdef LTC_SSH
/**
Curve/OID to SSH+ECDSA name string mapping
@param buffer [out] The destination for the name
@param buflen [in/out] The max size and resulting size (including terminator) of the name
@param key A public or private ECC key
@return CRYPT_OK if successful
*/
int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key *key)
{
char oidstr[64] = {0};
unsigned long oidlen = sizeof(oidstr);
int err, size = 0;
LTC_ARGCHK(buffer != NULL);
LTC_ARGCHK(buflen != NULL);
LTC_ARGCHK(key != NULL);
/* Get the OID of the curve */
if ((err = ecc_get_oid_str(oidstr, &oidlen, key)) != CRYPT_OK) goto error;
/* Check for three named curves: nistp256, nistp384, nistp521 */
if (XSTRCMP("1.2.840.10045.3.1.7", oidstr) == 0) {
/* nistp256 - secp256r1 - OID 1.2.840.10045.3.1.7 */
size = snprintf(buffer, *buflen, "ecdsa-sha2-nistp256");
}
else if (XSTRCMP("1.3.132.0.34", oidstr) == 0) {
/* nistp384 - secp384r1 - OID 1.3.132.0.34 */
size = snprintf(buffer, *buflen, "ecdsa-sha2-nistp384");
}
else if (XSTRCMP("1.3.132.0.35", oidstr) == 0) {
/* nistp521 - secp521r1 - OID 1.3.132.0.35 */
size = snprintf(buffer, *buflen, "ecdsa-sha2-nistp521");
} else {
/* Otherwise we use the OID... */
size = snprintf(buffer, *buflen, "ecdsa-sha2-%s", oidstr);
}
/* snprintf returns a negative value on error
* or the size that would have been written, but limits to buflen-1 chars plus terminator */
if (size < 0) {
err = CRYPT_ERROR;
} else if ((unsigned)size >= *buflen) {
err = CRYPT_BUFFER_OVERFLOW;
} else {
err = CRYPT_OK;
}
*buflen = size + 1; /* the string length + NUL byte */
error:
return err;
}
#endif

View File

@@ -0,0 +1,47 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#if defined(LTC_MECC) && defined(LTC_DER)
/**
@file ecc_verify_hash.c
ECC Crypto, Tom St Denis
*/
/**
Verify an ECC signature (ANSI X9.62 format)
@param sig The signature to verify
@param siglen The length of the signature (octets)
@param hash The hash (message digest) that was signed
@param hashlen The length of the hash (octets)
@param stat [out] Result of signature, 1==valid, 0==invalid
@param key The corresponding public ECC key
@return CRYPT_OK if successful (even if the signature is not valid)
*/
int ecc_verify_hash(const unsigned char *sig, unsigned long siglen,
const unsigned char *hash, unsigned long hashlen,
int *stat, const ecc_key *key)
{
void *r, *s;
int err;
LTC_ARGCHK(sig != NULL);
if ((err = ltc_mp_init_multi(&r, &s, NULL)) != CRYPT_OK) return err;
/* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) } */
if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
LTC_ASN1_INTEGER, 1UL, r,
LTC_ASN1_INTEGER, 1UL, s,
LTC_ASN1_EOL, 0UL, LTC_NULL)) != CRYPT_OK) { goto error; }
err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
error:
ltc_mp_deinit_multi(r, s, LTC_NULL);
return err;
}
#endif

View File

@@ -0,0 +1,53 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_MECC
/**
@file ecc_verify_hash.c
ECC Crypto, Tom St Denis
*/
/**
Verify an ECC signature (Ethereum format with recovery_id+27)
@param sig The signature to verify
@param siglen The length of the signature (octets)
@param hash The hash (message digest) that was signed
@param hashlen The length of the hash (octets)
@param stat [out] Result of signature, 1==valid, 0==invalid
@param key The corresponding public ECC key
@return CRYPT_OK if successful (even if the signature is not valid)
*/
int ecc_verify_hash_eth27(const unsigned char *sig, unsigned long siglen,
const unsigned char *hash, unsigned long hashlen,
int *stat, const ecc_key *key)
{
void *r, *s;
int err;
LTC_ARGCHK(sig != NULL);
LTC_ARGCHK(key != NULL);
/* Only valid for secp256k1 - OID 1.3.132.0.10 */
if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
return CRYPT_ERROR;
}
/* Only secp256k1 curves uses this format, so must be 65 bytes long */
if (siglen != 65) {
return CRYPT_INVALID_PACKET;
}
if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
if ((err = ltc_mp_read_unsigned_bin(r, (unsigned char *)sig, 32)) != CRYPT_OK) goto error;
if ((err = ltc_mp_read_unsigned_bin(s, (unsigned char *)sig + 32, 32)) != CRYPT_OK) goto error;
err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
error:
ltc_mp_deinit_multi(r, s, LTC_NULL);
return err;
}
#endif

View File

@@ -0,0 +1,137 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_MECC
int ecc_verify_hash_internal(void *r, void *s,
const unsigned char *hash, unsigned long hashlen,
int *stat, const ecc_key *key)
{
ecc_point *mG = NULL, *mQ = NULL;
void *v, *w, *u1, *u2, *e, *p, *m, *a, *a_plus3;
void *mu = NULL, *ma = NULL;
void *mp = NULL;
int err;
unsigned long pbits, pbytes, i, shift_right;
unsigned char ch, buf[MAXBLOCKSIZE];
LTC_ARGCHK(r != NULL);
LTC_ARGCHK(s != NULL);
LTC_ARGCHK(hash != NULL);
LTC_ARGCHK(stat != NULL);
LTC_ARGCHK(key != NULL);
/* default to invalid signature */
*stat = 0;
/* allocate ints */
if ((err = ltc_mp_init_multi(&v, &w, &u1, &u2, &e, &a_plus3, LTC_NULL)) != CRYPT_OK) {
return err;
}
p = key->dp.order;
m = key->dp.prime;
a = key->dp.A;
if ((err = ltc_mp_add_d(a, 3, a_plus3)) != CRYPT_OK) {
goto error;
}
/* allocate points */
mG = ltc_ecc_new_point();
mQ = ltc_ecc_new_point();
if (mQ == NULL || mG == NULL) {
err = CRYPT_MEM;
goto error;
}
/* check for zero */
if (ltc_mp_cmp_d(r, 0) != LTC_MP_GT || ltc_mp_cmp_d(s, 0) != LTC_MP_GT ||
ltc_mp_cmp(r, p) != LTC_MP_LT || ltc_mp_cmp(s, p) != LTC_MP_LT) {
err = CRYPT_INVALID_PACKET;
goto error;
}
/* read hash - truncate if needed */
pbits = ltc_mp_count_bits(p);
pbytes = (pbits+7) >> 3;
if (pbits > hashlen*8) {
if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)hash, hashlen)) != CRYPT_OK) { goto error; }
}
else if (pbits % 8 == 0) {
if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)hash, pbytes)) != CRYPT_OK) { goto error; }
}
else {
if (pbytes >= MAXBLOCKSIZE) {
err = CRYPT_BUFFER_OVERFLOW;
goto error;
}
shift_right = 8 - pbits % 8;
for (i=0, ch=0; i<pbytes; i++) {
buf[i] = ch;
ch = (hash[i] << (8-shift_right));
buf[i] = buf[i] ^ (hash[i] >> shift_right);
}
if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)buf, pbytes)) != CRYPT_OK) { goto error; }
}
/* w = s^-1 mod n */
if ((err = ltc_mp_invmod(s, p, w)) != CRYPT_OK) { goto error; }
/* u1 = ew */
if ((err = ltc_mp_mulmod(e, w, p, u1)) != CRYPT_OK) { goto error; }
/* u2 = rw */
if ((err = ltc_mp_mulmod(r, w, p, u2)) != CRYPT_OK) { goto error; }
/* find mG and mQ */
if ((err = ltc_ecc_copy_point(&key->dp.base, mG)) != CRYPT_OK) { goto error; }
if ((err = ltc_ecc_copy_point(&key->pubkey, mQ)) != CRYPT_OK) { goto error; }
/* find the montgomery mp */
if ((err = ltc_mp_montgomery_setup(m, &mp)) != CRYPT_OK) { goto error; }
/* for curves with a == -3 keep ma == NULL */
if (ltc_mp_cmp(a_plus3, m) != LTC_MP_EQ) {
if ((err = ltc_mp_init_multi(&mu, &ma, NULL)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_montgomery_normalization(mu, m)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_mulmod(a, mu, m, ma)) != CRYPT_OK) { goto error; }
}
/* compute u1*mG + u2*mQ = mG */
if (ltc_mp.ecc_mul2add == NULL) {
if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, a, m, 0)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, a, m, 0)) != CRYPT_OK) { goto error; }
/* add them */
if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, ma, m, mp)) != CRYPT_OK) { goto error; }
/* reduce */
if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK) { goto error; }
} else {
/* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, ma, m)) != CRYPT_OK) { goto error; }
}
/* v = X_x1 mod n */
if ((err = ltc_mp_mod(mG->x, p, v)) != CRYPT_OK) { goto error; }
/* does v == r */
if (ltc_mp_cmp(v, r) == LTC_MP_EQ) {
*stat = 1;
}
/* clear up and return */
err = CRYPT_OK;
error:
if (mG != NULL) ltc_ecc_del_point(mG);
if (mQ != NULL) ltc_ecc_del_point(mQ);
if (mu != NULL) ltc_mp_clear(mu);
if (ma != NULL) ltc_mp_clear(ma);
ltc_mp_deinit_multi(v, w, u1, u2, e, a_plus3, LTC_NULL);
if (mp != NULL) ltc_mp_montgomery_free(mp);
return err;
}
#endif

View File

@@ -0,0 +1,65 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#if defined(LTC_MECC) && defined(LTC_SSH)
/**
@file ecc_verify_hash.c
ECC Crypto, Tom St Denis
*/
/**
Verify an ECC signature (RFC5656 / SSH format)
@param sig The signature to verify
@param siglen The length of the signature (octets)
@param hash The hash (message digest) that was signed
@param hashlen The length of the hash (octets)
@param stat [out] Result of signature, 1==valid, 0==invalid
@param key The corresponding public ECC key
@return CRYPT_OK if successful (even if the signature is not valid)
*/
int ecc_verify_hash_rfc5656(const unsigned char *sig, unsigned long siglen,
const unsigned char *hash, unsigned long hashlen,
int *stat, const ecc_key *key)
{
void *r, *s;
int err;
char name[64], name2[64];
unsigned long namelen = sizeof(name);
unsigned long name2len = sizeof(name2);
unsigned long slen = siglen;
LTC_ARGCHK(sig != NULL);
LTC_ARGCHK(key != NULL);
if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
/* Decode as SSH data sequence, per RFC4251 */
if ((err = ssh_decode_sequence_multi(sig, &slen,
LTC_SSHDATA_STRING, name, &namelen,
LTC_SSHDATA_MPINT, r,
LTC_SSHDATA_MPINT, s,
LTC_SSHDATA_EOL, LTC_NULL)) != CRYPT_OK) goto error;
if (slen != siglen) {
err = CRYPT_INVALID_PACKET;
goto error;
}
/* Check curve matches identifier string */
if ((err = ecc_ssh_ecdsa_encode_name(name2, &name2len, key)) != CRYPT_OK) goto error;
if (XSTRCMP(name,name2) != 0) {
err = CRYPT_INVALID_ARG;
goto error;
}
err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
error:
ltc_mp_deinit_multi(r, s, LTC_NULL);
return err;
}
#endif

View File

@@ -0,0 +1,52 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_MECC
/**
@file ecc_verify_hash.c
ECC Crypto, Tom St Denis
*/
/**
Verify an ECC signature (RFC7518 format)
@param sig The signature to verify
@param siglen The length of the signature (octets)
@param hash The hash (message digest) that was signed
@param hashlen The length of the hash (octets)
@param stat [out] Result of signature, 1==valid, 0==invalid
@param key The corresponding public ECC key
@return CRYPT_OK if successful (even if the signature is not valid)
*/
int ecc_verify_hash_rfc7518(const unsigned char *sig, unsigned long siglen,
const unsigned char *hash, unsigned long hashlen,
int *stat, const ecc_key *key)
{
void *r, *s;
int err;
unsigned long i;
LTC_ARGCHK(sig != NULL);
LTC_ARGCHK(key != NULL);
if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
/* RFC7518 format - raw (r,s) */
i = ltc_mp_unsigned_bin_size(key->dp.order);
if (siglen != (2 * i)) {
err = CRYPT_INVALID_PACKET;
goto error;
}
if ((err = ltc_mp_read_unsigned_bin(r, (unsigned char *)sig, i)) != CRYPT_OK) goto error;
if ((err = ltc_mp_read_unsigned_bin(s, (unsigned char *)sig + i, i)) != CRYPT_OK) goto error;
err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
error:
ltc_mp_deinit_multi(r, s, LTC_NULL);
return err;
}
#endif

View File

@@ -0,0 +1,53 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_MECC
int ltc_ecc_export_point(unsigned char *out, unsigned long *outlen, void *x, void *y, unsigned long size, int compressed)
{
int err;
unsigned char buf[ECC_BUF_SIZE];
unsigned long xsize, ysize;
if (size > sizeof(buf)) return CRYPT_BUFFER_OVERFLOW;
if ((xsize = ltc_mp_unsigned_bin_size(x)) > size) return CRYPT_BUFFER_OVERFLOW;
if ((ysize = ltc_mp_unsigned_bin_size(y)) > size) return CRYPT_BUFFER_OVERFLOW;
if(compressed) {
if (*outlen < (1 + size)) {
*outlen = 1 + size;
return CRYPT_BUFFER_OVERFLOW;
}
/* store first byte */
out[0] = ltc_mp_isodd(y) ? 0x03 : 0x02;
/* pad and store x */
zeromem(buf, sizeof(buf));
if ((err = ltc_mp_to_unsigned_bin(x, buf + (size - xsize))) != CRYPT_OK) return err;
XMEMCPY(out+1, buf, size);
/* adjust outlen */
*outlen = 1 + size;
}
else {
if (*outlen < (1 + 2*size)) {
*outlen = 1 + 2*size;
return CRYPT_BUFFER_OVERFLOW;
}
/* store byte 0x04 */
out[0] = 0x04;
/* pad and store x */
zeromem(buf, sizeof(buf));
if ((err = ltc_mp_to_unsigned_bin(x, buf + (size - xsize))) != CRYPT_OK) return err;
XMEMCPY(out+1, buf, size);
/* pad and store y */
zeromem(buf, sizeof(buf));
if ((err = ltc_mp_to_unsigned_bin(y, buf + (size - ysize))) != CRYPT_OK) return err;
XMEMCPY(out+1+size, buf, size);
/* adjust outlen */
*outlen = 1 + 2*size;
}
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,61 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_MECC
int ltc_ecc_import_point(const unsigned char *in, unsigned long inlen, void *prime, void *a, void *b, void *x, void *y)
{
int err;
unsigned long size;
void *t1, *t2;
/* init key + temporary numbers */
if (ltc_mp_init_multi(&t1, &t2, LTC_NULL) != CRYPT_OK) {
return CRYPT_MEM;
}
size = ltc_mp_unsigned_bin_size(prime);
if (in[0] == 0x04 && (inlen&1) && ((inlen-1)>>1) == size) {
/* read uncompressed point */
/* load x */
if ((err = ltc_mp_read_unsigned_bin(x, in+1, size)) != CRYPT_OK) { goto cleanup; }
/* load y */
if ((err = ltc_mp_read_unsigned_bin(y, in+1+size, size)) != CRYPT_OK) { goto cleanup; }
}
else if ((in[0] == 0x02 || in[0] == 0x03) && (inlen-1) == size && ltc_mp.sqrtmod_prime != NULL) {
/* read compressed point - BEWARE: requires sqrtmod_prime */
/* load x */
if ((err = ltc_mp_read_unsigned_bin(x, in+1, size)) != CRYPT_OK) { goto cleanup; }
/* compute x^3 */
if ((err = ltc_mp_sqr(x, t1)) != CRYPT_OK) { goto cleanup; }
if ((err = ltc_mp_mulmod(t1, x, prime, t1)) != CRYPT_OK) { goto cleanup; }
/* compute x^3 + a*x */
if ((err = ltc_mp_mulmod(a, x, prime, t2)) != CRYPT_OK) { goto cleanup; }
if ((err = ltc_mp_add(t1, t2, t1)) != CRYPT_OK) { goto cleanup; }
/* compute x^3 + a*x + b */
if ((err = ltc_mp_add(t1, b, t1)) != CRYPT_OK) { goto cleanup; }
/* compute sqrt(x^3 + a*x + b) */
if ((err = ltc_mp_sqrtmod_prime(t1, prime, t2)) != CRYPT_OK) { goto cleanup; }
/* adjust y */
if ((ltc_mp_isodd(t2) && in[0] == 0x03) || (!ltc_mp_isodd(t2) && in[0] == 0x02)) {
if ((err = ltc_mp_mod(t2, prime, y)) != CRYPT_OK) { goto cleanup; }
}
else {
if ((err = ltc_mp_submod(prime, t2, prime, y)) != CRYPT_OK) { goto cleanup; }
}
}
else {
err = CRYPT_INVALID_PACKET;
goto cleanup;
}
err = CRYPT_OK;
cleanup:
ltc_mp_deinit_multi(t1, t2, LTC_NULL);
return err;
}
#endif

View File

@@ -0,0 +1,62 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_MECC
/** Returns whether [x,y] is a point on curve defined by dp
@param dp curve parameters
@param x x point coordinate
@param y y point coordinate
@return CRYPT_OK if valid
*/
int ltc_ecc_is_point(const ltc_ecc_dp *dp, void *x, void *y)
{
void *prime, *a, *b, *t1, *t2;
int err;
prime = dp->prime;
b = dp->B;
a = dp->A;
if ((err = ltc_mp_init_multi(&t1, &t2, LTC_NULL)) != CRYPT_OK) return err;
/* compute y^2 */
if ((err = ltc_mp_sqr(y, t1)) != CRYPT_OK) goto cleanup;
/* compute x^3 */
if ((err = ltc_mp_sqr(x, t2)) != CRYPT_OK) goto cleanup;
if ((err = ltc_mp_mod(t2, prime, t2)) != CRYPT_OK) goto cleanup;
if ((err = ltc_mp_mul(x, t2, t2)) != CRYPT_OK) goto cleanup;
/* compute y^2 - x^3 */
if ((err = ltc_mp_sub(t1, t2, t1)) != CRYPT_OK) goto cleanup;
/* compute y^2 - x^3 - a*x */
if ((err = ltc_mp_submod(prime, a, prime, t2)) != CRYPT_OK) goto cleanup;
if ((err = ltc_mp_mulmod(t2, x, prime, t2)) != CRYPT_OK) goto cleanup;
if ((err = ltc_mp_addmod(t1, t2, prime, t1)) != CRYPT_OK) goto cleanup;
/* adjust range (0, prime) */
while (ltc_mp_cmp_d(t1, 0) == LTC_MP_LT) {
if ((err = ltc_mp_add(t1, prime, t1)) != CRYPT_OK) goto cleanup;
}
while (ltc_mp_cmp(t1, prime) != LTC_MP_LT) {
if ((err = ltc_mp_sub(t1, prime, t1)) != CRYPT_OK) goto cleanup;
}
/* compare to b */
if (ltc_mp_cmp(t1, b) != LTC_MP_EQ) {
err = CRYPT_INVALID_PACKET;
} else {
err = CRYPT_OK;
}
cleanup:
ltc_mp_deinit_multi(t1, t2, LTC_NULL);
return err;
}
#endif

View File

@@ -0,0 +1,53 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_MECC
/* http://crypto.stackexchange.com/questions/41468/point-at-infinity-for-jacobian-coordinates
* a point at infinity is any point (x,y,0) such that y^2 == x^3, except (0,0,0)
*/
int ltc_ecc_is_point_at_infinity(const ecc_point *P, const void *modulus, int *retval)
{
int err;
void *x3, *y2;
/* trivial case */
if (!ltc_mp_iszero(P->z)) {
*retval = 0;
return CRYPT_OK;
}
/* point (0,0,0) is not at infinity */
if (ltc_mp_iszero(P->x) && ltc_mp_iszero(P->y)) {
*retval = 0;
return CRYPT_OK;
}
/* initialize */
if ((err = ltc_mp_init_multi(&x3, &y2, LTC_NULL)) != CRYPT_OK) goto done;
/* compute y^2 */
if ((err = ltc_mp_mulmod(P->y, P->y, modulus, y2)) != CRYPT_OK) goto cleanup;
/* compute x^3 */
if ((err = ltc_mp_mulmod(P->x, P->x, modulus, x3)) != CRYPT_OK) goto cleanup;
if ((err = ltc_mp_mulmod(P->x, x3, modulus, x3)) != CRYPT_OK) goto cleanup;
/* test y^2 == x^3 */
err = CRYPT_OK;
if ((ltc_mp_cmp(x3, y2) == LTC_MP_EQ) && !ltc_mp_iszero(y2)) {
*retval = 1;
} else {
*retval = 0;
}
cleanup:
ltc_mp_deinit_multi(x3, y2, LTC_NULL);
done:
return err;
}
#endif

View File

@@ -0,0 +1,63 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file ltc_ecc_map.c
ECC Crypto, Tom St Denis
*/
#ifdef LTC_MECC
/**
Map a projective jacbobian point back to affine space
@param P [in/out] The point to map
@param modulus The modulus of the field the ECC curve is in
@param mp The "b" value from montgomery_setup()
@return CRYPT_OK on success
*/
int ltc_ecc_map(ecc_point *P, const void *modulus, void *mp)
{
void *t1, *t2;
int err;
LTC_ARGCHK(P != NULL);
LTC_ARGCHK(modulus != NULL);
LTC_ARGCHK(mp != NULL);
if (ltc_mp_iszero(P->z)) {
return ltc_ecc_set_point_xyz(0, 0, 1, P);
}
if ((err = ltc_mp_init_multi(&t1, &t2, LTC_NULL)) != CRYPT_OK) {
return err;
}
/* first map z back to normal */
if ((err = ltc_mp_montgomery_reduce(P->z, modulus, mp)) != CRYPT_OK) { goto done; }
/* get 1/z */
if ((err = ltc_mp_invmod(P->z, modulus, t1)) != CRYPT_OK) { goto done; }
/* get 1/z^2 and 1/z^3 */
if ((err = ltc_mp_sqr(t1, t2)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_mod(t2, modulus, t2)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_mul(t1, t2, t1)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_mod(t1, modulus, t1)) != CRYPT_OK) { goto done; }
/* multiply against x/y */
if ((err = ltc_mp_mul(P->x, t2, P->x)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(P->x, modulus, mp)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_mul(P->y, t1, P->y)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(P->y, modulus, mp)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_set(P->z, 1)) != CRYPT_OK) { goto done; }
err = CRYPT_OK;
done:
ltc_mp_deinit_multi(t1, t2, LTC_NULL);
return err;
}
#endif

View File

@@ -0,0 +1,198 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
/**
@file ltc_ecc_mul2add.c
ECC Crypto, Shamir's Trick, Tom St Denis
*/
#ifdef LTC_MECC
#ifdef LTC_ECC_SHAMIR
/** Computes kA*A + kB*B = C using Shamir's Trick
@param A First point to multiply
@param kA What to multiple A by
@param B Second point to multiply
@param kB What to multiple B by
@param C [out] Destination point (can overlap with A or B)
@param ma ECC curve parameter a in montgomery form
@param modulus Modulus for curve
@return CRYPT_OK on success
*/
int ltc_ecc_mul2add(const ecc_point *A, void *kA,
const ecc_point *B, void *kB,
ecc_point *C,
const void *ma,
const void *modulus)
{
ecc_point *precomp[16];
unsigned bitbufA, bitbufB, lenA, lenB, len, nA, nB, nibble;
unsigned x, y;
unsigned char *tA, *tB;
int err, first;
void *mp, *mu;
/* argchks */
LTC_ARGCHK(A != NULL);
LTC_ARGCHK(B != NULL);
LTC_ARGCHK(C != NULL);
LTC_ARGCHK(kA != NULL);
LTC_ARGCHK(kB != NULL);
LTC_ARGCHK(modulus != NULL);
/* allocate memory */
tA = XCALLOC(1, ECC_BUF_SIZE);
if (tA == NULL) {
return CRYPT_MEM;
}
tB = XCALLOC(1, ECC_BUF_SIZE);
if (tB == NULL) {
XFREE(tA);
return CRYPT_MEM;
}
/* get sizes */
lenA = ltc_mp_unsigned_bin_size(kA);
lenB = ltc_mp_unsigned_bin_size(kB);
len = MAX(lenA, lenB);
/* sanity check */
if ((lenA > ECC_BUF_SIZE) || (lenB > ECC_BUF_SIZE)) {
err = CRYPT_INVALID_ARG;
goto ERR_T;
}
/* extract and justify kA */
ltc_mp_to_unsigned_bin(kA, (len - lenA) + tA);
/* extract and justify kB */
ltc_mp_to_unsigned_bin(kB, (len - lenB) + tB);
/* allocate the table */
for (x = 0; x < 16; x++) {
precomp[x] = ltc_ecc_new_point();
if (precomp[x] == NULL) {
for (y = 0; y < x; ++y) {
ltc_ecc_del_point(precomp[y]);
}
err = CRYPT_MEM;
goto ERR_T;
}
}
/* init montgomery reduction */
if ((err = ltc_mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) {
goto ERR_P;
}
if ((err = ltc_mp_init(&mu)) != CRYPT_OK) {
goto ERR_MP;
}
if ((err = ltc_mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) {
goto ERR_MU;
}
/* copy ones ... */
if ((err = ltc_mp_mulmod(A->x, mu, modulus, precomp[1]->x)) != CRYPT_OK) { goto ERR_MU; }
if ((err = ltc_mp_mulmod(A->y, mu, modulus, precomp[1]->y)) != CRYPT_OK) { goto ERR_MU; }
if ((err = ltc_mp_mulmod(A->z, mu, modulus, precomp[1]->z)) != CRYPT_OK) { goto ERR_MU; }
if ((err = ltc_mp_mulmod(B->x, mu, modulus, precomp[1<<2]->x)) != CRYPT_OK) { goto ERR_MU; }
if ((err = ltc_mp_mulmod(B->y, mu, modulus, precomp[1<<2]->y)) != CRYPT_OK) { goto ERR_MU; }
if ((err = ltc_mp_mulmod(B->z, mu, modulus, precomp[1<<2]->z)) != CRYPT_OK) { goto ERR_MU; }
/* precomp [i,0](A + B) table */
if ((err = ltc_mp.ecc_ptdbl(precomp[1], precomp[2], ma, modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
if ((err = ltc_mp.ecc_ptadd(precomp[1], precomp[2], precomp[3], ma, modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
/* precomp [0,i](A + B) table */
if ((err = ltc_mp.ecc_ptdbl(precomp[1<<2], precomp[2<<2], ma, modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
if ((err = ltc_mp.ecc_ptadd(precomp[1<<2], precomp[2<<2], precomp[3<<2], ma, modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
/* precomp [i,j](A + B) table (i != 0, j != 0) */
for (x = 1; x < 4; x++) {
for (y = 1; y < 4; y++) {
if ((err = ltc_mp.ecc_ptadd(precomp[x], precomp[(y<<2)], precomp[x+(y<<2)], ma, modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
}
}
nibble = 3;
first = 1;
bitbufA = tA[0];
bitbufB = tB[0];
/* for every byte of the multiplicands */
for (x = 0;; ) {
/* grab a nibble */
if (++nibble == 4) {
if (x == len) break;
bitbufA = tA[x];
bitbufB = tB[x];
nibble = 0;
++x;
}
/* extract two bits from both, shift/update */
nA = (bitbufA >> 6) & 0x03;
nB = (bitbufB >> 6) & 0x03;
bitbufA = (bitbufA << 2) & 0xFF;
bitbufB = (bitbufB << 2) & 0xFF;
/* if both zero, if first, continue */
if ((nA == 0) && (nB == 0) && (first == 1)) {
continue;
}
/* double twice, only if this isn't the first */
if (first == 0) {
/* double twice */
if ((err = ltc_mp.ecc_ptdbl(C, C, ma, modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
if ((err = ltc_mp.ecc_ptdbl(C, C, ma, modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
}
/* if not both zero */
if ((nA != 0) || (nB != 0)) {
if (first == 1) {
/* if first, copy from table */
first = 0;
if ((err = ltc_ecc_copy_point(precomp[nA + (nB<<2)], C)) != CRYPT_OK) { goto ERR_MU; }
} else {
/* if not first, add from table */
if ((err = ltc_mp.ecc_ptadd(C, precomp[nA + (nB<<2)], C, ma, modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
}
}
}
/* reduce to affine */
err = ltc_ecc_map(C, modulus, mp);
/* clean up */
ERR_MU:
ltc_mp_clear(mu);
ERR_MP:
ltc_mp_montgomery_free(mp);
ERR_P:
for (x = 0; x < 16; x++) {
ltc_ecc_del_point(precomp[x]);
}
ERR_T:
#ifdef LTC_CLEAN_STACK
zeromem(tA, ECC_BUF_SIZE);
zeromem(tB, ECC_BUF_SIZE);
#endif
XFREE(tA);
XFREE(tB);
return err;
}
#endif
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,205 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file ltc_ecc_mulmod.c
ECC Crypto, Tom St Denis
*/
#ifdef LTC_MECC
#ifndef LTC_ECC_TIMING_RESISTANT
/* size of sliding window, don't change this! */
#define WINSIZE 4
/**
Perform a point multiplication
@param k The scalar to multiply by
@param G The base point
@param R [out] Destination for kG
@param a ECC curve parameter a
@param modulus The modulus of the field the ECC curve is in
@param map Boolean whether to map back to affine or not (1==map, 0 == leave in projective)
@return CRYPT_OK on success
*/
int ltc_ecc_mulmod(const void *k, const ecc_point *G, ecc_point *R, const void *a, const void *modulus, int map)
{
ecc_point *tG, *M[8];
int i, j, err, inf;
void *mp = NULL, *mu = NULL, *ma = NULL, *a_plus3 = NULL;
ltc_mp_digit buf;
int first, bitbuf, bitcpy, bitcnt, mode, digidx;
LTC_ARGCHK(k != NULL);
LTC_ARGCHK(G != NULL);
LTC_ARGCHK(R != NULL);
LTC_ARGCHK(modulus != NULL);
if ((err = ltc_ecc_is_point_at_infinity(G, modulus, &inf)) != CRYPT_OK) return err;
if (inf) {
/* return the point at infinity */
return ltc_ecc_set_point_xyz(1, 1, 0, R);
}
/* init montgomery reduction */
if ((err = ltc_mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_init(&mu)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) { goto error; }
/* for curves with a == -3 keep ma == NULL */
if ((err = ltc_mp_init(&a_plus3)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_add_d(a, 3, a_plus3)) != CRYPT_OK) { goto error; }
if (ltc_mp_cmp(a_plus3, modulus) != LTC_MP_EQ) {
if ((err = ltc_mp_init(&ma)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_mulmod(a, mu, modulus, ma)) != CRYPT_OK) { goto error; }
}
/* alloc ram for window temps */
for (i = 0; i < 8; i++) {
M[i] = ltc_ecc_new_point();
if (M[i] == NULL) {
for (j = 0; j < i; j++) {
ltc_ecc_del_point(M[j]);
}
err = CRYPT_MEM;
goto error;
}
}
/* make a copy of G incase R==G */
tG = ltc_ecc_new_point();
if (tG == NULL) { err = CRYPT_MEM; goto done; }
/* tG = G and convert to montgomery */
if (ltc_mp_cmp_d(mu, 1) == LTC_MP_EQ) {
if ((err = ltc_ecc_copy_point(G, tG)) != CRYPT_OK) { goto done; }
} else {
if ((err = ltc_mp_mulmod(G->x, mu, modulus, tG->x)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_mulmod(G->y, mu, modulus, tG->y)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_mulmod(G->z, mu, modulus, tG->z)) != CRYPT_OK) { goto done; }
}
ltc_mp_clear(mu);
mu = NULL;
/* calc the M tab, which holds kG for k==8..15 */
/* M[0] == 8G */
if ((err = ltc_mp.ecc_ptdbl(tG, M[0], ma, modulus, mp)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp.ecc_ptdbl(M[0], M[0], ma, modulus, mp)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp.ecc_ptdbl(M[0], M[0], ma, modulus, mp)) != CRYPT_OK) { goto done; }
/* now find (8+k)G for k=1..7 */
for (j = 9; j < 16; j++) {
if ((err = ltc_mp.ecc_ptadd(M[j-9], tG, M[j-8], ma, modulus, mp)) != CRYPT_OK) { goto done; }
}
/* setup sliding window */
mode = 0;
bitcnt = 1;
buf = 0;
digidx = ltc_mp_get_digit_count(k) - 1;
bitcpy = bitbuf = 0;
first = 1;
/* perform ops */
for (;;) {
/* grab next digit as required */
if (--bitcnt == 0) {
if (digidx == -1) {
break;
}
buf = ltc_mp_get_digit(k, digidx);
bitcnt = (int) ltc_mp.bits_per_digit;
--digidx;
}
/* grab the next msb from the ltiplicand */
i = (buf >> (ltc_mp.bits_per_digit - 1)) & 1;
buf <<= 1;
/* skip leading zero bits */
if (mode == 0 && i == 0) {
continue;
}
/* if the bit is zero and mode == 1 then we double */
if (mode == 1 && i == 0) {
if ((err = ltc_mp.ecc_ptdbl(R, R, ma, modulus, mp)) != CRYPT_OK) { goto done; }
continue;
}
/* else we add it to the window */
bitbuf |= (i << (WINSIZE - ++bitcpy));
mode = 2;
if (bitcpy == WINSIZE) {
/* if this is the first window we do a simple copy */
if (first == 1) {
/* R = kG [k = first window] */
if ((err = ltc_ecc_copy_point(M[bitbuf-8], R)) != CRYPT_OK) { goto done; }
first = 0;
} else {
/* normal window */
/* ok window is filled so double as required and add */
/* double first */
for (j = 0; j < WINSIZE; j++) {
if ((err = ltc_mp.ecc_ptdbl(R, R, ma, modulus, mp)) != CRYPT_OK) { goto done; }
}
/* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranteed */
if ((err = ltc_mp.ecc_ptadd(R, M[bitbuf-8], R, ma, modulus, mp)) != CRYPT_OK) { goto done; }
}
/* empty window and reset */
bitcpy = bitbuf = 0;
mode = 1;
}
}
/* if bits remain then double/add */
if (mode == 2 && bitcpy > 0) {
/* double then add */
for (j = 0; j < bitcpy; j++) {
/* only double if we have had at least one add first */
if (first == 0) {
if ((err = ltc_mp.ecc_ptdbl(R, R, ma, modulus, mp)) != CRYPT_OK) { goto done; }
}
bitbuf <<= 1;
if ((bitbuf & (1 << WINSIZE)) != 0) {
if (first == 1){
/* first add, so copy */
if ((err = ltc_ecc_copy_point(tG, R)) != CRYPT_OK) { goto done; }
first = 0;
} else {
/* then add */
if ((err = ltc_mp.ecc_ptadd(R, tG, R, ma, modulus, mp)) != CRYPT_OK) { goto done; }
}
}
}
}
/* map R back from projective space */
if (map) {
err = ltc_ecc_map(R, modulus, mp);
} else {
err = CRYPT_OK;
}
done:
ltc_ecc_del_point(tG);
for (i = 0; i < 8; i++) {
ltc_ecc_del_point(M[i]);
}
error:
if (ma != NULL) ltc_mp_clear(ma);
if (a_plus3 != NULL) ltc_mp_clear(a_plus3);
if (mu != NULL) ltc_mp_clear(mu);
if (mp != NULL) ltc_mp_montgomery_free(mp);
return err;
}
#endif
#undef WINSIZE
#endif

View File

@@ -0,0 +1,151 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file ltc_ecc_mulmod_timing.c
ECC Crypto, Tom St Denis
*/
#ifdef LTC_MECC
#ifdef LTC_ECC_TIMING_RESISTANT
/**
Perform a point multiplication (timing resistant)
@param k The scalar to multiply by
@param G The base point
@param R [out] Destination for kG
@param a ECC curve parameter a
@param modulus The modulus of the field the ECC curve is in
@param map Boolean whether to map back to affine or not (1==map, 0 == leave in projective)
@return CRYPT_OK on success
*/
int ltc_ecc_mulmod(const void *k, const ecc_point *G, ecc_point *R, const void *a, const void *modulus, int map)
{
ecc_point *tG, *M[3];
int i, j, err, inf;
void *mp = NULL, *mu = NULL, *ma = NULL, *a_plus3 = NULL;
ltc_mp_digit buf;
int bitcnt, mode, digidx;
LTC_ARGCHK(k != NULL);
LTC_ARGCHK(G != NULL);
LTC_ARGCHK(R != NULL);
LTC_ARGCHK(modulus != NULL);
if ((err = ltc_ecc_is_point_at_infinity(G, modulus, &inf)) != CRYPT_OK) return err;
if (inf) {
/* return the point at infinity */
return ltc_ecc_set_point_xyz(1, 1, 0, R);
}
/* init montgomery reduction */
if ((err = ltc_mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_init(&mu)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) { goto error; }
/* for curves with a == -3 keep ma == NULL */
if ((err = ltc_mp_init(&a_plus3)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_add_d(a, 3, a_plus3)) != CRYPT_OK) { goto error; }
if (ltc_mp_cmp(a_plus3, modulus) != LTC_MP_EQ) {
if ((err = ltc_mp_init(&ma)) != CRYPT_OK) { goto error; }
if ((err = ltc_mp_mulmod(a, mu, modulus, ma)) != CRYPT_OK) { goto error; }
}
/* alloc ram for window temps */
for (i = 0; i < 3; i++) {
M[i] = ltc_ecc_new_point();
if (M[i] == NULL) {
for (j = 0; j < i; j++) {
ltc_ecc_del_point(M[j]);
}
ltc_mp_clear(mu);
ltc_mp_montgomery_free(mp);
return CRYPT_MEM;
}
}
/* make a copy of G incase R==G */
tG = ltc_ecc_new_point();
if (tG == NULL) { err = CRYPT_MEM; goto done; }
/* tG = G and convert to montgomery */
if ((err = ltc_mp_mulmod(G->x, mu, modulus, tG->x)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_mulmod(G->y, mu, modulus, tG->y)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_mulmod(G->z, mu, modulus, tG->z)) != CRYPT_OK) { goto done; }
ltc_mp_clear(mu);
mu = NULL;
/* calc the M tab */
/* M[0] == G */
if ((err = ltc_ecc_copy_point(tG, M[0])) != CRYPT_OK) { goto done; }
/* M[1] == 2G */
if ((err = ltc_mp.ecc_ptdbl(tG, M[1], ma, modulus, mp)) != CRYPT_OK) { goto done; }
/* setup sliding window */
mode = 0;
bitcnt = 1;
buf = 0;
digidx = ltc_mp_get_digit_count(k) - 1;
/* perform ops */
for (;;) {
/* grab next digit as required */
if (--bitcnt == 0) {
if (digidx == -1) {
break;
}
buf = ltc_mp_get_digit(k, digidx);
bitcnt = (int) LTC_MP_DIGIT_BIT;
--digidx;
}
/* grab the next msb from the ltiplicand */
i = (int)((buf >> (LTC_MP_DIGIT_BIT - 1)) & 1);
buf <<= 1;
if (mode == 0 && i == 0) {
/* dummy operations */
if ((err = ltc_mp.ecc_ptadd(M[0], M[1], M[2], ma, modulus, mp)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp.ecc_ptdbl(M[1], M[2], ma, modulus, mp)) != CRYPT_OK) { goto done; }
continue;
}
if (mode == 0 && i == 1) {
mode = 1;
/* dummy operations */
if ((err = ltc_mp.ecc_ptadd(M[0], M[1], M[2], ma, modulus, mp)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp.ecc_ptdbl(M[1], M[2], ma, modulus, mp)) != CRYPT_OK) { goto done; }
continue;
}
if ((err = ltc_mp.ecc_ptadd(M[0], M[1], M[i^1], ma, modulus, mp)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp.ecc_ptdbl(M[i], M[i], ma, modulus, mp)) != CRYPT_OK) { goto done; }
}
/* copy result out */
if ((err = ltc_ecc_copy_point(M[0], R)) != CRYPT_OK) { goto done; }
/* map R back from projective space */
if (map) {
err = ltc_ecc_map(R, modulus, mp);
} else {
err = CRYPT_OK;
}
done:
ltc_ecc_del_point(tG);
for (i = 0; i < 3; i++) {
ltc_ecc_del_point(M[i]);
}
error:
if (ma != NULL) ltc_mp_clear(ma);
if (a_plus3 != NULL) ltc_mp_clear(a_plus3);
if (mu != NULL) ltc_mp_clear(mu);
if (mp != NULL) ltc_mp_montgomery_free(mp);
return err;
}
#endif
#endif

View File

@@ -0,0 +1,61 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file ltc_ecc_points.c
ECC Crypto, Tom St Denis
*/
#ifdef LTC_MECC
/**
Allocate a new ECC point
@return A newly allocated point or NULL on error
*/
ecc_point *ltc_ecc_new_point(void)
{
ecc_point *p;
p = XCALLOC(1, sizeof(*p));
if (p == NULL) {
return NULL;
}
if (ltc_mp_init_multi(&p->x, &p->y, &p->z, LTC_NULL) != CRYPT_OK) {
XFREE(p);
return NULL;
}
return p;
}
/** Free an ECC point from memory
@param p The point to free
*/
void ltc_ecc_del_point(ecc_point *p)
{
/* prevents free'ing null arguments */
if (p != NULL) {
ltc_mp_deinit_multi(p->x, p->y, p->z, LTC_NULL); /* note: p->z may be NULL but that's ok with this function anyways */
XFREE(p);
}
}
int ltc_ecc_set_point_xyz(ltc_mp_digit x, ltc_mp_digit y, ltc_mp_digit z, ecc_point *p)
{
int err;
if ((err = ltc_mp.set_int(p->x, x)) != CRYPT_OK) return err;
if ((err = ltc_mp.set_int(p->y, y)) != CRYPT_OK) return err;
if ((err = ltc_mp.set_int(p->z, z)) != CRYPT_OK) return err;
return CRYPT_OK;
}
int ltc_ecc_copy_point(const ecc_point *src, ecc_point *dst)
{
int err;
if ((err = ltc_mp.copy(src->x, dst->x)) != CRYPT_OK) return err;
if ((err = ltc_mp.copy(src->y, dst->y)) != CRYPT_OK) return err;
if ((err = ltc_mp.copy(src->z, dst->z)) != CRYPT_OK) return err;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,199 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file ltc_ecc_projective_add_point.c
ECC Crypto, Tom St Denis
*/
#if defined(LTC_MECC) && (!defined(LTC_MECC_ACCEL) || defined(LTM_DESC))
/**
Add two ECC points
@param P The point to add
@param Q The point to add
@param R [out] The destination of the double
@param ma ECC curve parameter a in montgomery form
@param modulus The modulus of the field the ECC curve is in
@param mp The "b" value from montgomery_setup()
@return CRYPT_OK on success
*/
int ltc_ecc_projective_add_point(const ecc_point *P, const ecc_point *Q, ecc_point *R,
const void *ma, const void *modulus, void *mp)
{
void *t1, *t2, *x, *y, *z;
int err, inf;
LTC_ARGCHK(P != NULL);
LTC_ARGCHK(Q != NULL);
LTC_ARGCHK(R != NULL);
LTC_ARGCHK(modulus != NULL);
LTC_ARGCHK(mp != NULL);
if ((err = ltc_mp_init_multi(&t1, &t2, &x, &y, &z, LTC_NULL)) != CRYPT_OK) {
return err;
}
if ((err = ltc_ecc_is_point_at_infinity(P, modulus, &inf)) != CRYPT_OK) return err;
if (inf) {
/* P is point at infinity >> Result = Q */
err = ltc_ecc_copy_point(Q, R);
goto done;
}
if ((err = ltc_ecc_is_point_at_infinity(Q, modulus, &inf)) != CRYPT_OK) return err;
if (inf) {
/* Q is point at infinity >> Result = P */
err = ltc_ecc_copy_point(P, R);
goto done;
}
if ((ltc_mp_cmp(P->x, Q->x) == LTC_MP_EQ) && (ltc_mp_cmp(P->z, Q->z) == LTC_MP_EQ)) {
if (ltc_mp_cmp(P->y, Q->y) == LTC_MP_EQ) {
/* here P = Q >> Result = 2 * P (use doubling) */
ltc_mp_deinit_multi(t1, t2, x, y, z, LTC_NULL);
return ltc_ecc_projective_dbl_point(P, R, ma, modulus, mp);
}
if ((err = ltc_mp_sub(modulus, Q->y, t1)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp(P->y, t1) == LTC_MP_EQ) {
/* here Q = -P >>> Result = the point at infinity */
err = ltc_ecc_set_point_xyz(1, 1, 0, R);
goto done;
}
}
if ((err = ltc_mp_copy(P->x, x)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_copy(P->y, y)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_copy(P->z, z)) != CRYPT_OK) { goto done; }
/* if Z is one then these are no-operations */
if (Q->z != NULL) {
/* T1 = Z' * Z' */
if ((err = ltc_mp_sqr(Q->z, t1)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
/* X = X * T1 */
if ((err = ltc_mp_mul(t1, x, x)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(x, modulus, mp)) != CRYPT_OK) { goto done; }
/* T1 = Z' * T1 */
if ((err = ltc_mp_mul(Q->z, t1, t1)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
/* Y = Y * T1 */
if ((err = ltc_mp_mul(t1, y, y)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(y, modulus, mp)) != CRYPT_OK) { goto done; }
}
/* T1 = Z*Z */
if ((err = ltc_mp_sqr(z, t1)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
/* T2 = X' * T1 */
if ((err = ltc_mp_mul(Q->x, t1, t2)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; }
/* T1 = Z * T1 */
if ((err = ltc_mp_mul(z, t1, t1)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
/* T1 = Y' * T1 */
if ((err = ltc_mp_mul(Q->y, t1, t1)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
/* Y = Y - T1 */
if ((err = ltc_mp_sub(y, t1, y)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp_d(y, 0) == LTC_MP_LT) {
if ((err = ltc_mp_add(y, modulus, y)) != CRYPT_OK) { goto done; }
}
/* T1 = 2T1 */
if ((err = ltc_mp_add(t1, t1, t1)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp(t1, modulus) != LTC_MP_LT) {
if ((err = ltc_mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; }
}
/* T1 = Y + T1 */
if ((err = ltc_mp_add(t1, y, t1)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp(t1, modulus) != LTC_MP_LT) {
if ((err = ltc_mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; }
}
/* X = X - T2 */
if ((err = ltc_mp_sub(x, t2, x)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp_d(x, 0) == LTC_MP_LT) {
if ((err = ltc_mp_add(x, modulus, x)) != CRYPT_OK) { goto done; }
}
/* T2 = 2T2 */
if ((err = ltc_mp_add(t2, t2, t2)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp(t2, modulus) != LTC_MP_LT) {
if ((err = ltc_mp_sub(t2, modulus, t2)) != CRYPT_OK) { goto done; }
}
/* T2 = X + T2 */
if ((err = ltc_mp_add(t2, x, t2)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp(t2, modulus) != LTC_MP_LT) {
if ((err = ltc_mp_sub(t2, modulus, t2)) != CRYPT_OK) { goto done; }
}
/* if Z' != 1 */
if (Q->z != NULL) {
/* Z = Z * Z' */
if ((err = ltc_mp_mul(z, Q->z, z)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(z, modulus, mp)) != CRYPT_OK) { goto done; }
}
/* Z = Z * X */
if ((err = ltc_mp_mul(z, x, z)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(z, modulus, mp)) != CRYPT_OK) { goto done; }
/* T1 = T1 * X */
if ((err = ltc_mp_mul(t1, x, t1)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
/* X = X * X */
if ((err = ltc_mp_sqr(x, x)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(x, modulus, mp)) != CRYPT_OK) { goto done; }
/* T2 = T2 * x */
if ((err = ltc_mp_mul(t2, x, t2)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; }
/* T1 = T1 * X */
if ((err = ltc_mp_mul(t1, x, t1)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
/* X = Y*Y */
if ((err = ltc_mp_sqr(y, x)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(x, modulus, mp)) != CRYPT_OK) { goto done; }
/* X = X - T2 */
if ((err = ltc_mp_sub(x, t2, x)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp_d(x, 0) == LTC_MP_LT) {
if ((err = ltc_mp_add(x, modulus, x)) != CRYPT_OK) { goto done; }
}
/* T2 = T2 - X */
if ((err = ltc_mp_sub(t2, x, t2)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp_d(t2, 0) == LTC_MP_LT) {
if ((err = ltc_mp_add(t2, modulus, t2)) != CRYPT_OK) { goto done; }
}
/* T2 = T2 - X */
if ((err = ltc_mp_sub(t2, x, t2)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp_d(t2, 0) == LTC_MP_LT) {
if ((err = ltc_mp_add(t2, modulus, t2)) != CRYPT_OK) { goto done; }
}
/* T2 = T2 * Y */
if ((err = ltc_mp_mul(t2, y, t2)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; }
/* Y = T2 - T1 */
if ((err = ltc_mp_sub(t2, t1, y)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp_d(y, 0) == LTC_MP_LT) {
if ((err = ltc_mp_add(y, modulus, y)) != CRYPT_OK) { goto done; }
}
/* Y = Y/2 */
if (ltc_mp_isodd(y)) {
if ((err = ltc_mp_add(y, modulus, y)) != CRYPT_OK) { goto done; }
}
if ((err = ltc_mp_div_2(y, y)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_copy(x, R->x)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_copy(y, R->y)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_copy(z, R->z)) != CRYPT_OK) { goto done; }
err = CRYPT_OK;
done:
ltc_mp_deinit_multi(t1, t2, x, y, z, LTC_NULL);
return err;
}
#endif

View File

@@ -0,0 +1,182 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/* ### Point doubling in Jacobian coordinate system ###
*
* let us have a curve: y^2 = x^3 + a*x + b
* in Jacobian coordinates it becomes: y^2 = x^3 + a*x*z^4 + b*z^6
*
* The doubling of P = (Xp, Yp, Zp) is given by R = (Xr, Yr, Zr) where:
* Xr = M^2 - 2*S
* Yr = M * (S - Xr) - 8*T
* Zr = 2 * Yp * Zp
*
* M = 3 * Xp^2 + a*Zp^4
* T = Yp^4
* S = 4 * Xp * Yp^2
*
* SPECIAL CASE: when a == -3 we can compute M as
* M = 3 * (Xp^2 - Zp^4) = 3 * (Xp + Zp^2) * (Xp - Zp^2)
*/
/**
@file ltc_ecc_projective_dbl_point.c
ECC Crypto, Tom St Denis
*/
#if defined(LTC_MECC) && (!defined(LTC_MECC_ACCEL) || defined(LTM_DESC))
/**
Double an ECC point
@param P The point to double
@param R [out] The destination of the double
@param ma ECC curve parameter a in montgomery form
@param modulus The modulus of the field the ECC curve is in
@param mp The "b" value from montgomery_setup()
@return CRYPT_OK on success
*/
int ltc_ecc_projective_dbl_point(const ecc_point *P, ecc_point *R, const void *ma, const void *modulus, void *mp)
{
void *t1, *t2;
int err, inf;
LTC_ARGCHK(P != NULL);
LTC_ARGCHK(R != NULL);
LTC_ARGCHK(modulus != NULL);
LTC_ARGCHK(mp != NULL);
if ((err = ltc_mp_init_multi(&t1, &t2, LTC_NULL)) != CRYPT_OK) {
return err;
}
if (P != R) {
if ((err = ltc_ecc_copy_point(P, R)) != CRYPT_OK) { goto done; }
}
if ((err = ltc_ecc_is_point_at_infinity(P, modulus, &inf)) != CRYPT_OK) return err;
if (inf) {
/* if P is point at infinity >> Result = point at infinity */
err = ltc_ecc_set_point_xyz(1, 1, 0, R);
goto done;
}
/* t1 = Z * Z */
if ((err = ltc_mp_sqr(R->z, t1)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
/* Z = Y * Z */
if ((err = ltc_mp_mul(R->z, R->y, R->z)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(R->z, modulus, mp)) != CRYPT_OK) { goto done; }
/* Z = 2Z */
if ((err = ltc_mp_add(R->z, R->z, R->z)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp(R->z, modulus) != LTC_MP_LT) {
if ((err = ltc_mp_sub(R->z, modulus, R->z)) != CRYPT_OK) { goto done; }
}
if (ma == NULL) { /* special case for curves with a == -3 (10% faster than general case) */
/* T2 = X - T1 */
if ((err = ltc_mp_sub(R->x, t1, t2)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp_d(t2, 0) == LTC_MP_LT) {
if ((err = ltc_mp_add(t2, modulus, t2)) != CRYPT_OK) { goto done; }
}
/* T1 = X + T1 */
if ((err = ltc_mp_add(t1, R->x, t1)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp(t1, modulus) != LTC_MP_LT) {
if ((err = ltc_mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; }
}
/* T2 = T1 * T2 */
if ((err = ltc_mp_mul(t1, t2, t2)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; }
/* T1 = 2T2 */
if ((err = ltc_mp_add(t2, t2, t1)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp(t1, modulus) != LTC_MP_LT) {
if ((err = ltc_mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; }
}
/* T1 = T1 + T2 */
if ((err = ltc_mp_add(t1, t2, t1)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp(t1, modulus) != LTC_MP_LT) {
if ((err = ltc_mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; }
}
}
else {
/* T2 = T1 * T1 */
if ((err = ltc_mp_sqr(t1, t2)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; }
/* T1 = T2 * a */
if ((err = ltc_mp_mul(t2, ma, t1)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; }
/* T2 = X * X */
if ((err = ltc_mp_sqr(R->x, t2)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; }
/* T1 = T2 + T1 */
if ((err = ltc_mp_add(t1, t2, t1)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp(t1, modulus) != LTC_MP_LT) {
if ((err = ltc_mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; }
}
/* T1 = T2 + T1 */
if ((err = ltc_mp_add(t1, t2, t1)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp(t1, modulus) != LTC_MP_LT) {
if ((err = ltc_mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; }
}
/* T1 = T2 + T1 */
if ((err = ltc_mp_add(t1, t2, t1)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp(t1, modulus) != LTC_MP_LT) {
if ((err = ltc_mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; }
}
}
/* Y = 2Y */
if ((err = ltc_mp_add(R->y, R->y, R->y)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp(R->y, modulus) != LTC_MP_LT) {
if ((err = ltc_mp_sub(R->y, modulus, R->y)) != CRYPT_OK) { goto done; }
}
/* Y = Y * Y */
if ((err = ltc_mp_sqr(R->y, R->y)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK) { goto done; }
/* T2 = Y * Y */
if ((err = ltc_mp_sqr(R->y, t2)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; }
/* T2 = T2/2 */
if (ltc_mp_isodd(t2)) {
if ((err = ltc_mp_add(t2, modulus, t2)) != CRYPT_OK) { goto done; }
}
if ((err = ltc_mp_div_2(t2, t2)) != CRYPT_OK) { goto done; }
/* Y = Y * X */
if ((err = ltc_mp_mul(R->y, R->x, R->y)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK) { goto done; }
/* X = T1 * T1 */
if ((err = ltc_mp_sqr(t1, R->x)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(R->x, modulus, mp)) != CRYPT_OK) { goto done; }
/* X = X - Y */
if ((err = ltc_mp_sub(R->x, R->y, R->x)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp_d(R->x, 0) == LTC_MP_LT) {
if ((err = ltc_mp_add(R->x, modulus, R->x)) != CRYPT_OK) { goto done; }
}
/* X = X - Y */
if ((err = ltc_mp_sub(R->x, R->y, R->x)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp_d(R->x, 0) == LTC_MP_LT) {
if ((err = ltc_mp_add(R->x, modulus, R->x)) != CRYPT_OK) { goto done; }
}
/* Y = Y - X */
if ((err = ltc_mp_sub(R->y, R->x, R->y)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp_d(R->y, 0) == LTC_MP_LT) {
if ((err = ltc_mp_add(R->y, modulus, R->y)) != CRYPT_OK) { goto done; }
}
/* Y = Y * T1 */
if ((err = ltc_mp_mul(R->y, t1, R->y)) != CRYPT_OK) { goto done; }
if ((err = ltc_mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK) { goto done; }
/* Y = Y - T2 */
if ((err = ltc_mp_sub(R->y, t2, R->y)) != CRYPT_OK) { goto done; }
if (ltc_mp_cmp_d(R->y, 0) == LTC_MP_LT) {
if ((err = ltc_mp_add(R->y, modulus, R->y)) != CRYPT_OK) { goto done; }
}
err = CRYPT_OK;
done:
ltc_mp_deinit_multi(t2, t1, LTC_NULL);
return err;
}
#endif

View File

@@ -0,0 +1,59 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/* origin of this code - OLPC */
#ifdef LTC_MECC
/**
Verify a key according to ANSI spec
@param key The key to validate
@return CRYPT_OK if successful
*/
int ltc_ecc_verify_key(const ecc_key *key)
{
int err, inf;
ecc_point *point;
void *prime = key->dp.prime;
void *order = key->dp.order;
void *a = key->dp.A;
/* Test 1: Are the x and y points of the public key in the field? */
if (ltc_mp.compare_d(key->pubkey.z, 1) == LTC_MP_EQ) {
if ((ltc_mp.compare(key->pubkey.x, prime) != LTC_MP_LT) ||
(ltc_mp.compare(key->pubkey.y, prime) != LTC_MP_LT) ||
(ltc_mp.compare_d(key->pubkey.x, 0) == LTC_MP_LT) ||
(ltc_mp.compare_d(key->pubkey.y, 0) == LTC_MP_LT) ||
(ltc_mp_iszero(key->pubkey.x) && ltc_mp_iszero(key->pubkey.y))
)
{
err = CRYPT_INVALID_PACKET;
goto done2;
}
}
/* Test 2: is the public key on the curve? */
if ((err = ltc_ecc_is_point(&key->dp, key->pubkey.x, key->pubkey.y)) != CRYPT_OK) { goto done2; }
/* Test 3: does nG = O? (n = order, O = point at infinity, G = public key) */
point = ltc_ecc_new_point();
if ((err = ltc_ecc_mulmod(order, &(key->pubkey), point, a, prime, 1)) != CRYPT_OK) { goto done1; }
err = ltc_ecc_is_point_at_infinity(point, prime, &inf);
if (err != CRYPT_OK || inf) {
err = CRYPT_ERROR;
}
else {
err = CRYPT_OK;
}
done1:
ltc_ecc_del_point(point);
done2:
return err;
}
#endif