Git Product home page Git Product logo

ecc's Introduction

elliptic-curve cryptography

macOS Linux Windows javascript iOS Android Codacy Badge Codacy Badge javadoc Maintainability Rating Security Rating Quality Gate Status

Library to work with elliptic-curve cryptography based on libsodium and blst.

Bindings
Java jvm/ecc maven
Javascript js/ecc npm
Python python/ecc PyPI version

Features

OPRF Oblivious pseudo-random functions

This is an implementation of draft-irtf-cfrg-voprf-21 ciphersuite OPRF(ristretto255, SHA-512) using libsodium.

An Oblivious Pseudorandom Function (OPRF) is a two-party protocol between client and server for computing the output of a Pseudorandom Function (PRF). The server provides the PRF secret key, and the client provides the PRF input. At the end of the protocol, the client learns the PRF output without learning anything about the PRF secret key, and the server learns neither the PRF input nor output.

There are two variations of the basic protocol:

  • VOPRF: is OPRF with the notion of verifiability. Clients can verify that the server used a specific private key during the execution of the protocol.
  • POPRF: is a partially-oblivious VOPRF that allows clients and servers to provide public input to the PRF computation.

The OPRF flow is shown below (from the IRTF draft):

    Client(input)                                        Server(skS)
  -------------------------------------------------------------------
  blind, blindedElement = Blind(input)

                             blindedElement
                               ---------->

                evaluatedElement = BlindEvaluate(skS, blindedElement)

                             evaluatedElement
                               <----------

  output = Finalize(input, blind, evaluatedElement)

For the advanced modes VOPRF and POPRF refer to the published draft.

OPAQUE The OPAQUE Asymmetric PAKE Protocol

This is an implementation of draft-irtf-cfrg-opaque-12 using libsodium.

OPAQUE consists of two stages: registration and authenticated key exchange. In the first stage, a client registers its password with the server and stores its encrypted credentials in the server, but the server never knows what the password is.

The registration flow is shown below (from the IRTF draft):

       creds                                   parameters
         |                                         |
         v                                         v
       Client                                    Server
       ------------------------------------------------
                   registration request
                ------------------------->
                   registration response
                <-------------------------
                         record
                ------------------------->
      ------------------------------------------------
         |                                         |
         v                                         v
     export_key                                 record

In the second stage, the client outputs two values, an "export_key" (matching that from registration) and a "session_key". The server outputs a single value "session_key" that matches that of the client.

The authenticated key exchange flow is shown below (from the IRTF draft):

       creds                             (parameters, record)
         |                                         |
         v                                         v
       Client                                    Server
       ------------------------------------------------
                      AKE message 1
                ------------------------->
                      AKE message 2
                <-------------------------
                      AKE message 3
                ------------------------->
      ------------------------------------------------
         |                                         |
         v                                         v
   (export_key, session_key)                  session_key

The public API for implementing the protocol is:

  • Client
opaque_ristretto255_sha512_CreateRegistrationRequest
opaque_ristretto255_sha512_FinalizeRequest
opaque_ristretto255_sha512_3DH_ClientInit
opaque_ristretto255_sha512_3DH_ClientFinish
  • Server
opaque_ristretto255_sha512_CreateRegistrationResponse
opaque_ristretto255_sha512_3DH_ServerInit
opaque_ristretto255_sha512_3DH_ServerFinish

Two-Round Threshold Schnorr Signatures with FROST

This is an implementation of draft-irtf-cfrg-frost-13 using libsodium.

The draft presents a two-round signing variant of FROST, a Flexible Round-Optimized Schnorr Threshold signature scheme. FROST signatures can be issued after a threshold number of entities cooperate to issue a signature, allowing for improved distribution of trust and redundancy with respect to a secret key.

Unlike signatures in a single-party setting, threshold signatures require cooperation among a threshold number of signers each holding a share of a common private key. The security of threshold schemes in general assume that an adversary can corrupt strictly fewer than a threshold number of participants.

This implementation follows the trusted dealer key generation documented in the Appendix B of the draft using Shamir and Verifiable Secret Sharing.

Ethereum BLS Signature

Ethereum uses BLS signatures as specified in the IETF draft draft-irtf-cfrg-bls-signature-05 ciphersuite BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_.

This library provides the following API:

ecc_sign_eth_bls_KeyGen
ecc_sign_eth_bls_SkToPk
ecc_sign_eth_bls_KeyValidate
ecc_sign_eth_bls_Sign
ecc_sign_eth_bls_Verify
ecc_sign_eth_bls_Aggregate
ecc_sign_eth_bls_FastAggregateVerify
ecc_sign_eth_bls_AggregateVerify

BLS is a digital signature scheme with aggregation properties that can be applied to signatures and public keys. For this reason, in the context of blockchains, BLS signatures are used for authenticating transactions, votes during consensus protocols, and to reduce bandwidth and storage requirements.

BLS12-381 Pairing

In the context of pairing friendly elliptic curves, a pairing is a map e: G1xG2 -> GT such that for each a, b, P and Q

e(a * P, b * Q) = e(P, Q)^(a * b)

You can use this to obtain such pairings:

// c code, for a very similar java code, look at the unit tests
byte_t a[ecc_bls12_381_SCALARSIZE];
byte_t b[ecc_bls12_381_SCALARSIZE];
ecc_bls12_381_scalar_random(a);
ecc_bls12_381_scalar_random(b);

byte_t aP[ecc_bls12_381_G1SIZE];
byte_t bQ[ecc_bls12_381_G2SIZE];

ecc_bls12_381_g1_scalarmult_base(aP, a); // a * P
ecc_bls12_381_g2_scalarmult_base(bQ, b); // b * Q

byte_t pairing[ecc_bls12_381_FP12SIZE];
ecc_bls12_381_pairing(pairing, aP, bQ); // e(a * P, b * Q)

Read more at:
https://hackmd.io/@benjaminion/bls12-381
https://en.wikipedia.org/wiki/Pairing-based_cryptography

Proxy Re-Encryption (PRE)

With a pairing-friendly elliptic curve and a well-defined pairing operation, you can implement a proxy re-encryption scheme.

This library provides an implementation using BLS12-381.

Example of how to use it:

// This is a java code sample, but for a similar plain C code sample look at the unit tests

// client A setup public/private keys and signing keys
KeyPair keysA = pre_schema1_KeyGen();
SigningKeyPair signingA = pre_schema1_SigningKeyGen();

// client B setup public/private keys (signing keys are not used here)
KeyPair keysB = pre_schema1_KeyGen();

// proxy server setup signing keys
SigningKeyPair signingProxy = pre_schema1_SigningKeyGen();

// client A selects a plaintext message, this message
// in itself is random but can be used as a seed
// for symmetric encryption keys
byte[] message = pre_schema1_MessageGen();

// client A encrypts the message to itself, making it
// possible to send this ciphertext to the proxy.
byte[] ciphertextLevel1 = pre_schema1_Encrypt(message, keysA.pk, signingA);

// client A sends ciphertextLevel1 to the proxy server and
// eventually client A allows client B to see the encrypted
// message, in this case the proxy needs to re-encrypt
// ciphertextLevel1 (without ever knowing the plaintext).
// In order to do that, client A needs to create a re-encryption
// key that the proxy can use to perform such operation.

// client A creates a re-encryption key the proxy can use
// to re-encrypt the ciphertext (ciphertextLevel1) in order for
// client B be able to recover the original message
byte[] reEncKey = pre_schema1_ReKeyGen(keysA.sk, keysB.pk, signingA);

// the proxy re-encrypts the ciphertext ciphertextLevel1 with such
// a key that allows client B to recover the original message
byte[] ciphertextLevel2 = pre_schema1_ReEncrypt(
    ciphertextLevel1,
    reEncKey,
    signingA.spk, keysB.pk,
    signingProxy
);

// client B is able to decrypt ciphertextLevel2 and the result
// is the original plaintext message
byte[] messageDecrypted = pre_schema1_DecryptLevel2(
    ciphertextLevel2,
    keysB.sk, signingProxy.spk
);

// now both client A and client B share the same plaintext message
// messageDecrypted is equal to message

Read more at:
"A Fully Secure Unidirectional and Multi-user Proxy Re-encryption Scheme" by H. Wang and Z. Cao, 2009
"A Multi-User CCA-Secure Proxy Re-Encryption Scheme" by Y. Cai and X. Liu, 2014
"Cryptographically Enforced Orthogonal Access Control at Scale" by B. Wall and P. Walsh, 2018
https://en.wikipedia.org/wiki/Proxy_re-encryption

Cryptographic primitives and utilities

ecc_hash_sha256
ecc_hash_sha512

ecc_kdf_scrypt
ecc_kdf_argon2id

ecc_aead_chacha20poly1305_encrypt
ecc_aead_chacha20poly1305_decrypt

Bindings and building

To generate the static files for bindings:

python3 bindings/gen_code.py

To build c shared and static libraries and jvm bindings:

./build-c.sh

To build javascript bindings:

./build-js.sh

ecc's People

Contributors

aldenml avatar gubatron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

alexanderkud

ecc's Issues

Proxy re encryption with 3rd party encrypting message

Hello,

I'm trying to achieve the following scheme
C encrypt a message with A public key and send it to the Proxy
A creates a re-encryption key that the proxy can use to share data with B

I managed to achieve it only if the re-encryption is signed by C
pre_schema1_ReKeyGen(keysA.sk, keysB.pk, signingC);

This is not very practical in the following situation
A has a data repository, managed by Proxy
anyone can contribute to this data repository by positing messages encrypted with A.pk
A select who can read these data by creating reEncKey for each recipient.

In this situation it would mean that A would have to create n reEncKeys for each Contributor/Recipient pair.

Do I miss a point that would allow to have only one reEncKey per recipient ?

Here is a sample working code

let ecc;

async function main() {

  // client A setup public/private keys and signing keys
  const keysA = await ecc.pre_schema1_KeyGen();
  const signingA = await ecc.pre_schema1_SigningKeyGen();

  // client B setup public/private keys (signing keys are not used here)
  const keysB = await ecc.pre_schema1_KeyGen();

  // proxy server setup signing keys
  const signingProxy = await ecc.pre_schema1_SigningKeyGen();

  // client C is the origin encrypting party
  const signingC = await ecc.pre_schema1_SigningKeyGen();

  // client C select a plaintext message
  const message = await ecc.pre_schema1_MessageGen();
  const messageS = uintArrayToString(message);

  // client C encrypts the message with A key
  const ciphertextLevel1 = await ecc.pre_schema1_Encrypt(
    message,
    keysA.pk,
    signingC);

  // client A is able to decrypt ciphertextLevel1 
  const messageDecrypted1 = await ecc.pre_schema1_DecryptLevel1(
    ciphertextLevel1,
    keysA.sk,
    signingC.spk
  );

  console.log(' Message decrypted == message ', (messageS == uintArrayToString(messageDecrypted1)));

  
  // client A allows client B to see the encrypted

  // client A creates a re-encryption key that the proxy can use
  // to re-encrypt the ciphertext (ciphertextLevel1) in order for
  // client B be able to recover the original message
  const reEncKey = await ecc.pre_schema1_ReKeyGen(
    keysA.sk, 
    keysB.pk, 
    signingC // ⚠️ HERE I WOULD LIKE TO AVOID USING `C` signing Key
  );

  // the proxy re-encrypt the ciphertext ciphertextLevel1 with such
  // a key that allows client B to recover the original message
  const ciphertextLevel2 = await ecc.pre_schema1_ReEncrypt(
    ciphertextLevel1,
    reEncKey,
    signingC.spk, // ⚠️ HERE I WOULD LIKE TO AVOID USING `C` signing Key
    keysB.pk, 
    signingProxy
  );

  // client B is able to decrypt ciphertextLevel2 and the result
  // is the original plaintext message
  const messageDecrypted2 = await ecc.pre_schema1_DecryptLevel2(
    ciphertextLevel2,
    keysB.sk, signingProxy.spk
  );

  // now both client A and client B share the same plaintext message
  // messageDecrypted is equal to message

  console.log(' Message recrypted/decrypted == message ', (messageS == uintArrayToString(messageDecrypted2)));

}


function uintArrayToString(u8) {
  return Buffer.from(u8).toString('base64');
}

function stringToUintArray(b64) {
  return new Uint8Array(Buffer.from(b64, 'base64'))
}

(async () => {
  ecc = await import('@aldenml/ecc');
  await main();
})();

ecc_frost_ristretto255_sha512_trusted_dealer_keygen memory access out of bounds

Tried to get your Frost implementation to work, but failed with "memory access out of bounds"

I observed that under:
https://github.com/aldenml/ecc/blob/master/bindings/js/libecc-post.js

Module.ecc_frost_ristretto255_sha512_secret_share_shard_with_coefficients = (
const ptr_points = mput(points, n*ecc_frost_ristretto255_sha512_SCALARSIZE);

Shouldn't this be?
const ptr_points = mput(points, n*ecc_frost_ristretto255_sha512_POINTSIZE);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.