use bls12_381::{ G1Affine, G1Projective, Scalar }; pub const BLS_PUBKEY_SIZE: usize = 48; pub type BLSPubkey = [u8; BLS_PUBKEY_SIZE]; // Originally implemented in https://github.com/metacraft-labs/dvt-circuits/blob/master/crates/bls_utils/src/bls.rs #[guests_macro::proving_entrypoint] pub fn main( pks: Vec, target: String, ) -> bool { let pks: Vec = pks .iter().map(|pk| -> BLSPubkey { hex::decode(pk).unwrap().try_into().unwrap() }) .map(|pk| G1Affine::from_compressed(&pk).into_option().unwrap()).collect(); let id = bls_id_from_u32(1); let result = evaluate_polynomial(pks, id); hex::encode(result.to_compressed()) == target } pub fn bls_id_from_u32(id: u32) -> Scalar { let unwrapped_le: [u8; 4] = (id as u32).to_le_bytes(); let mut bytes = [0u8; 32]; bytes[..4].copy_from_slice(&unwrapped_le); Scalar::from_bytes(&bytes).unwrap() } // https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing // // In Shamir's secret sharing, a secret is encoded as a n-degree polynomial // F where the secret value is equal to F(0). Here, F(0) is provided as mask[0]. // // A key share is generated by evaluating the polynomial in the `id` point. // Later we can use at least N of these points to recover the original secret. // // Furthermore, if we sign some message M with at least K of the secret key // shares we can restore from them the signature of the same message signed // with original secret key. // // For a more gentle introductiont to Shamir's secret sharing, see also: // // https://github.com/dashpay/dips/blob/master/dip-0006/bls_m-of-n_threshold_scheme_and_dkg.md // https://medium.com/toruslabs/what-distributed-key-generation-is-866adc79620 pub fn evaluate_polynomial(cfs: Vec, x: Scalar) -> G1Affine { let cfst: Vec = cfs.iter().map(|c| G1Projective::from(c)).collect(); let count = cfst.len(); if count == 0 { return G1Affine::identity(); } else if count == 1 { return cfs[0]; } else { let mut y = cfst[count - 1]; for i in 2..(count + 1) { y = y * x + cfs[count - i]; } return G1Affine::from(y); } }