Merge pull request #1300 from urbit/rings

Ring signature support on Azimuth points
This commit is contained in:
Elliot Glaysher 2019-06-24 17:08:04 -07:00 committed by GitHub
commit f8c226042e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 699 additions and 13 deletions

View File

@ -4,13 +4,18 @@ let
deps = import ../deps { inherit pkgs; };
ent = import ./ent { inherit pkgs; };
arvo = import ./arvo { inherit pkgs; };
herb = import ../../pkg/herb { inherit pkgs; };
ent = import ./ent { inherit pkgs; };
arvo = import ./arvo { inherit pkgs; };
herb = import ../../pkg/herb { inherit pkgs; };
ge-additions = import ./ge-additions {
inherit pkgs;
inherit (deps) ed25519;
};
mkUrbit = { debug }:
import ./urbit {
inherit pkgs ent debug;
inherit pkgs ent debug ge-additions;
inherit (deps) argon2 murmur3 uv ed25519 sni scrypt softfloat3;
inherit (deps) secp256k1 h2o;
};
@ -20,4 +25,4 @@ let
in
{ inherit ent arvo herb urbit urbit-debug; }
{ inherit ent ge-additions arvo herb urbit urbit-debug; }

View File

@ -0,0 +1,7 @@
source $stdenv/setup
cp -r $src ./src
chmod -R u+w ./src
cd ./src
PREFIX=$out make install

View File

@ -0,0 +1,12 @@
{ env_name, env, deps }:
env.make_derivation rec {
name = "ge-additions";
builder = ./release.sh;
src = ../../../pkg/ge-additions;
cross_inputs = [ deps.ed25519 ];
CC = "${env.host}-gcc";
AR = "${env.host}-ar";
}

View File

@ -0,0 +1,9 @@
{ pkgs, ed25519 }:
pkgs.stdenv.mkDerivation rec {
name = "ge-additions";
builder = ./builder.sh;
src = ../../../pkg/ge-additions;
nativeBuildInputs = [ ed25519 ];
}

View File

@ -0,0 +1,13 @@
source $setup
cp -r $src ./src
chmod -R u+w ./src
cd ./src
for dep in $cross_inputs; do
export CFLAGS="${CFLAGS-} -I$dep/include"
export LDFLAGS="${LDFLAGS-} -L$dep/lib"
done
PREFIX=$out make install

View File

@ -1,7 +1,7 @@
{
pkgs,
debug,
argon2, ed25519, ent, h2o, murmur3, scrypt, secp256k1, sni, softfloat3, uv
argon2, ed25519, ent, ge-additions, h2o, murmur3, scrypt, secp256k1, sni, softfloat3, uv
}:
let
@ -14,7 +14,7 @@ let
[ curl gmp libsigsegv ncurses openssl zlib lmdb ];
vendor =
[ argon2 softfloat3 ed25519 ent h2o scrypt uv murmur3 secp256k1 sni ];
[ argon2 softfloat3 ed25519 ent ge-additions h2o scrypt uv murmur3 secp256k1 sni ];
in

View File

@ -1,6 +1,6 @@
{ env_name, env, deps }:
{ ent, name ? "urbit", debug ? false }:
{ ent, ge-additions, name ? "urbit", debug ? false }:
let
@ -10,7 +10,7 @@ let
vendor =
with deps;
[ argon2 softfloat3 ed25519 h2o scrypt uv murmur3 secp256k1 sni ];
[ argon2 softfloat3 ed25519 ge-additions h2o scrypt uv murmur3 secp256k1 sni ];
in

View File

@ -16,16 +16,20 @@ let
ent = env:
import ./pkgs/ent/cross.nix env;
ge-additions = env:
import ./pkgs/ge-additions/cross.nix env;
urbit = env:
import ./pkgs/urbit/release.nix env
{ ent = ent env; debug = false; name = "urbit"; };
{ ent = ent env; ge-additions = ge-additions env; debug = false; name = "urbit"; };
builds-for-platform = plat:
plat.deps // {
inherit (plat.env) curl libgmp libsigsegv ncurses openssl zlib lmdb;
inherit (plat.env) cmake_toolchain;
ent = ent plat;
urbit = urbit plat;
ent = ent plat;
ge-additions = ge-additions plat;
urbit = urbit plat;
};
darwin_extra = {

27
pkg/ge-additions/LICENSE Normal file
View File

@ -0,0 +1,27 @@
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.

20
pkg/ge-additions/Makefile Normal file
View File

@ -0,0 +1,20 @@
CC ?= cc
AR ?= ar
PREFIX ?= ./out
################################################################################
.PHONY: all test install clean
all: ge-additions.c ge-additions.h
$(CC) $(CFLAGS) -O3 -Wall -Werror -pedantic -std=gnu99 -c ge-additions.c
$(AR) rcs libge-additions.a ge-additions.o
install: all
@mkdir -p $(PREFIX)/lib/
@mkdir -p $(PREFIX)/include/
cp libge-additions.a $(PREFIX)/lib/
cp ge-additions.h $(PREFIX)/include/
clean:
rm -rf ./out

View File

@ -0,0 +1,20 @@
# 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 does. The providence of this code starts with Adam Langley taking
the SUPERCOP C implementation and producing an ed25519 implementation for it
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.

View File

@ -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 does. The providence of this code starts with Adam Langley taking
// the SUPERCOP C implementation and producing an ed25519 implementation for it
// 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 <fe.h>
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);
}

View File

@ -0,0 +1,8 @@
#ifndef GE_ADDITIONS_H
#define GE_ADDITIONS_H
#include <ge.h>
void ge_scalarmult(ge_p3* h, const unsigned char* a, const ge_p3* A);
#endif

2
pkg/urbit/configure vendored
View File

@ -6,7 +6,7 @@ URBIT_VERSION=0.8.0
deps=" \
curl gmp sigsegv argon2 ed25519 ent h2o scrypt sni uv murmur3 secp256k1 \
softfloat3 ncurses ssl crypto z lmdb \
softfloat3 ncurses ssl crypto z lmdb ge-additions \
"
echo '#pragma once' >include/config.h

View File

@ -155,6 +155,11 @@
u3_noun u3wee_sign(u3_noun);
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_scalarmult_base(u3_noun);
u3_noun u3wee_add_scalarmult_scalarmult_base(u3_noun);
u3_noun u3wee_add_double_scalarmult(u3_noun);
u3_noun u3we_hmac(u3_noun);

View File

@ -0,0 +1,106 @@
/* gen164/5/ed_add_double_scalarmult.c
**
*/
#include "all.h"
#include <ed25519.h>
#include <ge.h>
#include "ge-additions.h"
/* functions
*/
u3_noun
u3qc_add_double_scalarmult(u3_atom a,
u3_atom a_point,
u3_atom b,
u3_atom b_point)
{
c3_y met_w;
met_w = u3r_met(3, a);
if (met_w > 32) {
return u3m_bail(c3__fail);
}
c3_y a_y[32];
memset(a_y, 0, 32);
u3r_bytes(0, met_w, a_y, a);
met_w = u3r_met(3, a_point);
if (met_w > 32) {
return u3m_bail(c3__fail);
}
c3_y a_point_y[32];
memset(a_point_y, 0, 32);
u3r_bytes(0, met_w, a_point_y, a_point);
met_w = u3r_met(3, b);
if (met_w > 32) {
return u3m_bail(c3__fail);
}
c3_y b_y[32];
memset(b_y, 0, 32);
u3r_bytes(0, met_w, b_y, b);
met_w = u3r_met(3, b_point);
if (met_w > 32) {
return u3m_bail(c3__fail);
}
c3_y b_point_y[32];
memset(b_point_y, 0, 32);
u3r_bytes(0, met_w, b_point_y, b_point);
ge_p3 A;
if (ge_frombytes_negate_vartime(&A, a_point_y) != 0) {
return u3m_bail(c3__exit);
}
ge_p3 B;
if (ge_frombytes_negate_vartime(&B, b_point_y) != 0) {
return u3m_bail(c3__exit);
}
// Undo the negation from above. See add_scalar.c in the ed25519 distro.
fe_neg(A.X, A.X);
fe_neg(A.T, A.T);
fe_neg(B.X, B.X);
fe_neg(B.T, B.T);
// Perform the multiplications of a*A and b*B
ge_p3 a_result, b_result;
ge_scalarmult(&a_result, a_y, &A);
ge_scalarmult(&b_result, b_y, &B);
// Sum those two points
ge_cached b_result_cached;
ge_p3_to_cached(&b_result_cached, &b_result);
ge_p1p1 sum;
ge_add(&sum, &a_result, &b_result_cached);
ge_p3 final_result;
ge_p1p1_to_p3(&final_result, &sum);
c3_y output_y[32];
ge_p3_tobytes(output_y, &final_result);
return u3i_bytes(32, output_y);
}
u3_noun
u3wee_add_double_scalarmult(u3_noun cor)
{
u3_noun a, b, c, d;
if ( (c3n == u3r_mean(cor, u3x_sam_2, &a,
u3x_sam_6, &b,
u3x_sam_14, &c,
u3x_sam_15, &d, 0)) ||
(c3n == u3ud(a)) ||
(c3n == u3ud(b)) ||
(c3n == u3ud(c)) )
{
return u3m_bail(c3__exit);
} else {
return u3qc_add_double_scalarmult(a, b, c, d);
}
}

View File

@ -0,0 +1,78 @@
/* gen164/5/ed_double_scalarmult.c
**
*/
#include "all.h"
#include <ed25519.h>
#include <ge.h>
/* functions
*/
u3_noun
u3qc_add_scalarmult_scalarmult_base(u3_atom a,
u3_atom a_point,
u3_atom b)
{
c3_y met_w;
met_w = u3r_met(3, a);
if (met_w > 32) {
return u3m_bail(c3__fail);
}
c3_y a_y[32];
memset(a_y, 0, 32);
u3r_bytes(0, met_w, a_y, a);
met_w = u3r_met(3, a_point);
if (met_w > 32) {
return u3m_bail(c3__fail);
}
c3_y a_point_y[32];
memset(a_point_y, 0, 32);
u3r_bytes(0, met_w, a_point_y, a_point);
met_w = u3r_met(3, b);
if (met_w > 32) {
return u3m_bail(c3__fail);
}
c3_y b_y[32];
memset(b_y, 0, 32);
u3r_bytes(0, met_w, b_y, b);
ge_p3 A;
if (ge_frombytes_negate_vartime(&A, a_point_y) != 0) {
return u3m_bail(c3__exit);
}
// Undo the negation from above. See add_scalar.c in the ed25519 distro.
fe_neg(A.X, A.X);
fe_neg(A.T, A.T);
ge_p2 r;
ge_double_scalarmult_vartime(&r, a_y, &A, b_y);
c3_y output_y[32];
ge_tobytes(output_y, &r);
return u3i_bytes(32, output_y);
}
u3_noun
u3wee_add_scalarmult_scalarmult_base(u3_noun cor)
{
u3_noun a, b, c;
if ( (c3n == u3r_mean(cor, u3x_sam_2, &a,
u3x_sam_6, &b,
u3x_sam_7, &c, 0)) ||
(c3n == u3ud(a)) ||
(c3n == u3ud(b)) ||
(c3n == u3ud(c)) )
{
return u3m_bail(c3__exit);
} else {
return u3qc_add_scalarmult_scalarmult_base(a, b, c);
}
}

View File

@ -0,0 +1,79 @@
/* gen164/5/ed_point_add.c
**
*/
#include "all.h"
#include <ed25519.h>
#include <ge.h>
/* functions
*/
u3_noun
u3qc_point_add(u3_atom a,
u3_atom b)
{
c3_y met_w;
met_w = u3r_met(3, a);
if (met_w > 32) {
return u3m_bail(c3__fail);
}
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__fail);
}
c3_y b_y[32];
memset(b_y, 0, 32);
u3r_bytes(0, met_w, b_y, b);
ge_p3 A;
if (ge_frombytes_negate_vartime(&A, a_y) != 0) {
return u3m_bail(c3__exit);
}
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(A.X, A.X);
fe_neg(A.T, A.T);
fe_neg(B.X, B.X);
fe_neg(B.T, B.T);
ge_cached b_cached;
ge_p3_to_cached(&b_cached, &B);
ge_p1p1 sum;
ge_add(&sum, &A, &b_cached);
ge_p3 result;
ge_p1p1_to_p3(&result, &sum);
c3_y output_y[32];
ge_p3_tobytes(output_y, &result);
return u3i_bytes(32, output_y);
}
u3_noun
u3wee_point_add(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_point_add(a, b);
}
}

View File

@ -0,0 +1,66 @@
/* gen164/5/ed_scalarmult.c
**
*/
#include "all.h"
#include <ed25519.h>
#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);
}
}

View File

@ -0,0 +1,36 @@
/* gen164/5/ed_scalarmult_base.c
**
*/
#include "all.h"
#include <ed25519.h>
#include <ge.h>
/* functions
*/
u3_noun
u3wee_scalarmult_base(u3_noun cor)
{
u3_noun scalar = u3r_at(u3x_sam, cor);
if ( (u3_none == scalar) || (c3n == u3ud(scalar)) ) {
return u3m_bail(c3__exit);
}
c3_w met_w = u3r_met(3, scalar);
if ( met_w > 32 ) {
return u3m_bail(c3__fail);
}
c3_y scalar_y[32];
memset(scalar_y, 0, 32);
u3r_bytes(0, met_w, scalar_y, scalar);
ge_p3 R;
ge_scalarmult_base(&R, scalar_y);
c3_y output_y[32];
ge_p3_tobytes(output_y, &R);
return u3i_bytes(32, output_y);
}

View File

@ -188,11 +188,33 @@ static c3_c* _141_hex_coed__ed_shar_ha[] = {
0
};
static u3j_harm _141_hex_coed__ed_point_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_add_scalarmult_scalarmult_base_a[] =
{{".2", u3wee_add_scalarmult_scalarmult_base}, {}};
static u3j_harm _141_hex_coed__ed_add_double_scalarmult_a[] =
{{".2", u3wee_add_double_scalarmult}, {}};
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 },
{ "point-add", 7, _141_hex_coed__ed_point_add_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 },
{ "add-scalarmult-scalarmult-base", 7,
_141_hex_coed__ed_add_scalarmult_scalarmult_base_a, 0, 0 },
{ "add-double-scalarmult", 7,
_141_hex_coed__ed_add_double_scalarmult_a, 0, 0 },
{}
};
static c3_c* _141_hex_coed__ed_ha[] = {