1st commit: add MLDSA sig verification #990

Open
uwiger wants to merge 2 commits from uw-mldsa-crypto into master
7 changed files with 119 additions and 12 deletions
Showing only changes of commit ed72e393ab - Show all commits

View File

@ -1,5 +1,7 @@
%% -*- mode: erlang; indent-tabs-mode: nil -*- %% -*- mode: erlang; indent-tabs-mode: nil -*-
{minimum_otp_vsn, "28.1"}.
{erl_opts, [debug_info]}. {erl_opts, [debug_info]}.
{deps, [ {gmbytecode, {deps, [ {gmbytecode,

View File

@ -1,13 +1,4 @@
{"1.2.0", [{<<"base58">>,
[{<<"gmbytecode">>,
{git,"https://git.qpq.swiss/QPQ-AG/gmbytecode.git",
{ref, "97cea33be8f3a35d26055664da7aa59531ff5537"}},
0},
{<<"gmserialization">>,
{git,"https://git.qpq.swiss/QPQ-AG/gmserialization.git",
{ref,"ac64e01b0f675c1a34c70a827062f381920742db"}},
1},
{<<"base58">>,
{git,"https://git.qpq.swiss/QPQ-AG/erl-base58.git", {git,"https://git.qpq.swiss/QPQ-AG/erl-base58.git",
{ref,"e6aa62eeae3d4388311401f06e4b939bf4e94b9c"}}, {ref,"e6aa62eeae3d4388311401f06e4b939bf4e94b9c"}},
2}, 2},
@ -23,8 +14,15 @@
{git,"https://git.qpq.swiss/QPQ-AG/getopt.git", {git,"https://git.qpq.swiss/QPQ-AG/getopt.git",
{ref,"dbab6262a2430809430deda9d8650f58f9d80898"}}, {ref,"dbab6262a2430809430deda9d8650f58f9d80898"}},
1}, 1},
{<<"gmbytecode">>,
{git,"https://git.qpq.swiss/QPQ-AG/gmbytecode.git",
{ref,"97cea33be8f3a35d26055664da7aa59531ff5537"}},
0},
{<<"gmserialization">>,
{git,"https://git.qpq.swiss/QPQ-AG/gmserialization.git",
{ref,"ac64e01b0f675c1a34c70a827062f381920742db"}},
1},
{<<"jsx">>, {<<"jsx">>,
{git,"https://github.com/talentdeficit/jsx.git", {git,"https://github.com/talentdeficit/jsx.git",
{ref,"3074d4865b3385a050badf7828ad31490d860df5"}}, {ref,"3074d4865b3385a050badf7828ad31490d860df5"}},
0}]}. 0}].

View File

@ -781,6 +781,9 @@ global_env() ->
{"verify_sig_secp256k1", Fun([Hash, Bytes(64), SignId], Bool)}, {"verify_sig_secp256k1", Fun([Hash, Bytes(64), SignId], Bool)},
{"ecverify_secp256k1", Fun([Hash, Bytes(20), Bytes(65)], Bool)}, {"ecverify_secp256k1", Fun([Hash, Bytes(20), Bytes(65)], Bool)},
{"ecrecover_secp256k1", Fun([Hash, Bytes(65)], Option(Bytes(20)))}, {"ecrecover_secp256k1", Fun([Hash, Bytes(65)], Option(Bytes(20)))},
{"verify_sig_mldsa44", Fun([Hash, Bytes(any), SignId], Bool)},
{"verify_sig_mldsa65", Fun([Hash, Bytes(any), SignId], Bool)},
{"verify_sig_mldsa87", Fun([Hash, Bytes(any), SignId], Bool)},
{"sha3", Fun1(A, Hash)}, {"sha3", Fun1(A, Hash)},
{"sha256", Fun1(A, Hash)}, {"sha256", Fun1(A, Hash)},
{"blake2b", Fun1(A, Hash)}, {"blake2b", Fun1(A, Hash)},

View File

@ -40,6 +40,7 @@
contract_to_address | address_to_contract | crypto_verify_sig | crypto_verify_sig_secp256k1 | contract_to_address | address_to_contract | crypto_verify_sig | crypto_verify_sig_secp256k1 |
crypto_sha3 | crypto_sha256 | crypto_blake2b | crypto_poseidon | crypto_sha3 | crypto_sha256 | crypto_blake2b | crypto_poseidon |
crypto_ecverify_secp256k1 | crypto_ecrecover_secp256k1 | crypto_ecverify_secp256k1 | crypto_ecrecover_secp256k1 |
crypto_verify_sig_mldsa44 | crypto_verify_sig_mldsa65 | crypto_verify_sig_mldsa87 |
mcl_bls12_381_g1_neg | mcl_bls12_381_g1_norm | mcl_bls12_381_g1_valid | mcl_bls12_381_g1_neg | mcl_bls12_381_g1_norm | mcl_bls12_381_g1_valid |
mcl_bls12_381_g1_is_zero | mcl_bls12_381_g1_add | mcl_bls12_381_g1_mul | mcl_bls12_381_g1_is_zero | mcl_bls12_381_g1_add | mcl_bls12_381_g1_mul |
mcl_bls12_381_g2_neg | mcl_bls12_381_g2_norm | mcl_bls12_381_g2_valid | mcl_bls12_381_g2_neg | mcl_bls12_381_g2_norm | mcl_bls12_381_g2_valid |
@ -285,6 +286,8 @@ builtins() ->
{"lookup_default", 3}, {"delete", 2}, {"member", 2}, {"size", 1}]}, {"lookup_default", 3}, {"delete", 2}, {"member", 2}, {"size", 1}]},
{["Crypto"], [{"verify_sig", 3}, {"verify_sig_secp256k1", 3}, {["Crypto"], [{"verify_sig", 3}, {"verify_sig_secp256k1", 3},
{"ecverify_secp256k1", 3}, {"ecrecover_secp256k1", 2}, {"ecverify_secp256k1", 3}, {"ecrecover_secp256k1", 2},
{"verify_sig_mldsa44", 3}, {"verify_sig_mldsa65", 3},
{"verify_sig_mldsa87", 3},
{"sha3", 1}, {"sha256", 1}, {"blake2b", 1}, {"poseidon", 2}]}, {"sha3", 1}, {"sha256", 1}, {"blake2b", 1}, {"poseidon", 2}]},
{["MCL_BLS12_381"], [{"g1_neg", 1}, {"g1_norm", 1}, {"g1_valid", 1}, {"g1_is_zero", 1}, {"g1_add", 2}, {"g1_mul", 2}, {["MCL_BLS12_381"], [{"g1_neg", 1}, {"g1_norm", 1}, {"g1_valid", 1}, {"g1_is_zero", 1}, {"g1_add", 2}, {"g1_mul", 2},
{"g2_neg", 1}, {"g2_norm", 1}, {"g2_valid", 1}, {"g2_is_zero", 1}, {"g2_add", 2}, {"g2_mul", 2}, {"g2_neg", 1}, {"g2_norm", 1}, {"g2_valid", 1}, {"g2_is_zero", 1}, {"g2_add", 2}, {"g2_mul", 2},
@ -1163,6 +1166,7 @@ op_builtins() ->
int_to_str, int_to_bytes, int_mulmod, int_to_str, int_to_bytes, int_mulmod,
address_to_str, address_to_bytes, address_to_contract, address_to_str, address_to_bytes, address_to_contract,
crypto_verify_sig, crypto_verify_sig_secp256k1, crypto_sha3, crypto_sha256, crypto_blake2b, crypto_verify_sig, crypto_verify_sig_secp256k1, crypto_sha3, crypto_sha256, crypto_blake2b,
crypto_verify_sig_mldsa44, crypto_verify_sig_mldsa65, crypto_verify_sig_mldsa87,
crypto_poseidon, crypto_ecverify_secp256k1, crypto_ecrecover_secp256k1, crypto_poseidon, crypto_ecverify_secp256k1, crypto_ecrecover_secp256k1,
mcl_bls12_381_g1_neg, mcl_bls12_381_g1_norm, mcl_bls12_381_g1_valid, mcl_bls12_381_g1_neg, mcl_bls12_381_g1_norm, mcl_bls12_381_g1_valid,
mcl_bls12_381_g1_is_zero, mcl_bls12_381_g1_add, mcl_bls12_381_g1_mul, mcl_bls12_381_g1_is_zero, mcl_bls12_381_g1_add, mcl_bls12_381_g1_mul,

View File

@ -0,0 +1,21 @@
// Contract using Quantum-Resistant signing (MLDSA65)
contract QrAuth =
record state = { nonce : int, owner : address, owner_pub : bytes }
entrypoint init(pub : bytes) = { nonce = 1
, owner = Call.caller
, owner_pub = pub }
stateful entrypoint authorize(n : int, s : signature) : bool =
require(n >= state.nonce, "Nonce too low")
require(n =< state.nonce, "Nonce too high")
put(state{ nonce = n + 1 })
switch(Auth.tx_hash)
None => abort("Not in Auth context")
Some(tx_hash) => Crypto.verify_sig_mldsa65(to_sign(tx_hash, n), state.owner_pub, s)
entrypoint to_sign(h : hash, n : int) =
Crypto.blake2b((h, n))
entrypoint weird_string() : string =
"\x19Weird String\x42\nMore\n"

View File

@ -0,0 +1,76 @@
// namespace Chain =
// record tx = { paying_for : option(Chain.paying_for_tx)
// , ga_metas : list(Chain.ga_meta_tx)
// , actor : address
// , fee : int
// , ttl : int
// , tx : Chain.base_tx }
// datatype ga_meta_tx = GAMetaTx(address, int)
// datatype paying_for_tx = PayingForTx(address, int)
// datatype base_tx = SpendTx(address, int, string)
// | OracleRegisterTx | OracleQueryTx | OracleResponseTx | OracleExtendTx
// | NamePreclaimTx | NameClaimTx(hash) | NameUpdateTx(string)
// | NameRevokeTx(hash) | NameTransferTx(address, string)
// | ChannelCreateTx(address) | ChannelDepositTx(address, int) | ChannelWithdrawTx(address, int) |
// | ChannelForceProgressTx(address) | ChannelCloseMutualTx(address) | ChannelCloseSoloTx(address)
// | ChannelSlashTx(address) | ChannelSettleTx(address) | ChannelSnapshotSoloTx(address)
// | ContractCreateTx(int) | ContractCallTx(address, int)
// | GAAttachTx
// Contract implementing Quantum-resistant (MLDSA65) authentication
contract QrAuthTx =
record state = { nonce : int, owner : address, owner_pub : bytes }
datatype foo = Bar | Baz()
entrypoint init(pub : bytes) = { nonce = 1
, owner = Call.caller
, owner_pub = pub }
stateful entrypoint authorize(n : int, s : signature) : bool =
require(n >= state.nonce, "Nonce too low")
require(n =< state.nonce, "Nonce too high")
put(state{ nonce = n + 1 })
switch(Auth.tx_hash)
None => abort("Not in Auth context")
Some(tx_hash) =>
let Some(tx0) = Auth.tx
let x : option(Chain.paying_for_tx) = tx0.paying_for
let x : list(Chain.ga_meta_tx) = tx0.ga_metas
let x : int = tx0.fee + tx0.ttl
let x : address = tx0.actor
let x : Chain.tx = { tx = Chain.NamePreclaimTx, paying_for = None, ga_metas = [],
fee = 123, ttl = 0, actor = Call.caller }
switch(tx0.tx)
Chain.SpendTx(receiver, amount, payload) => verify(tx_hash, n, s)
Chain.OracleRegisterTx => false
Chain.OracleQueryTx => false
Chain.OracleResponseTx => false
Chain.OracleExtendTx => false
Chain.NamePreclaimTx => false
Chain.NameClaimTx(name) => false
Chain.NameUpdateTx(name) => false
Chain.NameRevokeTx(name) => false
Chain.NameTransferTx(to, name) => false
Chain.ChannelCreateTx(other_party) => false
Chain.ChannelDepositTx(channel, amount) => false
Chain.ChannelWithdrawTx(channel, amount) => false
Chain.ChannelForceProgressTx(channel) => false
Chain.ChannelCloseMutualTx(channel) => false
Chain.ChannelCloseSoloTx(channel) => false
Chain.ChannelSlashTx(channel) => false
Chain.ChannelSettleTx(channel) => false
Chain.ChannelSnapshotSoloTx(channel) => false
Chain.ContractCreateTx(amount) => false
Chain.ContractCallTx(ct_address, amount) => false
Chain.GAAttachTx => false
function verify(tx_hash, n, s) =
Crypto.verify_sig_mldsa65(to_sign(tx_hash, n), state.owner_pub, s)
entrypoint to_sign(h : hash, n : int) =
Crypto.blake2b((h, n))
entrypoint weird_string() : string =
"\x19Weird String\x42\nMore\n"

View File

@ -29,6 +29,9 @@ contract UnappliedBuiltins =
function crypto_verify_sig_secp256k1() = Crypto.verify_sig_secp256k1 function crypto_verify_sig_secp256k1() = Crypto.verify_sig_secp256k1
function crypto_ecverify_secp256k1() = Crypto.ecverify_secp256k1 function crypto_ecverify_secp256k1() = Crypto.ecverify_secp256k1
function crypto_ecrecover_secp256k1() = Crypto.ecrecover_secp256k1 function crypto_ecrecover_secp256k1() = Crypto.ecrecover_secp256k1
function crypto_verify_sig_mldsa44() = Crypto.verify_sig_mldsa44
function crypto_verify_sig_mldsa65() = Crypto.verify_sig_mldsa65
function crypto_verify_sig_mldsa87() = Crypto.verify_sig_mldsa87
function crypto_sha3() = Crypto.sha3 : t => _ function crypto_sha3() = Crypto.sha3 : t => _
function crypto_sha256() = Crypto.sha256 : t => _ function crypto_sha256() = Crypto.sha256 : t => _
function crypto_blake2b() = Crypto.blake2b : t => _ function crypto_blake2b() = Crypto.blake2b : t => _