Commit e50ac707 authored by Mark Haines's avatar Mark Haines
Browse files

Squashed 'lib/curve25519-donna/' content from commit 28772f3

git-subtree-dir: lib/curve25519-donna
git-subtree-split: 28772f37a4b8a57ab9439b9e79b19f9abee686da
parents
/curve25519-donna-c64.a
/curve25519-donna.a
/test-curve25519-donna
/speed-curve25519-donna
/test-curve25519-donna-c64
/speed-curve25519-donna-c64
/test-sc-curve25519-donna-c64
/build
*.o
*.pyc
/dist
/MANIFEST
Copyright 2008, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
curve25519-donna: Curve25519 elliptic curve, public key function
http://code.google.com/p/curve25519-donna/
Adam Langley <agl@imperialviolet.org>
Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
More information about curve25519 can be found here
http://cr.yp.to/ecdh.html
djb's sample implementation of curve25519 is written in a special assembly
language called qhasm and uses the floating point registers.
This is, almost, a clean room reimplementation from the curve25519 paper. It
uses many of the tricks described therein. Only the crecip function is taken
from the sample implementation.
CFLAGS=-Wmissing-prototypes -Wdeclaration-after-statement -O2 -Wall
CFLAGS_32=-m32
targets: curve25519-donna.a curve25519-donna-c64.a
test: test-donna test-donna-c64
clean:
rm -f *.o *.a *.pp test-curve25519-donna test-curve25519-donna-c64 speed-curve25519-donna speed-curve25519-donna-c64 test-noncanon-curve25519-donna test-noncanon-curve25519-donna-c64
curve25519-donna.a: curve25519-donna.o
ar -rc curve25519-donna.a curve25519-donna.o
ranlib curve25519-donna.a
curve25519-donna.o: curve25519-donna.c
gcc -c curve25519-donna.c $(CFLAGS) $(CFLAGS_32)
curve25519-donna-c64.a: curve25519-donna-c64.o
ar -rc curve25519-donna-c64.a curve25519-donna-c64.o
ranlib curve25519-donna-c64.a
curve25519-donna-c64.o: curve25519-donna-c64.c
gcc -c curve25519-donna-c64.c $(CFLAGS)
test-donna: test-curve25519-donna
./test-curve25519-donna | head -123456 | tail -1
test-donna-c64: test-curve25519-donna-c64
./test-curve25519-donna-c64 | head -123456 | tail -1
test-curve25519-donna: test-curve25519.c curve25519-donna.a
gcc -o test-curve25519-donna test-curve25519.c curve25519-donna.a $(CFLAGS) $(CFLAGS_32)
test-curve25519-donna-c64: test-curve25519.c curve25519-donna-c64.a
gcc -o test-curve25519-donna-c64 test-curve25519.c curve25519-donna-c64.a $(CFLAGS)
speed-curve25519-donna: speed-curve25519.c curve25519-donna.a
gcc -o speed-curve25519-donna speed-curve25519.c curve25519-donna.a $(CFLAGS) $(CFLAGS_32)
speed-curve25519-donna-c64: speed-curve25519.c curve25519-donna-c64.a
gcc -o speed-curve25519-donna-c64 speed-curve25519.c curve25519-donna-c64.a $(CFLAGS)
test-sc-curve25519-donna-c64: test-sc-curve25519.c curve25519-donna-c64.a
gcc -o test-sc-curve25519-donna-c64 -O test-sc-curve25519.c curve25519-donna-c64.a test-sc-curve25519.s $(CFLAGS)
test-noncanon-donna: test-noncanon-curve25519-donna
./test-noncanon-curve25519-donna
test-noncanon-donna-c64: test-noncanon-curve25519-donna-c64
./test-noncanon-curve25519-donna-c64
test-noncanon-curve25519-donna: test-noncanon.c curve25519-donna.a
gcc -o test-noncanon-curve25519-donna test-noncanon.c curve25519-donna.a $(CFLAGS) $(CFLAGS_32)
test-noncanon-curve25519-donna-c64: test-noncanon.c curve25519-donna-c64.a
gcc -o test-noncanon-curve25519-donna-c64 test-noncanon.c curve25519-donna-c64.a $(CFLAGS)
See http://code.google.com/p/curve25519-donna/ for details.
BUILDING:
If you run `make`, two .a archives will be built, similar to djb's curve25519
code. Alternatively, read on:
The C implementation is contained within curve25519-donna.c. It has no external
dependancies and is BSD licenced. You can copy/include/link it directly in with
your program. Recommended C flags: -O2
The x86-64 bit implementation is contained within curve25519-donna-x86-64.c and
curve25519-donna-x86-64.s. Build like this:
% cpp curve25519-donna-x86-64.s > curve25519-donna-x86-64.s.pp
% as -o curve25519-donna-x86-64.s.o curve25519-donna-x86-64.s.pp
% gcc -O2 -c curve25519-donna-x86-64.c
Then the two .o files can be linked in
USAGE:
The usage is exactly the same as djb's code (as described at
http://cr.yp.to/ecdh.html) expect that the function is called curve25519_donna.
In short,
To generate a private key just generate 32 random bytes.
To generate the public key, just do:
static const uint8_t basepoint[32] = {9};
curve25519_donna(mypublic, mysecret, basepoint);
To generate an agreed key do:
uint8_t shared_key[32];
curve25519_donna(shared_key, mysecret, theirpublic);
And hash the shared_key with a cryptographic hash function before using.
/*
James Robson
Public domain.
*/
#include "Curve25519Donna.h"
#include <stdio.h>
#include <stdlib.h>
extern void curve25519_donna(unsigned char *output, const unsigned char *a,
const unsigned char *b);
unsigned char*
as_unsigned_char_array(JNIEnv* env, jbyteArray array, int* len);
jbyteArray as_byte_array(JNIEnv* env, unsigned char* buf, int len);
jbyteArray as_byte_array(JNIEnv* env, unsigned char* buf, int len) {
jbyteArray array = (*env)->NewByteArray(env, len);
(*env)->SetByteArrayRegion(env, array, 0, len, (jbyte*)buf);
//int i;
//for (i = 0;i < len;++i) printf("%02x",(unsigned int) buf[i]); printf(" ");
//printf("\n");
return array;
}
unsigned char*
as_unsigned_char_array(JNIEnv* env, jbyteArray array, int* len) {
*len = (*env)->GetArrayLength(env, array);
unsigned char* buf = (unsigned char*)calloc(*len+1, sizeof(char));
(*env)->GetByteArrayRegion (env, array, 0, *len, (jbyte*)buf);
return buf;
}
JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_curve25519Donna
(JNIEnv *env, jobject obj, jbyteArray a, jbyteArray b) {
unsigned char o[32] = {0};
int l1, l2;
unsigned char* a1 = as_unsigned_char_array(env, a, &l1);
unsigned char* b1 = as_unsigned_char_array(env, b, &l2);
if ( !(l1 == 32 && l2 == 32) ) {
fprintf(stderr, "Error, must be length 32");
return NULL;
}
curve25519_donna(o, (const unsigned char*)a1, (const unsigned char*)b1);
free(a1);
free(b1);
return as_byte_array(env, (unsigned char*)o, 32);
}
JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_makePrivate
(JNIEnv *env, jobject obj, jbyteArray secret) {
int len;
unsigned char* k = as_unsigned_char_array(env, secret, &len);
if (len != 32) {
fprintf(stderr, "Error, must be length 32");
return NULL;
}
k[0] &= 248;
k[31] &= 127;
k[31] |= 64;
return as_byte_array(env, k, 32);
}
JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_getPublic
(JNIEnv *env, jobject obj, jbyteArray privkey) {
int len;
unsigned char* private = as_unsigned_char_array(env, privkey, &len);
if (len != 32) {
fprintf(stderr, "Error, must be length 32");
return NULL;
}
unsigned char pubkey[32];
unsigned char basepoint[32] = {9};
curve25519_donna(pubkey, private, basepoint);
return as_byte_array(env, (unsigned char*)pubkey, 32);
}
JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_makeSharedSecret
(JNIEnv *env, jobject obj, jbyteArray privkey, jbyteArray their_pubkey) {
unsigned char shared_secret[32];
int l1, l2;
unsigned char* private = as_unsigned_char_array(env, privkey, &l1);
unsigned char* pubkey = as_unsigned_char_array(env, their_pubkey, &l2);
if ( !(l1 == 32 && l2 == 32) ) {
fprintf(stderr, "Error, must be length 32");
return NULL;
}
curve25519_donna(shared_secret, private, pubkey);
return as_byte_array(env, (unsigned char*)shared_secret, 32);
}
JNIEXPORT void JNICALL Java_Curve25519Donna_helowrld
(JNIEnv *env, jobject obj) {
printf("helowrld\n");
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Curve25519Donna */
#ifndef _Included_Curve25519Donna
#define _Included_Curve25519Donna
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Curve25519Donna
* Method: curve25519Donna
* Signature: ([B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_curve25519Donna
(JNIEnv *, jobject, jbyteArray, jbyteArray);
/*
* Class: Curve25519Donna
* Method: makePrivate
* Signature: ([B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_makePrivate
(JNIEnv *, jobject, jbyteArray);
/*
* Class: Curve25519Donna
* Method: getPublic
* Signature: ([B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_getPublic
(JNIEnv *, jobject, jbyteArray);
/*
* Class: Curve25519Donna
* Method: makeSharedSecret
* Signature: ([B[B)[B
*/
JNIEXPORT jbyteArray JNICALL Java_Curve25519Donna_makeSharedSecret
(JNIEnv *, jobject, jbyteArray, jbyteArray);
/*
* Class: Curve25519Donna
* Method: helowrld
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_Curve25519Donna_helowrld
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
/*
James Robson
Public domain.
*/
public class Curve25519Donna {
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
int v;
for ( int j = 0; j < bytes.length; j++ ) {
v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
public native byte[] curve25519Donna(byte[] a, byte[] b);
public native byte[] makePrivate(byte[] secret);
public native byte[] getPublic(byte[] privkey);
public native byte[] makeSharedSecret(byte[] privkey, byte[] theirPubKey);
public native void helowrld();
// Uncomment if your Java is 32-bit:
//static { System.loadLibrary("Curve25519Donna"); }
// Otherwise, load this 64-bit .jnilib:
static { System.loadLibrary("Curve25519Donna_64"); }
/*
To give the old tires a kick (OSX):
java -cp `pwd` Curve25519Donna
*/
public static void main (String[] args) {
Curve25519Donna c = new Curve25519Donna();
// These should be 32 bytes long
byte[] user1Secret = "abcdefghijklmnopqrstuvwxyz123456".getBytes();
byte[] user2Secret = "654321zyxwvutsrqponmlkjihgfedcba".getBytes();
// You can use the curve function directly...
//byte[] o = c.curve25519Donna(a, b);
//System.out.println("o = " + bytesToHex(o));
// ... but it's not really necessary. Just use the following
// convenience methods:
byte[] privKey = c.makePrivate(user1Secret);
byte[] pubKey = c.getPublic(privKey);
byte[] privKey2 = c.makePrivate(user2Secret);
byte[] pubKey2 = c.getPublic(privKey2);
System.out.println("'user1' privKey = " + bytesToHex(privKey));
System.out.println("'user1' pubKey = " + bytesToHex(pubKey));
System.out.println("===================================================");
System.out.println("'user2' privKey = " + bytesToHex(privKey2));
System.out.println("'user2' pubKey = " + bytesToHex(pubKey2));
System.out.println("===================================================");
byte[] ss1 = c.makeSharedSecret(privKey, pubKey2);
System.out.println("'user1' computes shared secret: " + bytesToHex(ss1));
byte[] ss2 = c.makeSharedSecret(privKey2, pubKey);
System.out.println("'user2' computes shared secret: " + bytesToHex(ss2));
}
}
CFLAGS=-Wmissing-prototypes -Wdeclaration-after-statement -O2 -Wall
CC=clang
targets: curve25519-donna.a curve25519-donna-c64.a
test: test-donna test-donna-c64
clean:
rm -f java-src/*.class java-src/*.jnilib *.dylib *.o *.a *.pp test-curve25519-donna test-curve25519-donna-c64 speed-curve25519-donna speed-curve25519-donna-c64
curve25519-donna.a: curve25519-donna.o
ar -rc curve25519-donna.a curve25519-donna.o
ranlib curve25519-donna.a
##### OSX dynamic library (32- & 64-bit)
curve25519donna.dylib: curve25519-donna.a curve25519-donna-c64.a
$(CC) -m32 -fpic -shared -Wl,-all_load curve25519-donna.a -Wl,-all_load -o libcurve25519donna.dylib
$(CC) -fpic -shared -Wl,-all_load curve25519-donna-c64.a -Wl,-all_load -o libcurve25519donna_64.dylib
##### OSX/Java section hence
# Java JNI - compiled for OSX (32- & 64-bit)
Curve25519Donna.class:
cd java-src; javah -jni Curve25519Donna; cd ..
cd java-src; javac Curve25519Donna.java; cd ..
Curve25519Donna.jnilib: curve25519-donna.a curve25519-donna-c64.a Curve25519Donna.class
@echo "Building 32-bit..."
clang -o java-src/libCurve25519Donna.jnilib $(CFLAGS) -lc -shared -m32 -I /System/Library/Frameworks/JavaVM.framework/Headers curve25519-donna.o java-src/Curve25519Donna.c
@echo "Building 64-bit..."
clang -o java-src/libCurve25519Donna_64.jnilib $(CFLAGS) -lc -shared -I /System/Library/Frameworks/JavaVM.framework/Headers curve25519-donna-c64.o java-src/Curve25519Donna.c
##### OSX/Java section end
curve25519-donna.o: curve25519-donna.c
$(CC) -c curve25519-donna.c $(CFLAGS) -m32
curve25519-donna-c64.a: curve25519-donna-c64.o
ar -rc curve25519-donna-c64.a curve25519-donna-c64.o
ranlib curve25519-donna-c64.a
curve25519-donna-c64.o: curve25519-donna-c64.c
$(CC) -c curve25519-donna-c64.c $(CFLAGS)
test-donna: test-curve25519-donna
./test-curve25519-donna | head -123456 | tail -1
test-donna-c64: test-curve25519-donna-c64
./test-curve25519-donna-c64 | head -123456 | tail -1
test-curve25519-donna: test-curve25519.c curve25519-donna.a
$(CC) -o test-curve25519-donna test-curve25519.c curve25519-donna.a $(CFLAGS) -m32
test-curve25519-donna-c64: test-curve25519.c curve25519-donna-c64.a
$(CC) -o test-curve25519-donna-c64 test-curve25519.c curve25519-donna-c64.a $(CFLAGS)
speed-curve25519-donna: speed-curve25519.c curve25519-donna.a
$(CC) -o speed-curve25519-donna speed-curve25519.c curve25519-donna.a $(CFLAGS) -m32
speed-curve25519-donna-c64: speed-curve25519.c curve25519-donna-c64.a
$(CC) -o speed-curve25519-donna-c64 speed-curve25519.c curve25519-donna-c64.a $(CFLAGS)
test-sc-curve25519-donna-c64: test-sc-curve25519.c curve25519-donna-c64.a
$(CC) -o test-sc-curve25519-donna-c64 -O test-sc-curve25519.c curve25519-donna-c64.a test-sc-curve25519.s $(CFLAGS)
/* Copyright 2008, Google Inc.
* All rights reserved.
*
* Code released into the public domain.
*
* curve25519-donna: Curve25519 elliptic curve, public key function
*
* http://code.google.com/p/curve25519-donna/
*
* Adam Langley <agl@imperialviolet.org>
*
* Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
*
* More information about curve25519 can be found here
* http://cr.yp.to/ecdh.html
*
* djb's sample implementation of curve25519 is written in a special assembly
* language called qhasm and uses the floating point registers.
*
* This is, almost, a clean room reimplementation from the curve25519 paper. It
* uses many of the tricks described therein. Only the crecip function is taken
* from the sample implementation.
*/
#include <string.h>
#include <stdint.h>
typedef uint8_t u8;
typedef uint64_t limb;
typedef limb felem[5];
// This is a special gcc mode for 128-bit integers. It's implemented on 64-bit
// platforms only as far as I know.
typedef unsigned uint128_t __attribute__((mode(TI)));
#undef force_inline
#define force_inline __attribute__((always_inline))
/* Sum two numbers: output += in */
static inline void force_inline
fsum(limb *output, const limb *in) {
output[0] += in[0];
output[1] += in[1];
output[2] += in[2];
output[3] += in[3];
output[4] += in[4];
}
/* Find the difference of two numbers: output = in - output
* (note the order of the arguments!)
*
* Assumes that out[i] < 2**52
* On return, out[i] < 2**55
*/
static inline void force_inline
fdifference_backwards(felem out, const felem in) {
/* 152 is 19 << 3 */
static const limb two54m152 = (((limb)1) << 54) - 152;
static const limb two54m8 = (((limb)1) << 54) - 8;
out[0] = in[0] + two54m152 - out[0];
out[1] = in[1] + two54m8 - out[1];
out[2] = in[2] + two54m8 - out[2];
out[3] = in[3] + two54m8 - out[3];
out[4] = in[4] + two54m8 - out[4];
}
/* Multiply a number by a scalar: output = in * scalar */
static inline void force_inline
fscalar_product(felem output, const felem in, const limb scalar) {
uint128_t a;
a = ((uint128_t) in[0]) * scalar;
output[0] = ((limb)a) & 0x7ffffffffffff;
a = ((uint128_t) in[1]) * scalar + ((limb) (a >> 51));
output[1] = ((limb)a) & 0x7ffffffffffff;
a = ((uint128_t) in[2]) * scalar + ((limb) (a >> 51));
output[2] = ((limb)a) & 0x7ffffffffffff;
a = ((uint128_t) in[3]) * scalar + ((limb) (a >> 51));
output[3] = ((limb)a) & 0x7ffffffffffff;
a = ((uint128_t) in[4]) * scalar + ((limb) (a >> 51));
output[4] = ((limb)a) & 0x7ffffffffffff;
output[0] += (a >> 51) * 19;
}
/* Multiply two numbers: output = in2 * in
*
* output must be distinct to both inputs. The inputs are reduced coefficient
* form, the output is not.
*
* Assumes that in[i] < 2**55 and likewise for in2.
* On return, output[i] < 2**52
*/
static inline void force_inline
fmul(felem output, const felem in2, const felem in) {
uint128_t t[5];
limb r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c;
r0 = in[0];
r1 = in[1];
r2 = in[2];
r3 = in[3];
r4 = in[4];
s0 = in2[0];
s1 = in2[1];
s2 = in2[2];
s3 = in2[3];
s4 = in2[4];
t[0] = ((uint128_t) r0) * s0;
t[1] = ((uint128_t) r0) * s1 + ((uint128_t) r1) * s0;
t[2] = ((uint128_t) r0) * s2 + ((uint128_t) r2) * s0 + ((uint128_t) r1) * s1;
t[3] = ((uint128_t) r0) * s3 + ((uint128_t) r3) * s0 + ((uint128_t) r1) * s2 + ((uint128_t) r2) * s1;
t[4] = ((uint128_t) r0) * s4 + ((uint128_t) r4) * s0 + ((uint128_t) r3) * s1 + ((uint128_t) r1) * s3 + ((uint128_t) r2) * s2;
r4 *= 19;
r1 *= 19;
r2 *= 19;
r3 *= 19;
t[0] += ((uint128_t) r4) * s1 + ((uint128_t) r1) * s4 + ((uint128_t) r2) * s3 + ((uint128_t) r3) * s2;
t[1] += ((uint128_t) r4) * s2 + ((uint128_t) r2) * s4 + ((uint128_t) r3) * s3;
t[2] += ((uint128_t) r4) * s3 + ((uint128_t) r3) * s4;
t[3] += ((uint128_t) r4) * s4;
r0 = (limb)t[0] & 0x7ffffffffffff; c = (limb)(t[0] >> 51);
t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffff; c = (limb)(t[1] >> 51);
t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffff; c = (limb)(t[2] >> 51);
t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffff; c = (limb)(t[3] >> 51);
t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffff; c = (limb)(t[4] >> 51);
r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffff;
r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffff;
r2 += c;
output[0] = r0;