![tecnovert@tecnovert.net](/assets/img/avatar_default.png)
12 changed files with 334 additions and 10 deletions
@ -0,0 +1,25 @@ |
|||
|
|||
size_t secp256k1_dleag_size(size_t n_bits); |
|||
|
|||
int secp256k1_dleag_prove( |
|||
const secp256k1_context *ctx, |
|||
unsigned char *proof_out, |
|||
size_t *proof_len, /* Input length of proof_out buffer, output length of proof. */ |
|||
const unsigned char *key, /* 32 bytes */ |
|||
size_t n_bits, |
|||
const unsigned char *nonce, /* 32 bytes */ |
|||
const secp256k1_generator *gen_s_a, |
|||
const secp256k1_generator *gen_s_b, |
|||
const unsigned char *gen_e_a, |
|||
const unsigned char *gen_e_b |
|||
); |
|||
|
|||
int secp256k1_dleag_verify( |
|||
const secp256k1_context *ctx, |
|||
const unsigned char *proof, |
|||
size_t proof_len, |
|||
const secp256k1_generator *gen_s_a, |
|||
const secp256k1_generator *gen_s_b, |
|||
const unsigned char *gen_e_a, |
|||
const unsigned char *gen_e_b |
|||
); |
@ -0,0 +1,32 @@ |
|||
int ecdsaotves_enc_sign( |
|||
const secp256k1_context *ctx, |
|||
unsigned char *ct_out, |
|||
const unsigned char *skS, |
|||
const unsigned char *pkE, |
|||
const unsigned char *msg32 |
|||
); |
|||
|
|||
int ecdsaotves_enc_verify( |
|||
const secp256k1_context *ctx, |
|||
const unsigned char *pkS, |
|||
const unsigned char *pkE, |
|||
const unsigned char *msg32, |
|||
const unsigned char *ct |
|||
); |
|||
|
|||
int ecdsaotves_dec_sig( |
|||
const secp256k1_context *ctx, |
|||
unsigned char *sig_out, |
|||
size_t *sig_length, |
|||
const unsigned char *skE, |
|||
const unsigned char *ct |
|||
); |
|||
|
|||
int ecdsaotves_rec_enc_key( |
|||
const secp256k1_context *ctx, |
|||
unsigned char *key_out, |
|||
const unsigned char *pkE, |
|||
const unsigned char *ct, |
|||
const unsigned char *dersig, |
|||
size_t sig_length |
|||
); |
@ -0,0 +1,2 @@ |
|||
extern const unsigned char ed25519_gen[32]; |
|||
extern const unsigned char ed25519_gen2[32]; |
@ -0,0 +1,7 @@ |
|||
typedef struct { |
|||
unsigned char data[64]; |
|||
} secp256k1_generator; |
|||
|
|||
extern const secp256k1_generator secp256k1_generator_const_g; |
|||
extern const secp256k1_generator secp256k1_generator_const_h; |
|||
|
@ -0,0 +1,65 @@ |
|||
from coincurve.context import GLOBAL_CONTEXT |
|||
from coincurve.flags import EC_COMPRESSED, EC_UNCOMPRESSED |
|||
from ._libsecp256k1 import ffi, lib |
|||
|
|||
|
|||
def dleag_proof_len(bits=252): |
|||
return lib.secp256k1_dleag_size(bits) |
|||
|
|||
|
|||
def get_nonce(): |
|||
try: |
|||
import secrets |
|||
|
|||
return secrets.token_bytes(32) |
|||
except Exception: |
|||
from os import urandom |
|||
|
|||
return urandom(32) |
|||
|
|||
|
|||
def dleag_prove(private_key, context=GLOBAL_CONTEXT): |
|||
proof_length = dleag_proof_len() |
|||
proof_output = ffi.new('unsigned char[{}]'.format(proof_length)) |
|||
|
|||
proof_length_p = ffi.new('size_t *') |
|||
proof_length_p[0] = proof_length |
|||
|
|||
# nonce_bytes = ffi.from_buffer(secrets.token_bytes(32)) |
|||
nonce_bytes = get_nonce() |
|||
rv = lib.secp256k1_dleag_prove( |
|||
context.ctx, |
|||
proof_output, |
|||
proof_length_p, |
|||
private_key.secret, |
|||
252, |
|||
nonce_bytes, |
|||
ffi.addressof(lib.secp256k1_generator_const_g), |
|||
ffi.addressof(lib.secp256k1_generator_const_h), |
|||
lib.ed25519_gen, |
|||
lib.ed25519_gen2, |
|||
) |
|||
|
|||
if rv != 1: |
|||
raise ValueError('secp256k1_dleag_prove failed') |
|||
|
|||
# TODO: How to clear memory? Add random module to secp256k1? |
|||
# ffi.memmove(nonce_bytes, bytes([0] * 32), 32) |
|||
return bytes(ffi.buffer(proof_output, proof_length)) |
|||
|
|||
|
|||
def dleag_verify(proof, context=GLOBAL_CONTEXT): |
|||
proof_bytes = ffi.from_buffer(proof) |
|||
proof_length = len(proof) |
|||
|
|||
rv = lib.secp256k1_dleag_verify( |
|||
context.ctx, |
|||
proof_bytes, |
|||
proof_length, |
|||
ffi.addressof(lib.secp256k1_generator_const_g), |
|||
ffi.addressof(lib.secp256k1_generator_const_h), |
|||
lib.ed25519_gen, |
|||
lib.ed25519_gen2, |
|||
) |
|||
|
|||
return True if rv == 1 else False |
@ -0,0 +1,89 @@ |
|||
from coincurve.context import GLOBAL_CONTEXT |
|||
from coincurve.utils import bytes_to_int, int_to_bytes, sha256 |
|||
from ._libsecp256k1 import ffi, lib |
|||
|
|||
|
|||
def ecdsaotves_enc_sign(private_key_sign, public_key_encrypt, msg, context=GLOBAL_CONTEXT): |
|||
ct_length = 196 |
|||
ct_output = ffi.new('unsigned char[{}]'.format(ct_length)) |
|||
|
|||
if len(private_key_sign) != 32: |
|||
raise ValueError('private_key_sign must be 32 bytes') |
|||
if len(public_key_encrypt) != 33: |
|||
raise ValueError('public_key_encrypt must be 33 bytes') |
|||
if len(msg) != 32: |
|||
raise ValueError('msg must be 32 bytes') |
|||
|
|||
rv = lib.ecdsaotves_enc_sign( |
|||
context.ctx, |
|||
ct_output, |
|||
private_key_sign, |
|||
public_key_encrypt, |
|||
msg, |
|||
) |
|||
|
|||
if rv != 1: |
|||
raise ValueError('ecdsaotves_enc_sign failed') |
|||
|
|||
return bytes(ffi.buffer(ct_output, ct_length)) |
|||
|
|||
|
|||
def ecdsaotves_enc_verify(public_key_sign, public_key_encrypt, msg, ct, context=GLOBAL_CONTEXT): |
|||
if len(public_key_sign) != 33: |
|||
raise ValueError('public_key_sign must be 33 bytes') |
|||
if len(public_key_encrypt) != 33: |
|||
raise ValueError('public_key_encrypt must be 33 bytes') |
|||
if len(msg) != 32: |
|||
raise ValueError('msg must be 32 bytes') |
|||
if len(ct) != 196: |
|||
raise ValueError('ciphertext must be 196 bytes') |
|||
|
|||
rv = lib.ecdsaotves_enc_verify( |
|||
context.ctx, |
|||
public_key_sign, |
|||
public_key_encrypt, |
|||
msg, |
|||
ct, |
|||
) |
|||
|
|||
return True if rv == 1 else False |
|||
|
|||
|
|||
def ecdsaotves_dec_sig(private_key_encrypt, ct, context=GLOBAL_CONTEXT): |
|||
if len(private_key_encrypt) != 32: |
|||
raise ValueError('private_key_encrypt must be 32 bytes') |
|||
if len(ct) != 196: |
|||
raise ValueError('ciphertext must be 196 bytes') |
|||
|
|||
output_length = ffi.new('size_t *') |
|||
output_length[0] = 100 |
|||
sig_output = ffi.new('unsigned char[{}]'.format(100)) |
|||
|
|||
rv = lib.ecdsaotves_dec_sig( |
|||
context.ctx, |
|||
sig_output, |
|||
output_length, |
|||
private_key_encrypt, |
|||
ct, |
|||
) |
|||
if rv != 1: |
|||
raise ValueError('ecdsaotves_dec_sig failed') |
|||
|
|||
return bytes(ffi.buffer(sig_output, output_length[0])) |
|||
|
|||
|
|||
def ecdsaotves_rec_enc_key(public_key_encrypt, ct, sig_der, context=GLOBAL_CONTEXT): |
|||
|
|||
if len(public_key_encrypt) != 33: |
|||
raise ValueError('public_key_encrypt must be 33 bytes') |
|||
if len(ct) != 196: |
|||
raise ValueError('ciphertext must be 196 bytes') |
|||
|
|||
key_output = ffi.new('unsigned char[{}]'.format(32)) |
|||
|
|||
sig_length = len(sig_der) |
|||
rv = lib.ecdsaotves_rec_enc_key(context.ctx, key_output, public_key_encrypt, ct, sig_der, sig_length) |
|||
if rv != 1: |
|||
raise ValueError('ecdsaotves_rec_enc_key failed') |
|||
|
|||
return bytes(ffi.buffer(key_output, 32)) |
@ -0,0 +1,35 @@ |
|||
from asn1crypto.keys import ECDomainParameters, ECPointBitString, ECPrivateKey, PrivateKeyAlgorithm, PrivateKeyInfo |
|||
|
|||
from coincurve.context import GLOBAL_CONTEXT |
|||
from coincurve.ecdsa import cdata_to_der, der_to_cdata, deserialize_recoverable, recover, serialize_recoverable |
|||
from coincurve.flags import EC_COMPRESSED, EC_UNCOMPRESSED |
|||
from coincurve.utils import bytes_to_int, int_to_bytes_padded |
|||
from ._libsecp256k1 import ffi, lib |
|||
|
|||
|
|||
DEFAULT_NONCE = (ffi.NULL, ffi.NULL) |
|||
GROUP_ORDER_INT = 2 ** 252 + 27742317777372353535851937790883648493 |
|||
|
|||
|
|||
def get_valid_secret(): |
|||
try: |
|||
import secrets |
|||
|
|||
return int_to_bytes_padded(9 + secrets.randbelow(GROUP_ORDER_INT - 9)) |
|||
except Exception: |
|||
from os import urandom |
|||
|
|||
while True: |
|||
secret = urandom(32) |
|||
if 9 < bytes_to_int(secret) < GROUP_ORDER_INT: |
|||
return secret |
|||
|
|||
|
|||
class Ed25519PrivateKey: |
|||
def __init__(self, secret=None, context=GLOBAL_CONTEXT): |
|||
self.context = context |
|||
|
|||
|
|||
class Ed25519PublicKey: |
|||
def __init__(self, data, context=GLOBAL_CONTEXT): |
|||
self.context = context |
@ -0,0 +1,12 @@ |
|||
from coincurve.dleag import dleag_prove, dleag_verify |
|||
from coincurve.ed25519 import get_valid_secret |
|||
from coincurve.keys import PrivateKey, PublicKey |
|||
|
|||
|
|||
class TestDLEAG: |
|||
def test_dleag(self): |
|||
secret = get_valid_secret() |
|||
private_key = PrivateKey(secret) |
|||
proof = dleag_prove(private_key) |
|||
|
|||
assert True == dleag_verify(proof) |
@ -0,0 +1,33 @@ |
|||
import sys |
|||
from coincurve.ecdsaotves import ecdsaotves_enc_sign, ecdsaotves_enc_verify, ecdsaotves_dec_sig, ecdsaotves_rec_enc_key |
|||
from coincurve.keys import PrivateKey, PublicKey |
|||
from coincurve.utils import get_valid_secret, sha256 |
|||
|
|||
|
|||
class TestECDSAOTVES: |
|||
def test_ecdsaotves(self): |
|||
secret_sign = get_valid_secret() |
|||
secret_encrypt = get_valid_secret() |
|||
|
|||
pk_sign = PublicKey.from_secret(secret_sign) |
|||
pk_encrypt = PublicKey.from_secret(secret_encrypt) |
|||
pk_sb = pk_sign.format() |
|||
pk_eb = pk_encrypt.format() |
|||
|
|||
message = 'otves message' |
|||
if sys.version_info[0] > 2: |
|||
message_hash = sha256(bytes(message, 'utf-8')) |
|||
else: |
|||
message_hash = sha256(message) |
|||
|
|||
ct = ecdsaotves_enc_sign(secret_sign, pk_eb, message_hash) |
|||
|
|||
assert ecdsaotves_enc_verify(pk_sb, pk_eb, message_hash, ct) |
|||
|
|||
sig = ecdsaotves_dec_sig(secret_encrypt, ct) |
|||
|
|||
assert pk_sign.verify(sig, message_hash, hasher=None) |
|||
|
|||
secret_rec = ecdsaotves_rec_enc_key(pk_eb, ct, sig) |
|||
|
|||
assert secret_rec == secret_encrypt |
Loading…
Reference in new issue