@shakesco/silent 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -70,6 +70,24 @@ function main() {
70
70
  }
71
71
  ```
72
72
 
73
+ #### Create a change address
74
+
75
+ Create a change silent payment address that won't break privacy. Consider a scenario where you have sent 10 silent payments to friends and have sent the change to your public address. In this case, you would have compromised not only your private transactions but also those of your friends. So, let's create a change address:
76
+
77
+ ```js {filename="index.js"}
78
+ function main() {
79
+ const b_scan = "";
80
+ const b_spend = "";
81
+ const keys = KeyGeneration.fromPrivateKeys({
82
+ b_scan: b_scan,
83
+ b_spend: b_spend,
84
+ network: "testnet",
85
+ });
86
+ const changeSilentPaymentAddress = keys.toLabeledSilentPaymentAddress(0); //should always be zero!(https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#labels_for_change)
87
+ console.log(changeSilentPaymentAddress.toAddress()); // change silent payment address
88
+ }
89
+ ```
90
+
73
91
  ### Create a taproot address destination
74
92
 
75
93
  Here is where you create a destination address for the user to send to a newly generated Taproot address, derived from the receiver's silent payment address generated above.
@@ -196,7 +214,4 @@ Thats it! 🎊🎊🎊
196
214
 
197
215
  ### Contribute
198
216
 
199
- If you love what we do to progress privacy, [contribute](https://me-qr.com/text/vPod5qN0 "btc_addr") to further development
200
-
201
- <img src="./images/bitcoin.png" alt="btc_addr" style="display: inline-block; margin-right: 100px; margin-left: 70px;" width="200">
202
- <img src="./images/silent.png" alt="silent_addr" width="200" style="display: inline-block; margin-right: 10px;">
217
+ If you love what we do to progress privacy, [contribute](https://donate.shakesco.com/@shakesco.sns "shakesco_donate") to further development
@@ -10,6 +10,7 @@ const {
10
10
  decodeBech32,
11
11
  } = require("../utils/bech32");
12
12
  const Network = require("../utils/network");
13
+ const { generateLabel, tweakAdd } = require("../utils/label");
13
14
  const bip32 = BIP32Factory(tinysecp);
14
15
 
15
16
  const SCAN_PATH = "m/352'/1'/0'/1'/0";
@@ -190,6 +191,24 @@ class KeyGeneration extends SilentPaymentAddress {
190
191
  }
191
192
  );
192
193
  }
194
+
195
+ toLabeledSilentPaymentAddress(m) {
196
+ const label = generateLabel(m, this.b_scan);
197
+
198
+ const B_m = tweakAdd(
199
+ this.B_spend,
200
+ BigInt("0x" + Buffer.from(label).toString("hex"))
201
+ );
202
+
203
+ return new KeyGeneration({
204
+ b_scan: this.b_scan,
205
+ b_spend: this.b_spend,
206
+ B_scan: this.B_scan,
207
+ B_spend: B_m,
208
+ network: this.network,
209
+ version: this.version,
210
+ });
211
+ }
193
212
  }
194
213
 
195
214
  module.exports = { KeyGeneration, SilentPaymentDestination };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shakesco/silent",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Bitcoin Silent Payments",
5
5
  "main": "index.js",
6
6
  "author": "Shawn Kimtai",
@@ -16,7 +16,8 @@
16
16
  "dependencies": {
17
17
  "bip32": "^5.0.0-rc.0",
18
18
  "bip39": "^3.1.0",
19
- "elliptic": "^6.5.7",
19
+ "bn.js": "^5.2.1",
20
+ "elliptic": "6.6.0",
20
21
  "tiny-secp256k1": "^2.2.3"
21
22
  }
22
23
  }
package/utils/label.js ADDED
@@ -0,0 +1,99 @@
1
+ const crypto = require("crypto");
2
+ const EC = require("elliptic").ec;
3
+ const ec = new EC("secp256k1");
4
+ const BN = require("bn.js");
5
+
6
+ function privateKeyToBytes(privateKey) {
7
+ // Convert to hex string padded to 64 characters (32 bytes)
8
+ const hexString = privateKey.toString("hex").padStart(64, "0");
9
+
10
+ // Convert hex string to Uint8Array
11
+ return new Uint8Array(Buffer.from(hexString, "hex"));
12
+ }
13
+
14
+ function generateLabel(m, b_scan) {
15
+ return taggedHash(
16
+ concatBytes([privateKeyToBytes(b_scan), serUint32(m)]),
17
+ "BIP0352/Label"
18
+ );
19
+ }
20
+
21
+ function tweakAdd(publicKey, tweak) {
22
+ // Convert tweak to BN (Big Number) format
23
+ const tweakBN =
24
+ typeof tweak === "bigint" ? new BN(tweak.toString(16), 16) : new BN(tweak);
25
+
26
+ // Multiply generator point by tweak
27
+ const tweakMul = ec.g.mul(tweakBN);
28
+
29
+ // Add the original point and the tweaked generator point
30
+ return publicKey.add(tweakMul);
31
+ }
32
+
33
+ function serUint32(n) {
34
+ return toBytes(BigInt(n), 4);
35
+ }
36
+
37
+ function toBytes(val, length, order = "big") {
38
+ if (val === BigInt(0)) {
39
+ return new Array(length).fill(0);
40
+ }
41
+
42
+ const bigMaskEight = BigInt(0xff);
43
+
44
+ const byteList = new Array(length).fill(0);
45
+
46
+ for (let i = 0; i < length; i++) {
47
+ byteList[length - i - 1] = Number(val & bigMaskEight);
48
+ val = val >> BigInt(8);
49
+ }
50
+
51
+ if (order === "little") {
52
+ return byteList.reverse();
53
+ }
54
+
55
+ return byteList;
56
+ }
57
+
58
+ function taggedHash(data, tag) {
59
+ const tagHash = sha256Hash(new TextEncoder().encode(tag));
60
+ const concat = concatBytes([tagHash, tagHash, data]);
61
+ return sha256Hash(concat);
62
+ }
63
+
64
+ function sha256Hash(data) {
65
+ return crypto.createHash("sha256").update(data).digest();
66
+ }
67
+
68
+ function concatBytes(lists) {
69
+ // First make sure we're dealing with an array
70
+ if (!Array.isArray(lists)) {
71
+ throw new Error("Input must be an array of arrays");
72
+ }
73
+
74
+ // Filter out any undefined/null values first
75
+ const validLists = lists.filter((list) => list != null);
76
+
77
+ // Calculate total length
78
+ let totalLength = 0;
79
+ for (const list of validLists) {
80
+ totalLength += list.length;
81
+ }
82
+
83
+ // Create result array filled with zeros
84
+ const result = new Uint8Array(totalLength);
85
+
86
+ // Copy data
87
+ let offset = 0;
88
+ for (const list of validLists) {
89
+ result.set(list, offset);
90
+ offset += list.length;
91
+ }
92
+
93
+ return result;
94
+ }
95
+
96
+ module.exports = {
97
+ generateLabel,
98
+ tweakAdd,
99
+ };
Binary file
package/images/silent.png DELETED
Binary file