@@ -69,12 +69,10 @@ BUILDPYS= $(SAGES:test/%.sage=$(BUILD_PY)/%.py) | |||
.PHONY: clean all test test_ct bench todo doc lib bat sage sagetest gen_headers | |||
.PRECIOUS: $(BUILD_ASM)/%.s $(BUILD_C)/*/%.c $(BUILD_H)/*/%.h $(BUILD_IBIN)/% | |||
GEN_HEADERS=\ | |||
$(BUILD_INC)/decaf/decaf_255.h \ | |||
$(BUILD_INC)/decaf/decaf_448.h \ | |||
$(BUILD_INC)/decaf/decaf_255.hxx \ | |||
$(BUILD_INC)/decaf/decaf_448.hxx \ | |||
$( src/public_include/decaf/* : src/public_include = $(BUILD_INC) ) | |||
HEADER_SRCS= $(shell find src/public_include -name "*.h*") | |||
GEN_HEADERS_0= $(HEADER_SRCS:src/public_include/%=$(BUILD_INC)/%) | |||
GEN_HEADERS_1= $(GEN_HEADERS_0:%.tmpl.h=%.h) | |||
GEN_HEADERS= $(GEN_HEADERS_1:%.tmpl.hxx=%.hxx) | |||
HEADERS= Makefile $(shell find src test -name "*.h") $(BUILD_OBJ)/timestamp $(GEN_HEADERS) | |||
# components needed by the lib | |||
@@ -90,7 +88,6 @@ scan: clean | |||
-enable-checker osx -enable-checker security -enable-checker unix \ | |||
make all | |||
# Internal test programs, which are not part of the final build/bin directory. | |||
$(BUILD_IBIN)/test: $(BUILD_OBJ)/test_decaf.o lib | |||
ifeq ($(UNAME),Darwin) | |||
@@ -125,10 +122,15 @@ $(BUILD_OBJ)/%.o: $(BUILD_ASM)/%.s | |||
$(ASM) $(ASFLAGS) -c -o $@ $< | |||
gen_headers: $(GEN_HEADERS) | |||
$(BUILD_INC)/%: src/public_include/% $(BUILD_OBJ)/timestamp | |||
cp -f $< $@ | |||
$(BUILD_INC)/%.h: src/public_include/%.tmpl.h src/gen_headers/* | |||
python -B src/gen_headers/template.py --per=global --guard=$(@:$(BUILD_INC)/%=%) -o $@ $< | |||
$(GEN_HEADERS): src/gen_headers/*.py src/public_include/decaf/* | |||
python -B src/gen_headers/main.py --hpre=$(BUILD_INC) --ihpre=$(BUILD_H) --cpre=$(BUILD_C) | |||
cp src/public_include/decaf/* $(BUILD_INC)/decaf/ | |||
$(BUILD_INC)/%.hxx: src/public_include/%.tmpl.hxx src/gen_headers/* | |||
python -B src/gen_headers/template.py --per=global --guard=$(@:$(BUILD_INC)/%=%) -o $@ $< | |||
################################################################ | |||
# Per-field code: call with field, arch | |||
@@ -169,13 +171,22 @@ define define_curve | |||
LIBCOMPONENTS += $$(BUILD_OBJ)/$(1)/decaf.o $$(BUILD_OBJ)/$(1)/crypto.o $$(BUILD_OBJ)/$(1)/decaf_tables.o | |||
PER_OBJ_DIRS += $$(BUILD_OBJ)/$(1) | |||
HEADERS_OF_$(1) = $$(HEADERS_OF_$(2)) | |||
GLOBAL_HEADERS_OF_$(1) = $(BUILD_INC)/decaf/decaf_$(3).h $(BUILD_INC)/decaf/decaf_$(3).hxx \ | |||
$(BUILD_INC)/decaf/crypto_$(3).h $(BUILD_INC)/decaf/crypto_$(3).hxx | |||
HEADERS_OF_$(1) = $$(HEADERS_OF_$(2)) $$(GLOBAL_HEADERS_OF_$(1)) | |||
HEADERS += $$(GLOBAL_HEADERS_OF_$(1)) | |||
$$(BUILD_C)/$(1)/%.c: src/per_curve/%.tmpl.c src/gen_headers/* $$(HEADERS_OF_$(2)) | |||
python -B src/gen_headers/template.py --per=curve --item=$(1) --guard=$(1)/`basename $$@` -o $$@ $$< | |||
$$(BUILD_H)/$(1)/%.h: src/per_curve/%.tmpl.h src/gen_headers/* $$(HEADERS_OF_$(2)) | |||
python -B src/gen_headers/template.py --per=curve --item=$(1) --guard=$(1)/`basename $$@` -o $$@ $$< | |||
$$(BUILD_INC)/decaf/decaf_$(3).%: src/per_curve/decaf.tmpl.% src/gen_headers/* $$(HEADERS_OF_$(2)) | |||
python -B src/gen_headers/template.py --per=curve --item=$(1) --guard=$$(@:$(BUILD_INC)/%=%) -o $$@ $$< | |||
$$(BUILD_INC)/decaf/crypto_$(3).%: src/per_curve/crypto.tmpl.% src/gen_headers/* $$(HEADERS_OF_$(2)) | |||
python -B src/gen_headers/template.py --per=curve --item=$(1) --guard=$$(@:$(BUILD_INC)/%=%) -o $$@ $$< | |||
$$(BUILD_IBIN)/decaf_gen_tables_$(1): $$(BUILD_OBJ)/$(1)/decaf_gen_tables.o \ | |||
$$(BUILD_OBJ)/$(1)/decaf.o $$(BUILD_OBJ)/utils.o \ | |||
@@ -200,9 +211,9 @@ endef | |||
################################################################ | |||
# call code above to generate curves and fields | |||
$(eval $(call define_field,p25519,arch_x86_64)) | |||
$(eval $(call define_curve,curve25519,p25519)) | |||
$(eval $(call define_curve,curve25519,p25519,255)) | |||
$(eval $(call define_field,p448,arch_x86_64)) | |||
$(eval $(call define_curve,ed448goldilocks,p448)) | |||
$(eval $(call define_curve,ed448goldilocks,p448,448)) | |||
# The shakesum utility is in the public bin directory. | |||
$(BUILD_BIN)/shakesum: $(BUILD_OBJ)/shakesum.o $(BUILD_OBJ)/shake.o $(BUILD_OBJ)/utils.o | |||
@@ -84,6 +84,7 @@ def ceil_log2(x): | |||
out += 1 | |||
return out | |||
# TODO: reduce this because we can now have expressions. | |||
for field,data in field_data.iteritems(): | |||
if "modulus" not in data: | |||
data["modulus"] = eval(data["gf_desc"].replace("^","**")) | |||
@@ -1,50 +0,0 @@ | |||
from curve_data import curve_data, field_data | |||
from textwrap import dedent | |||
def redoc(filename,doc,author): | |||
doc = doc.replace("\n","\n * ") | |||
doc = dedent(""" | |||
/** | |||
* @file %(filename)s | |||
* @author %(author)s | |||
* | |||
* @copyright | |||
* Copyright (c) 2015-2016 Cryptography Research, Inc. \\n | |||
* Released under the MIT License. See LICENSE.txt for license information. | |||
* | |||
* %(doc)s | |||
* | |||
* @warning This file was automatically generated in Python. | |||
* Please do not edit it. | |||
*/""") % { "filename": filename, "doc": doc, "author" : author } | |||
doc = doc.replace(" * \n", " *\n") | |||
return doc[1:] | |||
gend_files = {} | |||
per_map = {"field":field_data, "curve":curve_data, "global":{"global":{}} } | |||
def gen_file(public,name,doc,code,per="global",author="Mike Hamburg"): | |||
is_header = name.endswith(".h") or name.endswith(".hxx") or name.endswith(".h++") | |||
for curve,data in per_map[per].iteritems(): | |||
ns_name = name % data | |||
_,_,name_base = ns_name.rpartition("/") | |||
header_guard = "__" + ns_name.replace(".","_").replace("/","_").upper() + "__" | |||
ns_doc = dedent(doc).strip().rstrip() | |||
ns_doc = redoc(ns_name, ns_doc % data, author) | |||
ns_code = code % data | |||
ret = ns_doc + "\n" | |||
if is_header: | |||
ns_code = dedent("""\n | |||
#ifndef %(header_guard)s | |||
#define %(header_guard)s 1 | |||
%(code)s | |||
#endif /* %(header_guard)s */ | |||
""") % { "header_guard" : header_guard, "code": ns_code } | |||
ret += ns_code[1:-1] | |||
gend_files[ns_name] = (public,ret) |
@@ -1,119 +0,0 @@ | |||
from gen_file import gen_file,gend_files | |||
import os | |||
import argparse | |||
import re | |||
parser = argparse.ArgumentParser(description='Generate Decaf headers and other such files.') | |||
parser.add_argument('--hpre', required = True, help = "Where to put the public header files") | |||
parser.add_argument('--ihpre', required = True, help = "Where to put the internal header files") | |||
parser.add_argument('--cpre', required = True, help = "Where to put the C/C++ implementation files") | |||
args = parser.parse_args() | |||
prefixes = { (True,"h") : args.hpre, (True,"hxx") : args.hpre, (False,"c") : args.cpre, (False,"h") : args.ihpre } | |||
from decaf_hxx import decaf_hxx | |||
from decaf_h import decaf_h | |||
from crypto_h import crypto_h | |||
from crypto_hxx import crypto_hxx | |||
from curve_data import curve_data | |||
root_hxx_code = "\n".join(( | |||
"#include <%s>" % name | |||
for name in sorted(gend_files) | |||
if re.match("^decaf/decaf_\d+.hxx$",name) | |||
)) | |||
root_hxx_code += """ | |||
namespace decaf { | |||
template <template<typename Group> class Run> | |||
void run_for_all_curves() { | |||
""" | |||
root_hxx_code += "\n".join(( | |||
" Run<%s>::run();" % cd["cxx_ns"] | |||
for cd in sorted(curve_data.values(), key=lambda x:x["c_ns"]) | |||
)) | |||
root_hxx_code += """ | |||
} | |||
} | |||
""" | |||
decaf_root_hxx = gen_file( | |||
public = True, | |||
per = "global", | |||
name = "decaf.hxx", | |||
doc = """@brief Decaf curve metaheader.""", | |||
code = "\n"+root_hxx_code+"\n" | |||
) | |||
crypto_h_code = "\n".join(( | |||
"#include <%s>" % name | |||
for name in sorted(gend_files) | |||
if re.match("^decaf/crypto_\d+.h$",name) | |||
)) | |||
crypto_h = gen_file( | |||
public = True, | |||
per = "global", | |||
name = "decaf/crypto.h", | |||
doc = """ | |||
Example Decaf crypto routines, metaheader. | |||
@warning These are merely examples, though they ought to be secure. But real | |||
protocols will decide differently on magic numbers, formats, which items to | |||
hash, etc. | |||
""", | |||
code = "\n"+crypto_h_code+"\n" | |||
) | |||
crypto_hxx_code = "\n".join(( | |||
"#include <%s>" % name | |||
for name in sorted(gend_files) | |||
if re.match("^decaf/crypto_\d+.hxx$",name) | |||
)) | |||
crypto_hxx = gen_file( | |||
public = True, | |||
per = "global", | |||
name = "decaf/crypto.hxx", | |||
doc = """ | |||
Example Decaf crypto routines, C++, metaheader. | |||
@warning These are merely examples, though they ought to be secure. But real | |||
protocols will decide differently on magic numbers, formats, which items to | |||
hash, etc. | |||
""", | |||
code = "\n"+crypto_hxx_code+"\n" | |||
) | |||
root_h_code = "\n".join(( | |||
"#include <%s>" % name | |||
for name in sorted(gend_files) | |||
if re.match("^decaf/decaf_\d+.h$",name) | |||
)) | |||
decaf_root_hxx = gen_file( | |||
public = True, | |||
per = "global", | |||
name = "decaf.h", | |||
doc = """ | |||
Master header for Decaf library. | |||
The Decaf library implements cryptographic operations on a elliptic curve | |||
groups of prime order p. It accomplishes this by using a twisted Edwards | |||
curve (isogenous to Ed448-Goldilocks or Ed25519) and wiping out the cofactor. | |||
The formulas are all complete and have no special cases. However, some | |||
functions can fail. For example, decoding functions can fail because not | |||
every string is the encoding of a valid group element. | |||
The formulas contain no data-dependent branches, timing or memory accesses, | |||
except for decaf_XXX_base_double_scalarmul_non_secret. | |||
""", | |||
code = "\n"+root_h_code+"\n" | |||
) | |||
for name,(public,code) in gend_files.iteritems(): | |||
_,_,name_suffix = name.rpartition(".") | |||
prefix = prefixes[(public,name_suffix)] | |||
if not os.path.exists(os.path.dirname(prefix + "/" + name)): | |||
os.makedirs(os.path.dirname(prefix + "/" + name)) | |||
with open(prefix + "/" + name,"w") as f: | |||
f.write(code + "\n") | |||
@@ -13,7 +13,7 @@ parser.add_argument('--guard', required = False, default = None, help = "header | |||
parser.add_argument('files', metavar='file', type=str, nargs='+', help='a list of files to fill') | |||
args = parser.parse_args() | |||
per_map = {"field":field_data, "curve":curve_data, "global":{"global":{}} } | |||
per_map = {"field":field_data, "curve":curve_data, "global":{"global":{"field":field_data,"curve":curve_data} }} | |||
def redoc(filename,doc,author): | |||
doc = doc.replace("\n","\n * ") | |||
@@ -1,17 +1,12 @@ | |||
from gen_file import gen_file | |||
/** | |||
* Example Decaf crypto routines. | |||
* @warning These are merely examples, though they ought to be secure. But real | |||
* protocols will decide differently on magic numbers, formats, which items to | |||
* hash, etc. | |||
* @warning Experimental! The names, parameter orders etc are likely to change. | |||
*/ | |||
crypto_h = gen_file( | |||
public = True, | |||
per = "curve", | |||
name = "decaf/crypto_%(shortname)s.h", | |||
doc = """ | |||
Example Decaf crypto routines. | |||
@warning These are merely examples, though they ought to be secure. But real | |||
protocols will decide differently on magic numbers, formats, which items to | |||
hash, etc. | |||
@warning Experimental! The names, parameter orders etc are likely to change. | |||
""", code = """ | |||
#include <decaf/%(c_ns)s.h> | |||
#include <decaf/$(c_ns).h> | |||
#include <decaf/strobe.h> | |||
#ifdef __cplusplus | |||
@@ -19,48 +14,48 @@ extern "C" { | |||
#endif | |||
/** Number of bytes for a symmetric key (expanded to full key) */ | |||
#define %(C_NS)s_SYMMETRIC_KEY_BYTES 32 | |||
#define $(C_NS)_SYMMETRIC_KEY_BYTES 32 | |||
/** A symmetric key, the compressed point of a private key. */ | |||
typedef unsigned char %(c_ns)s_symmetric_key_t[%(C_NS)s_SYMMETRIC_KEY_BYTES]; | |||
typedef unsigned char $(c_ns)_symmetric_key_t[$(C_NS)_SYMMETRIC_KEY_BYTES]; | |||
/** An encoded public key. */ | |||
typedef unsigned char %(c_ns)s_public_key_t[%(C_NS)s_SER_BYTES]; | |||
typedef unsigned char $(c_ns)_public_key_t[$(C_NS)_SER_BYTES]; | |||
/** A signature. */ | |||
typedef unsigned char %(c_ns)s_signature_t[%(C_NS)s_SER_BYTES + %(C_NS)s_SCALAR_BYTES]; | |||
typedef unsigned char $(c_ns)_signature_t[$(C_NS)_SER_BYTES + $(C_NS)_SCALAR_BYTES]; | |||
typedef struct { | |||
/** @cond internal */ | |||
/** The symmetric key from which everything is expanded */ | |||
%(c_ns)s_symmetric_key_t sym; | |||
$(c_ns)_symmetric_key_t sym; | |||
/** The scalar x */ | |||
%(c_ns)s_scalar_t secret_scalar; | |||
$(c_ns)_scalar_t secret_scalar; | |||
/** x*Base */ | |||
%(c_ns)s_public_key_t pub; | |||
$(c_ns)_public_key_t pub; | |||
/** @endcond */ | |||
} /** Private key structure for pointers. */ | |||
%(c_ns)s_private_key_s, | |||
$(c_ns)_private_key_s, | |||
/** A private key (gmp array[1] style). */ | |||
%(c_ns)s_private_key_t[1]; | |||
$(c_ns)_private_key_t[1]; | |||
/** | |||
* Derive a key from its compressed form. | |||
* @param [out] priv The derived private key. | |||
* @param [in] proto The compressed or proto-key, which must be 32 random bytes. | |||
*/ | |||
void %(c_ns)s_derive_private_key ( | |||
%(c_ns)s_private_key_t priv, | |||
const %(c_ns)s_symmetric_key_t proto | |||
void $(c_ns)_derive_private_key ( | |||
$(c_ns)_private_key_t priv, | |||
const $(c_ns)_symmetric_key_t proto | |||
) NONNULL2 API_VIS; | |||
/** | |||
* Destroy a private key. | |||
*/ | |||
void %(c_ns)s_destroy_private_key ( | |||
%(c_ns)s_private_key_t priv | |||
void $(c_ns)_destroy_private_key ( | |||
$(c_ns)_private_key_t priv | |||
) NONNULL1 API_VIS; | |||
/** | |||
@@ -68,9 +63,9 @@ void %(c_ns)s_destroy_private_key ( | |||
* @param [out] pub The extracted private key. | |||
* @param [in] priv The private key. | |||
*/ | |||
void %(c_ns)s_private_to_public ( | |||
%(c_ns)s_public_key_t pub, | |||
const %(c_ns)s_private_key_t priv | |||
void $(c_ns)_private_to_public ( | |||
$(c_ns)_public_key_t pub, | |||
const $(c_ns)_private_key_t priv | |||
) NONNULL2 API_VIS; | |||
/** | |||
@@ -89,11 +84,11 @@ void %(c_ns)s_private_to_public ( | |||
* @retval DECAF_FAILURE Key exchange failed. | |||
*/ | |||
decaf_error_t | |||
%(c_ns)s_shared_secret ( | |||
$(c_ns)_shared_secret ( | |||
uint8_t *shared, | |||
size_t shared_bytes, | |||
const %(c_ns)s_private_key_t my_privkey, | |||
const %(c_ns)s_public_key_t your_pubkey, | |||
const $(c_ns)_private_key_t my_privkey, | |||
const $(c_ns)_public_key_t your_pubkey, | |||
int me_first | |||
) NONNULL134 WARN_UNUSED API_VIS; | |||
@@ -105,10 +100,10 @@ decaf_error_t | |||
* @param [in] strobe A STROBE context with the message. | |||
*/ | |||
void | |||
%(c_ns)s_sign_strobe ( | |||
$(c_ns)_sign_strobe ( | |||
keccak_strobe_t strobe, | |||
%(c_ns)s_signature_t sig, | |||
const %(c_ns)s_private_key_t priv | |||
$(c_ns)_signature_t sig, | |||
const $(c_ns)_private_key_t priv | |||
) NONNULL3 API_VIS; | |||
/** | |||
@@ -120,9 +115,9 @@ void | |||
* @param [in] message_len The message's length. | |||
*/ | |||
void | |||
%(c_ns)s_sign ( | |||
%(c_ns)s_signature_t sig, | |||
const %(c_ns)s_private_key_t priv, | |||
$(c_ns)_sign ( | |||
$(c_ns)_signature_t sig, | |||
const $(c_ns)_private_key_t priv, | |||
const unsigned char *message, | |||
size_t message_len | |||
) NONNULL3 API_VIS; | |||
@@ -138,10 +133,10 @@ void | |||
* @return DECAF_FAILURE The signature did not verify successfully. | |||
*/ | |||
decaf_error_t | |||
%(c_ns)s_verify_strobe ( | |||
$(c_ns)_verify_strobe ( | |||
keccak_strobe_t strobe, | |||
const %(c_ns)s_signature_t sig, | |||
const %(c_ns)s_public_key_t pub | |||
const $(c_ns)_signature_t sig, | |||
const $(c_ns)_public_key_t pub | |||
) NONNULL3 API_VIS WARN_UNUSED; | |||
/** | |||
@@ -156,9 +151,9 @@ decaf_error_t | |||
* @return DECAF_FAILURE The signature did not verify successfully. | |||
*/ | |||
decaf_error_t | |||
%(c_ns)s_verify ( | |||
const %(c_ns)s_signature_t sig, | |||
const %(c_ns)s_public_key_t pub, | |||
$(c_ns)_verify ( | |||
const $(c_ns)_signature_t sig, | |||
const $(c_ns)_public_key_t pub, | |||
const unsigned char *message, | |||
size_t message_len | |||
) NONNULL3 API_VIS WARN_UNUSED; | |||
@@ -166,4 +161,3 @@ decaf_error_t | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
""") |
@@ -1,17 +1,12 @@ | |||
from gen_file import gen_file | |||
/* | |||
* Example Decaf cyrpto routines, C++ wrapper. | |||
* @warning These are merely examples, though they ought to be secure. But real | |||
* protocols will decide differently on magic numbers, formats, which items to | |||
* hash, etc. | |||
* @warning Experimental! The names, parameter orders etc are likely to change. | |||
*/ | |||
crypto_hxx = gen_file( | |||
public = True, | |||
per = "curve", | |||
name = "decaf/crypto_%(shortname)s.hxx", | |||
doc = """ | |||
Example Decaf cyrpto routines, C++ wrapper. | |||
@warning These are merely examples, though they ought to be secure. But real | |||
protocols will decide differently on magic numbers, formats, which items to | |||
hash, etc. | |||
@warning Experimental! The names, parameter orders etc are likely to change. | |||
""", code = """ | |||
#include <decaf.hxx> | |||
#include <decaf/decaf_$(gf_bits).hxx> | |||
#include <decaf/shake.hxx> | |||
#include <decaf/strobe.hxx> | |||
@@ -31,21 +26,21 @@ template <typename Group> class PublicKey; | |||
/** A private key for crypto over some Group */ | |||
template <typename Group> class PrivateKey; | |||
/** A public key for crypto over %(name)s */ | |||
template<> class PublicKey<%(cxx_ns)s> | |||
: public Serializable< PublicKey<%(cxx_ns)s> > { | |||
/** A public key for crypto over $(name) */ | |||
template<> class PublicKey<$(cxx_ns)> | |||
: public Serializable< PublicKey<$(cxx_ns)> > { | |||
private: | |||
/** @cond internal */ | |||
typedef %(c_ns)s_public_key_t Wrapped; | |||
typedef $(c_ns)_public_key_t Wrapped; | |||
Wrapped wrapped; | |||
template<class Group> friend class PrivateKey; | |||
/** @endcond */ | |||
public: | |||
/** Underlying group */ | |||
typedef %(cxx_ns)s Group; | |||
typedef $(cxx_ns) Group; | |||
/** Signature size. */ | |||
static const size_t SIG_BYTES = sizeof(%(c_ns)s_signature_t); | |||
static const size_t SIG_BYTES = sizeof($(c_ns)_signature_t); | |||
/** Serialization size. */ | |||
static const size_t SER_BYTES = sizeof(Wrapped); | |||
@@ -56,7 +51,7 @@ public: | |||
} | |||
/** Read a private key from a string*/ | |||
inline explicit PublicKey(const PrivateKey<%(cxx_ns)s> &b) NOEXCEPT; | |||
inline explicit PublicKey(const PrivateKey<$(cxx_ns)> &b) NOEXCEPT; | |||
/** Create but don't initialize */ | |||
inline explicit PublicKey(const NOINIT&) NOEXCEPT { } | |||
@@ -74,7 +69,7 @@ public: | |||
const Block &message, | |||
const FixedBlock<SIG_BYTES> &sig | |||
) const throw(CryptoException) { | |||
if (DECAF_SUCCESS != %(c_ns)s_verify(sig.data(),wrapped,message.data(),message.size())) { | |||
if (DECAF_SUCCESS != $(c_ns)_verify(sig.data(),wrapped,message.data(),message.size())) { | |||
throw(CryptoException()); | |||
} | |||
} | |||
@@ -84,33 +79,33 @@ public: | |||
Strobe &context, | |||
const FixedBlock<SIG_BYTES> &sig | |||
) const throw(CryptoException) { | |||
if (DECAF_SUCCESS != %(c_ns)s_verify_strobe(context.wrapped,sig.data(),wrapped)) { | |||
if (DECAF_SUCCESS != $(c_ns)_verify_strobe(context.wrapped,sig.data(),wrapped)) { | |||
throw(CryptoException()); | |||
} | |||
} | |||
}; | |||
/** A private key for crypto over %(name)s */ | |||
template<> class PrivateKey<%(cxx_ns)s> | |||
: public Serializable< PrivateKey<%(cxx_ns)s> > { | |||
/** A private key for crypto over $(name) */ | |||
template<> class PrivateKey<$(cxx_ns)> | |||
: public Serializable< PrivateKey<$(cxx_ns)> > { | |||
private: | |||
/** @cond internal */ | |||
typedef %(c_ns)s_private_key_t Wrapped; | |||
typedef $(c_ns)_private_key_t Wrapped; | |||
Wrapped wrapped; | |||
template<class Group> friend class PublicKey; | |||
/** @endcond */ | |||
public: | |||
/** Underlying group */ | |||
typedef %(cxx_ns)s Group; | |||
typedef $(cxx_ns) Group; | |||
/** Signature size. */ | |||
static const size_t SIG_BYTES = sizeof(%(c_ns)s_signature_t); | |||
static const size_t SIG_BYTES = sizeof($(c_ns)_signature_t); | |||
/** Serialization size. */ | |||
static const size_t SER_BYTES = sizeof(Wrapped); | |||
/** Compressed size. */ | |||
static const size_t SYM_BYTES = %(C_NS)s_SYMMETRIC_KEY_BYTES; | |||
static const size_t SYM_BYTES = $(C_NS)_SYMMETRIC_KEY_BYTES; | |||
/** Create but don't initialize */ | |||
inline explicit PrivateKey(const NOINIT&) NOEXCEPT { } | |||
@@ -122,18 +117,18 @@ public: | |||
/** Read a private key from a string*/ | |||
inline explicit PrivateKey(const FixedBlock<SYM_BYTES> &b) NOEXCEPT { | |||
%(c_ns)s_derive_private_key(wrapped, b.data()); | |||
$(c_ns)_derive_private_key(wrapped, b.data()); | |||
} | |||
/** Create at random */ | |||
inline explicit PrivateKey(Rng &r) NOEXCEPT { | |||
FixedArrayBuffer<SYM_BYTES> tmp(r); | |||
%(c_ns)s_derive_private_key(wrapped, tmp.data()); | |||
$(c_ns)_derive_private_key(wrapped, tmp.data()); | |||
} | |||
/** Secure destructor */ | |||
inline ~PrivateKey() NOEXCEPT { | |||
%(c_ns)s_destroy_private_key(wrapped); | |||
$(c_ns)_destroy_private_key(wrapped); | |||
} | |||
/** Serialization size. */ | |||
@@ -152,18 +147,18 @@ public: | |||
} | |||
/** Get the public key */ | |||
inline PublicKey<%(cxx_ns)s> pub() const NOEXCEPT { | |||
PublicKey<%(cxx_ns)s> ret(*this); return ret; | |||
inline PublicKey<$(cxx_ns)> pub() const NOEXCEPT { | |||
PublicKey<$(cxx_ns)> ret(*this); return ret; | |||
} | |||
/** Derive a shared secret */ | |||
inline SecureBuffer sharedSecret( | |||
const PublicKey<%(cxx_ns)s> &pub, | |||
const PublicKey<$(cxx_ns)> &pub, | |||
size_t bytes, | |||
bool me_first | |||
) const throw(CryptoException,std::bad_alloc) { | |||
SecureBuffer ret(bytes); | |||
if (DECAF_SUCCESS != %(c_ns)s_shared_secret(ret.data(),bytes,wrapped,pub.wrapped,me_first)) { | |||
if (DECAF_SUCCESS != $(c_ns)_shared_secret(ret.data(),bytes,wrapped,pub.wrapped,me_first)) { | |||
throw(CryptoException()); | |||
} | |||
return ret; | |||
@@ -173,33 +168,32 @@ public: | |||
inline decaf_error_t __attribute__((warn_unused_result)) | |||
sharedSecretNoexcept( | |||
Buffer ret, | |||
const PublicKey<%(cxx_ns)s> &pub, | |||
const PublicKey<$(cxx_ns)> &pub, | |||
bool me_first | |||
) const NOEXCEPT { | |||
return %(c_ns)s_shared_secret(ret.data(),ret.size(),wrapped,pub.wrapped,me_first); | |||
return $(c_ns)_shared_secret(ret.data(),ret.size(),wrapped,pub.wrapped,me_first); | |||
} | |||
/** Sign a message. */ | |||
inline SecureBuffer sign(const Block &message) const { | |||
SecureBuffer sig(SIG_BYTES); | |||
%(c_ns)s_sign(sig.data(), wrapped, message.data(), message.size()); | |||
$(c_ns)_sign(sig.data(), wrapped, message.data(), message.size()); | |||
return sig; | |||
} | |||
/** Sign a message. */ | |||
inline SecureBuffer verify(Strobe &context) const { | |||
SecureBuffer sig(SIG_BYTES); | |||
%(c_ns)s_sign_strobe(context.wrapped, sig.data(), wrapped); | |||
$(c_ns)_sign_strobe(context.wrapped, sig.data(), wrapped); | |||
return sig; | |||
} | |||
}; | |||
/** @cond internal */ | |||
PublicKey<%(cxx_ns)s>::PublicKey(const PrivateKey<%(cxx_ns)s> &b) NOEXCEPT { | |||
%(c_ns)s_private_to_public(wrapped,b.wrapped); | |||
PublicKey<$(cxx_ns)>::PublicKey(const PrivateKey<$(cxx_ns)> &b) NOEXCEPT { | |||
$(c_ns)_private_to_public(wrapped,b.wrapped); | |||
} | |||
/** @endcond */ | |||
#undef NOEXCEPT | |||
} /* namespace decaf */ | |||
""") | |||
} /* namespace decaf */ |
@@ -19,7 +19,7 @@ | |||
#define IMAGINE_TWIST $(imagine_twist) | |||
#define COFACTOR $(cofactor) | |||
/** Comb config: number of combs, n, t, s. */ | |||
/* Comb config: number of combs, n, t, s. */ | |||
#define COMBS_N $(combs.n) | |||
#define COMBS_T $(combs.t) | |||
#define COMBS_S $(combs.s) | |||
@@ -39,9 +39,7 @@ static const scalar_t sc_p = {{{ | |||
}}}; | |||
static const decaf_word_t MONTGOMERY_FACTOR = (decaf_word_t)0x$("%x" % pow(-q,2**64-1,2**64))ull; | |||
const uint8_t API_NS(x_base_point)[SER_BYTES] /* TODO */ = { | |||
$(ser(mont_base,8)) | |||
}; | |||
const uint8_t API_NS(x_base_point)[SER_BYTES] = { $(ser(mont_base,8)) }; | |||
#if COFACTOR==8 | |||
static const gf SQRT_ONE_MINUS_D = {FIELD_LITERAL( | |||
@@ -1,11 +1,5 @@ | |||
from gen_file import gen_file | |||
decaf_h = gen_file( | |||
public = True, | |||
per = "curve", | |||
name = "decaf/%(c_ns)s.h", | |||
doc = """@brief A group of prime order p, based on %(iso_to)s.""", | |||
code = """ | |||
/** @brief A group of prime order p, based on $(iso_to). */ | |||
#include <decaf/common.h> | |||
#ifdef __cplusplus | |||
@@ -13,78 +7,78 @@ extern "C" { | |||
#endif | |||
/** @cond internal */ | |||
#define %(C_NS)s_SCALAR_LIMBS ((%(scalar_bits)d-1)/DECAF_WORD_BITS+1) | |||
#define $(C_NS)_SCALAR_LIMBS (($(scalar_bits)-1)/DECAF_WORD_BITS+1) | |||
/** @endcond */ | |||
/** The number of bits in a scalar */ | |||
#define %(C_NS)s_SCALAR_BITS %(scalar_bits)d | |||
#define $(C_NS)_SCALAR_BITS $(scalar_bits) | |||
/** @cond internal */ | |||
#ifndef __DECAF_%(gf_shortname)s_GF_DEFINED__ | |||
#define __DECAF_%(gf_shortname)s_GF_DEFINED__ 1 | |||
#ifndef __DECAF_$(gf_shortname)_GF_DEFINED__ | |||
#define __DECAF_$(gf_shortname)_GF_DEFINED__ 1 | |||
/** @brief Galois field element internal structure */ | |||
typedef struct gf_%(gf_shortname)s_s { | |||
decaf_word_t limb[%(gf_impl_bits)d/DECAF_WORD_BITS]; | |||
} __attribute__((aligned(32))) gf_%(gf_shortname)s_s, gf_%(gf_shortname)s_t[1]; | |||
#endif /* __DECAF_%(gf_shortname)s_GF_DEFINED__ */ | |||
typedef struct gf_$(gf_shortname)_s { | |||
decaf_word_t limb[$(gf_impl_bits)/DECAF_WORD_BITS]; | |||
} __attribute__((aligned(32))) gf_$(gf_shortname)_s, gf_$(gf_shortname)_t[1]; | |||
#endif /* __DECAF_$(gf_shortname)_GF_DEFINED__ */ | |||
/** @endcond */ | |||
/** Number of bytes in a serialized point. */ | |||
#define %(C_NS)s_SER_BYTES %(ser_bytes)d | |||
#define $(C_NS)_SER_BYTES $(ser_bytes) | |||
/** Number of bytes in a serialized scalar. */ | |||
#define %(C_NS)s_SCALAR_BYTES %(scalar_ser_bytes)d | |||
#define $(C_NS)_SCALAR_BYTES $(scalar_ser_bytes) | |||
/** Number of bytes in an x%(gf_shortname)s public key */ | |||
#define X%(gf_shortname)s_PUBLIC_BYTES %(x_pub_bytes)d | |||
/** Number of bytes in an x$(gf_shortname) public key */ | |||
#define X$(gf_shortname)_PUBLIC_BYTES $(x_pub_bytes) | |||
/** Number of bytes in an x%(gf_shortname)s private key */ | |||
#define X%(gf_shortname)s_PRIVATE_BYTES %(x_priv_bytes)d | |||
/** Number of bytes in an x$(gf_shortname) private key */ | |||
#define X$(gf_shortname)_PRIVATE_BYTES $(x_priv_bytes) | |||
/** Twisted Edwards extended homogeneous coordinates */ | |||
typedef struct %(c_ns)s_point_s { | |||
typedef struct $(c_ns)_point_s { | |||
/** @cond internal */ | |||
gf_%(gf_shortname)s_t x,y,z,t; | |||
gf_$(gf_shortname)_t x,y,z,t; | |||
/** @endcond */ | |||
} %(c_ns)s_point_t[1]; | |||
} $(c_ns)_point_t[1]; | |||
/** Precomputed table based on a point. Can be trivial implementation. */ | |||
struct %(c_ns)s_precomputed_s; | |||
struct $(c_ns)_precomputed_s; | |||
/** Precomputed table based on a point. Can be trivial implementation. */ | |||
typedef struct %(c_ns)s_precomputed_s %(c_ns)s_precomputed_s; | |||
typedef struct $(c_ns)_precomputed_s $(c_ns)_precomputed_s; | |||
/** Size and alignment of precomputed point tables. */ | |||
extern const size_t %(c_ns)s_sizeof_precomputed_s API_VIS, %(c_ns)s_alignof_precomputed_s API_VIS; | |||
extern const size_t $(c_ns)_sizeof_precomputed_s API_VIS, $(c_ns)_alignof_precomputed_s API_VIS; | |||
/** Scalar is stored packed, because we don't need the speed. */ | |||
typedef struct %(c_ns)s_scalar_s { | |||
typedef struct $(c_ns)_scalar_s { | |||
/** @cond internal */ | |||
decaf_word_t limb[%(C_NS)s_SCALAR_LIMBS]; | |||
decaf_word_t limb[$(C_NS)_SCALAR_LIMBS]; | |||
/** @endcond */ | |||
} %(c_ns)s_scalar_t[1]; | |||
} $(c_ns)_scalar_t[1]; | |||
/** A scalar equal to 1. */ | |||
extern const %(c_ns)s_scalar_t %(c_ns)s_scalar_one API_VIS; | |||
extern const $(c_ns)_scalar_t $(c_ns)_scalar_one API_VIS; | |||
/** A scalar equal to 0. */ | |||
extern const %(c_ns)s_scalar_t %(c_ns)s_scalar_zero API_VIS; | |||
extern const $(c_ns)_scalar_t $(c_ns)_scalar_zero API_VIS; | |||
/** The identity point on the curve. */ | |||
extern const %(c_ns)s_point_t %(c_ns)s_point_identity API_VIS; | |||
extern const $(c_ns)_point_t $(c_ns)_point_identity API_VIS; | |||
/** An arbitrarily chosen base point on the curve. | |||
* @warning TODO: this is subject to change. It is currently | |||
* the preimage of the X%(gf_shortname)s base point. Sometime | |||
* soon, we will merge and finalize support for X%(gf_shortname)s | |||
* and Ed%(gf_shortname)s integration. This might make some | |||
* the preimage of the X$(gf_shortname) base point. Sometime | |||
* soon, we will merge and finalize support for X$(gf_shortname) | |||
* and Ed$(gf_shortname) integration. This might make some | |||
* multiple of the current basepoint (eg twice it, or the cofactor | |||
* times it) more convenient API-wise, and trigger a changeover. | |||
*/ | |||
extern const %(c_ns)s_point_t %(c_ns)s_point_base API_VIS; | |||
extern const $(c_ns)_point_t $(c_ns)_point_base API_VIS; | |||
/** Precomputed table for the base point on the curve. */ | |||
extern const struct %(c_ns)s_precomputed_s *%(c_ns)s_precomputed_base API_VIS; | |||
extern const struct $(c_ns)_precomputed_s *$(c_ns)_precomputed_base API_VIS; | |||
/** | |||
* @brief Read a scalar from wire format or from bytes. | |||
@@ -96,9 +90,9 @@ extern const struct %(c_ns)s_precomputed_s *%(c_ns)s_precomputed_base API_VIS; | |||
* @retval DECAF_FAILURE The scalar was greater than the modulus, | |||
* and has been reduced modulo that modulus. | |||
*/ | |||
decaf_error_t %(c_ns)s_scalar_decode ( | |||
%(c_ns)s_scalar_t out, | |||
const unsigned char ser[%(C_NS)s_SCALAR_BYTES] | |||
decaf_error_t $(c_ns)_scalar_decode ( | |||
$(c_ns)_scalar_t out, | |||
const unsigned char ser[$(C_NS)_SCALAR_BYTES] | |||
) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
/** | |||
@@ -109,8 +103,8 @@ decaf_error_t %(c_ns)s_scalar_decode ( | |||
* @param [in] ser_len Length of serialized form. | |||
* @param [out] out Deserialized form. | |||
*/ | |||
void %(c_ns)s_scalar_decode_long ( | |||
%(c_ns)s_scalar_t out, | |||
void $(c_ns)_scalar_decode_long ( | |||
$(c_ns)_scalar_t out, | |||
const unsigned char *ser, | |||
size_t ser_len | |||
) API_VIS NONNULL2 NOINLINE; | |||
@@ -121,9 +115,9 @@ void %(c_ns)s_scalar_decode_long ( | |||
* @param [out] ser Serialized form of a scalar. | |||
* @param [in] s Deserialized scalar. | |||
*/ | |||
void %(c_ns)s_scalar_encode ( | |||
unsigned char ser[%(C_NS)s_SCALAR_BYTES], | |||
const %(c_ns)s_scalar_t s | |||
void $(c_ns)_scalar_encode ( | |||
unsigned char ser[$(C_NS)_SCALAR_BYTES], | |||
const $(c_ns)_scalar_t s | |||
) API_VIS NONNULL2 NOINLINE NOINLINE; | |||
/** | |||
@@ -132,10 +126,10 @@ void %(c_ns)s_scalar_encode ( | |||
* @param [in] b Another scalar. | |||
* @param [out] out a+b. | |||
*/ | |||
void %(c_ns)s_scalar_add ( | |||
%(c_ns)s_scalar_t out, | |||
const %(c_ns)s_scalar_t a, | |||
const %(c_ns)s_scalar_t b | |||
void $(c_ns)_scalar_add ( | |||
$(c_ns)_scalar_t out, | |||
const $(c_ns)_scalar_t a, | |||
const $(c_ns)_scalar_t b | |||
) API_VIS NONNULL3 NOINLINE; | |||
/** | |||
@@ -145,9 +139,9 @@ void %(c_ns)s_scalar_add ( | |||
* @retval DECAF_TRUE The scalars are equal. | |||
* @retval DECAF_FALSE The scalars are not equal. | |||
*/ | |||
decaf_bool_t %(c_ns)s_scalar_eq ( | |||
const %(c_ns)s_scalar_t a, | |||
const %(c_ns)s_scalar_t b | |||
decaf_bool_t $(c_ns)_scalar_eq ( | |||
const $(c_ns)_scalar_t a, | |||
const $(c_ns)_scalar_t b | |||
) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
/** | |||
@@ -156,10 +150,10 @@ decaf_bool_t %(c_ns)s_scalar_eq ( | |||
* @param [in] b Another scalar. | |||
* @param [out] out a-b. | |||
*/ | |||
void %(c_ns)s_scalar_sub ( | |||
%(c_ns)s_scalar_t out, | |||
const %(c_ns)s_scalar_t a, | |||
const %(c_ns)s_scalar_t b | |||
void $(c_ns)_scalar_sub ( | |||
$(c_ns)_scalar_t out, | |||
const $(c_ns)_scalar_t a, | |||
const $(c_ns)_scalar_t b | |||
) API_VIS NONNULL3 NOINLINE; | |||
/** | |||
@@ -168,10 +162,10 @@ void %(c_ns)s_scalar_sub ( | |||
* @param [in] b Another scalar. | |||
* @param [out] out a*b. | |||
*/ | |||
void %(c_ns)s_scalar_mul ( | |||
%(c_ns)s_scalar_t out, | |||
const %(c_ns)s_scalar_t a, | |||
const %(c_ns)s_scalar_t b | |||
void $(c_ns)_scalar_mul ( | |||
$(c_ns)_scalar_t out, | |||
const $(c_ns)_scalar_t a, | |||
const $(c_ns)_scalar_t b | |||
) API_VIS NONNULL3 NOINLINE; | |||
/** | |||
@@ -180,9 +174,9 @@ void %(c_ns)s_scalar_mul ( | |||
* @param [out] out 1/a. | |||
* @return DECAF_SUCCESS The input is nonzero. | |||
*/ | |||
decaf_error_t %(c_ns)s_scalar_invert ( | |||
%(c_ns)s_scalar_t out, | |||
const %(c_ns)s_scalar_t a | |||
decaf_error_t $(c_ns)_scalar_invert ( | |||
$(c_ns)_scalar_t out, | |||
const $(c_ns)_scalar_t a | |||
) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
/** | |||
@@ -191,9 +185,9 @@ decaf_error_t %(c_ns)s_scalar_invert ( | |||
* @param [in] a A scalar. | |||
* @param [out] out Will become a copy of a. | |||
*/ | |||
static inline void NONNULL2 %(c_ns)s_scalar_copy ( | |||
%(c_ns)s_scalar_t out, | |||
const %(c_ns)s_scalar_t a | |||
static inline void NONNULL2 $(c_ns)_scalar_copy ( | |||
$(c_ns)_scalar_t out, | |||
const $(c_ns)_scalar_t a | |||
) { | |||
*out = *a; | |||
} | |||
@@ -203,8 +197,8 @@ static inline void NONNULL2 %(c_ns)s_scalar_copy ( | |||
* @param [in] a An integer. | |||
* @param [out] out Will become equal to a. | |||
*/ | |||
void %(c_ns)s_scalar_set_unsigned ( | |||
%(c_ns)s_scalar_t out, | |||
void $(c_ns)_scalar_set_unsigned ( | |||
$(c_ns)_scalar_t out, | |||
uint64_t a | |||
) API_VIS NONNULL1; | |||
@@ -214,9 +208,9 @@ void %(c_ns)s_scalar_set_unsigned ( | |||
* @param [out] ser The byte representation of the point. | |||
* @param [in] pt The point to encode. | |||
*/ | |||
void %(c_ns)s_point_encode ( | |||
uint8_t ser[%(C_NS)s_SER_BYTES], | |||
const %(c_ns)s_point_t pt | |||
void $(c_ns)_point_encode ( | |||
uint8_t ser[$(C_NS)_SER_BYTES], | |||
const $(c_ns)_point_t pt | |||
) API_VIS NONNULL2 NOINLINE; | |||
/** | |||
@@ -233,9 +227,9 @@ void %(c_ns)s_point_encode ( | |||
* @retval DECAF_FAILURE The decoding didn't succeed, because | |||
* ser does not represent a point. | |||
*/ | |||
decaf_error_t %(c_ns)s_point_decode ( | |||
%(c_ns)s_point_t pt, | |||
const uint8_t ser[%(C_NS)s_SER_BYTES], | |||
decaf_error_t $(c_ns)_point_decode ( | |||
$(c_ns)_point_t pt, | |||
const uint8_t ser[$(C_NS)_SER_BYTES], | |||
decaf_bool_t allow_identity | |||
) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
@@ -246,9 +240,9 @@ decaf_error_t %(c_ns)s_point_decode ( | |||
* @param [out] a A copy of the point. | |||
* @param [in] b Any point. | |||
*/ | |||
static inline void NONNULL2 %(c_ns)s_point_copy ( | |||
%(c_ns)s_point_t a, | |||
const %(c_ns)s_point_t b | |||
static inline void NONNULL2 $(c_ns)_point_copy ( | |||
$(c_ns)_point_t a, | |||
const $(c_ns)_point_t b | |||
) { | |||
*a=*b; | |||
} | |||
@@ -262,9 +256,9 @@ static inline void NONNULL2 %(c_ns)s_point_copy ( | |||
* @retval DECAF_TRUE The points are equal. | |||
* @retval DECAF_FALSE The points are not equal. | |||
*/ | |||
decaf_bool_t %(c_ns)s_point_eq ( | |||
const %(c_ns)s_point_t a, | |||
const %(c_ns)s_point_t b | |||
decaf_bool_t $(c_ns)_point_eq ( | |||
const $(c_ns)_point_t a, | |||
const $(c_ns)_point_t b | |||
) API_VIS WARN_UNUSED NONNULL2 NOINLINE; | |||
/** | |||
@@ -276,22 +270,22 @@ decaf_bool_t %(c_ns)s_point_eq ( | |||
* @param [in] a An addend. | |||
* @param [in] b An addend. | |||
*/ | |||
void %(c_ns)s_point_add ( | |||
%(c_ns)s_point_t sum, | |||
const %(c_ns)s_point_t a, | |||
const %(c_ns)s_point_t b | |||
void $(c_ns)_point_add ( | |||
$(c_ns)_point_t sum, | |||
const $(c_ns)_point_t a, | |||
const $(c_ns)_point_t b | |||
) API_VIS NONNULL3; | |||
/** | |||
* @brief Double a point. Equivalent to | |||
* %(c_ns)s_point_add(two_a,a,a), but potentially faster. | |||
* $(c_ns)_point_add(two_a,a,a), but potentially faster. | |||
* | |||
* @param [out] two_a The sum a+a. | |||
* @param [in] a A point. | |||
*/ | |||
void %(c_ns)s_point_double ( | |||
%(c_ns)s_point_t two_a, | |||
const %(c_ns)s_point_t a | |||
void $(c_ns)_point_double ( | |||
$(c_ns)_point_t two_a, | |||
const $(c_ns)_point_t a | |||
) API_VIS NONNULL2; | |||
/** | |||
@@ -303,10 +297,10 @@ void %(c_ns)s_point_double ( | |||
* @param [in] a The minuend. | |||
* @param [in] b The subtrahend. | |||
*/ | |||
void %(c_ns)s_point_sub ( | |||
%(c_ns)s_point_t diff, | |||
const %(c_ns)s_point_t a, | |||
const %(c_ns)s_point_t b | |||
void $(c_ns)_point_sub ( | |||
$(c_ns)_point_t diff, | |||
const $(c_ns)_point_t a, | |||
const $(c_ns)_point_t b | |||
) API_VIS NONNULL3; | |||
/** | |||
@@ -316,9 +310,9 @@ void %(c_ns)s_point_sub ( | |||
* @param [out] nega The negated input point | |||
* @param [in] a The input point. | |||
*/ | |||
void %(c_ns)s_point_negate ( | |||
%(c_ns)s_point_t nega, | |||
const %(c_ns)s_point_t a | |||
void $(c_ns)_point_negate ( | |||
$(c_ns)_point_t nega, | |||
const $(c_ns)_point_t a | |||
) API_VIS NONNULL2; | |||
/** | |||
@@ -328,10 +322,10 @@ void %(c_ns)s_point_negate ( | |||
* @param [in] base The point to be scaled. | |||
* @param [in] scalar The scalar to multiply by. | |||
*/ | |||
void %(c_ns)s_point_scalarmul ( | |||
%(c_ns)s_point_t scaled, | |||
const %(c_ns)s_point_t base, | |||
const %(c_ns)s_scalar_t scalar | |||
void $(c_ns)_point_scalarmul ( | |||
$(c_ns)_point_t scaled, | |||
const $(c_ns)_point_t base, | |||
const $(c_ns)_scalar_t scalar | |||
) API_VIS NONNULL3 NOINLINE; | |||
/** | |||
@@ -351,10 +345,10 @@ void %(c_ns)s_point_scalarmul ( | |||
* @retval DECAF_FAILURE The scalarmul didn't succeed, because | |||
* base does not represent a point. | |||
*/ | |||
decaf_error_t %(c_ns)s_direct_scalarmul ( | |||
uint8_t scaled[%(C_NS)s_SER_BYTES], | |||
const uint8_t base[%(C_NS)s_SER_BYTES], | |||
const %(c_ns)s_scalar_t scalar, | |||
decaf_error_t $(c_ns)_direct_scalarmul ( | |||
uint8_t scaled[$(C_NS)_SER_BYTES], | |||
const uint8_t base[$(C_NS)_SER_BYTES], | |||
const $(c_ns)_scalar_t scalar, | |||
decaf_bool_t allow_identity, | |||
decaf_bool_t short_circuit | |||
) API_VIS NONNULL3 WARN_UNUSED NOINLINE; | |||
@@ -371,14 +365,14 @@ decaf_error_t %(c_ns)s_direct_scalarmul ( | |||
* @retval DECAF_FAILURE The scalarmul didn't succeed, because the base | |||
* point is in a small subgroup. | |||
*/ | |||
decaf_error_t %(c_ns)s_x_direct_scalarmul ( /* TODO: rename? */ | |||
uint8_t out[X%(gf_shortname)s_PUBLIC_BYTES], | |||
const uint8_t base[X%(gf_shortname)s_PUBLIC_BYTES], | |||
const uint8_t scalar[X%(gf_shortname)s_PRIVATE_BYTES] | |||
decaf_error_t $(c_ns)_x_direct_scalarmul ( /* TODO: rename? */ | |||
uint8_t out[X$(gf_shortname)_PUBLIC_BYTES], | |||
const uint8_t base[X$(gf_shortname)_PUBLIC_BYTES], | |||
const uint8_t scalar[X$(gf_shortname)_PRIVATE_BYTES] | |||
) API_VIS NONNULL3 WARN_UNUSED NOINLINE; | |||
/** The base point for X%(gf_shortname)s Diffie-Hellman */ | |||
extern const uint8_t %(c_ns)s_x_base_point[X%(gf_shortname)s_PUBLIC_BYTES] API_VIS; | |||
/** The base point for X$(gf_shortname) Diffie-Hellman */ | |||
extern const uint8_t $(c_ns)_x_base_point[X$(gf_shortname)_PUBLIC_BYTES] API_VIS; | |||
/** | |||
* @brief RFC 7748 Diffie-Hellman base point scalarmul. This function uses | |||
@@ -387,9 +381,9 @@ extern const uint8_t %(c_ns)s_x_base_point[X%(gf_shortname)s_PUBLIC_BYTES] API_V | |||
* @param [out] scaled The scaled point base*scalar | |||
* @param [in] scalar The scalar to multiply by. | |||
*/ | |||
void %(c_ns)s_x_base_scalarmul ( | |||
uint8_t out[X%(gf_shortname)s_PUBLIC_BYTES], | |||
const uint8_t scalar[X%(gf_shortname)s_PRIVATE_BYTES] | |||
void $(c_ns)_x_base_scalarmul ( | |||
uint8_t out[X$(gf_shortname)_PUBLIC_BYTES], | |||
const uint8_t scalar[X$(gf_shortname)_PRIVATE_BYTES] | |||
) API_VIS NONNULL2 NOINLINE; | |||
/** | |||
@@ -401,9 +395,9 @@ void %(c_ns)s_x_base_scalarmul ( | |||
* @param [out] a A precomputed table of multiples of the point. | |||
* @param [in] b Any point. | |||
*/ | |||
void %(c_ns)s_precompute ( | |||
%(c_ns)s_precomputed_s *a, | |||
const %(c_ns)s_point_t b | |||
void $(c_ns)_precompute ( | |||
$(c_ns)_precomputed_s *a, | |||
const $(c_ns)_point_t b | |||
) API_VIS NONNULL2 NOINLINE; | |||
/** | |||
@@ -411,23 +405,23 @@ void %(c_ns)s_precompute ( | |||
* scaled = scalar*base. | |||
* Some implementations do not include precomputed points; for | |||
* those implementations, this function is the same as | |||
* %(c_ns)s_point_scalarmul | |||
* $(c_ns)_point_scalarmul | |||
* | |||
* @param [out] scaled The scaled point base*scalar | |||
* @param [in] base The point to be scaled. | |||
* @param [in] scalar The scalar to multiply by. | |||
*/ | |||
void %(c_ns)s_precomputed_scalarmul ( | |||
%(c_ns)s_point_t scaled, | |||
const %(c_ns)s_precomputed_s *base, | |||
const %(c_ns)s_scalar_t scalar | |||
void $(c_ns)_precomputed_scalarmul ( | |||
$(c_ns)_point_t scaled, | |||
const $(c_ns)_precomputed_s *base, | |||
const $(c_ns)_scalar_t scalar | |||
) API_VIS NONNULL3 NOINLINE; | |||
/** | |||
* @brief Multiply two base points by two scalars: | |||
* scaled = scalar1*base1 + scalar2*base2. | |||
* | |||
* Equivalent to two calls to %(c_ns)s_point_scalarmul, but may be | |||
* Equivalent to two calls to $(c_ns)_point_scalarmul, but may be | |||
* faster. | |||
* | |||
* @param [out] combo The linear combination scalar1*base1 + scalar2*base2. | |||
@@ -436,12 +430,12 @@ void %(c_ns)s_precomputed_scalarmul ( | |||
* @param [in] base2 A second point to be scaled. | |||
* @param [in] scalar2 A second scalar to multiply by. | |||
*/ | |||
void %(c_ns)s_point_double_scalarmul ( | |||
%(c_ns)s_point_t combo, | |||
const %(c_ns)s_point_t base1, | |||
const %(c_ns)s_scalar_t scalar1, | |||
const %(c_ns)s_point_t base2, | |||
const %(c_ns)s_scalar_t scalar2 | |||
void $(c_ns)_point_double_scalarmul ( | |||
$(c_ns)_point_t combo, | |||
const $(c_ns)_point_t base1, | |||
const $(c_ns)_scalar_t scalar1, | |||
const $(c_ns)_point_t base2, | |||
const $(c_ns)_scalar_t scalar2 | |||
) API_VIS NONNULL5 NOINLINE; | |||
/** | |||
@@ -450,7 +444,7 @@ void %(c_ns)s_point_double_scalarmul ( | |||
* a1 = scalar1 * base | |||
* a2 = scalar2 * base | |||
* | |||
* Equivalent to two calls to %(c_ns)s_point_scalarmul, but may be | |||
* Equivalent to two calls to $(c_ns)_point_scalarmul, but may be | |||
* faster. | |||
* | |||
* @param [out] a1 The first multiple. It may be the same as the input point. | |||
@@ -459,19 +453,19 @@ void %(c_ns)s_point_double_scalarmul ( | |||
* @param [in] scalar1 A first scalar to multiply by. | |||
* @param [in] scalar2 A second scalar to multiply by. | |||
*/ | |||
void %(c_ns)s_point_dual_scalarmul ( | |||
%(c_ns)s_point_t a1, | |||
%(c_ns)s_point_t a2, | |||
const %(c_ns)s_point_t base1, | |||
const %(c_ns)s_scalar_t scalar1, | |||
const %(c_ns)s_scalar_t scalar2 | |||
void $(c_ns)_point_dual_scalarmul ( | |||
$(c_ns)_point_t a1, | |||
$(c_ns)_point_t a2, | |||
const $(c_ns)_point_t base1, | |||
const $(c_ns)_scalar_t scalar1, | |||
const $(c_ns)_scalar_t scalar2 | |||
) API_VIS NONNULL5 NOINLINE; | |||
/** | |||
* @brief Multiply two base points by two scalars: | |||
* scaled = scalar1*%(c_ns)s_point_base + scalar2*base2. | |||
* scaled = scalar1*$(c_ns)_point_base + scalar2*base2. | |||
* | |||
* Otherwise equivalent to %(c_ns)s_point_double_scalarmul, but may be | |||
* Otherwise equivalent to $(c_ns)_point_double_scalarmul, but may be | |||
* faster at the expense of being variable time. | |||
* | |||
* @param [out] combo The linear combination scalar1*base + scalar2*base2. | |||
@@ -482,11 +476,11 @@ void %(c_ns)s_point_dual_scalarmul ( | |||
* @warning: This function takes variable time, and may leak the scalars | |||
* used. It is designed for signature verification. | |||
*/ | |||
void %(c_ns)s_base_double_scalarmul_non_secret ( | |||
%(c_ns)s_point_t combo, | |||
const %(c_ns)s_scalar_t scalar1, | |||
const %(c_ns)s_point_t base2, | |||
const %(c_ns)s_scalar_t scalar2 | |||
void $(c_ns)_base_double_scalarmul_non_secret ( | |||
$(c_ns)_point_t combo, | |||
const $(c_ns)_scalar_t scalar1, | |||
const $(c_ns)_point_t base2, | |||
const $(c_ns)_scalar_t scalar2 | |||
) API_VIS NONNULL4 NOINLINE; | |||
/** | |||
@@ -498,10 +492,10 @@ void %(c_ns)s_base_double_scalarmul_non_secret ( | |||
* @param [in] b Any point. | |||
* @param [in] pick_b If nonzero, choose point b. | |||
*/ | |||
void %(c_ns)s_point_cond_sel ( | |||
%(c_ns)s_point_t out, | |||
const %(c_ns)s_point_t a, | |||
const %(c_ns)s_point_t b, | |||
void $(c_ns)_point_cond_sel ( | |||
$(c_ns)_point_t out, | |||
const $(c_ns)_point_t a, | |||
const $(c_ns)_point_t b, | |||
decaf_word_t pick_b | |||
) API_VIS NONNULL3 NOINLINE; | |||
@@ -514,10 +508,10 @@ void %(c_ns)s_point_cond_sel ( | |||
* @param [in] b Any scalar. | |||
* @param [in] pick_b If nonzero, choose scalar b. | |||
*/ | |||
void %(c_ns)s_scalar_cond_sel ( | |||
%(c_ns)s_scalar_t out, | |||
const %(c_ns)s_scalar_t a, | |||
const %(c_ns)s_scalar_t b, | |||
void $(c_ns)_scalar_cond_sel ( | |||
$(c_ns)_scalar_t out, | |||
const $(c_ns)_scalar_t a, | |||
const $(c_ns)_scalar_t b, | |||
decaf_word_t pick_b | |||
) API_VIS NONNULL3 NOINLINE; | |||
@@ -528,8 +522,8 @@ void %(c_ns)s_scalar_cond_sel ( | |||
* @retval DECAF_TRUE The point is valid. | |||
* @retval DECAF_FALSE The point is invalid. | |||
*/ | |||
decaf_bool_t %(c_ns)s_point_valid ( | |||
const %(c_ns)s_point_t toTest | |||
decaf_bool_t $(c_ns)_point_valid ( | |||
const $(c_ns)_point_t toTest | |||
) API_VIS WARN_UNUSED NONNULL1 NOINLINE; | |||
/** | |||
@@ -539,9 +533,9 @@ decaf_bool_t %(c_ns)s_point_valid ( | |||
* @param [out] q The point to torque. | |||
* @param [in] p The point to torque. | |||
*/ | |||
void %(c_ns)s_point_debugging_torque ( | |||
%(c_ns)s_point_t q, | |||
const %(c_ns)s_point_t p | |||
void $(c_ns)_point_debugging_torque ( | |||
$(c_ns)_point_t q, | |||
const $(c_ns)_point_t p | |||
) API_VIS NONNULL2 NOINLINE; | |||
/** | |||
@@ -553,10 +547,10 @@ void %(c_ns)s_point_debugging_torque ( | |||
* @param [in] p The point to scale. | |||
* @param [in] factor Serialized GF factor to scale. | |||
*/ | |||
void %(c_ns)s_point_debugging_pscale ( | |||
%(c_ns)s_point_t q, | |||
const %(c_ns)s_point_t p, | |||
const unsigned char factor[%(C_NS)s_SER_BYTES] | |||
void $(c_ns)_point_debugging_pscale ( | |||
$(c_ns)_point_t q, | |||
const $(c_ns)_point_t p, | |||
const unsigned char factor[$(C_NS)_SER_BYTES] | |||
) API_VIS NONNULL2 NOINLINE; | |||
/** | |||
@@ -564,7 +558,7 @@ void %(c_ns)s_point_debugging_pscale ( | |||
* | |||
* Call this function with the output of a hash to make a hash to the curve. | |||
* | |||
* This function runs Elligator2 on the %(c_ns)s Jacobi quartic model. It then | |||
* This function runs Elligator2 on the $(c_ns) Jacobi quartic model. It then | |||
* uses the isogeny to put the result in twisted Edwards form. As a result, | |||
* it is safe (cannot produce points of order 4), and would be compatible with | |||
* hypothetical other implementations of Decaf using a Montgomery or untwisted | |||
@@ -588,29 +582,29 @@ void %(c_ns)s_point_debugging_pscale ( | |||
* @param [out] pt The data hashed to the curve. | |||
*/ | |||
void | |||
%(c_ns)s_point_from_hash_nonuniform ( | |||
%(c_ns)s_point_t pt, | |||
const unsigned char hashed_data[%(C_NS)s_SER_BYTES] | |||
$(c_ns)_point_from_hash_nonuniform ( | |||
$(c_ns)_point_t pt, | |||
const unsigned char hashed_data[$(C_NS)_SER_BYTES] | |||
) API_VIS NONNULL2 NOINLINE; | |||
/** | |||
* @brief Indifferentiable hash function encoding to curve. | |||
* | |||
* Equivalent to calling %(c_ns)s_point_from_hash_nonuniform twice and adding. | |||
* Equivalent to calling $(c_ns)_point_from_hash_nonuniform twice and adding. | |||
* | |||
* @param [in] hashed_data Output of some hash function. | |||
* @param [out] pt The data hashed to the curve. | |||
*/ | |||
void %(c_ns)s_point_from_hash_uniform ( | |||
%(c_ns)s_point_t pt, | |||
const unsigned char hashed_data[2*%(C_NS)s_SER_BYTES] | |||
void $(c_ns)_point_from_hash_uniform ( | |||
$(c_ns)_point_t pt, | |||
const unsigned char hashed_data[2*$(C_NS)_SER_BYTES] | |||
) API_VIS NONNULL2 NOINLINE; | |||
/** | |||
* @brief Inverse of elligator-like hash to curve. | |||
* | |||
* This function writes to the buffer, to make it so that | |||
* %(c_ns)s_point_from_hash_nonuniform(buffer) = pt if | |||
* $(c_ns)_point_from_hash_nonuniform(buffer) = pt if | |||
* possible. Since there may be multiple preimages, the | |||
* "which" parameter chooses between them. To ensure uniform | |||
* inverse sampling, this function succeeds or fails | |||
@@ -625,9 +619,9 @@ void %(c_ns)s_point_from_hash_uniform ( | |||
* @retval DECAF_FAILURE The inverse failed. | |||
*/ | |||
decaf_error_t | |||
%(c_ns)s_invert_elligator_nonuniform ( | |||
unsigned char recovered_hash[%(C_NS)s_SER_BYTES], | |||
const %(c_ns)s_point_t pt, | |||
$(c_ns)_invert_elligator_nonuniform ( | |||
unsigned char recovered_hash[$(C_NS)_SER_BYTES], | |||
const $(c_ns)_point_t pt, | |||
uint16_t which | |||
) API_VIS NONNULL2 NOINLINE WARN_UNUSED; | |||
@@ -635,7 +629,7 @@ decaf_error_t | |||
* @brief Inverse of elligator-like hash to curve. | |||
* | |||
* This function writes to the buffer, to make it so that | |||
* %(c_ns)s_point_from_hash_uniform(buffer) = pt if | |||
* $(c_ns)_point_from_hash_uniform(buffer) = pt if | |||
* possible. Since there may be multiple preimages, the | |||
* "which" parameter chooses between them. To ensure uniform | |||
* inverse sampling, this function succeeds or fails | |||
@@ -650,36 +644,34 @@ decaf_error_t | |||
* @retval DECAF_FAILURE The inverse failed. | |||
*/ | |||
decaf_error_t | |||
%(c_ns)s_invert_elligator_uniform ( | |||
unsigned char recovered_hash[2*%(C_NS)s_SER_BYTES], | |||
const %(c_ns)s_point_t pt, | |||
$(c_ns)_invert_elligator_uniform ( | |||
unsigned char recovered_hash[2*$(C_NS)_SER_BYTES], | |||
const $(c_ns)_point_t pt, | |||
uint16_t which | |||
) API_VIS NONNULL2 NOINLINE WARN_UNUSED; | |||
/** | |||
* @brief Overwrite scalar with zeros. | |||
*/ | |||
void %(c_ns)s_scalar_destroy ( | |||
%(c_ns)s_scalar_t scalar | |||
void $(c_ns)_scalar_destroy ( | |||
$(c_ns)_scalar_t scalar | |||
) NONNULL1 API_VIS; | |||
/** | |||
* @brief Overwrite point with zeros. | |||
* @todo Use this internally. | |||
*/ | |||
void %(c_ns)s_point_destroy ( | |||
%(c_ns)s_point_t point | |||
void $(c_ns)_point_destroy ( | |||
$(c_ns)_point_t point | |||
) NONNULL1 API_VIS; | |||
/** | |||
* @brief Overwrite precomputed table with zeros. | |||
*/ | |||
void %(c_ns)s_precomputed_destroy ( | |||
%(c_ns)s_precomputed_s *pre | |||
void $(c_ns)_precomputed_destroy ( | |||
$(c_ns)_precomputed_s *pre | |||
) NONNULL1 API_VIS; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
""" | |||
) |
@@ -1,23 +1,18 @@ | |||
from gen_file import gen_file | |||
decaf_hxx = gen_file( | |||
public = True, | |||
per = "curve", | |||
name = "decaf/%(c_ns)s.hxx", | |||
doc = """ | |||
A group of prime order p, C++ wrapper. | |||
The Decaf library implements cryptographic operations on a an elliptic curve | |||
group of prime order p. It accomplishes this by using a twisted Edwards | |||
curve (isogenous to %(iso_to)s) and wiping out the cofactor. | |||
The formulas are all complete and have no special cases, except that | |||
%(c_ns)s_decode can fail because not every sequence of bytes is a valid group | |||
element. | |||
The formulas contain no data-dependent branches, timing or memory accesses, | |||
except for %(c_ns)s_base_double_scalarmul_non_secret. | |||
""", code = """ | |||
/** | |||
* A group of prime order p, C++ wrapper. | |||
* | |||
* The Decaf library implements cryptographic operations on a an elliptic curve | |||
* group of prime order p. It accomplishes this by using a twisted Edwards | |||
* curve (isogenous to $(iso_to)) and wiping out the cofactor. | |||
* | |||
* The formulas are all complete and have no special cases, except that | |||
* $(c_ns)_decode can fail because not every sequence of bytes is a valid group | |||
* element. | |||
* | |||
* The formulas contain no data-dependent branches, timing or memory accesses, | |||
* except for $(c_ns)_base_double_scalarmul_non_secret. | |||
*/ | |||
/** This code uses posix_memalign. */ | |||
#ifndef _XOPEN_SOURCE | |||
#define _XOPEN_SOURCE 600 | |||
@@ -25,7 +20,7 @@ decaf_hxx = gen_file( | |||
#include <stdlib.h> | |||
#include <string.h> /* for memcpy */ | |||
#include <decaf.h> | |||
#include <decaf/decaf_$(gf_bits).h> | |||
#include <decaf/secure_buffer.hxx> | |||
#include <string> | |||
#include <sys/types.h> | |||
@@ -42,18 +37,18 @@ decaf_hxx = gen_file( | |||
namespace decaf { | |||
/** | |||
* %(iso_to)s/Decaf instantiation of group. | |||
* $(iso_to)/Decaf instantiation of group. | |||
*/ | |||
struct %(cxx_ns)s { | |||
struct $(cxx_ns) { | |||
/** The name of the curve */ | |||
static inline const char *name() { return "%(name)s"; } | |||
static inline const char *name() { return "$(name)"; } | |||
/** The curve's cofactor (removed, but useful for testing) */ | |||
static const int REMOVED_COFACTOR = %(cofactor)d; | |||
static const int REMOVED_COFACTOR = $(cofactor); | |||
/** Residue class of field modulus: p == this mod 2*(this-1) */ | |||
static const int FIELD_MODULUS_TYPE = %(modulus_type)d; | |||
static const int FIELD_MODULUS_TYPE = $(modulus_type); | |||
/** @cond internal */ | |||
class Point; | |||
@@ -67,10 +62,10 @@ class Precomputed; | |||
class Scalar : public Serializable<Scalar> { | |||
public: | |||
/** wrapped C type */ | |||
typedef %(c_ns)s_scalar_t Wrapped; | |||
typedef $(c_ns)_scalar_t Wrapped; | |||
/** Size of a serialized element */ | |||
static const size_t SER_BYTES = %(C_NS)s_SCALAR_BYTES; | |||
static const size_t SER_BYTES = $(C_NS)_SCALAR_BYTES; | |||
/** access to the underlying scalar object */ | |||
Wrapped s; | |||
@@ -99,7 +94,7 @@ public: | |||
} | |||
/** Construct from decaf_scalar_t object. */ | |||
inline Scalar(const Wrapped &t = %(c_ns)s_scalar_zero) NOEXCEPT { %(c_ns)s_scalar_copy(s,t); } | |||
inline Scalar(const Wrapped &t = $(c_ns)_scalar_zero) NOEXCEPT { $(c_ns)_scalar_copy(s,t); } | |||
/** Copy constructor. */ | |||
inline Scalar(const Scalar &x) NOEXCEPT { *this = x; } | |||
@@ -112,20 +107,20 @@ public: | |||
/** Serializable instance */ | |||
inline void serialize_into(unsigned char *buffer) const NOEXCEPT { | |||
%(c_ns)s_scalar_encode(buffer, s); | |||
$(c_ns)_scalar_encode(buffer, s); | |||
} | |||
/** Assignment. */ | |||
inline Scalar& operator=(const Scalar &x) NOEXCEPT { %(c_ns)s_scalar_copy(s,x.s); return *this; } | |||
inline Scalar& operator=(const Scalar &x) NOEXCEPT { $(c_ns)_scalar_copy(s,x.s); return *this; } | |||
/** Assign from unsigned 64-bit integer. */ | |||
inline Scalar& operator=(uint64_t w) NOEXCEPT { %(c_ns)s_scalar_set_unsigned(s,w); return *this; } | |||
inline Scalar& operator=(uint64_t w) NOEXCEPT { $(c_ns)_scalar_set_unsigned(s,w); return *this; } | |||
/** Assign from signed int. */ | |||
inline Scalar& operator=(int64_t w) NOEXCEPT { | |||
Scalar t(-(uint64_t)INT_MIN); | |||
%(c_ns)s_scalar_set_unsigned(s,(uint64_t)w - (uint64_t)INT_MIN); | |||
$(c_ns)_scalar_set_unsigned(s,(uint64_t)w - (uint64_t)INT_MIN); | |||
*this -= t; | |||
return *this; | |||
} | |||
@@ -137,11 +132,11 @@ public: | |||
inline Scalar& operator=(int w) NOEXCEPT { return *this = (int64_t)w; } | |||
/** Destructor securely zeorizes the scalar. */ | |||
inline ~Scalar() NOEXCEPT { %(c_ns)s_scalar_destroy(s); } | |||
inline ~Scalar() NOEXCEPT { $(c_ns)_scalar_destroy(s); } | |||
/** Assign from arbitrary-length little-endian byte sequence in a Block. */ | |||
inline Scalar &operator=(const Block &bl) NOEXCEPT { | |||
%(c_ns)s_scalar_decode_long(s,bl.data(),bl.size()); return *this; | |||
$(c_ns)_scalar_decode_long(s,bl.data(),bl.size()); return *this; | |||
} | |||
/** | |||
@@ -151,35 +146,35 @@ public: | |||
static inline decaf_error_t WARN_UNUSED decode ( | |||
Scalar &sc, const FixedBlock<SER_BYTES> buffer | |||
) NOEXCEPT { | |||
return %(c_ns)s_scalar_decode(sc.s,buffer.data()); | |||
return $(c_ns)_scalar_decode(sc.s,buffer.data()); | |||
} | |||
/** Add. */ | |||
inline Scalar operator+ (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); %(c_ns)s_scalar_add(r.s,s,q.s); return r; } | |||
inline Scalar operator+ (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); $(c_ns)_scalar_add(r.s,s,q.s); return r; } | |||
/** Add to this. */ | |||
inline Scalar &operator+=(const Scalar &q) NOEXCEPT { %(c_ns)s_scalar_add(s,s,q.s); return *this; } | |||
inline Scalar &operator+=(const Scalar &q) NOEXCEPT { $(c_ns)_scalar_add(s,s,q.s); return *this; } | |||
/** Subtract. */ | |||
inline Scalar operator- (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); %(c_ns)s_scalar_sub(r.s,s,q.s); return r; } | |||
inline Scalar operator- (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); $(c_ns)_scalar_sub(r.s,s,q.s); return r; } | |||
/** Subtract from this. */ | |||
inline Scalar &operator-=(const Scalar &q) NOEXCEPT { %(c_ns)s_scalar_sub(s,s,q.s); return *this; } | |||
inline Scalar &operator-=(const Scalar &q) NOEXCEPT { $(c_ns)_scalar_sub(s,s,q.s); return *this; } | |||
/** Multiply */ | |||
inline Scalar operator* (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); %(c_ns)s_scalar_mul(r.s,s,q.s); return r; } | |||
inline Scalar operator* (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); $(c_ns)_scalar_mul(r.s,s,q.s); return r; } | |||
/** Multiply into this. */ | |||
inline Scalar &operator*=(const Scalar &q) NOEXCEPT { %(c_ns)s_scalar_mul(s,s,q.s); return *this; } | |||
inline Scalar &operator*=(const Scalar &q) NOEXCEPT { $(c_ns)_scalar_mul(s,s,q.s); return *this; } | |||
/** Negate */ | |||
inline Scalar operator- () const NOEXCEPT { Scalar r((NOINIT())); %(c_ns)s_scalar_sub(r.s,%(c_ns)s_scalar_zero,s); return r; } | |||
inline Scalar operator- () const NOEXCEPT { Scalar r((NOINIT())); $(c_ns)_scalar_sub(r.s,$(c_ns)_scalar_zero,s); return r; } | |||
/** Invert with Fermat's Little Theorem (slow!). If *this == 0, | |||
* throw CryptoException. */ | |||
inline Scalar inverse() const throw(CryptoException) { | |||
Scalar r; | |||
if (DECAF_SUCCESS != %(c_ns)s_scalar_invert(r.s,s)) { | |||
if (DECAF_SUCCESS != $(c_ns)_scalar_invert(r.s,s)) { | |||
throw CryptoException(); | |||
} | |||
return r; | |||
@@ -189,7 +184,7 @@ public: | |||
* and return DECAF_FAILURE. */ | |||
inline decaf_error_t WARN_UNUSED | |||
inverse_noexcept(Scalar &r) const NOEXCEPT { | |||
return %(c_ns)s_scalar_invert(r.s,s); | |||
return $(c_ns)_scalar_invert(r.s,s); | |||
} | |||
/** Divide by inverting q. If q == 0, return 0. */ | |||
@@ -202,7 +197,7 @@ public: | |||
inline bool operator!=(const Scalar &q) const NOEXCEPT { return !(*this == q); } | |||
/** Compare in constant time */ | |||
inline bool operator==(const Scalar &q) const NOEXCEPT { return !!%(c_ns)s_scalar_eq(s,q.s); } | |||
inline bool operator==(const Scalar &q) const NOEXCEPT { return !!$(c_ns)_scalar_eq(s,q.s); } | |||
/** Scalarmul with scalar on left. */ | |||
inline Point operator* (const Point &q) const NOEXCEPT { return q * (*this); } | |||
@@ -224,10 +219,10 @@ public: | |||
class Point : public Serializable<Point> { | |||
public: | |||
/** wrapped C type */ | |||
typedef %(c_ns)s_point_t Wrapped; | |||
typedef $(c_ns)_point_t Wrapped; | |||
/** Size of a serialized element */ | |||
static const size_t SER_BYTES = %(C_NS)s_SER_BYTES; | |||
static const size_t SER_BYTES = $(C_NS)_SER_BYTES; | |||
/** Bytes required for hash */ | |||
static const size_t HASH_BYTES = SER_BYTES; | |||
@@ -244,16 +239,16 @@ public: | |||
/** @endcond */ | |||
/** Constructor sets to identity by default. */ | |||
inline Point(const Wrapped &q = %(c_ns)s_point_identity) NOEXCEPT { %(c_ns)s_point_copy(p,q); } | |||
inline Point(const Wrapped &q = $(c_ns)_point_identity) NOEXCEPT { $(c_ns)_point_copy(p,q); } | |||
/** Copy constructor. */ | |||
inline Point(const Point &q) NOEXCEPT { *this = q; } | |||
/** Assignment. */ | |||
inline Point& operator=(const Point &q) NOEXCEPT { %(c_ns)s_point_copy(p,q.p); return *this; } | |||
inline Point& operator=(const Point &q) NOEXCEPT { $(c_ns)_point_copy(p,q.p); return *this; } | |||
/** Destructor securely zeorizes the point. */ | |||
inline ~Point() NOEXCEPT { %(c_ns)s_point_destroy(p); } | |||
inline ~Point() NOEXCEPT { $(c_ns)_point_destroy(p); } | |||
/** Construct from RNG */ | |||
inline explicit Point(Rng &rng, bool uniform = true) NOEXCEPT { | |||
@@ -291,7 +286,7 @@ public: | |||
static inline decaf_error_t WARN_UNUSED decode ( | |||
Point &p, const FixedBlock<SER_BYTES> &buffer, decaf_bool_t allow_identity=DECAF_TRUE | |||
) NOEXCEPT { | |||
return %(c_ns)s_point_decode(p.p,buffer.data(),allow_identity); | |||
return $(c_ns)_point_decode(p.p,buffer.data(),allow_identity); | |||
} | |||
/** | |||
@@ -314,15 +309,15 @@ public: | |||
if (s.size() < HASH_BYTES) { | |||
SecureBuffer b(HASH_BYTES); | |||
memcpy(b.data(), s.data(), s.size()); | |||
%(c_ns)s_point_from_hash_nonuniform(p,b.data()); | |||
$(c_ns)_point_from_hash_nonuniform(p,b.data()); | |||
} else if (s.size() == HASH_BYTES) { | |||
%(c_ns)s_point_from_hash_nonuniform(p,s.data()); | |||
$(c_ns)_point_from_hash_nonuniform(p,s.data()); | |||
} else if (s.size() < 2*HASH_BYTES) { | |||
SecureBuffer b(2*HASH_BYTES); | |||
memcpy(b.data(), s.data(), s.size()); | |||
%(c_ns)s_point_from_hash_uniform(p,b.data()); | |||
$(c_ns)_point_from_hash_uniform(p,b.data()); | |||
} else { | |||
%(c_ns)s_point_from_hash_uniform(p,s.data()); | |||
$(c_ns)_point_from_hash_uniform(p,s.data()); | |||
} | |||
} | |||
@@ -331,7 +326,7 @@ public: | |||
*/ | |||
inline operator SecureBuffer() const { | |||
SecureBuffer buffer(SER_BYTES); | |||
%(c_ns)s_point_encode(buffer.data(), p); | |||
$(c_ns)_point_encode(buffer.data(), p); | |||
return buffer; | |||
} | |||
@@ -340,41 +335,41 @@ public: | |||
/** Serializable instance */ | |||
inline void serialize_into(unsigned char *buffer) const NOEXCEPT { | |||
%(c_ns)s_point_encode(buffer, p); | |||
$(c_ns)_point_encode(buffer, p); | |||
} | |||
/** Point add. */ | |||
inline Point operator+ (const Point &q) const NOEXCEPT { Point r((NOINIT())); %(c_ns)s_point_add(r.p,p,q.p); return r; } | |||
inline Point operator+ (const Point &q) const NOEXCEPT { Point r((NOINIT())); $(c_ns)_point_add(r.p,p,q.p); return r; } | |||
/** Point add. */ | |||
inline Point &operator+=(const Point &q) NOEXCEPT { %(c_ns)s_point_add(p,p,q.p); return *this; } | |||
inline Point &operator+=(const Point &q) NOEXCEPT { $(c_ns)_point_add(p,p,q.p); return *this; } | |||
/** Point subtract. */ | |||
inline Point operator- (const Point &q) const NOEXCEPT { Point r((NOINIT())); %(c_ns)s_point_sub(r.p,p,q.p); return r; } | |||
inline Point operator- (const Point &q) const NOEXCEPT { Point r((NOINIT())); $(c_ns)_point_sub(r.p,p,q.p); return r; } | |||
/** Point subtract. */ | |||
inline Point &operator-=(const Point &q) NOEXCEPT { %(c_ns)s_point_sub(p,p,q.p); return *this; } | |||
inline Point &operator-=(const Point &q) NOEXCEPT { $(c_ns)_point_sub(p,p,q.p); return *this; } | |||
/** Point negate. */ | |||
inline Point operator- () const NOEXCEPT { Point r((NOINIT())); %(c_ns)s_point_negate(r.p,p); return r; } | |||
inline Point operator- () const NOEXCEPT { Point r((NOINIT())); $(c_ns)_point_negate(r.p,p); return r; } | |||
/** Double the point out of place. */ | |||
inline Point times_two () const NOEXCEPT { Point r((NOINIT())); %(c_ns)s_point_double(r.p,p); return r; } | |||
inline Point times_two () const NOEXCEPT { Point r((NOINIT())); $(c_ns)_point_double(r.p,p); return r; } | |||
/** Double the point in place. */ | |||
inline Point &double_in_place() NOEXCEPT { %(c_ns)s_point_double(p,p); return *this; } | |||
inline Point &double_in_place() NOEXCEPT { $(c_ns)_point_double(p,p); return *this; } | |||
/** Constant-time compare. */ | |||
inline bool operator!=(const Point &q) const NOEXCEPT { return ! %(c_ns)s_point_eq(p,q.p); } | |||
inline bool operator!=(const Point &q) const NOEXCEPT { return ! $(c_ns)_point_eq(p,q.p); } | |||
/** Constant-time compare. */ | |||
inline bool operator==(const Point &q) const NOEXCEPT { return !!%(c_ns)s_point_eq(p,q.p); } | |||
inline bool operator==(const Point &q) const NOEXCEPT { return !!$(c_ns)_point_eq(p,q.p); } | |||
/** Scalar multiply. */ | |||
inline Point operator* (const Scalar &s) const NOEXCEPT { Point r((NOINIT())); %(c_ns)s_point_scalarmul(r.p,p,s.s); return r; } | |||
inline Point operator* (const Scalar &s) const NOEXCEPT { Point r((NOINIT())); $(c_ns)_point_scalarmul(r.p,p,s.s); return r; } | |||
/** Scalar multiply in place. */ | |||
inline Point &operator*=(const Scalar &s) NOEXCEPT { %(c_ns)s_point_scalarmul(p,p,s.s); return *this; } | |||
inline Point &operator*=(const Scalar &s) NOEXCEPT { $(c_ns)_point_scalarmul(p,p,s.s); return *this; } | |||
/** Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
inline Point operator/ (const Scalar &s) const throw(CryptoException) { return (*this) * s.inverse(); } | |||
@@ -383,20 +378,20 @@ public: | |||
inline Point &operator/=(const Scalar &s) throw(CryptoException) { return (*this) *= s.inverse(); } | |||
/** Validate / sanity check */ | |||
inline bool validate() const NOEXCEPT { return %(c_ns)s_point_valid(p); } | |||
inline bool validate() const NOEXCEPT { return $(c_ns)_point_valid(p); } | |||
/** Double-scalar multiply, equivalent to q*qs + r*rs but faster. */ | |||
static inline Point double_scalarmul ( | |||
const Point &q, const Scalar &qs, const Point &r, const Scalar &rs | |||
) NOEXCEPT { | |||
Point p((NOINIT())); %(c_ns)s_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p; | |||
Point p((NOINIT())); $(c_ns)_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p; | |||
} | |||
/** Dual-scalar multiply, equivalent to this*r1, this*r2 but faster. */ | |||
inline void dual_scalarmul ( | |||
Point &q1, Point &q2, const Scalar &r1, const Scalar &r2 | |||
) const NOEXCEPT { | |||
%(c_ns)s_point_dual_scalarmul(q1.p,q2.p,p,r1.s,r2.s); | |||
$(c_ns)_point_dual_scalarmul(q1.p,q2.p,p,r1.s,r2.s); | |||
} | |||
/** | |||
@@ -415,20 +410,20 @@ public: | |||
* it doesn't). | |||
*/ | |||
inline Point non_secret_combo_with_base(const Scalar &s, const Scalar &s_base) NOEXCEPT { | |||
Point r((NOINIT())); %(c_ns)s_base_double_scalarmul_non_secret(r.p,s_base.s,p,s.s); return r; | |||
Point r((NOINIT())); $(c_ns)_base_double_scalarmul_non_secret(r.p,s_base.s,p,s.s); return r; | |||
} | |||
/** Return a point equal to *this, whose internal data is rotated by a torsion element. */ | |||
inline Point debugging_torque() const NOEXCEPT { | |||
Point q; | |||
%(c_ns)s_point_debugging_torque(q.p,p); | |||
$(c_ns)_point_debugging_torque(q.p,p); | |||
return q; | |||
} | |||
/** Return a point equal to *this, whose internal data has a modified representation. */ | |||
inline Point debugging_pscale(const FixedBlock<SER_BYTES> factor) const NOEXCEPT { | |||
Point q; | |||
%(c_ns)s_point_debugging_pscale(q.p,p,factor.data()); | |||
$(c_ns)_point_debugging_pscale(q.p,p,factor.data()); | |||
return q; | |||
} | |||
@@ -450,9 +445,9 @@ public: | |||
memcpy(buf2,buf.data(),(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size()); | |||
decaf_bool_t ret; | |||
if (buf.size() > HASH_BYTES) { | |||
ret = decaf_successful(%(c_ns)s_invert_elligator_uniform(buf2, p, hint)); | |||
ret = decaf_successful($(c_ns)_invert_elligator_uniform(buf2, p, hint)); | |||
} else { | |||
ret = decaf_successful(%(c_ns)s_invert_elligator_nonuniform(buf2, p, hint)); | |||
ret = decaf_successful($(c_ns)_invert_elligator_nonuniform(buf2, p, hint)); | |||
} | |||
if (buf.size() < HASH_BYTES) { | |||
ret &= decaf_memeq(&buf2[buf.size()], &buf2[HASH_BYTES], HASH_BYTES - buf.size()); | |||
@@ -477,10 +472,10 @@ public: | |||
} | |||
/** Return the base point */ | |||
static inline const Point base() NOEXCEPT { return Point(%(c_ns)s_point_base); } | |||
static inline const Point base() NOEXCEPT { return Point($(c_ns)_point_base); } | |||
/** Return the identity point */ | |||
static inline const Point identity() NOEXCEPT { return Point(%(c_ns)s_point_identity); } | |||
static inline const Point identity() NOEXCEPT { return Point($(c_ns)_point_identity); } | |||
}; | |||
/** | |||
@@ -491,7 +486,7 @@ public: | |||
*/ | |||
/** @cond internal */ | |||
typedef %(c_ns)s_precomputed_s Precomputed_U; | |||
typedef $(c_ns)_precomputed_s Precomputed_U; | |||
/** @endcond */ | |||
class Precomputed | |||
/** @cond internal */ | |||
@@ -543,7 +538,7 @@ public: | |||
*/ | |||
inline Precomputed &operator=(const Point &it) throw(std::bad_alloc) { | |||
alloc(); | |||
%(c_ns)s_precompute(ours.mine,it.p); | |||
$(c_ns)_precompute(ours.mine,it.p); | |||
return *this; | |||
} | |||
@@ -560,7 +555,7 @@ public: | |||
: OwnedOrUnowned<Precomputed,Precomputed_U>() { *this = it; } | |||
/** Fixed base scalarmul. */ | |||
inline Point operator* (const Scalar &s) const NOEXCEPT { Point r; %(c_ns)s_precomputed_scalarmul(r.p,get(),s.s); return r; } | |||
inline Point operator* (const Scalar &s) const NOEXCEPT { Point r; $(c_ns)_precomputed_scalarmul(r.p,get(),s.s); return r; } | |||
/** Multiply by s.inverse(). If s=0, maps to the identity. */ | |||
inline Point operator/ (const Scalar &s) const throw(CryptoException) { return (*this) * s.inverse(); } | |||
@@ -571,23 +566,23 @@ public: | |||
public: | |||
/** @cond internal */ | |||
friend class OwnedOrUnowned<Precomputed,Precomputed_U>; | |||
static inline size_t size() NOEXCEPT { return %(c_ns)s_sizeof_precomputed_s; } | |||
static inline size_t alignment() NOEXCEPT { return %(c_ns)s_alignof_precomputed_s; } | |||
static inline const Precomputed_U * defaultValue() NOEXCEPT { return %(c_ns)s_precomputed_base; } | |||
static inline size_t size() NOEXCEPT { return $(c_ns)_sizeof_precomputed_s; } | |||
static inline size_t alignment() NOEXCEPT { return $(c_ns)_alignof_precomputed_s; } | |||
static inline const Precomputed_U * defaultValue() NOEXCEPT { return $(c_ns)_precomputed_base; } | |||
/** @endcond */ | |||
}; | |||
struct DhLadder { | |||
public: | |||
/** Bytes in an X%(gf_shortname)s public key. */ | |||
static const size_t PUBLIC_BYTES = X%(gf_shortname)s_PUBLIC_BYTES; | |||
/** Bytes in an X$(gf_shortname) public key. */ | |||
static const size_t PUBLIC_BYTES = X$(gf_shortname)_PUBLIC_BYTES; | |||
/** Bytes in an X%(gf_shortname)s private key. */ | |||
static const size_t PRIVATE_BYTES = X%(gf_shortname)s_PRIVATE_BYTES; | |||
/** Bytes in an X$(gf_shortname) private key. */ | |||
static const size_t PRIVATE_BYTES = X$(gf_shortname)_PRIVATE_BYTES; | |||
/** Base point for a scalar multiplication. */ | |||
static const FixedBlock<PUBLIC_BYTES> base_point() NOEXCEPT { | |||
return FixedBlock<PUBLIC_BYTES>(%(c_ns)s_x_base_point); | |||
return FixedBlock<PUBLIC_BYTES>($(c_ns)_x_base_point); | |||
} | |||
/** Generate and return a shared secret with public key. */ | |||
@@ -596,7 +591,7 @@ public: | |||
const FixedBlock<PRIVATE_BYTES> &scalar | |||
) throw(std::bad_alloc,CryptoException) { | |||
SecureBuffer out(PUBLIC_BYTES); | |||
if (DECAF_SUCCESS != %(c_ns)s_x_direct_scalarmul(out.data(), pk.data(), scalar.data())) { | |||
if (DECAF_SUCCESS != $(c_ns)_x_direct_scalarmul(out.data(), pk.data(), scalar.data())) { | |||
throw CryptoException(); | |||
} | |||
return out; | |||
@@ -609,7 +604,7 @@ public: | |||
const FixedBlock<PUBLIC_BYTES> &pk, | |||
const FixedBlock<PRIVATE_BYTES> &scalar | |||
) NOEXCEPT { | |||
return %(c_ns)s_x_direct_scalarmul(out.data(), pk.data(), scalar.data()); | |||
return $(c_ns)_x_direct_scalarmul(out.data(), pk.data(), scalar.data()); | |||
} | |||
/** Generate and return a public key; equivalent to shared_secret(base_point(),scalar) | |||
@@ -619,7 +614,7 @@ public: | |||
const FixedBlock<PRIVATE_BYTES> &scalar | |||
) throw(std::bad_alloc) { | |||
SecureBuffer out(PUBLIC_BYTES); | |||
%(c_ns)s_x_base_scalarmul(out.data(), scalar.data()); | |||
$(c_ns)_x_base_scalarmul(out.data(), scalar.data()); | |||
return out; | |||
} | |||
@@ -631,21 +626,21 @@ public: | |||
FixedBuffer<PUBLIC_BYTES> &out, | |||
const FixedBlock<PRIVATE_BYTES> &scalar | |||
) NOEXCEPT { | |||
%(c_ns)s_x_base_scalarmul(out.data(), scalar.data()); | |||
$(c_ns)_x_base_scalarmul(out.data(), scalar.data()); | |||
} | |||
}; | |||
}; /* struct %(cxx_ns)s */ | |||
}; /* struct $(cxx_ns) */ | |||
/** @cond internal */ | |||
inline SecureBuffer %(cxx_ns)s::Scalar::direct_scalarmul ( | |||
inline SecureBuffer $(cxx_ns)::Scalar::direct_scalarmul ( | |||
const Block &in, | |||
decaf_bool_t allow_identity, | |||
decaf_bool_t short_circuit | |||
) const throw(CryptoException) { | |||
SecureBuffer out(%(cxx_ns)s::Point::SER_BYTES); | |||
SecureBuffer out($(cxx_ns)::Point::SER_BYTES); | |||
if (DECAF_SUCCESS != | |||
%(c_ns)s_direct_scalarmul(out.data(), in.data(), s, allow_identity, short_circuit) | |||
$(c_ns)_direct_scalarmul(out.data(), in.data(), s, allow_identity, short_circuit) | |||
) { | |||
throw CryptoException(); | |||
} | |||
@@ -655,6 +650,3 @@ inline SecureBuffer %(cxx_ns)s::Scalar::direct_scalarmul ( | |||
#undef NOEXCEPT | |||
} /* namespace decaf */ | |||
""" | |||
) | |||
@@ -0,0 +1,18 @@ | |||
/** | |||
* Master header for Decaf library. | |||
* | |||
* The Decaf library implements cryptographic operations on a elliptic curve | |||
* groups of prime order p. It accomplishes this by using a twisted Edwards | |||
* curve (isogenous to Ed448-Goldilocks or Ed25519) and wiping out the cofactor. | |||
* | |||
* The formulas are all complete and have no special cases. However, some | |||
* functions can fail. For example, decoding functions can fail because not | |||
* every string is the encoding of a valid group element. | |||
* | |||
* The formulas contain no data-dependent branches, timing or memory accesses, | |||
* except for decaf_XXX_base_double_scalarmul_non_secret. | |||
*/ | |||
$("\n".join([ | |||
"#include <decaf/decaf_%s.h>" % g for g in sorted([c["bits"] for _,c in curve.iteritems()]) | |||
])) |
@@ -0,0 +1,16 @@ | |||
/** Master header for Decaf library, C++ version. */ | |||
$("\n".join([ | |||
"#include <decaf/decaf_%s.hxx>" % g for g in sorted([c["bits"] for _,c in curve.iteritems()]) | |||
])) | |||
namespace decaf { | |||
template <template<typename Group> class Run> | |||
void run_for_all_curves() { | |||
$("\n".join([ | |||
" Run<%s>::run();" % cd["cxx_ns"] | |||
for cd in sorted(curve.values(), key=lambda x:x["c_ns"]) | |||
]) | |||
) | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
/** | |||
* Example Decaf crypto routines, metaheader. | |||
* @warning These are merely examples, though they ought to be secure. But real | |||
* protocols will decide differently on magic numbers, formats, which items to | |||
* hash, etc. | |||
*/ | |||
$("\n".join([ | |||
"#include <decaf/crypto_%s.h>" % g for g in sorted([c["bits"] for _,c in curve.iteritems()]) | |||
])) |
@@ -0,0 +1,10 @@ | |||
/** | |||
* Example Decaf crypto routines, C++ metaheader. | |||
* @warning These are merely examples, though they ought to be secure. But real | |||
* protocols will decide differently on magic numbers, formats, which items to | |||
* hash, etc. | |||
*/ | |||
$("\n".join([ | |||
"#include <decaf/crypto_%s.hxx>" % g for g in sorted([c["bits"] for _,c in curve.iteritems()]) | |||
])) |