arctic.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. use crate::lagrange::*;
  2. use crate::shine;
  3. use curve25519_dalek::ristretto::RistrettoPoint;
  4. use curve25519_dalek::scalar::Scalar;
  5. use sha2::Digest;
  6. use sha2::Sha256;
  7. pub use crate::lagrange::lagrange_polys;
  8. pub type PubKey = RistrettoPoint;
  9. pub struct SecKey {
  10. t: u32,
  11. k: u32,
  12. // This player's signature key share
  13. sk: Scalar,
  14. // This player's Shine key share
  15. shine_key: shine::PreprocKey,
  16. // The group public key
  17. pk: PubKey,
  18. }
  19. impl SecKey {
  20. pub fn delta(&self) -> usize {
  21. self.shine_key.delta()
  22. }
  23. }
  24. pub type R1Output = ([u8; 32], RistrettoPoint);
  25. pub type Signature = (RistrettoPoint, Scalar);
  26. // Generate Arctic keys using a trusted dealer. The output is the group
  27. // public key, a vector of each individual player's public key (unused
  28. // except in the robust Arctic case), and a vector of each individual
  29. // player's Arctic secret key.
  30. pub fn keygen(n: u32, t: u32) -> (PubKey, Vec<PubKey>, Vec<SecKey>) {
  31. assert!(t >= 1);
  32. assert!(n >= 2 * t - 1);
  33. let mut seckeys: Vec<SecKey> = Vec::new();
  34. // The Shine key shares
  35. let shinekeys = shine::Key::keygen(n, t);
  36. // The signature key shares
  37. let shamirpoly = ScalarPoly::rand((t as usize) - 1);
  38. let group_pubkey = shine::commit(&shamirpoly.coeffs[0]);
  39. let signkeys: Vec<Scalar> = (1..=n).map(|k| shamirpoly.eval(&Scalar::from(k))).collect();
  40. let player_pubkeys: Vec<PubKey> = signkeys.iter().map(shine::commit).collect();
  41. for k in 1..=n {
  42. seckeys.push(SecKey {
  43. t,
  44. k,
  45. sk: signkeys[(k - 1) as usize],
  46. shine_key: shine::PreprocKey::preproc(&shinekeys[(k as usize) - 1]),
  47. pk: group_pubkey,
  48. });
  49. }
  50. (group_pubkey, player_pubkeys, seckeys)
  51. }
  52. // The hash function used to generate the value y that's the input to
  53. // shine::gen.
  54. fn hash2(pk: &PubKey, msg: &[u8]) -> [u8; 32] {
  55. let mut hash = Sha256::new();
  56. hash.update(pk.compress().as_bytes());
  57. hash.update(msg);
  58. hash.finalize().into()
  59. }
  60. // The hash function that's used to generate the challenge c for the
  61. // Schnorr signature. This function has to match the one for the
  62. // Schnorr verification implementation you're interoperating with, and
  63. // will depend on what group you're operating over.
  64. fn hash3(combcomm: &RistrettoPoint, pk: &PubKey, msg: &[u8]) -> Scalar {
  65. let mut hash = Sha256::new();
  66. hash.update(combcomm.compress().as_bytes());
  67. hash.update(pk.compress().as_bytes());
  68. hash.update(msg);
  69. let mut hashval = [0u8; 32];
  70. hashval[0..32].copy_from_slice(&hash.finalize());
  71. Scalar::from_bytes_mod_order(hashval)
  72. }
  73. // The first round of the signature protocol.
  74. pub fn sign1(sk: &SecKey, coalition: &[u32], msg: &[u8]) -> R1Output {
  75. assert!(coalition.len() >= 2 * (sk.t as usize) - 1);
  76. let y = hash2(&sk.pk, msg);
  77. (y, sk.shine_key.gen(&y).1)
  78. }
  79. // The second round of the signature protocol. Note: it is vital that
  80. // the R1Output values received from all the parties' first round were
  81. // received over authenticated channels. If an adversary can forge
  82. // honest parties' round one messages, Arctic is _not_ secure.
  83. pub fn sign2_polys(
  84. pk: &PubKey,
  85. sk: &SecKey,
  86. coalition: &[u32],
  87. lag_polys: &[ScalarPoly],
  88. msg: &[u8],
  89. r1_outputs: &[R1Output],
  90. ) -> Option<Scalar> {
  91. // If the inputs are _malformed_, abort
  92. assert!(coalition.len() == lag_polys.len());
  93. assert!(coalition.len() == r1_outputs.len());
  94. assert!(coalition.len() >= 2 * (sk.t as usize) - 1);
  95. // Find my own entry in the coalition; abort if it's not there
  96. let kindex = coalition.iter().position(|&k| k == sk.k).unwrap();
  97. // If the inputs are just corrupt values from malicious other
  98. // parties, return None but don't crash
  99. let y = hash2(pk, msg);
  100. // Make sure all the parties are submitting commitments for the same
  101. // y (the same pk and msg).
  102. if r1_outputs.iter().any(|(yj, _)| yj != &y) {
  103. return None;
  104. }
  105. let (my_eval, my_commit) = sk.shine_key.gen(&y);
  106. assert!(r1_outputs[kindex].1 == my_commit);
  107. let commitments: Vec<RistrettoPoint> = r1_outputs
  108. .iter()
  109. .map(|(_, commitment)| *commitment)
  110. .collect();
  111. if !shine::verify_polys(sk.t, lag_polys, &commitments) {
  112. return None;
  113. }
  114. let combcomm = shine::agg_polys(sk.t, lag_polys, &commitments);
  115. let c = hash3(&combcomm, pk, msg);
  116. Some(my_eval + c * sk.sk)
  117. }
  118. pub fn sign2(
  119. pk: &PubKey,
  120. sk: &SecKey,
  121. coalition: &[u32],
  122. msg: &[u8],
  123. r1_outputs: &[R1Output],
  124. ) -> Option<Scalar> {
  125. let polys = lagrange_polys(coalition);
  126. sign2_polys(pk, sk, coalition, &polys, msg, r1_outputs)
  127. }
  128. pub fn combine_polys(
  129. pk: &PubKey,
  130. t: u32,
  131. coalition: &[u32],
  132. lag_polys: &[ScalarPoly],
  133. msg: &[u8],
  134. r1_outputs: &[R1Output],
  135. sigshares: &[Scalar],
  136. ) -> Option<Signature> {
  137. assert!(coalition.len() == lag_polys.len());
  138. assert!(coalition.len() == r1_outputs.len());
  139. assert!(coalition.len() == sigshares.len());
  140. assert!(coalition.len() >= 2 * (t as usize) - 1);
  141. let commitments: Vec<RistrettoPoint> = r1_outputs
  142. .iter()
  143. .map(|(_, commitment)| *commitment)
  144. .collect();
  145. let combcomm = shine::agg_polys(t, lag_polys, &commitments);
  146. let c = hash3(&combcomm, pk, msg);
  147. let z = interpolate_polys_0(lag_polys, sigshares);
  148. // Check the answer
  149. if shine::commit(&z) == combcomm + c * pk {
  150. return Some((combcomm, z));
  151. }
  152. None
  153. }
  154. pub fn combine(
  155. pk: &PubKey,
  156. t: u32,
  157. coalition: &[u32],
  158. msg: &[u8],
  159. r1_outputs: &[R1Output],
  160. sigshares: &[Scalar],
  161. ) -> Option<Signature> {
  162. let polys = lagrange_polys(coalition);
  163. combine_polys(pk, t, coalition, &polys, msg, r1_outputs, sigshares)
  164. }
  165. pub fn verify(pk: &PubKey, msg: &[u8], sig: &Signature) -> bool {
  166. let c = hash3(&sig.0, pk, msg);
  167. shine::commit(&sig.1) == sig.0 + c * pk
  168. }
  169. #[test]
  170. pub fn test_arctic_good() {
  171. let n = 7u32;
  172. let t = 4u32;
  173. let (pubkey, _, seckeys) = keygen(n, t);
  174. let coalition = (1..=n).collect::<Vec<u32>>();
  175. let msg = b"A message to be signed";
  176. let r1_outputs: Vec<R1Output> = seckeys
  177. .iter()
  178. .map(|key| sign1(key, &coalition, msg))
  179. .collect();
  180. let sigshares: Vec<Scalar> = seckeys
  181. .iter()
  182. .map(|key| sign2(&pubkey, key, &coalition, msg, &r1_outputs).unwrap())
  183. .collect();
  184. let sig = combine(&pubkey, t, &coalition, msg, &r1_outputs, &sigshares).unwrap();
  185. assert!(verify(&pubkey, msg, &sig));
  186. }
  187. #[test]
  188. #[should_panic]
  189. pub fn test_arctic_bad1() {
  190. let n = 7u32;
  191. let t = 4u32;
  192. let (pubkey, _, seckeys) = keygen(n, t);
  193. let coalition = (1..=n).collect::<Vec<u32>>();
  194. let msg = b"A message to be signed";
  195. let mut r1_outputs: Vec<R1Output> = seckeys
  196. .iter()
  197. .map(|key| sign1(key, &coalition, msg))
  198. .collect();
  199. // Modify player 1's commitment
  200. let v = r1_outputs[1].1;
  201. r1_outputs[0].1 += v;
  202. // Player 1 should abort because its own commit is no longer in the
  203. // list
  204. sign2(&pubkey, &seckeys[0], &coalition, msg, &r1_outputs);
  205. }
  206. #[test]
  207. pub fn test_arctic_bad2() {
  208. let n = 7u32;
  209. let t = 4u32;
  210. let (pubkey, _, seckeys) = keygen(n, t);
  211. let coalition = (1..=n).collect::<Vec<u32>>();
  212. let msg = b"A message to be signed";
  213. let mut r1_outputs: Vec<R1Output> = seckeys
  214. .iter()
  215. .map(|key| sign1(key, &coalition, msg))
  216. .collect();
  217. // Modify player 1's commitment
  218. let v = r1_outputs[1].1;
  219. r1_outputs[0].1 += v;
  220. // Player 2 should return None because the commitments are
  221. // inconsistent
  222. assert_eq!(
  223. sign2(&pubkey, &seckeys[1], &coalition, msg, &r1_outputs),
  224. None
  225. );
  226. }
  227. #[test]
  228. pub fn test_arctic_bad3() {
  229. let n = 7u32;
  230. let t = 4u32;
  231. let (pubkey, _, seckeys) = keygen(n, t);
  232. let coalition = (1..=n).collect::<Vec<u32>>();
  233. let msg = b"A message to be signed";
  234. let mut r1_outputs: Vec<R1Output> = seckeys
  235. .iter()
  236. .map(|key| sign1(key, &coalition, msg))
  237. .collect();
  238. // Modify player 1's y value
  239. r1_outputs[0].0[0] += 1;
  240. // Player 2 should return None because the y values are
  241. // inconsistent
  242. assert_eq!(
  243. sign2(&pubkey, &seckeys[1], &coalition, msg, &r1_outputs),
  244. None
  245. );
  246. }
  247. #[test]
  248. pub fn test_arctic_bad4() {
  249. let n = 7u32;
  250. let t = 4u32;
  251. let (pubkey, _, seckeys) = keygen(n, t);
  252. let coalition = (1..=n).collect::<Vec<u32>>();
  253. let msg = b"A message to be signed";
  254. let r1_outputs: Vec<R1Output> = seckeys
  255. .iter()
  256. .map(|key| sign1(key, &coalition, msg))
  257. .collect();
  258. // Use a different message in round 2
  259. let msg2 = b"A message to be signef";
  260. // Player 2 should return None because the y values are
  261. // inconsistent
  262. assert_eq!(
  263. sign2(&pubkey, &seckeys[1], &coalition, msg2, &r1_outputs),
  264. None
  265. );
  266. }
  267. #[test]
  268. pub fn test_arctic_bad5() {
  269. let n = 7u32;
  270. let t = 4u32;
  271. let (pubkey, _, seckeys) = keygen(n, t);
  272. let coalition = (1..=n).collect::<Vec<u32>>();
  273. let msg = b"A message to be signed";
  274. let r1_outputs: Vec<R1Output> = seckeys
  275. .iter()
  276. .map(|key| sign1(key, &coalition, msg))
  277. .collect();
  278. let mut sigshares: Vec<Scalar> = seckeys
  279. .iter()
  280. .map(|key| sign2(&pubkey, key, &coalition, msg, &r1_outputs).unwrap())
  281. .collect();
  282. // Modify player 0's signature share
  283. sigshares[0] += Scalar::one();
  284. // Combine should return None because the shares don't combine to a
  285. // valid signature
  286. assert_eq!(
  287. combine(&pubkey, t, &coalition, msg, &r1_outputs, &sigshares),
  288. None
  289. );
  290. }
  291. #[test]
  292. pub fn test_arctic_bad6() {
  293. let n = 7u32;
  294. let t = 4u32;
  295. let (pubkey, _, seckeys) = keygen(n, t);
  296. let coalition = (1..=n).collect::<Vec<u32>>();
  297. let msg = b"A message to be signed";
  298. let r1_outputs: Vec<R1Output> = seckeys
  299. .iter()
  300. .map(|key| sign1(key, &coalition, msg))
  301. .collect();
  302. let sigshares: Vec<Scalar> = seckeys
  303. .iter()
  304. .map(|key| sign2(&pubkey, key, &coalition, msg, &r1_outputs).unwrap())
  305. .collect();
  306. // Modify the message
  307. let msg2 = b"A message to be signef";
  308. assert_eq!(
  309. combine(&pubkey, t, &coalition, msg2, &r1_outputs, &sigshares),
  310. None
  311. );
  312. }