Skip to content

Commit

Permalink
Add a module to perform Schnorr signatures
Browse files Browse the repository at this point in the history
Currently not used in production but allow us to experiement
with signature aggregation in the consensus protocol.
  • Loading branch information
Geod24 authored and AndrejMitrovic committed Sep 5, 2019
1 parent 544a36e commit 62b75b3
Show file tree
Hide file tree
Showing 4 changed files with 461 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -42,7 +42,7 @@ addons:
- libsqlite3-dev

env:
- PATH=$HOME/bin/:$PATH PKG_CONFIG_PATH="/usr/local/opt/sqlite/lib/pkgconfig"
- PATH=$HOME/bin/:$PATH PKG_CONFIG_PATH="/usr/local/opt/sqlite/lib/pkgconfig" LIBRARY_PATH=/usr/local/lib/:$LIBRARY_PATH

# A note about OSX:
# Homebrew uses a massive git repository, that gets updated very frequently.
Expand Down
10 changes: 10 additions & 0 deletions ci/travis_linux_setup.sh
Expand Up @@ -6,3 +6,13 @@ set -o pipefail
mkdir -p $HOME/bin/
ln -s `which gcc-9` $HOME/bin/gcc # /usr/bin/gcc-9
ln -s `which g++-9` $HOME/bin/g++ # /usr/bin/g++-9

pushd $HOME
wget https://github.com/jedisct1/libsodium/archive/1.0.18-RELEASE.tar.gz
tar xvfz 1.0.18-RELEASE.tar.gz
cd libsodium-1.0.18-RELEASE
./configure
make -j4
sudo make install
sudo ldconfig # Refresh cache
popd
211 changes: 211 additions & 0 deletions source/agora/common/crypto/ECC.d
@@ -0,0 +1,211 @@
/*******************************************************************************
Elliptic-curve primitives
Those primitives are used for Schnorr signatures.
See_Also:
https://en.wikipedia.org/wiki/EdDSA#Ed25519
Copyright:
Copyright (c) 2019 BOS Platform Foundation Korea
All rights reserved.
License:
MIT License. See LICENSE for details.
*******************************************************************************/

module agora.common.crypto.ECC;

import agora.common.Hash;
import geod24.bitblob;
import libsodium;

///
nothrow @nogc unittest
{
const Scalar s1 = Scalar.random();
const Scalar s2 = Scalar.random();
const Scalar s3 = s1 + s2;

assert(s3 - s1 == s2);
assert(s3 - s2 == s1);
assert(s3 - s3 == Scalar.init);
assert(-s3 == -s1 - s2);
assert(-s3 == -s2 - s1);

const Scalar One = (s3 + (-s3));
assert(One * One == One);
// Get the generator
const Point G = One.toPoint();
assert(G + G == (One + One).toPoint());

const Point p1 = s1.toPoint();
const Point p2 = s2.toPoint();
const Point p3 = s3.toPoint();

assert(s1.toPoint() == p1);
assert(p3 - p1 == p2);
assert(p3 - p2 == p1);

assert(s1 * p2 + s2 * p2 == s3 * p2);
}

/*******************************************************************************
A field element in the finite field of order 2^255-19
Scalar are used as private key and source of noise for signatures.
*******************************************************************************/

public struct Scalar
{
/// Internal state
package BitBlob!(crypto_core_ed25519_SCALARBYTES * 8) data;

/// Construct a scalar from its string representation or a `ubyte[]`
public this (T) (T param)
if (is(typeof(this.data = typeof(this.data)(param))))
{
this.data = typeof(this.data)(param);
}

/// Reduce the hash to a scalar
public this (Hash param) nothrow @nogc
{
crypto_core_ed25519_scalar_reduce(this.data[].ptr, param[].ptr);
}

/// Expose `toString`
public void toString (scope void delegate(const(char)[]) @safe dg)
const @safe
{
this.data.toString(dg);
}

/// Operator overloads for `+`, `-`, `*`
public Scalar opBinary (string op)(const scope auto ref Scalar rhs)
const nothrow @nogc
{
Scalar result = void;
static if (op == "+")
crypto_core_ed25519_scalar_add(
result.data[].ptr, this.data[].ptr, rhs.data[].ptr);
else static if (op == "-")
crypto_core_ed25519_scalar_sub(
result.data[].ptr, this.data[].ptr, rhs.data[].ptr);
else static if (op == "*")
crypto_core_ed25519_scalar_mul(
result.data[].ptr, this.data[].ptr, rhs.data[].ptr);
else
static assert(0, "Operator " ~ op ~ " not implemented");
return result;
}

/// Get the complement of this scalar
public Scalar opUnary (string s)()
const nothrow @nogc
if (s == "-")
{
Scalar result = void;
crypto_core_ed25519_scalar_complement(result.data[].ptr, this.data[].ptr);
return result;
}

/// Generate a random scalar
public static Scalar random () nothrow @nogc
{
Scalar ret = void;
crypto_core_ed25519_scalar_random(ret.data[].ptr);
return ret;
}

/// Return the point corresponding to this scalar multiplied by the generator
public Point toPoint () const nothrow @nogc
out (val) { assert(crypto_core_ed25519_is_valid_point(val.data[].ptr)); }
do {
Point ret = void;
if (crypto_scalarmult_ed25519_base_noclamp(ret.data[].ptr, this.data[].ptr))
assert(0);
return ret;
}
}

/*******************************************************************************
Represent a point on Curve25519
A point is an element of the cyclic subgroup formed from the elliptic curve:
x^2 + y^2 = 1 - (121665 / 1216666) * x^2 * y^2
And the base point `B` where By=4/5 and Bx > 0.
*******************************************************************************/

public struct Point
{
/// Internal state
package BitBlob!(crypto_core_ed25519_BYTES * 8) data;

/// Construct a point from its string representation or a `ubyte[]`
public this (T) (T param)
nothrow @nogc
if (is(typeof(this.data = typeof(this.data)(param))))
{
this.data = typeof(this.data)(param);
}

/// Expose `toString`
public void toString (scope void delegate(const(char)[]) @safe dg)
const @safe
{
this.data.toString(dg);
}

/// Operator overloads for points additions
public Point opBinary (string op)(const scope auto ref Point rhs)
const nothrow @nogc
if (op == "+" || op == "-")
{
Point result = void;
static if (op == "+")
{
if (crypto_core_ed25519_add(
result.data[].ptr, this.data[].ptr, rhs.data[].ptr))
assert(0);
}
else static if (op == "-")
{
if (crypto_core_ed25519_sub(
result.data[].ptr, this.data[].ptr, rhs.data[].ptr))
assert(0);
}
else static assert(0, "Unhandled `" ~ op ~ "` operator for Point");
return result;
}

/// Operator overloads for scalar multiplication
public Point opBinary (string op)(const scope auto ref Scalar rhs)
const nothrow @nogc
if (op == "*")
{
Point result = void;
if (crypto_scalarmult_ed25519_noclamp(
result.data[].ptr, rhs.data[].ptr, this.data[].ptr))
assert(0);
return result;
}

/// Ditto
public Point opBinaryRight (string op)(const scope auto ref Scalar lhs)
const nothrow @nogc
if (op == "*")
{
Point result = void;
if (crypto_scalarmult_ed25519_noclamp(
result.data[].ptr, lhs.data[].ptr, this.data[].ptr))
assert(0);
return result;
}
}

0 comments on commit 62b75b3

Please sign in to comment.