mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-26 16:18:22 +00:00
feat(xmr): add support for HF15, BP+
This commit is contained in:
parent
14e08ca9db
commit
5e6582a3fe
@ -172,7 +172,7 @@ message MoneroTransactionSetInputRequest {
|
||||
/**
|
||||
* Response: Response to setting UTXO for signature. Contains sealed values needed for further protocol steps.
|
||||
* @next MoneroTransactionSetInputAck
|
||||
* @next MoneroTransactionInputsPermutationRequest
|
||||
* @next MoneroTransactionInputViniRequest
|
||||
*/
|
||||
message MoneroTransactionSetInputAck {
|
||||
optional bytes vini = 1; // xmrtypes.TxinToKey
|
||||
@ -183,21 +183,6 @@ message MoneroTransactionSetInputAck {
|
||||
optional bytes spend_key = 6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request: Sub request of MoneroTransactionSign. Permutation on key images.
|
||||
* @next MoneroTransactionInputsPermutationAck
|
||||
*/
|
||||
message MoneroTransactionInputsPermutationRequest {
|
||||
repeated uint32 perm = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Response: Response to setting permutation on key images
|
||||
* @next MoneroTransactionInputViniRequest
|
||||
*/
|
||||
message MoneroTransactionInputsPermutationAck {
|
||||
}
|
||||
|
||||
/**
|
||||
* Request: Sub request of MoneroTransactionSign. Sends one UTXO to device together with sealed values.
|
||||
* @next MoneroTransactionInputViniAck
|
||||
@ -327,7 +312,7 @@ message MoneroTransactionFinalAck {
|
||||
optional bytes salt = 2;
|
||||
optional bytes rand_mult = 3;
|
||||
optional bytes tx_enc_keys = 4;
|
||||
optional bytes opening_key = 5; // enc master key to decrypt MLSAGs after protocol finishes correctly
|
||||
optional bytes opening_key = 5; // enc master key to decrypt CLSAGs after protocol finishes correctly
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -297,8 +297,6 @@ enum MessageType {
|
||||
MessageType_MoneroTransactionInitAck = 502 [(wire_out) = true];
|
||||
MessageType_MoneroTransactionSetInputRequest = 503 [(wire_out) = true];
|
||||
MessageType_MoneroTransactionSetInputAck = 504 [(wire_out) = true];
|
||||
MessageType_MoneroTransactionInputsPermutationRequest = 505 [(wire_out) = true];
|
||||
MessageType_MoneroTransactionInputsPermutationAck = 506 [(wire_out) = true];
|
||||
MessageType_MoneroTransactionInputViniRequest = 507 [(wire_out) = true];
|
||||
MessageType_MoneroTransactionInputViniAck = 508 [(wire_out) = true];
|
||||
MessageType_MoneroTransactionAllInputsSetRequest = 509 [(wire_out) = true];
|
||||
|
@ -192,15 +192,6 @@ After receiving this message:
|
||||
|
||||
Trezor computes spending keys, `TxinToKey`, `pseudo_out`, HMACs for offloaded data
|
||||
|
||||
### `MoneroTransactionInputsPermutationRequest` (Deprecated)
|
||||
|
||||
UTXOs have to be sorted by the key image in the valid blockchain transaction.
|
||||
This message caries permutation on the key images so they are sorted in the desired way.
|
||||
|
||||
In Client version 3+ sending the permutation is deprecated. Original sort index is sent from the host
|
||||
when needed (to verify HMACs built on the original ordering). Moreover, permutation correctness is checked by
|
||||
the set size, HMAC validity and strict ordering on the key images.
|
||||
|
||||
### `MoneroTransactionInputViniRequest`
|
||||
|
||||
- Step needed to correctly hash all transaction inputs, in the right order (permutation computed in the previous step).
|
||||
|
@ -59,7 +59,6 @@ async def sign_tx_dispatch(state: State, msg, keychain: Keychain) -> tuple:
|
||||
await step_02_set_input.set_input(state, msg.src_entr),
|
||||
(
|
||||
MessageType.MoneroTransactionSetInputRequest,
|
||||
MessageType.MoneroTransactionInputsPermutationRequest,
|
||||
MessageType.MoneroTransactionInputViniRequest,
|
||||
),
|
||||
)
|
||||
|
@ -17,6 +17,8 @@ class RctType:
|
||||
"""
|
||||
There are several types of monero Ring Confidential Transactions
|
||||
like RCTTypeFull and RCTTypeSimple but currently we use only CLSAG
|
||||
and RCTTypeBulletproofPlus
|
||||
"""
|
||||
|
||||
CLSAG = 5
|
||||
RCTTypeBulletproofPlus = 6
|
||||
|
@ -103,6 +103,7 @@ class State:
|
||||
self.rsig_grouping: list[int] | None = []
|
||||
# is range proof computing offloaded or not
|
||||
self.rsig_offload: bool | None = False
|
||||
self.rsig_is_bp_plus: bool | None = False
|
||||
|
||||
# sum of all inputs' pseudo out masks
|
||||
self.sumpouts_alphas: Scalar = crypto.Scalar(0)
|
||||
|
@ -61,7 +61,6 @@ async def init_transaction(
|
||||
state.fee = tsx_data.fee
|
||||
state.account_idx = tsx_data.account
|
||||
state.last_step = state.STEP_INIT
|
||||
state.tx_type = signing.RctType.CLSAG
|
||||
if tsx_data.hard_fork:
|
||||
state.hard_fork = tsx_data.hard_fork
|
||||
if state.hard_fork < 13:
|
||||
@ -208,6 +207,11 @@ def _check_rsig_data(state: State, rsig_data: MoneroTransactionRsigData) -> None
|
||||
elif rsig_data.rsig_type not in (1, 2, 3):
|
||||
raise ValueError("Unknown rsig type")
|
||||
|
||||
state.tx_type = signing.RctType.CLSAG
|
||||
if rsig_data.bp_version == 4:
|
||||
state.rsig_is_bp_plus = True
|
||||
state.tx_type = signing.RctType.RCTTypeBulletproofPlus
|
||||
|
||||
if state.output_count > 2:
|
||||
state.rsig_offload = True
|
||||
|
||||
|
@ -15,7 +15,10 @@ from .state import State
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from apps.monero.xmr.serialize_messages.tx_ecdh import EcdhTuple
|
||||
from apps.monero.xmr.serialize_messages.tx_rsig_bulletproof import Bulletproof
|
||||
from apps.monero.xmr.serialize_messages.tx_rsig_bulletproof import (
|
||||
Bulletproof,
|
||||
BulletproofPlus,
|
||||
)
|
||||
from trezor.messages import (
|
||||
MoneroTransactionDestinationEntry,
|
||||
MoneroTransactionSetOutputAck,
|
||||
@ -303,7 +306,7 @@ def _rsig_bp(state: State) -> bytes:
|
||||
from apps.monero.xmr import range_signatures
|
||||
|
||||
rsig = range_signatures.prove_range_bp_batch(
|
||||
state.output_amounts, state.output_masks
|
||||
state.output_amounts, state.output_masks, state.rsig_is_bp_plus
|
||||
)
|
||||
state.mem_trace("post-bp" if __debug__ else None, collect=True)
|
||||
|
||||
@ -314,7 +317,7 @@ def _rsig_bp(state: State) -> bytes:
|
||||
state.full_message_hasher.rsig_val(rsig, raw=False)
|
||||
state.mem_trace("post-bp-hash" if __debug__ else None, collect=True)
|
||||
|
||||
rsig = _dump_rsig_bp(rsig)
|
||||
rsig = _dump_rsig_bp_plus(rsig) if state.rsig_is_bp_plus else _dump_rsig_bp(rsig)
|
||||
state.mem_trace(
|
||||
f"post-bp-ser, size: {len(rsig)}" if __debug__ else None, collect=True
|
||||
)
|
||||
@ -327,9 +330,15 @@ def _rsig_bp(state: State) -> bytes:
|
||||
|
||||
def _rsig_process_bp(state: State, rsig_data: MoneroTransactionRsigData):
|
||||
from apps.monero.xmr import range_signatures
|
||||
from apps.monero.xmr.serialize_messages.tx_rsig_bulletproof import Bulletproof
|
||||
from apps.monero.xmr.serialize_messages.tx_rsig_bulletproof import (
|
||||
Bulletproof,
|
||||
BulletproofPlus,
|
||||
)
|
||||
|
||||
bp_obj = serialize.parse_msg(rsig_data.rsig, Bulletproof)
|
||||
if state.rsig_is_bp_plus:
|
||||
bp_obj = serialize.parse_msg(rsig_data.rsig, BulletproofPlus)
|
||||
else:
|
||||
bp_obj = serialize.parse_msg(rsig_data.rsig, Bulletproof)
|
||||
rsig_data.rsig = None
|
||||
|
||||
# BP is hashed with raw=False as hash does not contain L, R
|
||||
@ -366,8 +375,45 @@ def _dump_rsig_bp(rsig: Bulletproof) -> bytes:
|
||||
utils.memcpy(buff, 32 * 4, rsig.taux, 0, 32)
|
||||
utils.memcpy(buff, 32 * 5, rsig.mu, 0, 32)
|
||||
|
||||
buff[32 * 6] = len(rsig.L)
|
||||
offset = 32 * 6 + 1
|
||||
offset = _dump_rsig_lr(buff, 32 * 6, rsig)
|
||||
|
||||
utils.memcpy(buff, offset, rsig.a, 0, 32)
|
||||
offset += 32
|
||||
utils.memcpy(buff, offset, rsig.b, 0, 32)
|
||||
offset += 32
|
||||
utils.memcpy(buff, offset, rsig.t, 0, 32)
|
||||
return buff
|
||||
|
||||
|
||||
def _dump_rsig_bp_plus(rsig: BulletproofPlus) -> bytes:
|
||||
if len(rsig.L) > 127:
|
||||
raise ValueError("Too large")
|
||||
|
||||
# Manual serialization as the generic purpose serialize.dump_msg_gc
|
||||
# is more memory intensive which is not desired in the range proof section.
|
||||
|
||||
# BP: "V", "A", "A1", "B", "r1", "s1", "d1", "V", "L", "R"
|
||||
# Commitment vector V is not serialized
|
||||
# Vector size under 127 thus varint occupies 1 B
|
||||
buff_size = 32 * (6 + 2 * (len(rsig.L))) + 2
|
||||
buff = bytearray(buff_size)
|
||||
|
||||
utils.memcpy(buff, 0, rsig.A, 0, 32)
|
||||
utils.memcpy(buff, 32, rsig.A1, 0, 32)
|
||||
utils.memcpy(buff, 32 * 2, rsig.B, 0, 32)
|
||||
utils.memcpy(buff, 32 * 3, rsig.r1, 0, 32)
|
||||
utils.memcpy(buff, 32 * 4, rsig.s1, 0, 32)
|
||||
utils.memcpy(buff, 32 * 5, rsig.d1, 0, 32)
|
||||
|
||||
_dump_rsig_lr(buff, 32 * 6, rsig)
|
||||
return buff
|
||||
|
||||
|
||||
def _dump_rsig_lr(
|
||||
buff: bytearray, offset: int, rsig: Bulletproof | BulletproofPlus
|
||||
) -> int:
|
||||
buff[offset] = len(rsig.L)
|
||||
offset += 1
|
||||
|
||||
for x in rsig.L:
|
||||
utils.memcpy(buff, offset, x, 0, 32)
|
||||
@ -379,18 +425,12 @@ def _dump_rsig_bp(rsig: Bulletproof) -> bytes:
|
||||
for x in rsig.R:
|
||||
utils.memcpy(buff, offset, x, 0, 32)
|
||||
offset += 32
|
||||
|
||||
utils.memcpy(buff, offset, rsig.a, 0, 32)
|
||||
offset += 32
|
||||
utils.memcpy(buff, offset, rsig.b, 0, 32)
|
||||
offset += 32
|
||||
utils.memcpy(buff, offset, rsig.t, 0, 32)
|
||||
return buff
|
||||
return offset
|
||||
|
||||
|
||||
def _return_rsig_data(
|
||||
rsig: bytes | None = None, mask: bytes | None = None
|
||||
) -> MoneroTransactionRsigData:
|
||||
) -> MoneroTransactionRsigData | None:
|
||||
if rsig is None and mask is None:
|
||||
return None
|
||||
|
||||
@ -420,9 +460,18 @@ def _get_ecdh_info_and_out_pk(
|
||||
so the recipient is able to reconstruct the commitment.
|
||||
"""
|
||||
out_pk_dest = crypto_helpers.encodepoint(tx_out_key)
|
||||
out_pk_commitment = crypto_helpers.encodepoint(
|
||||
crypto.gen_commitment_into(None, mask, amount)
|
||||
)
|
||||
if state.rsig_is_bp_plus:
|
||||
# HF15+ stores commitment multiplied by 8**-1
|
||||
inv8 = crypto.decodeint_into_noreduce(None, crypto_helpers.INV_EIGHT)
|
||||
mask8 = crypto.sc_mul_into(None, mask, inv8)
|
||||
amnt8 = crypto.Scalar(amount)
|
||||
amnt8 = crypto.sc_mul_into(amnt8, amnt8, inv8)
|
||||
out_pk_commitment = crypto.add_keys2_into(None, mask8, amnt8, crypto.xmr_H())
|
||||
del (inv8, mask8, amnt8)
|
||||
else:
|
||||
out_pk_commitment = crypto.gen_commitment_into(None, mask, amount)
|
||||
|
||||
out_pk_commitment = crypto_helpers.encodepoint(out_pk_commitment)
|
||||
crypto.sc_add_into(state.sumout, state.sumout, mask)
|
||||
ecdh_info = _ecdh_encode(amount, crypto_helpers.encodeint(amount_key))
|
||||
|
||||
|
@ -347,7 +347,7 @@ def _invert_batch(x):
|
||||
|
||||
for i in range(len(x) - 1, -1, -1):
|
||||
_sc_mul(tmp, acc, x[i])
|
||||
_sc_mul(x[i], acc, scratch[i])
|
||||
x[i] = _sc_mul(x[i], acc, scratch[i])
|
||||
memcpy(acc, 0, tmp, 0, 32)
|
||||
return x
|
||||
|
||||
@ -1161,6 +1161,55 @@ class KeyPow2Vct(KeyVBase):
|
||||
return self.cur_sc if self.raw else self.cur
|
||||
|
||||
|
||||
class KeyChallengeCacheVct(KeyVBase):
|
||||
"""
|
||||
Challenge cache vector for BP+ verification
|
||||
More on this in the verification code, near "challenge_cache" definition
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"nbits",
|
||||
"ch_",
|
||||
"chi",
|
||||
"precomp",
|
||||
"precomp_depth",
|
||||
"cur",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self, nbits: int, ch_: KeyVBase, chi: KeyVBase, precomputed: KeyVBase | None
|
||||
):
|
||||
super().__init__(1 << nbits)
|
||||
self.nbits = nbits
|
||||
self.ch_ = ch_
|
||||
self.chi = chi
|
||||
self.precomp = precomputed
|
||||
self.precomp_depth = 0
|
||||
self.cur = _ensure_dst_key()
|
||||
if not precomputed:
|
||||
return
|
||||
|
||||
while (1 << self.precomp_depth) < len(precomputed):
|
||||
self.precomp_depth += 1
|
||||
|
||||
def __getitem__(self, item):
|
||||
i = self.idxize(item)
|
||||
bits_done = 0
|
||||
|
||||
if self.precomp:
|
||||
_copy_key(self.cur, self.precomp[i >> (self.nbits - self.precomp_depth)])
|
||||
bits_done += self.precomp_depth
|
||||
else:
|
||||
_copy_key(self.cur, _ONE)
|
||||
|
||||
for j in range(self.nbits - 1, bits_done - 1, -1):
|
||||
if i & (1 << (self.nbits - 1 - j)) > 0:
|
||||
_sc_mul(self.cur, self.cur, self.ch_[j])
|
||||
else:
|
||||
_sc_mul(self.cur, self.cur, self.chi[j])
|
||||
return self.cur
|
||||
|
||||
|
||||
class KeyR0(KeyVBase):
|
||||
"""
|
||||
Vector r0. Allows only sequential access (no jumping). Resets on [0,1] access.
|
||||
@ -2736,6 +2785,9 @@ class BulletProofPlusBuilder:
|
||||
|
||||
return BulletproofPlus(V=V, A=A, A1=A1, B=B, r1=r1, s1=s1, d1=d1, L=L, R=R)
|
||||
|
||||
def verify(self, proof: BulletproofPlus) -> bool:
|
||||
return self.verify_batch([proof])
|
||||
|
||||
def verify_batch(self, proofs: list[BulletproofPlus]):
|
||||
"""
|
||||
BP+ batch verification
|
||||
@ -2763,7 +2815,8 @@ class BulletProofPlusBuilder:
|
||||
max_logm = 0
|
||||
|
||||
proof_data = []
|
||||
to_invert = []
|
||||
to_invert_offset = 0
|
||||
to_invert = _ensure_dst_keyvect(None, 11 * len(proofs))
|
||||
for proof in proofs:
|
||||
max_length = max(max_length, len(proof.L))
|
||||
nV += len(proof.V)
|
||||
@ -2806,11 +2859,17 @@ class BulletProofPlusBuilder:
|
||||
# batch scalar inversions
|
||||
pd.inv_offset = inv_offset
|
||||
for j in range(rounds): # max rounds is 10 = lg(16*64) = lg(1024)
|
||||
to_invert.append(bytearray(pd.challenges[j]))
|
||||
to_invert.append(bytearray(pd.y))
|
||||
to_invert.read(to_invert_offset, pd.challenges[j])
|
||||
to_invert_offset += 1
|
||||
|
||||
to_invert.read(to_invert_offset, pd.y)
|
||||
to_invert_offset += 1
|
||||
inv_offset += rounds + 1
|
||||
self.gc(2)
|
||||
|
||||
to_invert.resize(inv_offset)
|
||||
self.gc(2)
|
||||
|
||||
utils.ensure(max_length < 32, "At least one proof is too large")
|
||||
maxMN = 1 << max_length
|
||||
tmp2 = _ensure_dst_key()
|
||||
@ -2937,32 +2996,55 @@ class BulletProofPlusBuilder:
|
||||
yinv = inverses[pd.inv_offset + rounds]
|
||||
self.gc(6)
|
||||
|
||||
# Compute challenge products
|
||||
challenges_cache = _ensure_dst_keyvect(
|
||||
None, 1 << rounds
|
||||
) # [_ZERO] * (1 << rounds)
|
||||
# Description of challenges_cache:
|
||||
# Let define ch_[i] = pd.challenges[i] and
|
||||
# chi[i] = pd.challenges[i]^{-1}
|
||||
# Also define b_j[i] = i-th bit of integer j, 0 is MSB
|
||||
# encoded in {rounds} bits
|
||||
#
|
||||
# challenges_cache[i] contains multiplication ch_ or chi depending on the b_i
|
||||
# i.e., its binary representation. chi is for 0, ch_ for 1 in the b_i repr.
|
||||
#
|
||||
# challenges_cache[i] = \\mult_{j \in [0, rounds)} (b_i[j] * ch_[j]) +
|
||||
# (1-b_i[j]) * chi[j]
|
||||
# Originally, it is constructed iteratively, starting with 1 bit, 2 bits.
|
||||
# We cannot afford having it all precomputed, thus we precompute it up to
|
||||
# a threshold challenges_cache_depth_lim bits, the rest is evaluated on the fly
|
||||
challenges_cache_depth_lim = const(8)
|
||||
challenges_cache_depth = min(rounds, challenges_cache_depth_lim)
|
||||
challenges_cache = _ensure_dst_keyvect(None, 1 << challenges_cache_depth)
|
||||
|
||||
challenges_cache[0] = inverses[pd.inv_offset]
|
||||
challenges_cache[1] = pd.challenges[0]
|
||||
for j in range(1, rounds):
|
||||
|
||||
for j in range(1, challenges_cache_depth):
|
||||
slots = 1 << (j + 1)
|
||||
for s in range(slots - 1, -1, -2):
|
||||
challenges_cache.read(
|
||||
s,
|
||||
_sc_mul(
|
||||
challenges_cache[s],
|
||||
_tmp_bf_0,
|
||||
challenges_cache[s // 2],
|
||||
pd.challenges[j],
|
||||
pd.challenges[j], # even s
|
||||
),
|
||||
)
|
||||
challenges_cache.read(
|
||||
s - 1,
|
||||
_sc_mul(
|
||||
challenges_cache[s - 1],
|
||||
_tmp_bf_0,
|
||||
challenges_cache[s // 2],
|
||||
inverses[pd.inv_offset + j],
|
||||
inverses[pd.inv_offset + j], # odd s
|
||||
),
|
||||
)
|
||||
|
||||
if rounds > challenges_cache_depth:
|
||||
challenges_cache = KeyChallengeCacheVct(
|
||||
rounds,
|
||||
pd.challenges,
|
||||
inverses.slice_view(pd.inv_offset, pd.inv_offset + rounds + 1),
|
||||
challenges_cache,
|
||||
)
|
||||
|
||||
# Gi and Hi
|
||||
self.gc(7)
|
||||
e_r1_w_y = _ensure_dst_key()
|
||||
|
@ -3,10 +3,9 @@ from typing import TYPE_CHECKING
|
||||
from apps.monero.xmr import crypto_helpers
|
||||
from apps.monero.xmr.keccak_hasher import KeccakXmrArchive
|
||||
|
||||
from .serialize_messages.tx_rsig_bulletproof import Bulletproof
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from trezor.utils import HashContext
|
||||
from .serialize_messages.tx_rsig_bulletproof import Bulletproof, BulletproofPlus
|
||||
|
||||
|
||||
class PreMlsagHasher:
|
||||
@ -57,7 +56,9 @@ class PreMlsagHasher:
|
||||
self.kc_master.update(c_hash)
|
||||
self.rtcsig_hasher = None # type: ignore
|
||||
|
||||
def rsig_val(self, p: bytes | list[bytes] | Bulletproof, raw: bool = False) -> None:
|
||||
def rsig_val(
|
||||
self, p: bytes | list[bytes] | Bulletproof | BulletproofPlus, raw: bool = False
|
||||
) -> None:
|
||||
if self.state == 8:
|
||||
raise ValueError("State error")
|
||||
|
||||
@ -74,22 +75,30 @@ class PreMlsagHasher:
|
||||
self.rsig_hasher.update(p)
|
||||
return
|
||||
|
||||
assert isinstance(p, Bulletproof)
|
||||
from .serialize_messages.tx_rsig_bulletproof import Bulletproof, BulletproofPlus
|
||||
|
||||
is_plus = isinstance(p, BulletproofPlus)
|
||||
assert isinstance(p, Bulletproof) or is_plus
|
||||
|
||||
# Hash Bulletproof
|
||||
self.rsig_hasher.update(p.A)
|
||||
self.rsig_hasher.update(p.S)
|
||||
self.rsig_hasher.update(p.T1)
|
||||
self.rsig_hasher.update(p.T2)
|
||||
self.rsig_hasher.update(p.taux)
|
||||
self.rsig_hasher.update(p.mu)
|
||||
fields = (
|
||||
(p.A, p.A1, p.B, p.r1, p.s1, p.d1)
|
||||
if is_plus
|
||||
else (p.A, p.S, p.T1, p.T2, p.taux, p.mu)
|
||||
)
|
||||
for fld in fields:
|
||||
self.rsig_hasher.update(fld)
|
||||
|
||||
del (fields,)
|
||||
for i in range(len(p.L)):
|
||||
self.rsig_hasher.update(p.L[i])
|
||||
for i in range(len(p.R)):
|
||||
self.rsig_hasher.update(p.R[i])
|
||||
self.rsig_hasher.update(p.a)
|
||||
self.rsig_hasher.update(p.b)
|
||||
self.rsig_hasher.update(p.t)
|
||||
|
||||
if not is_plus:
|
||||
self.rsig_hasher.update(p.a)
|
||||
self.rsig_hasher.update(p.b)
|
||||
self.rsig_hasher.update(p.t)
|
||||
|
||||
def get_digest(self) -> bytes:
|
||||
if self.state != 6:
|
||||
|
@ -14,14 +14,19 @@ from typing import TYPE_CHECKING
|
||||
from apps.monero.xmr import crypto, crypto_helpers
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from apps.monero.xmr.serialize_messages.tx_rsig_bulletproof import Bulletproof
|
||||
from apps.monero.xmr.serialize_messages.tx_rsig_bulletproof import (
|
||||
Bulletproof,
|
||||
BulletproofPlus,
|
||||
)
|
||||
|
||||
|
||||
def prove_range_bp_batch(amounts: list[int], masks: list[crypto.Scalar]) -> Bulletproof:
|
||||
def prove_range_bp_batch(
|
||||
amounts: list[int], masks: list[crypto.Scalar], bp_plus: bool = False
|
||||
) -> Bulletproof | BulletproofPlus:
|
||||
"""Calculates Bulletproof in batches"""
|
||||
from apps.monero.xmr import bulletproof as bp
|
||||
|
||||
bpi = bp.BulletProofBuilder()
|
||||
bpi = bp.BulletProofPlusBuilder() if bp_plus else bp.BulletProofBuilder()
|
||||
bp_proof = bpi.prove_batch([crypto.Scalar(a) for a in amounts], masks)
|
||||
del (bpi, bp)
|
||||
gc.collect()
|
||||
@ -30,7 +35,9 @@ def prove_range_bp_batch(amounts: list[int], masks: list[crypto.Scalar]) -> Bull
|
||||
|
||||
|
||||
def verify_bp(
|
||||
bp_proof: Bulletproof, amounts: list[int], masks: list[crypto.Scalar]
|
||||
bp_proof: Bulletproof | BulletproofPlus,
|
||||
amounts: list[int],
|
||||
masks: list[crypto.Scalar],
|
||||
) -> bool:
|
||||
"""Verifies Bulletproof"""
|
||||
from apps.monero.xmr import bulletproof as bp
|
||||
@ -42,7 +49,13 @@ def verify_bp(
|
||||
crypto.scalarmult_into(C, C, crypto_helpers.INV_EIGHT_SC)
|
||||
bp_proof.V.append(crypto_helpers.encodepoint(C))
|
||||
|
||||
bpi = bp.BulletProofBuilder()
|
||||
from apps.monero.xmr.serialize_messages.tx_rsig_bulletproof import BulletproofPlus
|
||||
|
||||
bpi = (
|
||||
bp.BulletProofPlusBuilder()
|
||||
if isinstance(bp_proof, BulletproofPlus)
|
||||
else bp.BulletProofBuilder()
|
||||
)
|
||||
res = bpi.verify(bp_proof)
|
||||
gc.collect()
|
||||
return res
|
||||
|
@ -45,7 +45,6 @@ class BulletproofPlus(MessageType):
|
||||
("r1", ECKey),
|
||||
("s1", ECKey),
|
||||
("d1", ECKey),
|
||||
("V", _KeyV),
|
||||
("L", _KeyV),
|
||||
("R", _KeyV),
|
||||
)
|
||||
|
@ -180,8 +180,6 @@ if not utils.BITCOIN_ONLY:
|
||||
MoneroTransactionInitAck = 502
|
||||
MoneroTransactionSetInputRequest = 503
|
||||
MoneroTransactionSetInputAck = 504
|
||||
MoneroTransactionInputsPermutationRequest = 505
|
||||
MoneroTransactionInputsPermutationAck = 506
|
||||
MoneroTransactionInputViniRequest = 507
|
||||
MoneroTransactionInputViniAck = 508
|
||||
MoneroTransactionAllInputsSetRequest = 509
|
||||
|
@ -198,8 +198,6 @@ if TYPE_CHECKING:
|
||||
MoneroTransactionInitAck = 502
|
||||
MoneroTransactionSetInputRequest = 503
|
||||
MoneroTransactionSetInputAck = 504
|
||||
MoneroTransactionInputsPermutationRequest = 505
|
||||
MoneroTransactionInputsPermutationAck = 506
|
||||
MoneroTransactionInputViniRequest = 507
|
||||
MoneroTransactionInputViniAck = 508
|
||||
MoneroTransactionAllInputsSetRequest = 509
|
||||
|
@ -3833,26 +3833,6 @@ if TYPE_CHECKING:
|
||||
def is_type_of(cls, msg: protobuf.MessageType) -> TypeGuard["MoneroTransactionSetInputAck"]:
|
||||
return isinstance(msg, cls)
|
||||
|
||||
class MoneroTransactionInputsPermutationRequest(protobuf.MessageType):
|
||||
perm: "list[int]"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
perm: "list[int] | None" = None,
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def is_type_of(cls, msg: protobuf.MessageType) -> TypeGuard["MoneroTransactionInputsPermutationRequest"]:
|
||||
return isinstance(msg, cls)
|
||||
|
||||
class MoneroTransactionInputsPermutationAck(protobuf.MessageType):
|
||||
|
||||
@classmethod
|
||||
def is_type_of(cls, msg: protobuf.MessageType) -> TypeGuard["MoneroTransactionInputsPermutationAck"]:
|
||||
return isinstance(msg, cls)
|
||||
|
||||
class MoneroTransactionInputViniRequest(protobuf.MessageType):
|
||||
src_entr: "MoneroTransactionSourceEntry | None"
|
||||
vini: "bytes | None"
|
||||
|
@ -407,7 +407,7 @@ class TestMoneroBulletproof(unittest.TestCase):
|
||||
t=unhexlify(b"0de43b393686af8dd0d89f4832a2995cda14e6288de9ecd2b4bf2fa39baba408")
|
||||
)
|
||||
|
||||
def bproof_plus_1(self):
|
||||
def bproof_plus_2(self):
|
||||
return BulletproofPlus(
|
||||
V=[
|
||||
unhexlify(b"e0dae61095ac728a15d4d9754f1f9f956c22d4fa2deee2c0ff1def031b083e02"),
|
||||
@ -484,9 +484,9 @@ class TestMoneroBulletproof(unittest.TestCase):
|
||||
|
||||
def test_verify_plus(self):
|
||||
bpi = bp.BulletProofPlusBuilder()
|
||||
bpi.verify_batch([self.bproof_plus_1()])
|
||||
bpi.verify_batch([self.bproof_plus_2()])
|
||||
|
||||
def test_prove_plus_(self):
|
||||
def test_prove_plus_1(self):
|
||||
bpi = bp.BulletProofPlusBuilder()
|
||||
sv = [crypto.Scalar(123)]
|
||||
gamma = [crypto.Scalar(456)]
|
||||
@ -500,10 +500,10 @@ class TestMoneroBulletproof(unittest.TestCase):
|
||||
proof = bpi.prove_batch(sv, gamma)
|
||||
bpi.verify_batch([proof])
|
||||
|
||||
def test_prove_plus_8(self):
|
||||
def test_prove_plus_16(self):
|
||||
bpi = bp.BulletProofPlusBuilder()
|
||||
sv = [crypto.Scalar(i*123 + 45) for i in range(8)]
|
||||
gamma = [crypto.Scalar(i*456 * 17) for i in range(8)]
|
||||
sv = [crypto.Scalar(i*123 + 45) for i in range(16)]
|
||||
gamma = [crypto.Scalar(i*456 * 17) for i in range(16)]
|
||||
proof = bpi.prove_batch(sv, gamma)
|
||||
bpi.verify_batch([proof])
|
||||
|
||||
|
@ -206,8 +206,6 @@ class MessageType(IntEnum):
|
||||
MoneroTransactionInitAck = 502
|
||||
MoneroTransactionSetInputRequest = 503
|
||||
MoneroTransactionSetInputAck = 504
|
||||
MoneroTransactionInputsPermutationRequest = 505
|
||||
MoneroTransactionInputsPermutationAck = 506
|
||||
MoneroTransactionInputViniRequest = 507
|
||||
MoneroTransactionInputViniAck = 508
|
||||
MoneroTransactionAllInputsSetRequest = 509
|
||||
@ -5310,24 +5308,6 @@ class MoneroTransactionSetInputAck(protobuf.MessageType):
|
||||
self.spend_key = spend_key
|
||||
|
||||
|
||||
class MoneroTransactionInputsPermutationRequest(protobuf.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 505
|
||||
FIELDS = {
|
||||
1: protobuf.Field("perm", "uint32", repeated=True, required=False),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
perm: Optional[Sequence["int"]] = None,
|
||||
) -> None:
|
||||
self.perm: Sequence["int"] = perm if perm is not None else []
|
||||
|
||||
|
||||
class MoneroTransactionInputsPermutationAck(protobuf.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 506
|
||||
|
||||
|
||||
class MoneroTransactionInputViniRequest(protobuf.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 507
|
||||
FIELDS = {
|
||||
|
Loading…
Reference in New Issue
Block a user