-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathvrf.mjs
129 lines (85 loc) · 3.43 KB
/
vrf.mjs
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import { bls12_381 } from "@noble/curves/bls12-381"
import { sha3_256, sha3_512 } from '@noble/hashes/sha3'
import { mapHashToElement } from "./random.mjs"
//////////////////////////////////////////////////
// Verifiable Random Functions (construction 1) //
//////////////////////////////////////////////////
// Reference: https://docs.harmony.one/home/developers/harmony-specifics/tools/harmony-vrf
export function generateVR(privateKey, message) {
const encodedMessage = new TextEncoder().encode(message)
const signature = bls12_381.sign(encodedMessage, privateKey)
const random = sha3_256(signature)
return { random, signature }
}
export function checkVR(random, signature, message, publicKey) {
// Checks if the random is a hash of the signature
const calculatedRandom = sha3_256(signature)
let resultRandom = (calculatedRandom !== random)
// Checks if the signature signs the message and verifies with the public key
const encodedMessage = new TextEncoder().encode(message)
let resultSignature = bls12_381.verify(signature, encodedMessage, publicKey)
return (resultRandom && resultSignature)
}
//////////////////////////////////////////////////
// Verifiable Random Functions (construction 2) //
//////////////////////////////////////////////////
// Reference: https://eprint.iacr.org/2017/099.pdf
export let field = bls12_381.fields.Fr
function hash3(points) {
let normalizedPoints = bls12_381.G1.ProjectivePoint.normalizeZ(points)
let normalizedPointArrays = normalizedPoints.map((p) => p.toRawBytes())
let hash = sha3_512(concatenateArrays(normalizedPointArrays))
return mapHashToElement(hash, field)
}
function concatenateArrays(arrays) {
let totalLength = arrays.reduce((acc, cur) => acc + cur.length, 0)
let result = new Uint8Array(totalLength)
let position = 0
for(let i = 0; i < arrays.length; i++) {
result.set(arrays[i], position)
position += arrays[i].length
}
return result
}
export function generateIntermediateAndProof(privateKey, encodedMessage) {
const G = bls12_381.G1.ProjectivePoint.BASE
const H = bls12_381.G1.hashToCurve(encodedMessage) // H_1
const x = bls12_381.G1.normPrivateKeyToScalar(privateKey)
const xG = G.multiply(x)
const xH = H.multiply(x)
const k = bls12_381.G1.normPrivateKeyToScalar(
bls12_381.utils.randomPrivateKey()
)
const kG = G.multiply(k)
const kH = H.multiply(k)
// H_3: $\ell$-bit hash function (we aim for $\ell$ bits of security)
const c = hash3([G, H, xG, xH, kG, kH])
const s = field.sub(k, field.mul(c, x))
return { intermediate: xH, proof: { c, s } }
}
export function generateFinal(intermediate) {
const cofactor = bls12_381.G1.CURVE.h
// H_2: $2\ell$-bit hash function (we aim for $\ell$ bits of security)
const final = sha3_512(intermediate.multiply(cofactor).toRawBytes()) // 512 bits
return final
}
export function generateFinalAndVerify(encodedMessage, publicKey, intermediate, proof) {
const final = generateFinal(intermediate)
const G = bls12_381.G1.ProjectivePoint.BASE
const H = bls12_381.G1.hashToCurve(encodedMessage)
const xG = bls12_381.G1.ProjectivePoint.fromAffine(
bls12_381.G1.CURVE.fromBytes(publicKey)
)
const sG = G.multiply(proof.s)
const xH = intermediate
const sH = H.multiply(proof.s)
const kG = xG
.multiply(proof.c)
.add(sG)
const kH = xH
.multiply(proof.c)
.add(sH)
// H_3: $\ell$-bit hash function (we aim for $\ell$ bits of security)
const c = hash3([G, H, xG, xH, kG, kH])
return { final, valid: (proof.c == c) }
}