Serialization and Ed25519 #2
@@ -137,15 +137,28 @@ public final class Ed25519 {
|
||||
Scratch sc = new Scratch();
|
||||
Ge A = decompress(publicKey, sc);
|
||||
if (A == null) return false;
|
||||
Ge R = decompress(R_bytes, sc);
|
||||
if (R == null) return false;
|
||||
|
||||
byte[] kHash = sha512(R_bytes, publicKey, message);
|
||||
reduceScalar(kHash);
|
||||
byte[] k = Arrays.copyOfRange(kHash, 0, 32);
|
||||
Ge R_expected = new Ge();
|
||||
ge_double_scalarmul_vartime(R_expected, S_bytes, A, k, sc);
|
||||
byte[] R_check = compress(R_expected, sc);
|
||||
boolean ok = Arrays.equals(R_bytes, R_check);
|
||||
|
||||
Ge sB = scalarMulBase(S_bytes, sc);
|
||||
Ge kA = scalarMul(A, k, sc);
|
||||
Ge RHS = new Ge();
|
||||
ge_add(RHS, R, kA, sc);
|
||||
|
||||
byte[] LHS_bytes = compress(sB, sc);
|
||||
byte[] RHS_bytes = compress(RHS, sc);
|
||||
|
||||
boolean ok = Arrays.equals(LHS_bytes, RHS_bytes);
|
||||
|
||||
A.wipe();
|
||||
R_expected.wipe();
|
||||
R.wipe();
|
||||
sB.wipe();
|
||||
kA.wipe();
|
||||
RHS.wipe();
|
||||
sc.wipe();
|
||||
CryptoUtils.wipe(kHash);
|
||||
CryptoUtils.wipe(k);
|
||||
@@ -269,23 +282,35 @@ public final class Ed25519 {
|
||||
Ge p = new Ge();
|
||||
fe_frombytes(p.Y, b);
|
||||
fe_1(p.Z);
|
||||
|
||||
// u = y^2 - 1
|
||||
fe_sq(s.a, p.Y, s.t19);
|
||||
fe_mul(s.b, s.a, D, s.t19);
|
||||
fe_sub(s.a, s.a, p.Z);
|
||||
|
||||
// v = dy^2 + 1
|
||||
fe_sq(s.b, p.Y, s.t19);
|
||||
fe_mul(s.b, s.b, D, s.t19);
|
||||
fe_add(s.b, s.b, p.Z);
|
||||
|
||||
// check root of u/v
|
||||
fe_invert(s.c, s.b, s);
|
||||
fe_mul(s.a, s.a, s.c, s.t19);
|
||||
fe_pow22523(s.b, s.a, s);
|
||||
fe_sq(s.c, s.b, s.t19);
|
||||
fe_sub(s.c, s.c, s.a);
|
||||
if (fe_isnonzero(s.c)) {
|
||||
fe_mul(s.b, s.b, I, s.t19);
|
||||
fe_sq(s.c, s.b, s.t19);
|
||||
fe_sub(s.c, s.c, s.a);
|
||||
if (fe_isnonzero(s.c)) return null;
|
||||
fe_mul(s.c, s.a, s.c, s.t19); // x2 = u/v
|
||||
|
||||
fe_pow22523(s.a, s.c, s); // a = x2^((p-5)/8)
|
||||
fe_mul(s.a, s.c, s.a, s.t19); // x = x2 * a = x2^((p+3)/8)
|
||||
|
||||
fe_sq(s.b, s.a, s.t19);
|
||||
fe_sub(s.b, s.b, s.c); // x^2 - x2
|
||||
if (fe_isnonzero(s.b)) {
|
||||
fe_mul(s.a, s.a, I, s.t19);
|
||||
fe_sq(s.b, s.a, s.t19);
|
||||
fe_sub(s.b, s.b, s.c);
|
||||
if (fe_isnonzero(s.b)) return null;
|
||||
}
|
||||
if (fe_isnegative(s.b) != ((b[31] >> 7) & 1)) fe_neg(p.X, s.b);
|
||||
else fe_copy(p.X, s.b);
|
||||
|
||||
if (fe_isnegative(s.a) != ((b[31] >> 7) & 1)) fe_neg(p.X, s.a);
|
||||
else fe_copy(p.X, s.a);
|
||||
|
||||
fe_mul(p.T, p.X, p.Y, s.t19);
|
||||
return p;
|
||||
}
|
||||
@@ -409,7 +434,7 @@ public final class Ed25519 {
|
||||
|
||||
public static byte[] fe_contract(long[] h) {
|
||||
long[] val = Arrays.copyOf(h, 10);
|
||||
for (int p = 0; p < 3; p++) {
|
||||
for (int p = 0; p < 2; p++) {
|
||||
for (int i = 0; i < 9; i++) {
|
||||
long c = val[i] >> (i % 2 == 0 ? 26 : 25);
|
||||
val[i] &= (i % 2 == 0 ? 0x3FFFFFFL : 0x1FFFFFFL);
|
||||
|
||||
+16
-6
@@ -341,14 +341,24 @@ public class Testinator {
|
||||
private static String ed25519(String workingPath) throws IOException {
|
||||
Path testPath = Path.of(workingPath, "ed25519.test");
|
||||
Path resPath = Path.of(workingPath, "ed25519.java.txt");
|
||||
List<String> seeds = Files.readAllLines(testPath);
|
||||
List<String> lines = Files.readAllLines(testPath);
|
||||
List<String> results = new ArrayList<>();
|
||||
for (String seedHex : seeds) {
|
||||
if (seedHex.trim().isEmpty()) continue;
|
||||
byte[] seed = CryptoUtils.hexToBin(seedHex);
|
||||
byte[] pub = Ed25519.publicKey(seed);
|
||||
results.add(CryptoUtils.binToHex(pub));
|
||||
for (String line : lines) {
|
||||
if (line.trim().isEmpty()) continue;
|
||||
String[] parts = line.split("\\|");
|
||||
byte[] seed = CryptoUtils.hexToBin(parts[0]);
|
||||
byte[] msg = CryptoUtils.hexToBin(parts[1]);
|
||||
|
||||
byte[] pub = Ed25519.publicKey(seed);
|
||||
byte[] sig = Ed25519.sign(seed, msg);
|
||||
boolean verify = Ed25519.verify(pub, msg, sig);
|
||||
|
||||
results.add(CryptoUtils.binToHex(pub) + "|" + CryptoUtils.binToHex(sig) + "|" + verify);
|
||||
|
||||
CryptoUtils.wipe(seed);
|
||||
CryptoUtils.wipe(msg);
|
||||
CryptoUtils.wipe(pub);
|
||||
CryptoUtils.wipe(sig);
|
||||
}
|
||||
Files.write(resPath, results);
|
||||
return resPath.toString();
|
||||
|
||||
+92
-243
@@ -19,29 +19,24 @@
|
||||
%%% Logic
|
||||
|
||||
mods() ->
|
||||
#{"base64" => fun base64/0,
|
||||
"base58" => fun base58/0,
|
||||
"base58_check" => fun base58_check/0,
|
||||
"rlp" => fun rlp/0,
|
||||
"rlp_stream" => fun rlp_stream/0,
|
||||
"rlp_fail" => fun rlp_fail/0,
|
||||
"gaju_format" => fun gaju_format/0,
|
||||
"keccak256" => fun keccak256/0,
|
||||
"blake2b" => fun blake2b/0,
|
||||
"ed25519" => fun ed25519/0,
|
||||
"api_encode" => fun api_encode/0,
|
||||
"id_serialization" => fun id_serialization/0,
|
||||
"fe_parity" => fun fe_parity/0,
|
||||
"reduce_parity" => fun reduce_parity/0,
|
||||
"smb_parity" => fun smb_parity/0,
|
||||
"femul_parity" => fun femul_parity/0,
|
||||
"debug_femul" => fun debug_femul/0,
|
||||
"frombytes_parity" => fun frombytes_parity/0,
|
||||
"ge_parity" => fun ge_parity/0,
|
||||
"gen_consts" => fun gen_consts/0,
|
||||
"check_product_limbs" => fun check_product_limbs/0,
|
||||
"check_limbs" => fun check_limbs/0,
|
||||
"gen_coeffs" => fun gen_coeffs/0}.
|
||||
#{"base64" => fun base64/0,
|
||||
"base58" => fun base58/0,
|
||||
"base58_check" => fun base58_check/0,
|
||||
"rlp" => fun rlp/0,
|
||||
"rlp_stream" => fun rlp_stream/0,
|
||||
"rlp_fail" => fun rlp_fail/0,
|
||||
"gaju_format" => fun gaju_format/0,
|
||||
"keccak256" => fun keccak256/0,
|
||||
"blake2b" => fun blake2b/0,
|
||||
"ed25519" => fun ed25519/0,
|
||||
"api_encode" => fun api_encode/0,
|
||||
"id_serialization" => fun id_serialization/0,
|
||||
"fe_parity" => fun fe_parity/0,
|
||||
"reduce_parity" => fun reduce_parity/0,
|
||||
"smb_parity" => fun smb_parity/0,
|
||||
"femul_parity" => fun femul_parity/0,
|
||||
"frombytes_parity" => fun frombytes_parity/0,
|
||||
"ge_parity" => fun ge_parity/0}.
|
||||
|
||||
|
||||
start([]) ->
|
||||
@@ -132,7 +127,7 @@ base64() ->
|
||||
{ok, EDecB} = file:read_file(TestFile),
|
||||
{ok, JDecB} = file:read_file(JDec),
|
||||
EBinHash = crypto:hash(sha512, EDecB),
|
||||
JBinHash = crypto:hash(sha512, JEncB),
|
||||
JBinHash = crypto:hash(sha512, JDecB),
|
||||
EHash =:= JHash andalso EBinHash =:= JBinHash.
|
||||
|
||||
|
||||
@@ -300,36 +295,21 @@ ed25519() ->
|
||||
Temp = temp_dir(),
|
||||
TestFile = filename:join(Temp, "ed25519.test"),
|
||||
ok = filelib:ensure_dir(TestFile),
|
||||
Seeds = [rand:bytes(32) || _ <- lists:seq(1, 10)],
|
||||
ok = file:write_file(TestFile, unicode:characters_to_binary([[bin_to_hex(S), "\n"] || S <- Seeds])),
|
||||
|
||||
Expected = [ed25519_pub(S) || S <- Seeds],
|
||||
|
||||
Cases = [{rand:bytes(32), rand:bytes(rand:uniform(100))} || _ <- lists:seq(1, 20)],
|
||||
ok = file:write_file(TestFile, [[bin_to_hex(S), "|", bin_to_hex(M), "\n"] || {S, M} <- Cases]),
|
||||
Sequence =
|
||||
fun({S, M}) ->
|
||||
#{public := Pub} = ecu_eddsa:sign_seed_keypair(S),
|
||||
Sig = ecu_eddsa:sign_detached(M, S),
|
||||
V = ecu_eddsa:sign_verify_detached(Sig, M, Pub),
|
||||
lists:flatten(io_lib:format("~s|~s|~p", [bin_to_hex(Pub), bin_to_hex(Sig), V]))
|
||||
end,
|
||||
Expected = lists:map(Sequence, Cases),
|
||||
Run = "bin/run ed25519 " ++ Temp,
|
||||
Out = trim(os:cmd(Run)),
|
||||
{ok, JOutContent} = file:read_file(trim(Out)),
|
||||
JResults = string:split(trim(unicode:characters_to_list(JOutContent)), "\n", all),
|
||||
|
||||
case length(Expected) =:= length(JResults) andalso
|
||||
lists:all(fun({E, J}) -> E =:= J end, lists:zip(Expected, JResults)) of
|
||||
true -> true;
|
||||
false ->
|
||||
lists:foreach(fun({E, J}) ->
|
||||
if E =/= J -> io:format("E: ~ts~nJ: ~ts~n", [E, J]); true -> ok end
|
||||
end, lists:zip(Expected, JResults)),
|
||||
false
|
||||
end.
|
||||
|
||||
ed25519_pub(Seed) ->
|
||||
Hash = crypto:hash(sha512, Seed),
|
||||
<<K:32/binary, _/binary>> = Hash,
|
||||
% Clamp K
|
||||
<<K0, KMid:30/binary, K31>> = K,
|
||||
CK0 = K0 band 248,
|
||||
CK31 = (K31 band 127) bor 64,
|
||||
ClampedK = <<CK0, KMid/binary, CK31>>,
|
||||
Pub = ecu_ed25519:scalar_mul_base(ClampedK),
|
||||
bin_to_hex(ecu_ed25519:compress(Pub)).
|
||||
JResults = [trim(L) || L <- string:split(trim(unicode:characters_to_list(JOutContent)), "\n", all)],
|
||||
same_same(Expected, JResults).
|
||||
|
||||
|
||||
api_encode() ->
|
||||
@@ -340,15 +320,12 @@ api_encode() ->
|
||||
Lines = [io_lib:format("~ts|~ts", [string:uppercase(atom_to_list(T)), bin_to_hex(B)]) || {T, B} <- Cases],
|
||||
ok = filelib:ensure_dir(TestFile),
|
||||
ok = file:write_file(TestFile, unicode:characters_to_binary([[L, "\n"] || L <- Lines])),
|
||||
|
||||
Expected = [flatten(gmser_api_encoder:encode(T, B)) || {T, B} <- Cases],
|
||||
|
||||
Run = "bin/run api_encode " ++ Temp,
|
||||
Out = trim(os:cmd(Run)),
|
||||
{ok, JOutContent} = file:read_file(trim(Out)),
|
||||
JResults = string:split(trim(unicode:characters_to_list(JOutContent)), "\n", all),
|
||||
length(Expected) =:= length(JResults) andalso
|
||||
lists:all(fun({E, J}) -> E =:= J end, lists:zip(Expected, JResults)).
|
||||
same_same(Expected, JResults).
|
||||
|
||||
type_size(signature) -> 64;
|
||||
type_size(_) -> 32.
|
||||
@@ -362,40 +339,39 @@ id_serialization() ->
|
||||
Lines = [io_lib:format("~b|~ts", [Tag, bin_to_hex(B)]) || {Tag, B} <- Cases],
|
||||
ok = filelib:ensure_dir(TestFile),
|
||||
ok = file:write_file(TestFile, unicode:characters_to_binary([[L, "\n"] || L <- Lines])),
|
||||
|
||||
Expected = [bin_to_hex(gmser_id:encode(gmser_id:create(tag_to_erl(T), B))) || {T, B} <- Cases],
|
||||
|
||||
Run = "bin/run id_serialization " ++ Temp,
|
||||
Out = trim(os:cmd(Run)),
|
||||
{ok, JOutContent} = file:read_file(trim(Out)),
|
||||
JResults = string:split(trim(unicode:characters_to_list(JOutContent)), "\n", all),
|
||||
length(Expected) =:= length(JResults) andalso
|
||||
lists:all(fun({E, J}) -> E =:= J end, lists:zip(Expected, JResults)).
|
||||
same_same(Expected, JResults).
|
||||
|
||||
|
||||
fe_parity() ->
|
||||
Temp = temp_dir(),
|
||||
TestFile = filename:join(Temp, "fe.test"),
|
||||
ok = filelib:ensure_dir(TestFile),
|
||||
% Mask to 255 bits to avoid bit-255 sign bit ambiguity in fe_frombytes
|
||||
Inputs = [begin <<B:256/little>> = rand:bytes(32), bin_to_hex(<< (B band ((1 bsl 255) - 1)):256/little >>) end || _ <- lists:seq(1, 100)],
|
||||
RandomLittleFingers =
|
||||
fun() ->
|
||||
<<B:256/little>> = rand:bytes(32),
|
||||
bin_to_hex(<<(B band ((1 bsl 255) - 1)):256/little>>)
|
||||
end,
|
||||
Inputs = [RandomLittleFingers() || _ <- lists:seq(1, 100)],
|
||||
ok = file:write_file(TestFile, unicode:characters_to_binary([[I, "\n"] || I <- Inputs])),
|
||||
|
||||
Run = "bin/run fe_parity " ++ Temp,
|
||||
Out = trim(os:cmd(Run)),
|
||||
{ok, JOutContent} = file:read_file(trim(Out)),
|
||||
JResults = string:split(trim(unicode:characters_to_list(JOutContent)), "\n", all),
|
||||
|
||||
P = ecu_ed25519:p(),
|
||||
Expected = [begin <<B:256/little>> = hex_to_bin(I), bin_to_hex(pack_p(B rem P)) end || I <- Inputs],
|
||||
case length(Expected) =:= length(JResults) andalso
|
||||
lists:all(fun({E, J}) -> E =:= J end, lists:zip(Expected, JResults)) of
|
||||
true -> true;
|
||||
false ->
|
||||
lists:foreach(fun({E, J}) ->
|
||||
if E =/= J -> io:format("E: ~ts~nJ: ~ts~n", [E, J]); true -> ok end
|
||||
end, lists:zip(Expected, JResults)),
|
||||
false
|
||||
end.
|
||||
Pee =
|
||||
fun(I) ->
|
||||
<<B:256/little>> = hex_to_bin(I),
|
||||
bin_to_hex(pack_p(B rem P))
|
||||
end,
|
||||
Expected = lists:map(Pee, Inputs),
|
||||
same_same(Expected, JResults).
|
||||
|
||||
|
||||
reduce_parity() ->
|
||||
Temp = temp_dir(),
|
||||
@@ -403,22 +379,13 @@ reduce_parity() ->
|
||||
ok = filelib:ensure_dir(TestFile),
|
||||
Inputs = [rand:bytes(64) || _ <- lists:seq(1, 100)],
|
||||
ok = file:write_file(TestFile, unicode:characters_to_binary([[bin_to_hex(I), "\n"] || I <- Inputs])),
|
||||
|
||||
Run = "bin/run reduce_parity " ++ Temp,
|
||||
Out = trim(os:cmd(Run)),
|
||||
{ok, JOutContent} = file:read_file(trim(Out)),
|
||||
JResults = string:split(trim(unicode:characters_to_list(JOutContent)), "\n", all),
|
||||
|
||||
Expected = [bin_to_hex(ecu_ed25519:scalar_reduce(I)) || I <- Inputs],
|
||||
case length(Expected) =:= length(JResults) andalso
|
||||
lists:all(fun({E, J}) -> E =:= J end, lists:zip(Expected, JResults)) of
|
||||
true -> true;
|
||||
false ->
|
||||
lists:foreach(fun({E, J}) ->
|
||||
if E =/= J -> io:format("E: ~ts~nJ: ~ts~n", [E, J]); true -> ok end
|
||||
end, lists:zip(Expected, JResults)),
|
||||
false
|
||||
end.
|
||||
same_same(Expected, JResults).
|
||||
|
||||
|
||||
smb_parity() ->
|
||||
Temp = temp_dir(),
|
||||
@@ -426,22 +393,13 @@ smb_parity() ->
|
||||
ok = filelib:ensure_dir(TestFile),
|
||||
Inputs = [<<(rand:bytes(31))/binary, 0>> || _ <- lists:seq(1, 10)],
|
||||
ok = file:write_file(TestFile, unicode:characters_to_binary([[bin_to_hex(I), "\n"] || I <- Inputs])),
|
||||
|
||||
Run = "bin/run smb_parity " ++ Temp,
|
||||
Out = trim(os:cmd(Run)),
|
||||
{ok, JOutContent} = file:read_file(trim(Out)),
|
||||
JResults = string:split(trim(unicode:characters_to_list(JOutContent)), "\n", all),
|
||||
|
||||
Expected = [bin_to_hex(ecu_ed25519:compress(ecu_ed25519:scalar_mul_base_noclamp(I))) || I <- Inputs],
|
||||
case length(Expected) =:= length(JResults) andalso
|
||||
lists:all(fun({E, J}) -> E =:= J end, lists:zip(Expected, JResults)) of
|
||||
true -> true;
|
||||
false ->
|
||||
lists:foreach(fun({E, J}) ->
|
||||
if E =/= J -> io:format("E: ~ts~nJ: ~ts~n", [E, J]); true -> ok end
|
||||
end, lists:zip(Expected, JResults)),
|
||||
false
|
||||
end.
|
||||
same_same(Expected, JResults).
|
||||
|
||||
|
||||
femul_parity() ->
|
||||
Temp = temp_dir(),
|
||||
@@ -452,46 +410,37 @@ femul_parity() ->
|
||||
Inputs = [{Gen(), Gen()} || _ <- lists:seq(1, 10)],
|
||||
Lines = [bin_to_hex(A) ++ "|" ++ bin_to_hex(B) || {A, B} <- Inputs],
|
||||
ok = file:write_file(TestFile, unicode:characters_to_binary([[L, "\n"] || L <- Lines])),
|
||||
|
||||
Run = "bin/run femul_parity " ++ Temp,
|
||||
Out = trim(os:cmd(Run)),
|
||||
{ok, JOutContent} = file:read_file(trim(Out)),
|
||||
JResults = string:split(trim(unicode:characters_to_list(JOutContent)), "\n", all),
|
||||
|
||||
ExpectedBin = [bin_to_hex(pack_p(ecu_ed25519:f_mul(binary:decode_unsigned(A, little), binary:decode_unsigned(B, little)))) || {A, B} <- Inputs],
|
||||
same_same3(Inputs, ExpectedBin, JResults).
|
||||
|
||||
case length(ExpectedBin) =:= length(JResults) andalso
|
||||
lists:all(fun({E, J}) -> E =:= J end, lists:zip(ExpectedBin, JResults)) of
|
||||
true -> true;
|
||||
false ->
|
||||
lists:foreach(fun({{A, B}, E, J}) ->
|
||||
if E =/= J ->
|
||||
io:format("A: ~ts~nB: ~ts~nE: ~ts~nJ: ~ts~n", [bin_to_hex(A), bin_to_hex(B), E, J]);
|
||||
true -> ok end
|
||||
end, lists:zip3(Inputs, ExpectedBin, JResults)),
|
||||
false
|
||||
end.
|
||||
|
||||
debug_femul() ->
|
||||
A_bin = <<1, 0:248>>,
|
||||
B_bin = <<1, 1, 0:240>>,
|
||||
A = binary:decode_unsigned(A_bin, little),
|
||||
B = binary:decode_unsigned(B_bin, little),
|
||||
Res = ecu_ed25519:f_mul(A, B),
|
||||
io:format("A (hex): ~ts~n", [bin_to_hex(A_bin)]),
|
||||
io:format("B (hex): ~ts~n", [bin_to_hex(B_bin)]),
|
||||
io:format("Res (hex): ~ts~n", [bin_to_hex(pack_p(Res))]),
|
||||
same_same3(AB, L1, L2) ->
|
||||
same_same3(AB, L1, L2, true).
|
||||
|
||||
same_same3([_ | R1], [S | R2], [S | R3], Result) ->
|
||||
same_same3(R1, R2, R3, Result);
|
||||
same_same3([{A, B} | R1], [E | R2], [J | R3], _) ->
|
||||
ok = io:format("A: ~ts~nB: ~ts~nE: ~ts~nJ: ~ts~n", [bin_to_hex(A), bin_to_hex(B), E, J]),
|
||||
same_same3(R1, R2, R3, false);
|
||||
same_same3([], [], [], Result) ->
|
||||
Result.
|
||||
|
||||
|
||||
same_same(L1, L2) ->
|
||||
same_same(L1, L2, true).
|
||||
|
||||
same_same([S | R1], [S | R2], Result) ->
|
||||
same_same(R1, R2, Result);
|
||||
same_same([E | R1], [J | R2], _) ->
|
||||
ok = io:format("Mismatch!\nE: ~ts\nJ: ~ts\n", [E, J]),
|
||||
same_same(R1, R2, false);
|
||||
same_same([], [], Result) ->
|
||||
Result.
|
||||
|
||||
Limbs = fun F(Val, Idx) when Idx < 10 ->
|
||||
Size = if Idx rem 2 =:= 0 -> 26; true -> 25 end,
|
||||
L = Val band ((1 bsl Size) - 1),
|
||||
[L | F(Val bsr Size, Idx + 1)];
|
||||
F(_, _) -> []
|
||||
end,
|
||||
io:format("A limbs: ~w~n", [Limbs(A, 0)]),
|
||||
io:format("B limbs: ~w~n", [Limbs(B, 0)]),
|
||||
io:format("Res limbs: ~w~n", [Limbs(Res, 0)]),
|
||||
true.
|
||||
|
||||
frombytes_parity() ->
|
||||
Temp = temp_dir(),
|
||||
@@ -499,33 +448,31 @@ frombytes_parity() ->
|
||||
ok = filelib:ensure_dir(TestFile),
|
||||
Inputs = [rand:bytes(32) || _ <- lists:seq(1, 10)],
|
||||
ok = file:write_file(TestFile, unicode:characters_to_binary([[bin_to_hex(I), "\n"] || I <- Inputs])),
|
||||
|
||||
Run = "bin/run frombytes_parity " ++ Temp,
|
||||
Out = trim(os:cmd(Run)),
|
||||
{ok, JOutContent} = file:read_file(trim(Out)),
|
||||
JResults = string:split(trim(unicode:characters_to_list(JOutContent)), "\n", all),
|
||||
|
||||
Expected = [
|
||||
begin
|
||||
Limb =
|
||||
fun(I) ->
|
||||
Val = binary:decode_unsigned(I, little),
|
||||
Limbs = fun F(V, Idx) when Idx < 10 ->
|
||||
Size = if Idx rem 2 =:= 0 -> 26; true -> 25 end,
|
||||
Limbs =
|
||||
fun
|
||||
F(V, Idx) when Idx < 10 ->
|
||||
Size =
|
||||
case Idx rem 2 =:= 0 of
|
||||
true -> 26;
|
||||
false -> 25
|
||||
end,
|
||||
L = V band ((1 bsl Size) - 1),
|
||||
[L | F(V bsr Size, Idx + 1)];
|
||||
F(_, _) -> []
|
||||
end,
|
||||
F(_, _) ->
|
||||
[]
|
||||
end,
|
||||
string:join([integer_to_list(L) || L <- Limbs(Val, 0)], ",")
|
||||
end || I <- Inputs],
|
||||
end,
|
||||
Expected = lists:map(Limb, Inputs),
|
||||
same_same(Expected, JResults).
|
||||
|
||||
case length(Expected) =:= length(JResults) andalso
|
||||
lists:all(fun({E, J}) -> E =:= J end, lists:zip(Expected, JResults)) of
|
||||
true -> true;
|
||||
false ->
|
||||
lists:foreach(fun({E, J}) ->
|
||||
if E =/= J -> io:format("E: ~ts~nJ: ~ts~n", [E, J]); true -> ok end
|
||||
end, lists:zip(Expected, JResults)),
|
||||
false
|
||||
end.
|
||||
|
||||
ge_parity() ->
|
||||
A_bin = <<1, 2, 3, 0:232>>,
|
||||
@@ -533,49 +480,14 @@ ge_parity() ->
|
||||
P1_erl = ecu_ed25519:scalar_mul_base_noclamp(A_bin),
|
||||
P2_erl = ecu_ed25519:scalar_mul_base_noclamp(B_bin),
|
||||
P3_erl = ecu_ed25519:p_add(P1_erl, P2_erl),
|
||||
|
||||
E_comp = bin_to_hex(ecu_ed25519:compress(P3_erl)),
|
||||
|
||||
Run = "bin/run ge_parity " ++ bin_to_hex(A_bin) ++ " " ++ bin_to_hex(B_bin),
|
||||
Out = trim(os:cmd(Run)),
|
||||
case string:split(Out, "|||") of
|
||||
[JX | _] -> E_comp =:= trim(JX);
|
||||
_ -> false
|
||||
_ -> false
|
||||
end.
|
||||
|
||||
gen_consts() ->
|
||||
GetLimbs = fun(Val) ->
|
||||
Limbs = fun F(V, Idx) when Idx < 10 ->
|
||||
Size = if Idx rem 2 =:= 0 -> 26; true -> 25 end,
|
||||
L = V band ((1 bsl Size) - 1),
|
||||
[L | F(V bsr Size, Idx + 1)];
|
||||
F(_, _) -> []
|
||||
end,
|
||||
Limbs(Val, 0)
|
||||
end,
|
||||
|
||||
P = (1 bsl 255) - 19,
|
||||
|
||||
Y = (4 * ecu_ed25519:f_inv(5)) rem P,
|
||||
% X^2 = (y^2 - 1) / (d*y^2 + 1)
|
||||
Y2 = (Y * Y) rem P,
|
||||
D = (P - 121665) * ecu_ed25519:f_inv(121666) rem P,
|
||||
Num = (Y2 - 1 + P) rem P,
|
||||
Den = (D * Y2 + 1) rem P,
|
||||
X2 = (Num * ecu_ed25519:f_inv(Den)) rem P,
|
||||
X = ecu_ed25519:f_pow(X2, (P + 3) bsr 3), % compute square root
|
||||
|
||||
T = (X * Y) rem P,
|
||||
I = ecu_ed25519:f_pow(2, (P - 1) bsr 2),
|
||||
|
||||
io:format("BX: ~w~n", [GetLimbs(X)]),
|
||||
io:format("BY: ~w~n", [GetLimbs(Y)]),
|
||||
io:format("BXY: ~w~n", [GetLimbs(T)]),
|
||||
io:format("D: ~w~n", [GetLimbs(D)]),
|
||||
io:format("D2: ~w~n", [GetLimbs((2 * D) rem P)]),
|
||||
io:format("I: ~w~n", [GetLimbs(I)]),
|
||||
true.
|
||||
|
||||
pack_p(V) ->
|
||||
P = (1 bsl 255) - 19,
|
||||
V_pos = if V < 0 -> V + P; true -> V rem P end,
|
||||
@@ -583,69 +495,6 @@ pack_p(V) ->
|
||||
Size = byte_size(Enc),
|
||||
if Size < 32 -> <<Enc/binary, 0:(8*(32-Size))>>; true -> Enc end.
|
||||
|
||||
check_limbs() ->
|
||||
% Random values
|
||||
A_bin = <<11, 22, 33, 0:232>>,
|
||||
B_bin = <<44, 55, 66, 0:232>>,
|
||||
A = binary:decode_unsigned(A_bin, little),
|
||||
B = binary:decode_unsigned(B_bin, little),
|
||||
Res = A * B,
|
||||
|
||||
Limbs = fun F(Val, Idx) when Idx < 19 ->
|
||||
Size = if Idx rem 2 =:= 0 -> 26; true -> 25 end,
|
||||
L = Val band ((1 bsl Size) - 1),
|
||||
[L | F(Val bsr Size, Idx + 1)];
|
||||
F(_, _) -> []
|
||||
end,
|
||||
io:format("Expected product limbs: ~w~n", [Limbs(Res, 0)]),
|
||||
true.
|
||||
|
||||
check_product_limbs() ->
|
||||
A_bin = <<11, 22, 33, 44, 0:224>>,
|
||||
B_bin = <<55, 66, 77, 88, 0:224>>,
|
||||
A = binary:decode_unsigned(A_bin, little),
|
||||
B = binary:decode_unsigned(B_bin, little),
|
||||
|
||||
GetLimbs = fun(Val) ->
|
||||
Limbs = fun F(V, Idx) when Idx < 10 ->
|
||||
Size = if Idx rem 2 =:= 0 -> 26; true -> 25 end,
|
||||
L = V band ((1 bsl Size) - 1),
|
||||
[L | F(V bsr Size, Idx + 1)];
|
||||
F(_, _) -> []
|
||||
end,
|
||||
list_to_tuple(Limbs(Val, 0))
|
||||
end,
|
||||
|
||||
{A0, A1, A2, A3, A4, A5, A6, A7, A8, A9} = GetLimbs(A),
|
||||
{B0, B1, B2, B3, B4, B5, B6, B7, B8, B9} = GetLimbs(B),
|
||||
|
||||
T0 = A0*B0,
|
||||
T1 = A0*B1 + A1*B0,
|
||||
T2 = 2*A1*B1 + A0*B2 + A2*B0,
|
||||
T3 = A1*B2 + A2*B1 + A0*B3 + A3*B0,
|
||||
T4 = A2*B2 + 2*(A1*B3 + A3*B1) + A0*B4 + A4*B0,
|
||||
|
||||
io:format("T0: ~b, T1: ~b, T2: ~b, T3: ~b, T4: ~b~n", [T0, T1, T2, T3, T4]),
|
||||
true.
|
||||
|
||||
gen_coeffs() ->
|
||||
W = [0, 26, 51, 77, 102, 128, 153, 179, 204, 230],
|
||||
lists:foreach(fun(TargetIdx) ->
|
||||
io:format("Limb ~b: ", [TargetIdx]),
|
||||
_ = [
|
||||
begin
|
||||
Weight = lists:nth(I+1, W) + lists:nth(J+1, W),
|
||||
TargetWeight = lists:nth(TargetIdx+1, W),
|
||||
if Weight >= TargetWeight andalso Weight < TargetWeight + 26 ->
|
||||
Diff = Weight - TargetWeight,
|
||||
io:format("A~b*B~b*~b + ", [I, J, 1 bsl Diff]);
|
||||
true -> ok
|
||||
end
|
||||
end || I <- lists:seq(0, 9), J <- lists:seq(0, 9)],
|
||||
io:format("~n")
|
||||
end, lists:seq(0, 18)),
|
||||
true.
|
||||
|
||||
tag_to_erl(1) -> account;
|
||||
tag_to_erl(2) -> name;
|
||||
tag_to_erl(3) -> commitment;
|
||||
|
||||
Reference in New Issue
Block a user