From 70293fd181fea537a83cd18c39c99f30e48a93e9 Mon Sep 17 00:00:00 2001 From: narodnik Date: Fri, 6 May 2022 22:46:01 +0200 Subject: [PATCH] add missing code for inputs --- bin/daod/demo/main.py | 114 ++++++++++++++++++++++++++++++++++++++++-- src/tx/builder.rs | 2 + 2 files changed, 112 insertions(+), 4 deletions(-) diff --git a/bin/daod/demo/main.py b/bin/daod/demo/main.py index 21b20ac7c..ef9264014 100644 --- a/bin/daod/demo/main.py +++ b/bin/daod/demo/main.py @@ -20,7 +20,11 @@ class TransactionBuilder: clear_input.signature_secret = signature_secret self.clear_inputs.append(clear_input) - def add_input(self, input): + def add_input(self, all_coins, secret, note): + input = ClassNamespace() + input.all_coins = all_coins + input.secret = secret + input.note = note self.inputs.append(input) def add_output(self, value, token_id, public): @@ -54,8 +58,21 @@ class TransactionBuilder: tx.clear_inputs.append(tx_clear_input) input_blinds = [] + signature_secrets = [] for input in self.inputs: + # FIXME: BUG - see corresponding builder.rs file + input_blinds.append(input.note.value_blind) + + signature_secret = self.ec.random_scalar() + signature_secrets.append(signature_secret) + tx_input = ClassNamespace() + tx_input.__name__ = "TransactionInput" + tx_input.burn_proof = BurnProof( + input.note.value, input.note.token_id, input.note.value_blind, + token_blind, input.note.serial, input.note.coin_blind, + input.secret, input.all_coins, signature_secret, self.ec) + tx_input.revealed = tx_input.burn_proof.get_revealed() tx.inputs.append(tx_input) assert self.outputs @@ -97,13 +114,71 @@ class TransactionBuilder: secret = info.signature_secret signature = sign(unsigned_tx_data, secret, self.ec) input.signature = signature - for (input, info) in zip(tx.inputs, self.inputs): - secret = info.signature_secret - signature = sign(unsigned_tx_data, secret, self.ec) + for (input, signature_secret) in zip(tx.inputs, signature_secrets): + signature = sign(unsigned_tx_data, signature_secret, self.ec) input.signature = signature return tx +class BurnProof: + + def __init__(self, value, token_id, value_blind, token_blind, serial, + coin_blind, secret, all_coins, signature_secret, ec): + self.value = value + self.token_id = token_id + self.value_blind = value_blind + self.token_blind = token_blind + self.serial = serial + self.coin_blind = coin_blind + self.secret = secret + self.all_coins = all_coins + self.signature_secret = signature_secret + + self.ec = ec + + def get_revealed(self): + revealed = ClassNamespace() + revealed.nullifier = ff_hash(self.secret, self.serial) + + revealed.value_commit = pedersen_encrypt( + self.value, self.value_blind, self.ec + ) + revealed.token_commit = pedersen_encrypt( + self.token_id, self.token_blind, self.ec + ) + + revealed.all_coins = self.all_coins + + revealed.signature_public = self.ec.multiply(self.signature_secret, + self.ec.G) + + return revealed + + def verify(self, public): + revealed = self.get_revealed() + + public_key = self.ec.multiply(self.secret, self.ec.G) + coin = ff_hash( + self.ec.p, + public_key[0], + public_key[1], + self.value, + self.token_id, + self.serial, + self.coin_blind + ) + # Merkle root check + if coin not in self.all_coins: + return False + + return all([ + revealed.nullifier == public.nullifier, + revealed.value_commit == public.value_commit, + revealed.token_commit == public.token_commit, + revealed.all_coins == public.all_coins, + revealed.signature_public == public.signature_public + ]) + class MintProof: def __init__(self, value, token_id, value_blind, token_blind, serial, @@ -289,6 +364,37 @@ def main(argv): print(f"tx verify failed: {reason}", file=sys.stderr) return -1 + assert len(tx.outputs) > 0 + note = tx.outputs[0].enc_note + coin = ff_hash( + ec.p, + public[0], + public[1], + note.value, + note.token_id, + note.serial, + note.coin_blind + ) + assert coin == tx.outputs[0].mint_proof.get_revealed().coin + all_coins = [coin] + + builder = TransactionBuilder(ec) + builder.add_input(all_coins, secret, note) + + secret2 = ec.random_scalar() + public2 = ec.multiply(secret, ec.G) + + builder.add_output(1000, token_id, public2) + # Change + builder.add_output(note.value - 1000, token_id, public) + + tx = builder.build() + + is_verify, reason = tx.verify() + if not is_verify: + print(f"tx2 verify failed: {reason}", file=sys.stderr) + return -1 + return 0 if __name__ == "__main__": diff --git a/src/tx/builder.rs b/src/tx/builder.rs index 1c5dc9679..551d2bb2f 100644 --- a/src/tx/builder.rs +++ b/src/tx/builder.rs @@ -89,6 +89,8 @@ impl TransactionBuilder { let mut input_blinds = vec![]; let mut signature_secrets = vec![]; for input in self.inputs { + // FIXME: BUG - looks like we are reusing the value_blind from the output + // This must be a completely new random value or the value_commit will be the same. input_blinds.push(input.note.value_blind); let signature_secret = SecretKey::random(&mut OsRng);