From e42ad8ca9d3c07692233434eb6b1de438be2feef Mon Sep 17 00:00:00 2001 From: Elliot Glaysher Date: Thu, 13 Jun 2019 11:24:43 -0700 Subject: [PATCH] Jet ed25519 point scalar multiplication. This adds a jet for +scalarmult:ed:crypto. While previous jets could just call math from the ed25519 library, scalarmult wasn't provided by that library. This patch also translates an implementation of that function from DEDIS' BSDed ed25519 golang library. --- include/jets/w.h | 1 + jets/e/ed_scalarmult.c | 66 ++++++++++++++++ jets/e/ge_additions.c | 169 +++++++++++++++++++++++++++++++++++++++++ jets/e/ge_additions.h | 8 ++ jets/tree.c | 12 ++- meson.build | 19 +++++ 6 files changed, 271 insertions(+), 4 deletions(-) create mode 100644 jets/e/ed_scalarmult.c create mode 100644 jets/e/ge_additions.c create mode 100644 jets/e/ge_additions.h diff --git a/include/jets/w.h b/include/jets/w.h index 4581e2e15..3158a4d49 100644 --- a/include/jets/w.h +++ b/include/jets/w.h @@ -156,6 +156,7 @@ u3_noun u3wee_veri(u3_noun); u3_noun u3wee_shar(u3_noun); u3_noun u3wee_point_add(u3_noun); + u3_noun u3wee_scalarmult(u3_noun); u3_noun u3wee_double_scalarmult(u3_noun); u3_noun u3wee_scalarmult_base(u3_noun); diff --git a/jets/e/ed_scalarmult.c b/jets/e/ed_scalarmult.c new file mode 100644 index 000000000..7eeaf5bd0 --- /dev/null +++ b/jets/e/ed_scalarmult.c @@ -0,0 +1,66 @@ +/* gen164/5/ed_scalarmult.c +** +*/ +#include "all.h" + +#include + +#include "ge_additions.h" + +/* functions +*/ + u3_noun + u3qc_scalarmult(u3_atom a, + u3_atom b) + { + c3_y met_w; + + met_w = u3r_met(3, a); + if (met_w > 32) { + return u3m_bail(c3__exit); + } + c3_y a_y[32]; + memset(a_y, 0, 32); + u3r_bytes(0, met_w, a_y, a); + + met_w = u3r_met(3, b); + if (met_w > 32) { + return u3m_bail(c3__exit); + } + c3_y b_y[32]; + memset(b_y, 0, 32); + u3r_bytes(0, met_w, b_y, b); + + ge_p3 B; + if (ge_frombytes_negate_vartime(&B, b_y) != 0) { + return u3m_bail(c3__exit); + } + + // Undo the negation from above. See add_scalar.c in the ed25519 distro. + fe_neg(B.X, B.X); + fe_neg(B.T, B.T); + + ge_p3 result; + ge_scalarmult(&result, a_y, &B); + + c3_y output_y[32]; + ge_p3_tobytes(output_y, &result); + + return u3i_bytes(32, output_y); + } + + u3_noun + u3wee_scalarmult(u3_noun cor) + { + u3_noun a, b; + + if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, + u3x_sam_3, &b, 0)) || + (c3n == u3ud(a)) || + (c3n == u3ud(b)) ) + { + return u3m_bail(c3__exit); + } else { + return u3qc_scalarmult(a, b); + } + } diff --git a/jets/e/ge_additions.c b/jets/e/ge_additions.c new file mode 100644 index 000000000..43166558e --- /dev/null +++ b/jets/e/ge_additions.c @@ -0,0 +1,169 @@ +// Group Element Additions +// +// Urbit uses the ge.h code from the ed25519 library, which was ported from the +// ref10 SUPERCOP public domain implementation. That implementation doesn't +// contain several functions needed for ring signatures. +// +// This file is does. The providence of this code starts with Adam Langley +// taking the SUPERCOP C implementation and producing an ed25519 implementation +// for in golang (https://godoc.org/golang.org/x/crypto/ed25519). (If you look +// at the go code, you'll see the comments are the same as the comments in the +// C implementation.) +// +// From there, the DEDIS group from ETH Zurich took that implementation and +// added the additional methods to make a generalized ECC point library. While +// their project as a whole is MPL, they deliberately left their ed25519 +// implementation under the Go BSD-3 license: +// (https://github.com/dedis/kyber/blob/master/group/edwards25519/LICENSE) +// +// This file is a fairly straight translation from Go to C of DEDIS' additions, +// so this falls under the same license. +// +// ------ +// +// Copyright (c) 2009 The Go Authors. 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. + +#include "ge_additions.h" + +#include + +static unsigned char equal(signed char b, signed char c) { + unsigned char ub = b; + unsigned char uc = c; + unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ + uint64_t y = x; /* 0: yes; 1..255: no */ + y -= 1; /* large: yes; 0..254: no */ + y >>= 63; /* 1: yes; 0: no */ + return (unsigned char) y; +} + +static unsigned char negative(signed char b) { + uint64_t x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ + x >>= 63; /* 1: yes; 0: no */ + return (unsigned char) x; +} + +void ge_cached_0(ge_cached* c) { + fe_1(c->YplusX); + fe_1(c->YminusX); + fe_1(c->Z); + fe_0(c->T2d); +} + +void ge_cached_cmov(ge_cached* r, const ge_cached* u, int32_t b) +{ + fe_cmov(r->YplusX, u->YplusX, b); + fe_cmov(r->YminusX, u->YminusX, b); + fe_cmov(r->Z, u->Z, b); + fe_cmov(r->T2d, u->T2d, b); +} + +void ge_cached_neg(ge_cached* r, const ge_cached* t) +{ + fe_copy(r->YplusX, t->YminusX); + fe_copy(r->YminusX, t->YplusX); + fe_copy(r->Z, t->Z); + fe_neg(r->T2d, t->T2d); +} + +void select_cached(ge_cached* c, const ge_cached Ai[8], int32_t b) +{ + int32_t is_negative = negative(b); + int32_t b_abs = b - (((-is_negative) & b) << 1); + + ge_cached_0(c); + for (int32_t i = 0; i < 8; ++i) { + ge_cached_cmov(c, &Ai[i], equal(b_abs, i+1)); + } + + ge_cached minusC; + ge_cached_neg(&minusC, c); + ge_cached_cmov(c, &minusC, is_negative); +} + +// +void ge_scalarmult(ge_p3* h, const unsigned char* a, const ge_p3* A) +{ + signed char e[64]; + int i; + ge_p1p1 t; + ge_p3 u; + + for (i = 0; i < 32; ++i) { + e[2 * i + 0] = (a[i] >> 0) & 15; + e[2 * i + 1] = (a[i] >> 4) & 15; + } + + /* each e[i] is between 0 and 15 */ + /* e[63] is between 0 and 7 */ + signed char carry = 0; + for (i = 0; i < 63; ++i) { + e[i] += carry; + carry = e[i] + 8; + carry >>= 4; + e[i] -= carry << 4; + } + e[63] += carry; + /* each e[i] is between -8 and 8 */ + + // compute cached array of multiples of A from 1A through 8A + ge_cached Ai[8]; + ge_p3_to_cached(&Ai[0], A); + for (i = 0; i < 7; ++i) { + ge_add(&t, A, &Ai[i]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[i+1], &u); + } + + // special case for exponent nybble i == 63 + ge_p3_0(&u); + ge_cached c; + select_cached(&c, Ai, e[63]); + ge_add(&t, &u, &c); + + ge_p2 r; + for (i = 62; i >= 0; i--) { + // t <<= 4 + ge_p1p1_to_p2(&r, &t); + ge_p2_dbl(&t, &r); + ge_p1p1_to_p2(&r, &t); + ge_p2_dbl(&t, &r); + ge_p1p1_to_p2(&r, &t); + ge_p2_dbl(&t, &r); + ge_p1p1_to_p2(&r, &t); + ge_p2_dbl(&t, &r); + + // Add next nyble + ge_p1p1_to_p3(&u, &t); + select_cached(&c, Ai, e[i]); + ge_add(&t, &u, &c); + } + + ge_p1p1_to_p3(h, &t); +} diff --git a/jets/e/ge_additions.h b/jets/e/ge_additions.h new file mode 100644 index 000000000..3424ac689 --- /dev/null +++ b/jets/e/ge_additions.h @@ -0,0 +1,8 @@ +#ifndef GE_ADDITIONS_H +#define GE_ADDITIONS_H + +#include + +void ge_scalarmult(ge_p3* h, const unsigned char* a, const ge_p3* A); + +#endif diff --git a/jets/tree.c b/jets/tree.c index 8e0ab518f..fecfc1a98 100644 --- a/jets/tree.c +++ b/jets/tree.c @@ -178,19 +178,23 @@ static c3_c* _141_hex_coed__ed_shar_ha[] = { static u3j_harm _141_hex_coed__ed_add_a[] = {{".2", u3wee_point_add}, {}}; +static u3j_harm _141_hex_coed__ed_scalarmult_a[] = + {{".2", u3wee_scalarmult}, {}}; + +static u3j_harm _141_hex_coed__ed_scalarmult_base_a[] = + {{".2", u3wee_scalarmult_base}, {}}; + static u3j_harm _141_hex_coed__ed_double_scalarmult_a[] = {{".2", u3wee_double_scalarmult}, {}}; -static u3j_harm _141_hex_coed__ed_scalarmult_a[] = - {{".2", u3wee_scalarmult_base}, {}}; - static u3j_core _141_hex_coed__ed_d[] = { { "sign", 7, _141_hex_coed__ed_sign_a, 0, _141_hex_coed__ed_sign_ha }, { "puck", 7, _141_hex_coed__ed_puck_a, 0, _141_hex_coed__ed_puck_ha }, { "veri", 7, _141_hex_coed__ed_veri_a, 0, _141_hex_coed__ed_veri_ha }, { "shar", 7, _141_hex_coed__ed_shar_a, 0, _141_hex_coed__ed_shar_ha }, { "add", 7, _141_hex_coed__ed_add_a, 0, 0 }, - { "scalarmult-base", 7, _141_hex_coed__ed_scalarmult_a, 0, 0 }, + { "scalarmult", 7, _141_hex_coed__ed_scalarmult_a, 0, 0 }, + { "scalarmult-base", 7, _141_hex_coed__ed_scalarmult_base_a, 0, 0 }, { "double-scalarmult", 7, _141_hex_coed__ed_double_scalarmult_a, 0, 0 }, {} }; diff --git a/meson.build b/meson.build index f1791bccb..216ee5b28 100644 --- a/meson.build +++ b/meson.build @@ -138,6 +138,7 @@ jets_e_ed_src = [ 'jets/e/ed_veri.c', 'jets/e/ed_shar.c', 'jets/e/ed_point_add.c', +'jets/e/ed_scalarmult.c', 'jets/e/ed_scalarmult_base.c', 'jets/e/ed_double_scalarmult.c' ] @@ -333,9 +334,27 @@ murmur3_dep = dependency('murmur3', version: '>=0.1.0', fallback: ['murmur3', 'm secp256k1_dep = dependency('libsecp256k1', version: '>=0.1.0', fallback: ['secp256k1', 'secp256k1_dep']) softfloat3_dep = dependency('softfloat3', version: '>=3.0.0', fallback: ['softfloat3', 'softfloat3_dep']) +# Our ge additions must be in their own library because they cannot be compiled +# with '-funsigned-char' since they rely on signed characters. +ge_additions_src = [ + 'jets/e/ge_additions.c', +] + +ge_additions_include = include_directories('jets/e/') + +ge_additions_lib = static_library('ge-additions', +sources: ge_additions_src, +include_directories: ge_additions_include, +c_args: ['-Wall'], +dependencies: ed25519_dep, +install: false) + +gd_additions_dep = declare_dependency(link_with : ge_additions_lib) + deps = [argon2_dep, curl_dep, ed25519_dep, + gd_additions_dep, gmp_dep, libent_dep, libh2o_dep,