arctic.rs 9.8 KB

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