-
Notifications
You must be signed in to change notification settings - Fork 0
/
HomomorphicTransaction.sol
94 lines (73 loc) · 3.54 KB
/
HomomorphicTransaction.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// import {EC} from "./EC.sol";
import {Secp256k1} from "https://github.com/androlo/standard-contracts/contracts/src/crypto/Secp256k1.sol";
contract HomomorphicTransaction {
uint constant p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f;
uint constant baseX = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798;
uint constant baseY = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8;
uint public numTxs = 0;
event NewTransaction(uint index);
mapping (uint => bool) public isSpent;
mapping (uint => uint[5][]) public txins; // txindex, txoutindex, v, r, s
mapping (uint => uint[3][]) public txouts; // amount_x, amount_y, pubkeyHash
function mint(uint[3][] _outputs) public payable {
require(msg.value > 0);
uint[3] memory amount_in = Secp256k1._mul(msg.value, [baseX, baseY]);
uint[3] memory amount_out;
for (uint8 j = 0; j < _outputs.length; j++) {
uint[3] memory _out = _outputs[j];
require(Secp256k1.onCurve([_out[0], _out[1]]));
Secp256k1._addMixedM(amount_out, [_out[0], _out[1]]);
}
// x_1z_2^2 = x_2z_1^2
require(
mulmod(mulmod(amount_out[2], amount_out[2], p), amount_in[0], p)
==
mulmod(mulmod(amount_in[2], amount_in[2], p), amount_out[0], p)
);
// y_1z_2^3 = y_2z_1^3
require(
mulmod(mulmod(mulmod(amount_out[2], amount_out[2], p), amount_out[2], p), amount_in[1], p)
==
mulmod(mulmod(mulmod(amount_in[2], amount_in[2], p), amount_in[2], p), amount_out[1], p)
);
emit NewTransaction(numTxs);
txouts[numTxs] = _outputs;
numTxs++;
}
function send(uint[5][] _inputs, uint[3][] _outputs) public {
require(_inputs.length <= 10);
require(_outputs.length <= 10);
uint[3] memory amount_in;
for (uint8 i = 0; i < _inputs.length; i++) {
uint[5] memory _in = _inputs[i];
bytes32 message = keccak256(_in[0], _in[1]); // message to sign; composite of txindex and txoutindex;
require(isSpent[uint256(message)] == false); // check if corresponding txout is spent
uint[3] memory out = txouts[_in[0]][_in[1]]; // get txout pointer
Secp256k1._addMixedM(amount_in, [out[0], out[1]]);
require(uint256(ecrecover(message, uint8(_in[2]), bytes32(_in[3]), bytes32(_in[4]))) == out[2]);
isSpent[uint256(message)] = true;
}
uint[3] memory amount_out;
for (uint8 j = 0; j < _outputs.length; j++) {
uint[3] memory _out = _outputs[j];
require(Secp256k1.onCurve([_out[0], _out[1]]));
Secp256k1._addMixedM(amount_out, [_out[0], _out[1]]);
}
// x_1z_2^2 = x_2z_1^2
require(
mulmod(mulmod(amount_out[2], amount_out[2], p), amount_in[0], p)
==
mulmod(mulmod(amount_in[2], amount_in[2], p), amount_out[0], p)
);
// y_1z_2^3 = y_2z_1^3
require(
mulmod(mulmod(mulmod(amount_out[2], amount_out[2], p), amount_out[2], p), amount_in[1], p)
==
mulmod(mulmod(mulmod(amount_in[2], amount_in[2], p), amount_in[2], p), amount_out[1], p)
);
txins[numTxs] = _inputs;
txouts[numTxs] = _outputs;
emit NewTransaction(numTxs);
numTxs++;
}
}