-
Notifications
You must be signed in to change notification settings - Fork 1
/
keyAgreementCrypto.ts
115 lines (108 loc) · 3.95 KB
/
keyAgreementCrypto.ts
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
// Licensed to Inria Grand-Est / Loria under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. Inria Grand-Est / Loria licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
import { BN } from '../bn.js/bn'
import { env } from '../misc/env'
import { int8ArrayEqual } from './helper/cryptoHelper'
import { BNToIntArray, g, intArrayToBN, KDFDeriveKeyParams, KDFKeyParams, p, riSize } from './helper/keyAgreementCryptoHelper'
/**
* Prime number to use with the different modular operations.
*/
const red = BN.mont(p)
/**
* deriveKey derives a symmetric key given a shared secret.
* @param sharedSecret the shared secret computed with the key agreement protocol.
*/
export async function deriveKey(sharedSecret: Uint8Array): Promise<CryptoKey> {
const HKDFKey = await env.crypto.subtle.importKey(
KDFKeyParams.format,
sharedSecret,
KDFKeyParams.algorithm,
KDFKeyParams.extractable,
KDFKeyParams.keyUsages
)
return env.crypto.subtle.deriveKey(
KDFDeriveKeyParams.info,
HKDFKey,
KDFDeriveKeyParams.symmKeyParams,
KDFDeriveKeyParams.extractable,
KDFDeriveKeyParams.keyUsages
)
}
/**
* generateRi computes the secret value used by the protocol.
* @param ri the secret value generated by the user.
*/
export function generateRi(): BN {
return intArrayToBN(env.crypto.getRandomValues(new Uint8Array(riSize)) as Uint8Array)
}
/**
* computeZi computes the first value to broadcast to all users.
* @param ri the random number generated by the user.
*/
export function computeZi(ri: BN): Uint8Array {
const res = g
.toRed(red)
.redPow(ri)
.fromRed()
return BNToIntArray(res)
}
/**
* computeXi computes the second value to broadcast to all users once the zi from the left and right neighbor is received.
* @param ri the random number generated by the user.
* @param ziRight the computed zi by the 'left' neighbor (in a cycle)
* @param ziLeft the computed zi by the 'right' neighbor (in a cycle)
*/
export function computeXi(ri: BN, ziRight: Uint8Array, ziLeft: Uint8Array): Uint8Array {
const modInvM = new BN(ziLeft).toRed(red).redInvm()
const res = modInvM.redMul(new BN(ziRight).toRed(red)).redPow(ri)
return BNToIntArray(res.fromRed())
}
/**
* ComputeSki computes the shared secret.
* @param ri the random number generated by the user.
* @param xi the xi computed by the user.
* @param ziLeft the computed zi by the 'right' neighbor (in a cycle)
* @param xiList the list of all the xi computed by all the users.
*/
export function computeSharedSecret(ri: BN, xi: Uint8Array, ziLeft: Uint8Array, xiList: Uint8Array[]): Uint8Array {
const res = new BN(ziLeft).toRed(red).redPow(ri.muln(xiList.length))
const iInit = indexOf(xiList, xi)
const exponent = new BN(xiList.length - 1)
let xin
let ind: number
for (let i = 0; exponent.gtn(0); i++) {
ind = (iInit + i) % xiList.length
xin = new BN(xiList[ind]).toRed(red).redPow(exponent)
res.redIMul(xin)
exponent.isubn(1)
}
return BNToIntArray(res.fromRed())
}
/**
* indexOf returns the index of the xi in the given list.
* @param xiList the list of all the xi from the users.
* @param xi the xi computed by the user.
*/
function indexOf(xiList: Uint8Array[], xi: Uint8Array): number {
let indexOfXi = -1
xiList.forEach((element, index) => {
if (int8ArrayEqual(element, xi)) {
indexOfXi = index
}
})
return indexOfXi
}