ledger-app-monero/src/monero_clsag.c

284 lines
7.7 KiB
C

/*****************************************************************************
* Ledger Monero App.
* (c) 2017-2020 Cedric Mesnil <cslashm@gmail.com>, Ledger SAS.
* (c) 2020 Ledger SAS.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*****************************************************************************/
#include "os.h"
#include "cx.h"
#include "monero_types.h"
#include "monero_api.h"
#include "monero_vars.h"
/* ----------------------------------------------------------------------- */
/* --- --- */
/* ----------------------------------------------------------------------- */
/*
bool device_default::clsag_prepare(const rct::key &p,
const rct::key &z,
rct::key &I, rct::key &D,
const rct::key &H,
rct::key &a, rct::key &aG,
rct::key &aH) {
rct::skpkGen(a, aG); // aG = a*G
rct::scalarmultKey(aH, H, a); // aH = a*H
rct::scalarmultKey(I, H, p); // I = p*H
rct::scalarmultKey(D, H, z); // D = z*H
return true;
}
*/
int monero_apdu_clsag_prepare() {
unsigned char a[32];
unsigned char p[32];
unsigned char z[32];
unsigned char H[32];
unsigned char W[32];
int err = 0;
G_monero_vstate.tx_sign_cnt++;
if (G_monero_vstate.tx_sign_cnt == 0) {
return SW_SECURITY_MAX_SIGNATURE_REACHED;
}
err = monero_io_fetch_decrypt(p, 32, TYPE_SCALAR);
if (err) {
return err;
}
monero_io_fetch(z, 32);
monero_io_fetch(H, 32);
monero_io_discard(1);
// a
err = monero_rng_mod_order(a, sizeof(a));
if (err) {
return err;
}
monero_io_insert_encrypt(a, 32, TYPE_ALPHA);
// a.G
err = monero_ecmul_G(W, a, sizeof(W), sizeof(a));
if (err) {
return err;
}
monero_io_insert(W, 32);
// a.H
err = monero_ecmul_k(W, H, a, sizeof(W), sizeof(H), sizeof(a));
if (err) {
return err;
}
monero_io_insert(W, 32);
// I = p.H
err = monero_ecmul_k(W, H, p, sizeof(W), sizeof(H), sizeof(p));
if (err) {
return err;
}
monero_io_insert(W, 32);
// D = z.H
err = monero_ecmul_k(W, H, z, sizeof(W), sizeof(H), sizeof(z));
if (err) {
return err;
}
monero_io_insert(W, 32);
return SW_OK;
}
/* ----------------------------------------------------------------------- */
/* --- --- */
/* ----------------------------------------------------------------------- */
/*
bool device_default::clsag_hash(const rct::keyV &data,
rct::key &hash) {
hash = rct::hash_to_scalar(data);
return true;
}
*/
int monero_apdu_clsag_hash() {
unsigned char msg[32];
unsigned char c[32];
int err;
if (G_monero_vstate.io_p2 == 1) {
if (monero_keccak_init_H()) {
return SW_WRONG_DATA;
}
}
monero_io_fetch(msg, 32);
monero_io_discard(1);
err = monero_keccak_update_H(msg, 32);
if (err) {
return err;
}
if ((G_monero_vstate.options & 0x80) == 0) {
err = monero_keccak_final_H(c);
if (err) {
return err;
}
err = monero_reduce(c, c, sizeof(c), sizeof(c));
if (err) {
return err;
}
monero_io_insert(c, 32);
memcpy(G_monero_vstate.c, c, 32);
}
return SW_OK;
}
/* ----------------------------------------------------------------------- */
/* --- --- */
/* ----------------------------------------------------------------------- */
/*
bool device_default::clsag_sign(const rct::key &c,
const rct::key &a,
const rct::key &p, const
rct::key &z,
const rct::key &mu_P,
const rct::key &mu_C,
rct::key &s) {
rct::key s0_p_mu_P;
sc_mul(s0_p_mu_P.bytes, mu_P.bytes, p.bytes);
rct::key s0_add_z_mu_C;
sc_muladd(s0_add_z_mu_C.bytes, mu_C.bytes, z.bytes, s0_p_mu_P.bytes);
sc_mulsub(s.bytes, c.bytes, s0_add_z_mu_C.bytes, a.bytes);
return true;
}
*/
int monero_apdu_clsag_sign() {
unsigned char s[32];
unsigned char a[32];
unsigned char p[32];
unsigned char z[32];
unsigned char mu_P[32];
unsigned char mu_C[32];
int err = 0;
if (G_monero_vstate.tx_sig_mode == TRANSACTION_CREATE_FAKE) {
monero_io_fetch(a, 32);
monero_io_fetch(p, 32);
monero_io_fetch(z, 32);
monero_io_fetch(mu_P, 32);
monero_io_fetch(mu_C, 32);
} else if (G_monero_vstate.tx_sig_mode == TRANSACTION_CREATE_REAL) {
err = monero_io_fetch_decrypt(a, 32, TYPE_ALPHA);
if (err) {
return err;
}
err = monero_io_fetch_decrypt(p, 32, TYPE_SCALAR);
if (err) {
return err;
}
monero_io_fetch(z, 32);
monero_io_fetch(mu_P, 32);
monero_io_fetch(mu_C, 32);
} else {
return SW_SECURITY_INTERNAL;
}
monero_io_discard(1);
err = monero_check_scalar_not_null(a);
if (err) {
return err;
}
err = monero_check_scalar_not_null(p);
if (err) {
return err;
}
err = monero_check_scalar_not_null(z);
if (err) {
return err;
}
err = monero_reduce(a, a, sizeof(a), sizeof(a));
if (err) {
return err;
}
err = monero_reduce(p, p, sizeof(p), sizeof(p));
if (err) {
return err;
}
err = monero_reduce(z, z, sizeof(z), sizeof(z));
if (err) {
return err;
}
err = monero_reduce(mu_P, mu_P, sizeof(mu_P), sizeof(mu_P));
if (err) {
return err;
}
err = monero_reduce(mu_C, mu_C, sizeof(mu_C), sizeof(mu_C));
if (err) {
return err;
}
err = monero_reduce(G_monero_vstate.c, G_monero_vstate.c, sizeof(G_monero_vstate.c),
sizeof(G_monero_vstate.c));
if (err) {
return err;
}
// s0_p_mu_P = mu_P*p
// s0_add_z_mu_C = mu_C*z + s0_p_mu_P
//
// s = a - c*s0_add_z_mu_C
// = a - c*(mu_C*z + mu_P*p)
// s = p*mu_P
err = monero_multm(s, p, mu_P, sizeof(s), sizeof(p), sizeof(mu_P));
if (err) {
return err;
}
// mu_P = mu_C*z
err = monero_multm(mu_P, mu_C, z, sizeof(mu_P), sizeof(mu_C), sizeof(z));
if (err) {
return err;
}
// s = p*mu_P + mu_C*z
err = monero_addm(s, s, mu_P, sizeof(s), sizeof(s), sizeof(mu_P));
if (err) {
return err;
}
// mu_P = c * (p*mu_P + mu_C*z)
err = monero_multm(mu_P, G_monero_vstate.c, s, sizeof(mu_P), sizeof(G_monero_vstate.c),
sizeof(s));
if (err) {
return err;
}
// s = a - c*(p*mu_P + mu_C*z)
err = monero_subm(s, a, mu_P, sizeof(s), sizeof(a), sizeof(mu_P));
if (err) {
return err;
}
monero_io_insert(s, 32);
return SW_OK;
}