index.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /* Import core modules. */
  2. const crypto = require('crypto')
  3. const bigInt = require('big-integer')
  4. /* Initialize bit security. */
  5. const bitSecurity = 32
  6. /**
  7. * Big Math
  8. */
  9. const bigMath = {
  10. /**
  11. * Add
  12. */
  13. add(a, b, c) {
  14. if (c) {
  15. return bigInt(a.toString()).add(b.toString()).mod(c)
  16. }
  17. return bigInt(a.toString()).add(b.toString())
  18. },
  19. /**
  20. * Subtract
  21. */
  22. subtract(a, b, c) {
  23. if (c) {
  24. return bigInt(a.toString()).sub(b.toString()).mod(c)
  25. }
  26. return bigInt(a.toString()).sub(b.toString())
  27. },
  28. /**
  29. * Multiply
  30. */
  31. multiply(a, b, c) {
  32. if (c) {
  33. return bigInt(a.toString()).multiply(b.toString()).mod(c)
  34. }
  35. return bigInt(a.toString()).multiply(b.toString())
  36. },
  37. /**
  38. * Divide
  39. */
  40. divide(a, b, c) {
  41. if (c) {
  42. return bigInt(a.toString()).divide(b.toString()).mod(c)
  43. }
  44. return bigInt(a.toString()).divide(b.toString())
  45. },
  46. /**
  47. * Power
  48. */
  49. power(p, s, c) {
  50. if (c) {
  51. return bigInt(p.toString()).modPow(s, c)
  52. }
  53. return bigInt(p.toString()).pow(s)
  54. }
  55. }
  56. /**
  57. * Pedersen (Class)
  58. */
  59. class Pedersen {
  60. /**
  61. * Constructor
  62. */
  63. constructor(p, g, absctractMath = bigMath) {
  64. /* Set abstraction math. */
  65. this.absctractMath = absctractMath
  66. /* Set p. */
  67. this.p = bigInt(p, 16)
  68. /* Set g (Generator). */
  69. this.g = bigInt(g, 16)
  70. /* Calculate q. */
  71. // NOTE: Double `p`, then add `1`.
  72. this.q = this.absctractMath
  73. .multiply(this.p, 2)
  74. .add(1)
  75. }
  76. /**
  77. * New Offset
  78. */
  79. newOffset() {
  80. /* Initialize r value. */
  81. let r = bigInt.zero
  82. /* Loop. */
  83. // NOTE: r value MUST be greater than zero, but less than p.
  84. while (r.compare(0) !== 1 || r.compare(this.p) !== -1) {
  85. r = bigInt.fromArray([...crypto.randomBytes(bitSecurity)], 256)
  86. r = r.mod(this.p)
  87. }
  88. r = r.mod(this.p) // FIXME: Why do we need this??
  89. /* Return a padded 20-byte string. */
  90. return r.toString(16).padStart(40, '0')
  91. }
  92. /**
  93. * New Secret
  94. *
  95. * NOTE: This is an alias for newOffset.
  96. */
  97. newSecret() {
  98. return this.newOffset()
  99. }
  100. /**
  101. * Commit
  102. */
  103. commit(message, secret, r = this.newOffset()){
  104. /* Initialize r value. */
  105. // NOTE: This is a new secret / offset, set to base (16).
  106. r = bigInt(r, 16)
  107. /* Initialize m value. */
  108. let m = null
  109. /* Validate message. */
  110. if (bigInt.isInstance(message)) {
  111. /* Set m to base (10) value. */
  112. m = bigInt(message)
  113. } else {
  114. /* Set m to base (16) value. */
  115. m = bigInt(message, 16)
  116. }
  117. /* Generate h value. */
  118. const h = bigInt(this.g).modPow(bigInt(secret, 16), this.q)
  119. /* Generate c (Commitment) value. */
  120. const c = this.absctractMath.multiply(
  121. this.absctractMath.power(this.g, m, this.q),
  122. this.absctractMath.power(h, r, this.q),
  123. this.q
  124. )
  125. /* Return c (Commitment) values. */
  126. return [c.toString(16), r.toString(16)]
  127. }
  128. /**
  129. * Verify
  130. */
  131. verify(message, commitments, secret) {
  132. /* Combine all commitments. */
  133. const commitment = this.combine(commitments)
  134. /* Initialize r value. */
  135. const r = commitment[1]
  136. /* Generate c (Commitment). */
  137. // NOTE: We set the r value. */
  138. const c = this.commit(message.toString(16), secret, r)
  139. /* Return validation. */
  140. return c.toString() === commitment.toString()
  141. }
  142. /**
  143. * Combine
  144. */
  145. combine(commitments) {
  146. /* Initialize c (Commitment) value. */
  147. let c = bigInt.one
  148. /* Initialize r value. */
  149. let r = bigInt.zero
  150. /* Loop through commitment(s). */
  151. for (const commitment of commitments) {
  152. /* Multiply commitment values. */
  153. c = c.multiply(bigInt(commitment[0], 16)).mod(this.q)
  154. /* Add r values. */
  155. r = r.add(bigInt(commitment[1], 16))
  156. }
  157. /* Return combined c (Commitment). */
  158. return [c.toString(16), r.toString(16)]
  159. }
  160. }
  161. /* Export module. */
  162. module.exports = Pedersen